这一篇只解决一个问题:
LangGraph 中的数据是如何在节点之间流转的?
不要先背 API,先理解它的运行模型。
1. 为什么 Agent 需要 State?
普通函数:
css
function add(a, b) {
return a + b;
}
数据通过参数传递:
输入
↓
函数
↓
输出
但是 Agent 工作流:
用户输入
↓
分析任务
↓
调用工具
↓
获取结果
↓
总结回答
中间会产生大量数据:
例如:
css
{
question:"查询订单",
userId:"1001",
orderInfo:{},
toolResult:"",
answer:""
}
这些数据需要在不同步骤之间共享。
所以 LangGraph 引入:
State(状态)
2. State 是什么?
State 可以理解为:
整个 Graph 执行过程中的共享数据对象。
例如:
css
{
query:"",
answer:""
}
流程开始:
css
State
{
query:"1+2",
answer:""
}
经过节点:
css
Node
↓
更新 State
↓
{
query:"1+2",
answer:"3"
}
3. 如何定义 State?
LangGraph 使用:
scss
Annotation.Root()
定义状态结构。
例如:
javascript
const StateAnnotation = Annotation.Root({
query: Annotation({
reducer: (_prev,next)=>next,
default:()=> ""
}),
answer: Annotation({
reducer: (_prev,next)=>next,
default:()=> ""
})
});
表示:
我们的 State 有两个字段:
erlang
State
├── query
└── answer
4. Node 是什么?
Node 就是一个执行步骤。
本质:
perl
(state)=>update
例如:
javascript
const answerNode = (state)=>{
return {
answer:`你的问题是:${state.query}`
}
}
输入:
css
{
query:"hello",
answer:""
}
返回:
css
{
answer:"你的问题是:hello"
}
注意:
Node 不直接修改 State。
错误:
ini
state.answer="xxx"
LangGraph 推荐:
kotlin
return {
answer:"xxx"
}
为什么?
因为 LangGraph 会统一管理:
- 状态更新
- 状态合并
- 历史保存
5. Node 返回的是完整 State 吗?
不是。
这是很多人的第一个疑惑。
比如:
当前 State:
css
{
query:"hello",
answer:""
}
Node:
kotlin
return {
answer:"你好"
}
不是变成:
css
{
answer:"你好"
}
而是:
LangGraph 合并:
css
{
query:"hello",
answer:"你好"
}
所以:
Node 返回的是 State 的部分更新。
6. Reducer 是干什么的?
问题:
如果多个节点修改同一个字段怎么办?
例如:
两个节点:
Node1:
kotlin
return {
messages:["hello"]
}
Node2:
kotlin
return {
messages:["world"]
}
最终:
messages?
怎么办?
这就是 Reducer 的作用。
覆盖模式
默认:
lua
(prev,next)=>next
表示:
新的覆盖旧的。
例如:
之前:
vbnet
answer:"A"
节点返回:
vbnet
answer:"B"
结果:
vbnet
answer:"B"
累积模式
聊天记录:
css
messages: Annotation({
reducer:(prev,next)=>[
...prev,
...next
]
})
第一次:
css
[ "你好"]
第二次:
css
[ "你好", "你好,请问..."]
7. 一个完整 Demo
状态:
vbnet
const StateAnnotation = Annotation.Root({
text:Annotation({
reducer:(prev,next)=>next,
default:()=> ""
})
});
节点:
javascript
const step1=(state)=>({
text:`${state.text}->step1`
});
const step2=(state)=>({
text:`${state.text}->step2`
});
流程:
sql
START
↓
step1
↓
step2
↓
END
输入:
arduino
{
text:"hello"
}
执行:
第一次:
rust
hello
↓
hello->step1
第二次:
rust
hello->step1
↓
hello->step1->step2
最终:
arduino
{
text:"hello->step1->step2"
}
8. 用一句话理解 State + Node
不要记 API。
记这个模型:
markdown
当前 State
↓
Node读取
↓
Node返回部分更新
↓
Reducer合并
↓
新的 State
↓
下一个 Node
总结
LangGraph 的状态模型:
| 概念 | 作用 |
|---|---|
| State | 保存整个工作流的数据 |
| Node | 执行任务并返回状态更新 |
| Reducer | 决定状态如何合并 |
| Annotation | 定义 State 结构 |
一句话:
LangGraph 通过 State 在节点之间传递上下文,Node 负责产生状态更新,Reducer 负责控制更新方式,从而让整个 Agent 工作流能够持续演进。