Multi-Agent Research System with Single-Agent Baseline
Build a planner → parallel searchers → writer → critic research system in LangGraph that answers questions with a cited brief — checkpointed, resumable, with a human approval gate and logged structured handoffs — then benchmark it honestly against a single agent with the same tools. You scaffold the project yourself; the skeleton below is the file map.
pip install langgraph "langchain[anthropic]" langgraph-checkpoint-sqlite (swap in langchain[openai] if you're on the OpenAI tab). The last one matters: the durable SQLite checkpointer (SqliteSaver) lives in that separate package, and the kill-and-resume acceptance criterion fails with the default in-memory saver. If you use web search rather than a local corpus, you'll also need a search tool/API of your choice. Budget two to three days including the baseline comparison.What you're building
A research question goes in; a cited brief comes out. The planner decomposes the question into 2–3 subtasks; parallel searchers (web or a provided corpus) gather evidence, one clean context each; the writer integrates findings into a draft; the critic reviews against a rubric with at most one revision loop; a human gate pauses the graph for approve/reject-with-feedback before the final answer. Every handoff is a structured brief, logged to JSONL. Then the part that makes this a portfolio piece: the same 10 questions through a single agent with the same tools, and an honest comparison table.
Suggested structure
# state.py
import operator
from typing import Annotated, TypedDict
class ResearchState(TypedDict):
question: str
plan: list[str]
findings: Annotated[list[str], operator.add] # parallel-safe
draft: str
critique: str
revision_count: int
# handoff.py — HandoffBrief (pydantic) + log_handoff() -> handoffs.jsonl
# graph.py
# one model for every node AND the baseline — swappable by one string:
# model = init_chat_model("anthropic:claude-sonnet-5") # or: "openai:gpt-5.5"
builder = StateGraph(ResearchState)
builder.add_node("planner", planner) # decompose via structured output
builder.add_node("searcher", searcher) # fanned out per subtask
builder.add_node("writer", writer)
builder.add_node("critic", critic)
builder.add_node("human_gate", human_gate) # interrupt() lives here
builder.add_edge(START, "planner")
# TODO: fan-out dispatch planner -> N searcher runs (Send-style API)
builder.add_edge("searcher", "writer")
builder.add_edge("writer", "critic")
builder.add_conditional_edges("critic", route_after_critic,
{"revise": "writer", "gate": "human_gate"})
builder.add_conditional_edges("human_gate", route_after_gate,
{"revise": "writer", "done": END})
graph = builder.compile(checkpointer=sqlite_checkpointer) # durable!
# baseline.py — single agent, SAME tools, same model, same 10 questions
# compare.py — runs both, sums usage across ALL calls, judges pairwiserevision_count caps the critic loop at one revision per the spec.Ship it to your portfolio
- README with a 60-second demo — architecture diagram up top, then a short clip or GIF: question in, planner fans out, gate pauses, human approves, cited brief out. Hiring managers look at GitHub before the résumé; make the first minute count.
- Logged inter-agent traces — commit a sample
handoffs.jsonland link it from the README. A multi-agent system with specialized roles and logged inter-agent traces is a specifically-cited portfolio project in hiring guides, and the trace file is the artifact reviewers actually open. - Demonstrate the HITL approval flow — capture the pause (process exits), then the resume with both an approve and a reject-with-feedback. Approval gates in front of irreversible actions are what enterprises specifically screen for.
- An honest 'Limitations' section — where the single agent won or tied, the judge's noise floor, and what you'd measure next before trusting the multi-agent claim. A measured negative result reads as senior; a suspiciously uniform win reads as rigged.
- ◇Time-travel demo: use the checkpoint history to fork a run from before the writer step with a modified plan, and diff the outcomes
- ◇Add a token/cost budget to state that any node can trip, terminating the graph gracefully with a partial-results report
- ◇Practical test rehearsal: kill the process mid-run on camera, resume from the checkpoint, and narrate your baseline numbers as if defending them in an interview
Be honest — the gates only mean something if the criteria really pass.
Repo URL, demo link, notes to your future self — saved locally with your progress, and handy when you package the portfolio.