Project / 012Case study
AI Research Agent: Template-First Research Runs on LangGraph
A LangGraph research agent that plans, fans out parallel retrieval, merges evidence and writes a versioned report, with a live run room to watch it happen.
- AI systems
- Developer tools
- Status
- Prototype
- Role
- Sole developer
- Year
- 2026
- Language
- Python
- Platform
- Web
- Reading
- 4 min
- Stack
- LangGraph
- FastAPI
- SQLAlchemy
- SQLite
- OpenRouter
- LangSmith
- Next.js 15
- React Flow
- pytest

The problem
Most "research agents" are a single long prompt: you wait, you get a wall of text, and you cannot tell which claims came from where. I wanted a research workflow that is shaped by a template, streams its progress, and leaves a versioned artifact behind so a run can be inspected, compared and exported later.
The system
10 components · 10 connections · 2 request flows
A Next.js run room starts a research run on a FastAPI backend. The LangGraph graph plans the work, fans retrieval out in parallel, merges the evidence and synthesises a report that is stored as a versioned artifact.
- Client
- Service
- Worker
- External service
- Data store
- Trust boundary
Select a component to see its role, the technology behind it and what it connects to, or follow a request through the system hop by hop.
Component reference10 components · 2 flows · as text
Components · in request order
- Client · layer 01Run room
- Starts runs and shows them live
- Routes for the run room, reports, history, datasets, templates and metrics. Draws the graph topology with React Flow and renders the markdown report with exports.
- TechNext.js 15, React Flow
- ToResearch API (start run, stream events)
- Service · layer 02Research API
- Runs, streams and lists research runs
- POST /v1/research, GET /v1/research/stream for SSE, GET /v1/research/{run_id}, plus /v1/admin/runs and /v1/templates.
- TechFastAPI, SSE
- FromRun room (start run, stream events)
- ToResearch graph (invoke graph); Artifact store (history and reports)
- Service · layer 03Research graph
- LangGraph state machine
- planner, parallel retrieve, retrieve_merge, synthesize, END. Also loadable in LangGraph Studio through langgraph.json and traced with LangSmith.
- TechLangGraph, LangSmith
- FromResearch API (invoke graph)
- ToPlanner (plan)
- InsideLangGraph graph
- Worker · layer 04Planner
- Turns a question and template into subtasks
- The template registry decides the plan shape.
- TechTemplate registry
- FromResearch graph (plan)
- ToRetrieve (parallel) (Send fan-out); LLM provider (plan with model)
- InsideLangGraph graph
- Worker · layer 05Retrieve (parallel)
- One retrieval per subtask
- Fanned out with LangGraph Send so subtasks run in parallel.
- TechLangGraph Send
- FromPlanner (Send fan-out)
- ToWeb search and fetch (search and fetch); Merge (evidence)
- InsideLangGraph graph
- External service · layer 05LLM provider
- Chat model used by the planner
- OpenRouter through ChatOpenAI. Replaced by STUB_LLM in tests.
- TechOpenRouter
- FromPlanner (plan with model)
- Worker · layer 06Merge
- Combines evidence from all subtasks
- TechLangGraph
- FromRetrieve (parallel) (evidence)
- ToSynthesize (merged evidence)
- InsideLangGraph graph
- External service · layer 06Web search and fetch
- Finds and reads sources
- TechSearch, HTTP fetch
- FromRetrieve (parallel) (search and fetch)
- Worker · layer 07Synthesize
- Writes the report from merged evidence
- Heuristic synthesis into the template structure.
- TechPython
- FromMerge (merged evidence)
- ToArtifact store (save versioned artifact)
- InsideLangGraph graph
- Data store · layer 08Artifact store
- Versioned run artifacts and history
- TechSQLite, SQLAlchemy
- FromSynthesize (save versioned artifact); Research API (history and reports)
Request flows
A research run
The UI follows the same run over SSE while the graph executes.
- Step 1: Run room
- Step 2: Research API
- Step 3: Research graph
- Step 4: Planner
- Step 5: Retrieve (parallel)
- Step 6: Merge
- Step 7: Synthesize
- Step 8: Artifact store
Evidence gathering
- Step 1: Planner
- Step 2: Retrieve (parallel)
- Step 3: Web search and fetch
Trust boundaries
- LangGraph graph — Research graph, Planner, Retrieve (parallel), Merge, Synthesize
Decisions & trade-offs
5 decisions
- D01
Template-first instead of free-form prompting
A template registry decides the shape of the plan and the report, so two runs of the same kind produce comparable output instead of two different essays.
- D02
Fan out retrieval with LangGraph Send
The planner splits the question into subtasks and each one is retrieved in parallel, then merged before synthesis. Slow sources stop serialising the whole run.
- D03
Store artifacts, not just answers
Runs are persisted as versioned artifacts in SQLite through SQLAlchemy, which makes history, datasets and exports possible without re-running anything.
- D04
Stream the run, do not hide it
The backend exposes an SSE stream and the Next.js run room draws the graph topology live with React Flow, next to a metrics observatory and the markdown report.
- D05
A stub mode for tests and demos
STUB_LLM swaps the model for deterministic output so the graph, the API and the UI can be tested without spending tokens.
Outcomes
- Planner, parallel retrieval, merge and synthesis run as one LangGraph graph with SSE streaming.
- Every run is stored as a versioned artifact and can be reopened from /reports/{run_id}.
- The stack runs offline with STUB_LLM, and the backend ships with a pytest suite.
RoleSole developer
View on GitHubThe write-up
4 min read
Research agents usually fail in the same quiet way: one long prompt, one long answer, and no way to tell where a claim came from. This project is my attempt at the opposite shape. A run is a graph, the output follows a template, and everything is saved as a versioned artifact you can reopen.
What it does
You pick a template and ask a question. A LangGraph graph plans the work, retrieves for each subtask in parallel, merges the evidence and synthesises a report. The run room streams all of it while it happens.
How a run flows
Plan. The planner uses the template registry and an OpenRouter chat model to split the question into subtasks.
Retrieve. Each subtask is fanned out with LangGraph Send, so web search and page fetch run in parallel.
Merge. Evidence from every branch is combined before anything is written.
Synthesise. A heuristic synthesis step writes the report in the template structure.
Store. The result is saved as a versioned artifact through SQLAlchemy and SQLite.
The run room
The Next.js 15 frontend has routes for the live run, finished reports, history, datasets, templates and metrics. The graph topology is drawn with React Flow, with an observatory beside it and the markdown report rendered with export options.
Engineering notes
The API streams over SSE at /v1/research/stream and also serves /v1/research/{run_id}, /v1/admin/runs and /v1/templates.
The graph is registered in langgraph.json, so it opens in LangGraph Studio. LangSmith tracing is supported.
STUB_LLM replaces the model with deterministic output, so tests and demos cost nothing.
The backend has a pytest suite.
Status
This is the template-first v1: a working end-to-end loop that I use to explore how structured, inspectable research runs should feel. Synthesis is heuristic today, and a model-driven writer is the obvious next step.