Skip to content
Ashish.
All posts
Diagram of a multi-agent deep research architecture showing Planner, Researcher, and Synthesizer components.
6 min readDevelopmentML Engineers, DevelopersFeatured#deep research#research agent#multi agent#synthesis#citations#ai agents#llm

Building a Deep Research Agent: Multi-Agent Guide

A technical walkthrough for ML engineers on constructing a multi-agent research system that handles synthesis and citations.

By Ashish Kumar

Building a Deep Research Agent

Most LLM applications fail at research tasks not because the model lacks knowledge, but because the architecture cannot manage the complexity of multi-step reasoning and source verification. A "Deep Research" agent is not a single prompt; it is a stateful, multi-agent system that decomposes complex questions, retrieves evidence, and synthesizes answers with strict citation integrity. This walkthrough details the mechanical construction of such a system, focusing on the data flow between ai agents and the mechanisms that prevent hallucination. By treating this as an orchestration of specialized ai agents, we can build a robust research agent that handles the nuances of professional inquiry without human intervention.

The Multi-Agent Architecture

The core insight is decoupling. A monolithic RAG pipeline attempts to retrieve, read, and write in one pass. This fails for deep research because the context window becomes overloaded with irrelevant text, and the model loses track of which claim came from which source. We instead use a directed graph of specialized llm agents.

  1. The Planner: Decomposes a user’s high-level question into sub-queries. It maintains the global state of what has been answered and what remains unknown.
  2. The Researcher: Executes the sub-queries using hybrid search (vector + keyword). It extracts raw text chunks and preserves their metadata (URL, title, date) for citation.
  3. The Synthesizer: Takes the collected evidence and writes the final report. It is constrained by a strict schema that requires every claim to be linked to a specific evidence chunk.

This separation ensures that the Researcher focuses on recall (getting the right text) while the Synthesizer focuses on precision (correctly attributing the text). The research agent architecture allows for modular scaling, where each component can be optimized independently. This multi agent synthesis approach ensures that the final output is not just a collection of facts, but a coherent narrative derived from verified sources.

Technical diagram showing a directed graph with three nodes : Planner, Researcher, and Synthesizer. Arrows show data flow from Planner to Researcher, then to Synthesizer, with a feedback loop from Synthesizer back to Planner. Clean, minimalist style, blue and grey color palett…

The Retrieval Mechanism

The Researcher agent is the engine of data ingestion. It does not simply return text; it returns structured evidence objects. To achieve high recall, we use hybrid search. Dense vectors capture semantic meaning (e.g., "quantum entanglement"), while sparse BM25 keywords capture exact terms (e.g., "Bell's Theorem"). As noted in information retrieval research, combining dense and sparse retrieval methods significantly improves recall over either method alone.

The key technical detail here is metadata preservation. When the Researcher retrieves a chunk, it must attach the source identifier to the content. This is not optional; it is the foundation of citation management. By automating this process, the system enables automated research workflows that can handle thousands of queries without manual curation or verification steps.

# Pseudocode for the Researcher's output structure
class EvidenceChunk:
    content: str
    source_url: str
    source_title: str
    chunk_id: str  # Unique ID for cross-referencing
    relevance_score: float
 
def retrieve(query: str) -> List[EvidenceChunk]:
    vector_results = vector_store.search(query, top_k=5)
    keyword_results = bm25_search(query, top_k=5)
    
    # Merge and deduplicate by chunk_id
    combined = merge(vector_results, keyword_results)
    return [EvidenceChunk.from_doc(doc) for doc in combined]

By enforcing this structure, we ensure that every piece of text flowing downstream carries its provenance. This allows the Synthesizer to verify claims against the exact source material rather than relying on the model’s internal memory.

Citation Integrity and Grounded Generation

The Synthesizer agent receives the list of EvidenceChunk objects. Its job is to generate a coherent narrative. However, unlike a standard chatbot, it is penalized for generating claims that cannot be traced back to a chunk_id.

This is achieved through "grounded generation." The prompt instructs the model to output JSON where each paragraph or claim includes a reference to the specific chunk ID that supports it. If the model cannot find support for a claim in the provided chunks, it must omit the claim rather than hallucinate one.

{
  "summary": "Quantum entanglement allows particles to remain connected...",
  "claims": [
    {
      "statement": "Entangled particles affect each other instantaneously.",
      "citations": ["chunk_id_101", "chunk_id_105"]
    }
  ]
}

This structure forces the model to act as an editor rather than a creator. It can only arrange existing facts. This significantly reduces hallucination rates because the model’s vocabulary is constrained by the retrieved evidence. The trade-off is increased latency and token usage, but for research tasks, accuracy is paramount.

The Iterative Feedback Loop

A single pass of retrieval and synthesis is rarely sufficient. The Planner agent monitors the Synthesizer’s output. If the summary is vague, or if certain sub-questions remain unanswered, the Planner generates new, targeted queries.

For example, if the initial query is "Compare the energy efficiency of nuclear vs. solar power," the Synthesizer might find data on cost but not on carbon footprint. The Planner detects this gap (missing dimension) and instructs the Researcher to search specifically for "lifecycle carbon emissions nuclear solar."

This loop continues until the Planner determines that the evidence is sufficient. The termination condition is usually based on a confidence score from the Synthesizer or a maximum iteration limit. This iterative refinement is what distinguishes a "deep research" agent from a simple Q&A bot. It actively seeks out missing information rather than settling for the first plausible answer.

Conclusion

Building a deep research agent requires moving beyond simple RAG patterns. By decomposing the task into Planning, Retrieval, and Synthesis, and by enforcing strict citation structures, we create a system that is transparent, verifiable, and accurate. The complexity lies in the orchestration, but the result is an agent that can handle the nuances of professional research.

Related posts