Deep Research Agent
Design an agent that decomposes complex queries into sub-questions, searches the web in parallel, and produces faithfully cited synthesis reports.
Last updated: September 2026
An agent that takes an open-ended query, decomposes it into sub-questions, searches and reads many web sources in parallel, and produces a faithfully cited synthesis report. The core design principle is plan before searching - decomposition produces better, targeted retrieval than one big search. Every claim must trace to a retrieved passage; acknowledge gaps instead of filling them with hallucination.
“Plan before searching - decomposition produces better, targeted retrieval than one big search. Evidence over generation - every claim must trace to a retrieved passage. Acknowledge gaps; never fill with hallucination. Parallelism for latency - sub-questions run concurrently. Bottleneck is final synthesis, not retrieval.”
Clarifying Questions (Ask These First ~5 min)
| Question | Why it matters |
|---|---|
| General web or domain-specific? (papers, legal, finance) | Drives source selection + model choice |
| Latency budget - 30s or minutes acceptable? | Sync vs. async pipeline |
| Citation fidelity - verbatim quotes or paraphrase ok? | Grounding verification strictness |
| Single user or millions concurrent? | Caching, rate limiting, infrastructure |
| Every claim must cite a source, or synthesis ok? | Hallucination guardrail design |
| Output format - report, conversational, JSON? | Synthesis prompt design |
| Cost-per-query ceiling? | How many sources, how many LLM calls |
Architecture (Draw This)
User Query
→ [1] Planner LLM (decompose into 3-8 sub-questions)
→ [2] Parallel Fan-out (each sub-question runs independently)
↓ per sub-question:
→ [3] Search APIs (Google/Bing/Brave → top-K URLs)
→ [4] Fetch + Extract (HTML → clean text → 512-token chunks)
→ [5] Embed + Re-rank (vector similarity → cross-encoder re-rank)
→ [6] Reader LLM (extract claims + quotes + source URLs)
↑ ReAct loop (max 2-3 iterations if more evidence needed)
→ [7] Synthesis LLM (merge all evidence → structured report with [1][2] citations)
→ [8] Grounding Verifier (LLM-as-judge: does passage support this claim?)
Final Report + grounding scoreKey Components (30-second pitch each)
- 1Planner LLM - LLM decomposes query into 3-8 targeted sub-questions as structured JSON. Acts as a planner, not a researcher yet. Example: 'How has the EU AI Act impacted foundation model companies?' → 4 specific sub-questions on requirements, classification, compliance steps, and criticism.
- 2Parallel Fan-out - Each sub-question = independent research unit with its own mini-pipeline. Run all concurrently (Celery + Redis / Cloud Tasks). Track state: PENDING → SEARCHING → READING → DONE. Failed sub-question → mark LOW_CONFIDENCE, don't block entire report.
- 3Search & Retrieval - 1-3 search queries per sub-question (LLM generates query strings). Retrieve top 5-10 URLs. Deduplicate by URL + domain (avoid one outlet dominating). Source trust scoring: deprioritize known-misinformation domains. Cache results with 1hr TTL.
- 4Fetch + Extract - Headless fetcher for JS-rendered pages (Playwright / Firecrawl / Jina AI Reader). Strip boilerplate (Mozilla Readability / Trafilatura). Chunk to ~512 tokens with 50-token overlap. Metadata per chunk: { source_url, title, publish_date }.
- 5Reader LLM + ReAct Loop - Prompt: 'Extract all claims relevant to [sub-question]. For each claim, quote the exact supporting text and include the source URL.' Output: structured { claim, supporting_quote, source_url } list. ReAct: cap at 2-3 iterations to bound cost.
- 6Citation Grounding Verification - LLM-as-judge per citation: 'Does this passage support this claim? YES/NO + reason.' Use a different model than the one that wrote the report. Remove failed citations. Output a grounding score (% verified claims). Target: > 90% for research-grade tool.
Caching Strategy (3 Levels)
| Level | TTL | Why |
|---|---|---|
| Search results | 1 hr | Same query from different users |
| Page content | 24 hr | Page unlikely to change that fast |
| Embeddings | 7 days | Expensive to recompute |
3 Biggest Risks
- 1Cost per query - LLM calls + search API + compute stack up fast. Mitigated by caching at 3 levels + tiered query plans (quick 3-source vs. deep 20-source report).
- 2Source quality - Synthesis is only as good as retrieved web content. Mitigated by source trust scoring + grounding verification that removes unsupported claims.
- 3Latency - Deep research takes time by nature. Set user expectations upfront; stream report while verification runs in background. Parallelism is the main lever.
Google Stack: Gemini Pro (planner + reader LLM) → Gemini 1.5 Pro (synthesis, long-context) → Google Custom Search API → Vertex AI Vector Search (session chunk store) → text-embedding-004 (embeddings) → Cloud Tasks (parallel fan-out) → BigQuery (grounding audit log)
Azure Stack: Azure AI Foundry Agent Service + Deep Research tool (native multi-step research, preview 2026) → Grounding with Bing Search (web retrieval, curated real-time data) → Azure AI Search (hybrid BM25 + vector, corpus store) → Azure OpenAI GPT-4o (planner + reader + synthesis) → Azure Container Apps (parallel fan-out, serverless) → Azure Cache for Redis (3-level caching) → Azure Monitor (grounding audit log)
AWS Stack: Amazon Bedrock AgentCore (orchestration) → Amazon Nova Pro / Claude 3.5 (planner + reader) → Amazon Nova Premier (long-context synthesis) → Tavily / Brave Search API (web search, no native Bing equivalent) → OpenSearch Serverless (session chunk store) → Amazon Titan Text Embeddings v2 (embeddings) → AWS Step Functions + Lambda (parallel fan-out) → DynamoDB (cache + grounding audit)
Other Options: LangChain + Tavily Search + OpenAI GPT-4o (open-source orchestration, most flexible) | CrewAI + Perplexity API (agent framework with built-in web search) | Perplexity Deep Research API (managed, fastest to integrate but least customizable)
Frequently asked questions
How do you handle conflicting information across sources?
Synthesis prompt explicitly asks the model to surface disagreements with attribution. Never silently pick one source over another.
No relevant content found for a sub-question?
Evidence list is empty → synthesis prompt instructed to say 'no sources found' for that aspect, not hallucinate. Section flagged as LOW_CONFIDENCE.
Why re-ranker on top of embedding similarity?
Embeddings encode aggregate semantic proximity. Cross-encoder sees the exact (query, passage) pair - catches fine-grained relevance, especially for nuanced sub-questions where similar-sounding chunks differ in meaning.
Paywalled sites or scraper blocks?
Gracefully degrade - use search snippet instead of full page. Flag source as PARTIAL in citation metadata.
Could the verification LLM hallucinate a YES?
Known limitation. Mitigations: use a different model than the one that wrote the report, force structured output with a required quote, audit-sample verification calls.
10,000 queries per minute - how does it scale?
Move from ephemeral in-memory FAISS to shared session store (Redis + Vertex AI Vector Search). Query-level cache to detect near-duplicate queries and serve cached reports.
How do you prevent this from generating misinformation at scale?
Source trust scoring + rate limiting per user + output watermarking + log all synthesis calls. Citation grounding requirement makes fabrication harder - every claim must trace to a real URL.