Multi-agent research system that runs slow, iterative, critique-driven research. Decomposes problems into tasks, executes them with web search and code tools, synthesizes outputs, evaluates quality, and iterates until the answer is strong enough.
Different from Perplexity/ChatGPT: Built for depth over speed. Uses time budgets, adversarial evaluation, and multiple iterations to produce evidence-backed research reports.
In plain English: You ask a research question. Slowly goes down the tree (decompose → tasks → sub-tasks → deeper), then bubbles back up (all outputs merge into a single synthesis). It repeats until the answer is good enough.
"Best investors for voice AI?"
│
▼ go down
┌─────────────────────┐
│ Decompose │ ← Orchestrator
└─────────────────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
"Top VCs?" "What sectors?" "Example deals?"
│ │ │
│ ┌─────┴─────┐ │
│ ▼ ▼ │ go deeper
│ "Typical "Check size" │
│ sectors" │
└──────────┬───────────────┘
│
leaf outputs
│
▲ bubble up
│
┌─────────┴─────────┐
│ Synthesize │ ← merge all outputs
└─────────┬─────────┘
│
▼
Final report
│
▼
Evaluate → iterate or done
The main flow is a state graph that runs one iteration at a time, conditionally looping until done:
┌──────────────────────────┐
│ │
▼ │
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐
│ decompose │──▶│ execute │──▶│synthesize│──▶│ evaluate │────▶│ iterate │
└──────────┘ └──────────┘ └──────────┘ └──────────┘ └───────────┘
▲ │ │ │ │
│ │ │ │ │
│ │ │ │ (continue?) │
│ │ │ ▼ │
│ │ │ ┌──────────┐ │
│ │ │ │finalize │ │
│ │ │ └────┬─────┘ │
│ │ │ │ │
└────────────────┴────────────┴──────────────┴──────────────────┘
critique feeds back into next iteration
- decompose – Orchestrator breaks the problem (and prior critique) into tasks
- execute – Runs the task tree (see below); produces outputs
- synthesize – Merges outputs into one report
- evaluate – Scores quality, produces critique; decides: iterate or finalize
- iterate – Increment iteration, loop back to decompose
- finalize – Produce final synthesis, end
Inside each execution step, tasks form a dynamic tree. Here’s the idea in plain terms:
Example: "Who are the best investors for voice AI startups?"
YOUR QUESTION
│
▼ go down
┌────────────────┼────────────────┐
▼ ▼ ▼
"Top 5 VCs?" "What do they "Example deals?"
invest in?"
│ │ │
│ ┌────┴────┐ │
│ ▼ ▼ │ go deeper
│ "Typical "Check sizes" │
│ sectors" │
└────────────┼─────────────────────┘
│
leaf outputs
│
▲ bubble up
│
All answers merged
│
▼
One research report
- Step 1: Orchestrator breaks the question into 3–10 sub-questions.
- Step 2: Workers/Research agents answer each (web search, code, etc.).
- Step 3: If an answer suggests new questions (“What sectors?”), those become child tasks.
- Step 4: All task outputs bubble back up and merge into one synthesis.
Technical details:
- Root tasks – Orchestrator produces top-level tasks (depth 1)
- Child tasks – If a task’s output has
open_questions, those become child tasks (depth 2, 3, …) - Parallel execution – Tasks run in waves; a semaphore limits concurrency
- Expansion limits – Tree stops when:
max_task_depth,max_total_tasks, time budget, or wrap-up buffer is hit
- Orchestrator – Breaks the problem into parallel tasks (research / worker)
- Workers & Research agents – Use tools: web search, fetch page, run_command, read/write/search_replace files
- Synthesizer – Merges outputs into coherent reports
- Evaluator – Scores quality, finds weaknesses, drives iteration
- LangGraph – Coordinates the flow
- Python 3.10+
- Ollama (local) or Groq API key
- Optional:
TAVILY_API_KEYfor better search (falls back to DuckDuckGo)
pip install -r requirements.txt
cp .env.example .env
# Edit .env with your configFor local runs, ensure Ollama is running and pull a model:
ollama pull qwen2.5:7bpython main.py "Your research question here."Options:
| Flag | Description |
|---|---|
--backend ollama | groq |
LLM backend |
--model MODEL |
Override primary model |
--hours N |
Time budget in hours |
--iterations N |
Max eval iterations |
--runs-dir DIR |
Output directory (default: runs) |
--quiet |
Less console output |
Examples:
# Local Ollama (default)
python main.py "Best investors for voice AI startups - names, contacts, funds."
# Groq backend
python main.py "Market research: who buys deep research reports?" --backend groq
# Shorter run
python main.py "Quick overview of X" --hours 1 --iterations 2runs/{run_id}_output.md– Final reportruns/{run_id}.jsonl– Event logruns/{run_id}_it{N}_synthesis.md– Per-iteration synthesis
See .env.example. Key vars:
ACTIVE_BACKEND–ollamaorgroqPRIMARY_MODEL– e.g.qwen2.5:7b(Ollama) orllama-3.3-70b-versatile(Groq)TAVILY_API_KEY– Optional; improves search qualityTIME_BUDGET_MINUTES– Default 480 (8 hours)MAX_PARALLEL_AGENTS– 1 = serial (safest for Ollama), increase for Groq
MIT