实战:用 LangGraph 做一个多步研究 Agent
深度研究(一个问题 → 多轮检索 + 综合成报告)是 Agent 最有含金量的场景,也是单轮 RAG 解不了的。本文用 LangGraph 做一个研究 Agent:拆问题 → 并行检索 → 读全文 → 查漏补缺 → 综合成报告,讲清状态图设计、工具调用、循环控制——把"研究"这件开放的事工程化。
本文要点
- 主题聚焦:AI、AI Agent
- 适合人群:独立开发者、全栈工程师、AI 应用开发者
- 核心价值:快速理解背景、实践路径、常见误区和工程建议
"帮我研究一下 X,给一份报告"——这种任务,单轮 RAG 解不了(知识库未必有),需要 Agent 自主多步检索外部信息、综合判断。这是 Agent 最有含金量、也最能体现"自主"的场景。
这篇用 LangGraph 做一个研究 Agent,把"开放性研究"这件事工程化。
一、研究 Agent 和普通 RAG 的区别
普通 RAG:一次检索 + 一次生成,适合"知识库里能查到的具体问题"。
研究 Agent:多轮、自主——它要自己决定查什么、查够了没、要不要换关键词、最后综合多源信息成报告。比如"对比 A 和 B 两款框架的优劣",它要分别查 A、查 B、查对比,最后综合。
核心能力链:
问题 → 拆子问题 → 并行检索(搜索+读全文) → 评估(够不够) →
(不够)再检索 → (够了)综合成报告
二、用 LangGraph 画状态图
LangGraph 的"状态图"模型特别适合这种多步流程。先定义状态:
import { StateGraph, Annotation } from "@langchain/langgraph";
const ResearchState = Annotation.Root({
question: Annotation<string>, // 原始问题
subQuestions: Annotation<string[]>, // 拆出的子问题
findings: Annotation<Doc[]>( // 已收集的资料
{ reducer: (a, b) => dedup([...a, ...b]), default: () => [] }
),
drafts: Annotation<string[]>, // 各子问题的阶段性答案
report: Annotation<string>, // 最终报告
steps: Annotation<number>({ default: () => 0 }), // 步数(防失控)
});
findings 用 reducer 做去重合并(多个检索节点并行往里加,自动合并去重)。
然后画图:
plan → search(parallel) → reflect → (不够)search / (够)write → END
const graph = new StateGraph(ResearchState)
.addNode("plan", planNode) // 拆子问题
.addNode("search", searchNode) // 检索(可并行 fan-out)
.addNode("reflect", reflectNode) // 评估:够不够、缺什么
.addNode("write", writeNode) // 综合成报告
.addEdge(START, "plan")
.addEdge("plan", "search")
.addEdge("search", "reflect")
.addConditionalEdges("reflect", (s) =>
s.steps >= 5 || enough(s) ? "write" : "search" // 够了或到上限 → 写报告
)
.addEdge("write", END);
三、各节点的设计
plan(拆问题):一个 LLM 调用,把大问题拆成 3–5 个可独立检索的子问题。
输入: "对比 Qwen 和 Llama 在中文场景的优劣"
输出: ["Qwen 中文能力 benchmark", "Llama 中文能力", "Qwen vs Llama 对比", "..."]
search(检索):对每个子问题,调搜索工具(web search API),取 top 结果的摘要 + URL。关键:每个子问题独立检索,别用一个模糊 query 搜所有。
read(读全文,可选):对高相关的搜索结果,fetch 全文、切块、抽要点。这是质量分水岭——只看搜索摘要的研究很浅,读全文才能拿到细节。
reflect(评估):这是研究 Agent 的"大脑"。一个 LLM 调用,看当前 findings,判断:
- 信息够不够回答原问题?
- 有没有明显缺口(某子问题没查到)?
- 要不要再查(给新关键词)?
reflect 的输出决定"继续 search 还是去 write"。这个节点决定研究质量——做得好,Agent 会自主补漏;做得差,要么过早写报告(浅)、要么死循环(搜不完)。
write(综合):把 findings 按原问题综合成结构化报告,带引用(每条结论标注来源 URL)。研究 Agent 不带引用 = 不可信。
四、控制:别让它失控
研究 Agent 最容易出的问题:循环搜不完(reflect 一直觉得"不够")。控制手段:
- 硬上限:
steps >= 5强制结束去 write。没有上限的研究 Agent 会无限搜。 - reflect 给明确判据:"如果每个子问题都有 ≥2 条可信来源,就 enough"——别让它凭感觉。
- 预算约束:总检索次数/总 token 上限,撞到就收尾。
研究 Agent 的"够"是主观的,你需要用明确的判据 + 硬上限把它约束住。
五、质量的关键:reflect 和引用
研究 Agent 的好坏,70% 在 reflect 节点。一个差的 reflect:
- 过早收:报告浅、缺关键面。
- 不收:死循环烧钱。
调 reflect 的 prompt:给清晰的"够了"判据、让它说出"还缺什么"、给它最大步数意识。
另一个质量关键:引用。write 节点必须让每条结论带来源。研究 Agent 的产出是给人决策用的,没引用的结论没法采信。带引用的研究报告,价值是"综述"的十倍。
六、工程化补充
- 搜索工具的选择:用能返回正文/摘要的 API(如 Tavily、Brave Search API),别用只给链接的。Agent 要读内容,不只是 URL。
- 缓存:同一子问题的检索结果缓存(研究里会重复搜相似 query)。
- 流式:最终 write 流式输出,用户能边看边等(研究 Agent 跑一轮几十秒,全程黑盒很煎熬)。
- trace:每个节点(plan/search/reflect/write)的输入输出落 trace,研究质量出问题靠它定位("是 plan 拆错了,还是 reflect 过早收了")。
小结
研究 Agent 是 Agent 自主性的集中体现:拆问题 → 多步检索 → 自评 → 补漏 → 综合报告。LangGraph 的状态图把它讲透了——节点是各环节、边是控制流、reflect 是大脑。
记住四条:
- plan 拆好子问题,并行检索各管一段。
- reflect 是质量关键,给明确"够了"判据。
- 硬上限 + 预算,防死循环。
- 带引用,研究产出没引用就没价值。
把这套搭起来,你的 Agent 就能做"开放式研究"这种单轮 RAG 做不了的高价值任务——这才是 Agent 相比传统检索最不可替代的能力。
Related