DeepResearch: a multi-agent research system
Give it a research question; nine cooperating agents plan sub-questions, search the web in parallel, cross-check every claim against at least two sources, and return a cited report with a confidence tag on each claim. It runs end to end on your own machine for $0.
Problem
- A single research job can run for minutes and make dozens of LLM calls, so it has to run in parallel and survive a worker dying halfway through.
- An agent that fails or finds nothing must not quietly ship an ungrounded report as if it were verified.
Approach
- LangGraph’s Send() API fans sub-questions out in parallel, with per-node Postgres checkpointing.
- Jobs run on Celery and RabbitMQ rather than FastAPI background tasks, which would tie up the API server and rule out horizontal scaling. With late acknowledgement, a crashed worker’s job is redelivered to another replica.
- The critic can send gaps back to the planner, bounded by a retry-depth limit so it can’t research forever.
- Ollama and DuckDuckGo are the defaults; every provider is swapped through .env and LiteLLM, so paid APIs are opt-in.
- The code executor runs Python in a sibling container with no network and a 512 MB memory limit, so a crashed or hostile script can’t touch the worker.
What failed, and the tradeoffs
- DuckDuckGo’s unauthenticated search rate-limits fast, so expect low-citation reports until a paid search key is set. The writer shows a “no sources retrieved” warning rather than hiding it.
- Small local models occasionally write informally even with prompt constraints. That is a capability ceiling, not a code bug.
- The worker’s Docker socket mount is a container-escape vector that this repo does not mitigate beyond network isolation. It is flagged rather than fixed, and a production deployment should put a scoped proxy in front.
- The Kubernetes manifests are structurally complete, but only the Docker Compose path has been run against a live stack.
- Crash recovery has no automated test.
- The integration suite is flaky on Windows when pytest runs on the host, because cached async clients can outlive a test’s event loop.
Result
- Every claim is tagged HIGH, MEDIUM, LOW or UNVERIFIED, and citations that can’t be reached are flagged rather than silently kept.
- If an agent crashes mid-run, the job continues and the final report carries a visible warning.
- A typical job costs $0 on the default local stack.
Stack
- Python
- LangGraph
- Celery
- RabbitMQ
- FastAPI
- Next.js
- Postgres / pgvector
- Docker
Links
Next: indic-reg-bench: a benchmark for Indian regulatory documents →