Building DeepResearch from Scratch (Part 2): Architecture Design and Implementation with LangGraph

This article walks through the design and implementation of a multi‑agent DeepResearch application using the Pipeline‑Agent pattern with LangGraph and LangChain, detailing three agents for task planning, web search via Tavily, and report generation, and provides complete Python code and test results.

Fun with Large Models
Fun with Large Models
Fun with Large Models
Building DeepResearch from Scratch (Part 2): Architecture Design and Implementation with LangGraph

Architecture Overview

The DeepResearch pipeline is composed of three sequential agents:

Task‑planning agent – expands a user query into multiple research angles and extracts keywords.

Web‑search agent – uses the Tavily search tool to retrieve and summarise web content for each keyword.

Report‑generation agent – aggregates the collected information and produces a structured long‑form markdown report.

Task‑Planning Agent

Implemented with LangChain because the output structure is simple.

Create a .env file and add DEEPSEEK_API_KEY.

Install dependencies: pydantic, langchain, langgraph, langchain_deepseek, langchain_tavily.

Define a system prompt that asks the model to generate 5‑7 search terms for a given query.

PLANNER_INSTRUCTIONS = (
    "You are a helpful research assistant, Given a query, come up with a set of web searches "
    "to perform to best answer the query, Output between 5 and 7 terms to query for."
)
planner_prompt = ChatPromptTemplate.from_messages([
    ("system", PLANNER_INSTRUCTIONS),
    ("human", "{query}")
])

Structured output models:

class WebSearchItem(BaseModel):
    query: str  # The search term to use for the web search.
    reason: str # Reason why this search is important to the query.

class WebSearchPlan(BaseModel):
    searches: list[WebSearchItem]

The planner chain is created with .with_structured_output(WebSearchPlan). A test with the query “请问你对AI+教育有何看法” returns seven structured keywords.

Web‑Search Agent

Built with LangGraph’s create_react_agent to combine the Tavily tool and the language model.

Add TAVILY_API_KEY to .env.

Define a prompt that requires a concise 2‑3 paragraph summary (<300 words) for each term.

SEARCH_INSTRUCTIONS = (
    "You are a research assistant. Given a search term, you search the web and "
    "produce a concise summary of the results. The summary must be 2‑3 paragraphs and "
    "less than 300 words. Capture the main points. Write succinctly, no need for perfect "
    "grammar. This will be consumed by someone synthesising a report, so capture the "
    "essence and ignore fluff. Do not add any additional commentary."
)
search_tool = TavilySearch(max_results=5, topic="general")
search_agent = create_react_agent(model, prompt=SEARCH_INSTRUCTIONS, tools=[search_tool])

A test using the first keyword from the planner shows the agent retrieving five webpages and summarising them.

Report‑Writing Agent

Implemented with LangChain because no external tool calls are required.

Define a writer prompt that first asks for an outline then a detailed markdown report (10‑20 pages, ≥1500 words).

Create a ReportData Pydantic model with fields short_summary, markdown_report, and follow_up_questions.

WRITER_PROMPT = (
    "You are a senior researcher tasked with writing a cohesive report for a research query. "
    "You will be provided with the original query and some initial research done by a research assistant. "
    "First, produce an outline describing the structure and flow. Then generate the full report. "
    "The final output should be markdown, lengthy and detailed (10‑20 pages, at least 1500 words)."
)
writer_prompt = ChatPromptTemplate.from_messages([
    ("system", WRITER_PROMPT),
    ("human", "{query}")
])
writer_chain = writer_prompt | model.with_structured_output(ReportData)

End‑to‑End Integration

Helper functions wire the three agents together:

# Generate keyword plan
def plan_searches(query: str) -> WebSearchPlan:
    return planner_chain.invoke({"query": query})

# Perform a single web search
def search(item: WebSearchItem) -> str | None:
    try:
        final_query = f"Search Item: {item.query}
Reason for searching: {item.reason}"
        result = search_agent.invoke({"messages": [{"role": "user", "content": final_query}]})
        return str(result['messages'][-1].content)
    except Exception:
        return None

# Search all keywords
def perform_searches(plan: WebSearchPlan):
    results = []
    for item in plan.searches:
        res = search(item)
        if res is not None:
            results.append(res)
    return results

# Write the final report
def write_report(query: str, search_results) -> ReportData:
    summary = "".join(search_results)
    final_query = f"Original query: {query}
Summarized search results: {summary}"
    return writer_chain.invoke({"query": final_query})

# Full pipeline
def deepresearch(query: str) -> ReportData:
    plan = plan_searches(query)
    results = perform_searches(plan)
    report = write_report(query, results)
    print(report.markdown_report)
    return report

Running deepresearch('AI在教育方面的应用场景') produces a structured, content‑rich markdown report.

Conclusion

The end‑to‑end test confirms that the pipeline correctly executes task planning, multi‑angle web retrieval, and report synthesis, demonstrating the effectiveness of multi‑agent collaboration. Future extensions may include richer search capabilities (e.g., local document or knowledge‑base search) and deployment as a web service.

PythonAI agentsLangChainMulti-agent architectureLangGraphPipeline-Agent
Fun with Large Models
Written by

Fun with Large Models

Master's graduate from Beijing Institute of Technology, published four top‑journal papers, previously worked as a developer at ByteDance and Alibaba. Currently researching large models at a major state‑owned enterprise. Committed to sharing concise, practical AI large‑model development experience, believing that AI large models will become as essential as PCs in the future. Let's start experimenting now!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.