Skip to content

Repository files navigation

Deep Research Agent

A multi-agent deep research system built on LangGraph. Give it a question; it plans an investigation, runs several researcher agents in parallel across the web and social media, criticises its own evidence, and writes a cited report.

It is built to behave like a careful researcher rather than a search wrapper: it follows links to primary sources, notices when its sources disagree, and tells you what it could not establish.


What it does

"Is Dune: Part Three any good, and what do people actually think of it?"

  -> objective, time horizon and success criteria extracted
  -> 5 sub-questions planned across web, news and social channels
  -> 4 researcher agents dispatched in parallel
  -> 61 sources retrieved, 38 pages scraped, Reddit and YouTube sampled
  -> reviewer: "needs_more - critic consensus covered, audience split not quantified"
  -> 2 follow-up sub-questions dispatched
  -> reviewer: "sufficient, 84/100"
  -> 1,900-word report, every claim carrying a verified citation

Why it is built this way

Parallel researchers, not one agent doing everything. A single ReAct agent working through a large question serially is slow and its context degrades as unrelated results pile up. The planner splits the brief into independent sub-questions, each researched by its own agent with its own message history. They run concurrently and their findings are merged afterwards.

Citations are mechanically verified, not trusted. Every tool result registers what it retrieved in a run-scoped evidence store and hands the model a stable identifier such as [S14]. The model cites those identifiers; a verification pass then checks each one against the store and strips anything invented. The reference list is built from the store, not from the model's output, so every link in a finished report points at a page the system actually fetched.

An adversarial review gate. After research, a reviewer grades the evidence against the brief's success criteria and against statistics the findings alone would hide, such as how many "independent" sources resolve to one domain. If it finds actionable gaps, a targeted follow-up pass runs. Three separate conditions stop the loop so it cannot spin.

Honest degradation. Where a channel is unavailable or running on a weaker fallback, the tool result is labelled DEGRADED SOURCE, the agent is instructed not to make volume claims from it, and the limitation reaches the report. A run never quietly pretends to have social coverage it does not have.

Architecture

START
  |
scope                normalise the request into an explicit brief
  |
plan                 decompose into independent sub-questions
  |
dispatch --Send--> researcher x N        parallel ReAct agents
  |                      |
  |                 aggregate            merge, compress, dedupe
  |                      |
  |                   review             adversarial quality gate
  |                   /      \
  +--- replan <-- needs_more  sufficient --> synthesise
                                                 |
                                          verify_citations
                                                 |
                                                END

Full walkthrough in docs/CODE_FLOW.md; design rationale and the alternatives that were rejected in docs/ARCHITECTURE.md.

Quick start

git clone <your-repo> && cd Deep-Research-Agent

uv sync                       # or: pip install -r requirements.txt
uv run playwright install chromium

cp .env.example .env          # add one model key and one search key

Minimum viable .env:

OPENAI_API_KEY=sk-...
TAVILY_API_KEY=tvly-...

Then:

# One-off, streamed to the terminal
uv run deep-research "how are people receiving the new Dune film"

# Or edit the variables at the top of run_research.py and run it
uv run python run_research.py

# Or serve it
uv run uvicorn deep_research.api:app --port 8000

Reports are written to reports/ as Markdown. Full setup, including every optional channel, is in docs/SETUP.md.

Channels

Channel Requirement Without it
Web search Tavily, Serper, Brave or SerpAPI key Falls back to DuckDuckGo: keyless, rate limited, weaker
Page scraping playwright install chromium Static-only; JavaScript sites fail
Reddit Free script app credentials Public JSON, no comment trees, easily rate limited
X (Twitter) X_BEARER_TOKEN, pay-per-use Site-restricted web search, no engagement metrics
YouTube Free Data API v3 key Channel unavailable
Instagram Opt-in, real account, ban risk Web-search fallback, no post counts

Check what is actually live at any time:

curl localhost:8000/health

A note on the social landscape, since it changed recently and the code reflects that: X discontinued its free tier in February 2026 and moved new developers to pay-per-use credits, with full-archive search now Enterprise-only. Instagram's Graph API has no public hashtag-search endpoint at all. Reddit is the strongest free opinion source and the system is tuned to lean on it. See docs/TOOLS.md for the detail, including the ban risk on Instagram's private API.

Configuration

Everything lives in .env and is grouped into five typed settings classes in src/deep_research/config/settings.py. The knobs that change behaviour most:

MAX_RESEARCH_ITERATIONS=3          # review -> replan cycles
MAX_PARALLEL_RESEARCHERS=4         # concurrent researcher agents
MAX_TOOL_CALLS_PER_RESEARCHER=14   # budget per sub-question

Models are set per role, so a strong model plans, reviews and writes while a fast one does the high-volume tool calling:

PLANNER_MODEL=google:gemini-2.5-pro
RESEARCHER_MODEL=openai:gpt-4.1-mini
WRITER_MODEL=google:gemini-2.5-pro

Any provider init_chat_model supports works: openai:, anthropic:, google:, groq:.

Cost and time

A typical run is 3 to 8 minutes and 150k to 400k tokens. The researcher model dominates token spend, which is why it is configured separately. To run cheaper, lower MAX_PARALLEL_RESEARCHERS and MAX_TOOL_CALLS_PER_RESEARCHER; to run better, raise MAX_RESEARCH_ITERATIONS.

Tests

uv run pytest              # 55 tests, no network or API keys required

They cover the deterministic machinery: URL canonicalisation, source deduplication, citation verification, state reducers, fan-out and review routing. These are the places where a silent bug produces a report that looks right and is wrong.

Project layout

src/deep_research/
  config/       settings, prompts, logging
  evidence/     the citation-integrity layer
  graph/
    builder.py  graph assembly and Send fan-out
    nodes/      scope, planner, researcher, aggregator, reviewer, writer
  tools/
    web_search.py   provider chain: Tavily, Serper, Brave, SerpAPI, DuckDuckGo
    scraper.py      static fast path, Playwright escalation, robots, cache
    social/         reddit, x_twitter, youtube, instagram
    definitions.py  the LangChain tools the agents see
  runtime.py    run and stream entry points
  api.py        FastAPI with SSE
  cli.py
docs/           architecture, code flow, setup, tools
tests/

Known limits

  • Sequential-dependency questions ("find X, then use X to find Y") are handled poorly, because sub-questions are researched in parallel and cannot see each other's results. The follow-up iteration partially compensates.
  • Paywalled sources are not bypassed. They are recorded as inaccessible.
  • Non-English sources are retrieved but not translated.
  • Instagram is effectively an honest stub unless you accept the private-API ban risk.

Licence

MIT.

About

Multi-agent deep research system built on LangGraph. Plans, researches in parallel across web and social media, self-critiques, and writes cited reports.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages