Overview
You type a research question and a list of companies, and seven LangGraph agents turn it into a competitive report with charts. One agent plans the research, two gather evidence at the same time, one analyses it, one fact checks the analysis, and two more write the report and build the charts at the same time. The browser shows each agent's status live while the run is going.
I built it to see how far a multi-agent workflow can go on free infrastructure, and to find out where the pieces actually fail. A full run takes a few minutes.
How the Agents Fit Together
1. Coordinator writes a research plan: objectives, search keywords per company, which financial angles to cover and which comparisons to make. Every later agent reads that plan and adapts to it.
2. Web Research and Financial Intelligence run in parallel. Web Research searches the web and also calls the API of my Enterprise RAG project as a tool. Financial Intelligence looks for funding, revenue and growth.
3. Data Analyst merges both sets of findings into a SWOT analysis, a feature comparison and a positioning summary.
4. Fact Checker reviews the analysis and flags claims it cannot support. If the report contains words like "unverified" or "could not verify", the run pauses for one human approval step: continue or stop, with a 300 second timeout. If nobody answers, the run continues.
5. Content Synthesizer and Data Visualization run in parallel. One writes the executive summary and the detailed report, the other produces Chart.js specifications for bar, line, pie and doughnut charts.
The reports can be exported as PDF, Markdown or JSON.
What I Measured
I did not benchmark the parallel stages against a sequential run, so the page makes no speedup claim. What I did check, by driving the deployed app in a browser while it was up, is the behaviour. A few seconds after Start Research, the Coordinator shows Completed, Web Research and Financial Intelligence both show Running, and the other four agents show Queued. That is the two-stage fan-out doing what the graph says.
The measurement that did matter was how the system behaves under free-tier limits. Four runs in about twenty minutes used up the free Groq quota, and the agents started failing on screen with a rate limit message. That led to the retry design described below.
What Broke
Groq retired the model I had named in the code. The service named the model as a string in several places. The API key stayed valid and the client still started, so every call simply failed while the app looked healthy. The same retirement broke my Enterprise RAG service on the same day. The model name is now a setting with an environment override, which means the next retirement is a config change instead of a code search.
Free-tier rate limits. Groq meters each model per minute and per day, so waiting does not always help. Each agent now retries up to five times. A rate limit error is read for the wait time the provider reports, up to 30 seconds. If a model is rate limited, the agent moves to the next model in a fallback list, because another model is a separate quota. Other errors back off exponentially. If a search provider fails, the search tool falls back from Tavily to DuckDuckGo.
Parallel agents writing the same state. When two LangGraph nodes run at once, they must not overwrite each other's fields. List fields such as research findings, cost tracking and fact check results accumulate with operator.add. The agents that run in parallel write to different fields, so the merge is safe. I had to design the state schema around that from the start.
Design Decisions
A plan every agent uses, not dynamic routing. My first idea was to let the Coordinator decide which agents run for each query. Running all seven every time, with the Coordinator's plan steering each one, turned out to be more predictable, and the user can see the plan up front.
Token counting with tiktoken. The agents count tokens with tiktoken instead of estimating from characters, so context truncation and the per-agent cost tracking use the tokenizer that fits the model.
Caching and rate limiting. Search results are cached for one hour to protect the Tavily quota, in Redis when it is configured and in memory otherwise (the deployed copy ran on the in-memory cache), and the research endpoint is limited to 5 requests per minute.
Composition with the RAG project. The Web Research agent queries the Enterprise RAG API as a tool, so the two projects work together.
What I Learned
I chose a fixed workflow with one shared plan over letting a model pick the path, because a fixed graph is easier to debug and easier to pause at a human approval step. I did not measure it against dynamic routing.
Parallel state needs a schema designed for it. Either a field accumulates or exactly one agent writes it.
Named vendor models are a dependency like any other. Putting the model name in one setting, with a fallback list behind it, costs almost nothing.
Tech Stack
Backend: FastAPI, LangGraph, Ollama (local), Groq (deployed) Search: Tavily API, DuckDuckGo Caching: Redis Cloud Frontend: Next.js 16, TypeScript, Tailwind CSS, Chart.js, jsPDF Real-Time: WebSocket Deployment: Built for free tiers (Render, Vercel, Groq, Redis Cloud); the hosted copy is offline