Why I built this
LLMs hallucinate when asked to research. They fabricate citations, synthesize facts from thin air, and present opinion as evidence. I wanted to build a system that produces verifiable, sourced technical reports, the kind you’d trust enough to base engineering decisions on.
The key insight was decomposition: instead of one massive prompt that reasons and searches and writes, split the problem across specialized agents. A Planner generates search queries. A Reflector optimizes them. A Researcher executes them in parallel. A Synthesizer writes with inline citations. And a Critic, the most important piece, checks the report against the sources for hallucination, with the authority to send it back for revision.
The ChromaDB episodic memory was an unexpected win. After running hundreds of research jobs, I noticed common queries across runs. By short-circuiting the pipeline when a cached report exists (similarity >92%), we cut API costs by ~70% on repeated topics, turning a cost center into an efficiency gain.
Architecture
User Prompt → Planner (DSPy ChainOfThought)
→ Reflector (Query Optimizer)
→ Memory Retriever (ChromaDB)
— Cache Hit → Critic
— Cache Miss → Researcher (Tavily API, async parallel)
→ Human Approval (Graph Interrupt)
— Approved / Feedback → Synthesizer (Gemini Streaming)
→ Critic (DSPy ChainOfThought)
— Approved → Memory Writer (ChromaDB Persist) → End
— Rejected → Guardrail (Revisions >= 3?)
— Yes → End
— No → back to Synthesizer
Key features
- Multi-agent orchestration — 8-node LangGraph state machine with conditional routing, cyclic revision loops, and native graph interrupts
- Programmatic prompts (DSPy) — Planner and Critic use DSPy ChainOfThought with typed Signatures, replacing brittle raw prompts with self-optimizing modules
- Episodic memory — ChromaDB vector store short-circuits repeated topics (>92% similarity), saving ~70% on API costs on common queries
- Human-in-the-loop — native LangGraph interrupts pause execution before synthesis; users review sources and can provide custom revision feedback
- Self-correction — DSPy Critic scores reports 1-10 and detects hallucination; routes back to synthesizer for revisions (max 3 loops)
- Async parallelization —
asyncio.gather()executes all Tavily searches concurrently (~3x latency improvement) - Full observability — Langfuse traces with custom scores (latency, tool success rate, critic revisions), structured logging with correlation IDs
- Four interfaces — CLI (
research-agent), Streamlit UI, FastAPI REST API (SSE streaming), MCP Server (Claude Desktop integration)
Quick start
git clone https://github.com/YOURNAME/research-agent.git
cd research-agent
# With Docker (recommended)
docker compose up
# Or locally
pip install -e .
cp .env.example .env # edit with your keys
research-agent research --topic "How does LangGraph state differ from standard memory?"
Visit http://localhost:8501 for the Streamlit UI, or http://localhost:8000/docs for Swagger API docs.
Environment variables
GEMINI_API_KEY=your_google_ai_studio_key
TAVILY_API_KEY=your_tavily_search_key
LANGFUSE_PUBLIC_KEY= # optional – observability
LANGFUSE_SECRET_KEY= # optional – observability
LANGFUSE_HOST=https://cloud.langfuse.com
LOG_LEVEL=INFO # DEBUG, INFO, WARNING, ERROR
Performance
| Metric | Value |
|---|---|
| Avg. end-to-end latency | ~8s |
| Avg. latency (cached) | ~3s |
| Tool success rate | >95% |
| API cost per run | ~$0.002 |
| Test coverage | 66/66 passing |
| Supported Python | 3.11, 3.12 |
Tech stack
| Category | Technology |
|---|---|
| Orchestration | LangGraph (state machine, checkpointing, interrupts) |
| LLM framework | LangChain + DSPy |
| LLM provider | Gemini 3.1 Flash Lite Preview (OpenAI-compatible API) |
| Web search | Tavily (async parallel) |
| Vector memory | ChromaDB + SentenceTransformers (all-MiniLM-L6-v2) |
| Observability | Langfuse (traces, scores, dashboard) |
| Backend | FastAPI + SSE streaming |
| Frontend | Streamlit (3-phase UI) |
| Infrastructure | Docker Compose, Render, GitHub Actions |
| Code quality | ruff, mypy, pre-commit, pytest (66 tests) |
Architecture decisions
Detailed, RFC-style Architecture Decision Records covering all major technology choices live in docs/adr/.
License
MIT