前言
LangChain 作为一个2022就已经开源的框架,在设计上也是满足当时的需求,在大模型还没有那么强的时间点,AI能执行一个线性的流程就已经能满足了人们的想象和期待了。
时间再回到今天,在大模型能力爆炸式增长下,人们使用大模型的方式也逐步进化,Claude Code、OpenCode、Cusor等Agent的出现,Context、Rule、Skills、Harness等概念的流行,极大扩展了Agent的能力边界。线性的LangChain显然满足不了现在大模型的能力。在2025年这个AI爆发的时间节点,出现了LangGraph。
LangGraph
不同于LangChian的链式设计,LangGraph它将应用程序建模为一个图(Graph),通过节点、边和状态的协同工作来编排复杂的工作流。

为什么需要 LangGraph?
LangChain 的组合是线性的 :A → B → C → D,数据单向流动。
但很多 AI 场景需要循环和分支:
makefile
Agent 循环: LLM ⇄ 工具执行(需要循环)
审批工作流: 提交 → 审查 ⇄ 修改 → 批准(需要条件和循环)
多 Agent: Supervisor → Researcher → Writer → Supervisor(复杂路由)
这些用纯 LangChain 很难表达,LangGraph 就是为此设计的。
三个核心概念
LangGraph 的所有能力都建立在三个概念之上:State(状态)、Node(节点)、Edge(边) 。理解三者的协作方式,就理解了 LangGraph 的全部。它们的关系可以一句话概括:State 是共享数据、Node 改 State、Edge 决定下一个 Node 是谁。
1. State(状态)------ 图的"全局共享数据"
State 是整个图运行期间所有节点共享的数据结构。前端的朋友会对这个概念非常熟悉,他和前端里的State概念很像,表示在程序中流转的数据。状态在图中的节点执行时传递,每个节点在执行后使用其返回值更新此内部状态。图更新其内部状态的方式由所选图类型或自定义函数定义。
State 用 Annotation.Root 声明式定义,每个字段可以指定自己的 reducer------也就是"当节点更新这个字段时,应该怎么和现有值合并"。这个设计至关重要:
messages字段:每轮对话产生的 AI 消息和工具结果都该追加 到历史里,所以 reducer 是[...current, ...update]。如果没有这个,每一步都会把之前的历史覆盖掉,Agent 就"失忆"了。iteration_count这种字段:默认 reducer 是直接覆盖,因为计数器只要最新值。
这种"每个字段自带合并策略"的设计让多分支并行更新 State 时不会互相打架------A 节点追加 messages、B 节点更新 retrieved_docs,两边的 partial update 用各自的 reducer 合并,互不干扰。
2. Node(节点)------ 图的"处理单元"
Node 是图里干活的函数。每个节点接收完整的当前 State ,执行一段逻辑(调 LLM、跑工具、查数据库、做校验......),然后返回部分更新 (Partial<State>)。
关键设计:节点只返回它要更新的字段,不返回完整的新 State。框架拿到这个 partial 后,会用对应字段的 reducer 自动合并进当前 State。这带来三个直接后果:
- 节点之间解耦 ------你写
agent节点时不需要知道tools节点存在,只要从state.messages读、往里写就行。 - 并行安全 ------多个节点可以同时更新不同字段,因为 reducer 处理合并。
- 可 Checkpoint ------节点本身是无状态纯函数(输入 state → 输出 update),所有状态都在图里,所以每一步的状态快照能被完整序列化保存。
typescript
async function callModel(state: typeof State.State): Promise<Partial<typeof State.State>> {
const response = await model.invoke(state.messages);
return { messages: [response] }; // 只更新 messages 字段
}
3. Edge(边)------ 图的"流转规则"
Edge 决定执行完一个节点之后该去哪。这是 LangGraph 能表达循环和分支的根本机制------这些控制流在 LCEL 链里是写不出来的。LangGraph 有三种边:
- 普通边 (
addEdge):A 执行完一定去 B。等价于"A → B"的固定连线,是最简单的顺序流转。 - 条件边 (
addConditionalEdges):A 执行完后调用一个路由函数 ,由路由函数根据当前 State 决定去哪个节点。等价于声明式的switch/if-else,但路由规则写在图结构里------这意味着流程可以被可视化、被审计、被静态分析。 - 回环边 (节点连回前序节点):这是图区别于链的根本特征。链只能 A→B→C 一条道走到底;图可以让 C→A 形成循环------这正是 Agent 反复"思考→行动→观察"的实现方式。
typescript
// 普通边:A → B,无条件
.addEdge("agent", "tools")
// 条件边:A → ?,根据状态决定
.addConditionalEdges("agent", (state) => {
if (state.messages.at(-1)?.tool_calls?.length) return "tools";
return END;
})
// 回环边:tools → agent(形成循环,这就是 Agent 的 ReAct 循环)
.addEdge("tools", "agent")
三者如何协作
把上面三个概念串起来,一次完整的图执行是这样的:
sql
用户调用 invoke(input)
↓
框架初始化 State(用 input 填充初始字段)
↓
按 Edge 规则选下一个 Node(从 START 出发)
↓
Node 执行:读 State → 返回 partial update
↓
框架按 reducer 把 update 合并进 State
↓
(可选)Checkpointer 保存当前 State 快照
↓
按 Edge 规则选下一个 Node ...... 循环直到走到 END

基础案例
typescript
// ─── 1. 第一个 StateGraph ──────────────────
console.log("📌 1. 构建第一个 StateGraph:简单的步骤流水线\n");
// 定义状态结构
const PipelineState = Annotation.Root({
text: Annotation<string>, // 文本内容
step: Annotation<string>, // 当前步骤名
history: Annotation<string[]>({ // 步骤历史(reducer: 追加而非覆盖)
default: () => [],
reducer: (current, update) => [...current, ...update],
}),
});
// 构建图
const pipelineGraph = new StateGraph(PipelineState)
// 添加节点:每个节点是一个处理函数
.addNode("trim", (state) => {
const trimmed = state.text.trim();
return {
text: trimmed,
step: "trim",
history: [`[trim] 去除首尾空格`],
};
})
.addNode("lowercase", (state) => {
return {
text: state.text.toLowerCase(),
step: "lowercase",
history: [`[lowercase] 转为小写`],
};
})
.addNode("addPrefix", (state) => {
return {
text: `处理结果: ${state.text}`,
step: "addPrefix",
history: [`[addPrefix] 添加前缀`],
};
})
// 添加边:定义节点间的流转
.addEdge(START, "trim") // 从开始 → trim
.addEdge("trim", "lowercase") // trim → lowercase
.addEdge("lowercase", "addPrefix") // lowercase → addPrefix
.addEdge("addPrefix", END) // addPrefix → 结束
// 编译为可运行的实例
.compile();
console.log("图结构: START → trim → lowercase → addPrefix → END\n");
const result = await pipelineGraph.invoke({
text: " Hello LangGraph! ",
step: "",
history: [],
});
console.log(` 输入: " Hello LangGraph! "`);
console.log(` 输出: ${result.text}`);
console.log(` 历史: ${result.history.join(" → ")}\n`);
上面的例子,我们可以简单看到State、Node、Edge三者的关系。
- State是全局的状态,因此作为一个
StateGraph的构造参数。 - 通过
addNode添加多个Node,Node中定义了行为,行为中简单处理并返回了State. - 通过
addEdge添加节点间流转的规则,两个参数表示这两个步骤中间要形成一个向下流通的关系。
以上就是一个线性的LangGrapha。
带分支处理的图
只是线性的LangGraph仍然是链的结构,图是非线性的,可以有分支处理,也可以回退循坏。下面是一个带分支处理的图。
typescript
// 一个简单的"审批工作流"
const ApprovalState = Annotation.Root({
document: Annotation<string>,
status: Annotation<"draft" | "review" | "approved" | "rejected">,
reviewerCount: Annotation<number>,
});
const approvalGraph = new StateGraph(ApprovalState)
.addNode("submit", (state) => {
console.log(" 📄 提交文档进行审批...");
return {
status: "review" as const,
reviewerCount: 0,
};
})
.addNode("review", (state) => {
const count = state.reviewerCount + 1;
console.log(` 🔍 第 ${count} 位审查者正在审查...`);
// 模拟:第二次审查时通过
const newStatus = count >= 2 ? "approved" : "review";
return {
status: newStatus as "approved" | "review",
reviewerCount: count,
};
})
.addNode("approved", (state) => {
console.log(" ✅ 文档已批准!");
return {};
})
.addNode("rejected", (state) => {
console.log(" ❌ 文档被拒绝");
return {};
})
.addEdge(START, "submit")
.addEdge("submit", "review")
// 条件边:根据 status 决定下一步
.addConditionalEdges("review", (state) => {
console.log(` 🤔 当前状态: ${state.status}`);
if (state.status === "approved") return "approved";
if (state.status === "rejected") return "rejected";
return "review"; // 继续审查
})
.addEdge("approved", END)
.addEdge("rejected", END)
.compile();
console.log("审批工作流: submit → review ⇄ (条件循环) → approved/rejected\n");
console.log(' 模拟场景:需要2位审查者都通过\n');
const approvalResult = await approvalGraph.invoke({
document: "项目计划书 v2.0",
status: "draft",
reviewerCount: 0,
});
console.log(`\n 最终状态: ${approvalResult.status}`);
console.log(` 审查次数: ${approvalResult.reviewerCount}\n`);
这里设计了一个流程,从开始之后下一步是提交,提交之后是审查,审查会产生两个分支,一个是通过,一个是拒绝,需要两位审查者都通过才能结束流程。
这里addConditionalEdges就是添加一个分支判断条件,会根据当前的State中的status参数去判断要进入哪一个Node中,review这个Node中模拟了审批的过程,并且增加了条件,必须第二次进入到review这个Node中才能将State中的Status置为approved以进入下一个最终的Nodeapproved。
总结
LangGraph是在LangChain思想上的一个演进,从链式的线性执行,到了图的多状态流转、可回溯执行,更加符合了当前复杂的大模型应用。
LangGraph = 用"图"的方式编排有状态的 AI 工作流。支持循环、分支、暂停/恢复、状态持久化。