Portfolio Projects · Project 2 of 10
Project 2: Multi-Agent Research Assistant (LangGraph)
Agents are the hottest interview topic of 2025–26. You'll build a supervisor + specialist agents system that researches a topic, writes a report with sources, and has a reviewer agent check it, with step limits, tracing and a human-approval step.
What you'll build
- A user asks: "Compare vector databases for a startup."
- A Planner breaks the question into sub-questions, a Researcher searches the web or docs, a Writer drafts the report, and a Reviewer checks claims against sources and asks for fixes.
- The final markdown report includes citations, a cost and latency summary, and a trace.
Architecture
User → Supervisor (LangGraph state machine)
├─ planner → sub-questions
├─ researcher → tools: web_search, fetch_page, vector_search (max 6 tool calls)
├─ writer → draft report with [n] citations
└─ reviewer → pass / revise (max 2 loops) → human approval → final report
State: {question, plan[], notes[], draft, review, steps, sources[]}
Tech stack
LangGraph, LangChain tools, Tavily or DuckDuckGo search, an LLM with tool calling, Pydantic for structured outputs, LangSmith or Langfuse for tracing, Streamlit for the UI.
Step by step
- Define typed state with Pydantic or a
TypedDict. - Planner node: structured output gives a list of 3–5 sub-questions.
- Researcher node: a tool-calling loop with a max-steps guard; save notes with source URLs.
- Writer node: compose the report using only the notes, citing [n].
- Reviewer node: a checklist of claims supported, coverage, clarity; it returns
passorrevisewith feedback. - Conditional edges:
revisegoes back to the writer (at most 2 times);passgoes to human approval (an interrupt). - Tracing: log tokens, latency and cost per node.
- Evaluate on 10 topics: citation accuracy, factual errors found, time and cost.
Starter code
from typing import TypedDict, List
from langgraph.graph import StateGraph, END
class S(TypedDict): question: str; plan: List[str]; notes: List[str]; draft: str; review: str; loops: int
def planner(s): s["plan"] = plan_llm(s["question"]); return s
def researcher(s): s["notes"] = [research(q) for q in s["plan"]]; return s
def writer(s): s["draft"] = write_llm(s["question"], s["notes"], s.get("review", "")); return s
def reviewer(s): s["review"] = review_llm(s["draft"], s["notes"]); s["loops"] = s.get("loops", 0) + 1; return s
route = lambda s: "writer" if s["review"].startswith("REVISE") and s["loops"] < 2 else END
g = StateGraph(S)
for n, f in [("planner", planner), ("researcher", researcher), ("writer", writer), ("reviewer", reviewer)]: g.add_node(n, f)
g.set_entry_point("planner"); g.add_edge("planner", "researcher"); g.add_edge("researcher", "writer"); g.add_edge("writer", "reviewer")
g.add_conditional_edges("reviewer", route, {"writer": "writer", END: END})
app = g.compile()
print(app.invoke({"question": "Compare vector databases for a startup"})["draft"])
Deploy it
Use a Streamlit UI showing each agent's progress live (stream graph events), hosted on Hugging Face Spaces. Store API keys in secrets. Record a 60-second demo video for LinkedIn.
Put it on your resume
- Built a multi-agent research assistant in LangGraph (planner, researcher, writer, reviewer) with tool calling, step limits, a reviewer feedback loop and human approval.
- Cut factual errors by ~60% vs a single-agent baseline on a 10-topic evaluation set, tracking cost and latency per node with LangSmith.
Interview questions you'll get
- When should you use multiple agents instead of one? What are the costs?
- How do agents share memory and state? How do you stop infinite loops?
- How do you evaluate an agent's trajectory, not just its final answer?
- How do you secure tool calls (prompt injection from web pages)?
Practise these in Mock Interview → Agents & MCP.
Stretch goals
- Expose the tools through an MCP server.
- Parallel research branches (fan-out / fan-in).
- Long-term memory of past reports in a vector store.
Created by Ajeetkumar