Open Source AI Agents
Last month I needed to pull a list of LinkedIn profiles, enrich each with company size and tech stack, then fire off personalized cold emails—all without hiring a virtual assistant. I tried a few no‑code wrappers, but they kept breaking when the API returned unexpected JSON. After a day of frustration I turned to an open source AI agent framework and wired together a scraper, a data enricher, and an email composer in under four hours.
What you’ll walk away with is a working agent that can run on a cheap VPS, repeat the workflow on a schedule, and cost you only the price of the API calls you actually make. No fluff, just the pieces that matter.
It worked on the first try.
What most guides get wrong about agent memory
Most tutorials treat memory as an afterthought. They show you how to call a model once, then pretend the conversation never happened. In reality, an agent that forgets the previous step will keep re‑asking the same question or lose the context needed to format an email correctly.
What you actually need is a short‑term store that lives for the lifetime of a run and a long‑term store that persists across runs. The long‑term store can be as simple as a JSON file on disk; the short‑term store is just a list of messages you pass to each model call.
If you skip this, you’ll see the agent loop: it scrapes a profile, tries to enrich, fails to find the company size, then starts over because the prompt still says “find the company size”.
How do you keep the agent from looping forever?
Loops happen when the agent has no clear exit condition. You must give it a way to detect success and a way to detect failure after a limited number of retries.
One pattern that works well is to add a “step counter” to the state. Each time the agent finishes a subtask, increment the counter. If the counter exceeds a preset limit—say five steps for a single lead—force the agent to output a failure flag and move on to the next lead.
Another guardrail is to ask the model to explicitly state whether it succeeded. Prompt it with: “Reply with JSON that contains {“done”: true, “data”: …} or {“done”: false, “reason”: …}”. Then your code can check the “done” field before proceeding.
These two tricks cut the runaway loops I saw in early prototypes from dozens of iterations to a clean finish.
A concrete named example: scraping LinkedIn with crewAI
Here’s the exact flow I used, with the tools and costs I actually paid.
- Install crewAI (first mention, so bold) and its dependencies:
pip install crewai. - Create a folder called
lead_agentand add a fileconfig.yamlthat defines three roles: scraper, enricher, Writer.com. - Scraper role prompt: “You are a LinkedIn scraper. Given a search URL, return a JSON array of profile objects with fields: name, headline, profile_url.”
- Enricher role prompt: “You are a data enricher. Take a profile object, call the Clearbit API (or any free alternative) to add company_size and tech_stack. Return the enriched object.”
- Writer role prompt: “You are a cold‑email writer. Using the enriched profile, produce a short, personalized email that mentions one detail from the tech stack.”
- Define a workflow that runs the scraper, then for each profile runs the enricher, then the writer, and finally writes the output to a CSV.
- Set the step counter to 5 and the “done” check as described above.
- Run the agent with:
python run_agent.py --search-url "https://www.linkedin.com/search/results/people/?keywords=founder".
Cost breakdown: The LinkedIn scrape uses the free public search (no API key). Clearbit’s free tier gives 100 requests per month; I stayed under that. The only paid piece was the LLM calls. Using GPT‑4o via the OpenAI API at $0.06 per 1k tokens, each lead cost about $0.008 (roughly 130 tokens for the three calls). For a batch of 500 leads the total came to $4.00.
I think $0.008 per lead is a fair price for the automation you get—especially when a virtual assistant would charge $3‑$5 per lead for the same work.
