状态管理 (State Management)
状态是 LangGraphGo 的核心。与许多无状态的编排框架不同,LangGraphGo 显式地定义和管理状态。理解状态 Schema 和 Reducer 是构建复杂图的关键。
1. State Schema 与 Reducers
背景与功能
在图中,多个节点可能会并行运行并尝试更新状态。如果只是简单地覆盖状态,会导致数据竞争和丢失。Reducer 定义了如何安全地合并来自不同节点的更新。
例如,对于聊天记录,我们通常希望追加新消息(Append),而不是覆盖旧消息(Overwrite)。
实现原理
State Schema 是一个 Map,定义了状态中每个字段的名称和对应的合并函数(Reducer)。当运行时收到节点的输出时,它会查找对应的 Reducer 来处理更新。
代码展示
// 定义 Schema
schema := &graph.StateSchema{
"messages": graph.AppendReducer, // 消息列表:追加模式
"summary": graph.OverwriteReducer, // 摘要:覆盖模式
"count": func(old, new interface{}) interface{} { // 自定义:累加模式
return old.(int) + new.(int)
},
}
// 应用 Schema 到图
g.SetSchema(schema)
2. 临时通道 (Ephemeral Channels)
背景与功能
并非所有状态都需要持久化。有时你需要传递一个临时的信号或错误消息,只在当前步骤有效,下一步就应该消失。这类似于编程语言中的局部变量。
实现原理
LangGraphGo 提供了 EphemeralReducer。使用此 Reducer 的字段,在每个 Superstep 结束时会被自动清空。
代码展示
// 注册临时字段
schema.RegisterReducer("error_signal", graph.EphemeralReducer)
// 节点 A 发送错误
return map[string]interface{}{"error_signal": "something went wrong"}, nil
// 节点 B (在同一步或紧接的下一步) 可以读取到 error_signal
// 但在之后的步骤中,error_signal 将变为空
3. 智能消息 (Smart Messages)
背景与功能
在处理聊天记录时,简单的追加并不总是够用。例如,当 Agent 重新生成回复时,我们希望替换掉上一条旧的回复,而不是追加一条新的。或者,我们想更新某条历史消息的内容。
实现原理
MessagesStateGraph 预置了智能的 AddMessages Reducer。它基于消息的 ID 进行合并:如果新消息的 ID
已存在,则更新旧消息(Upsert);如果不存在,则追加。
代码展示
// 使用预置的 MessagesStateGraph
g := graph.NewMessagesStateGraph()
// 第一次生成
g.AddNode("ai", func(...) {
return []llms.MessageContent{{ID: "msg_1", Content: "Thinking..."}}, nil
})
// 第二次生成 (更新)
g.AddNode("ai_update", func(...) {
// ID 相同,内容将被替换
return []llms.MessageContent{{ID: "msg_1", Content: "The answer is 42."}}, nil
})
4. Command API
背景与功能
通常,控制流是由图的边定义的。但在某些复杂场景下,节点内部可能需要更细粒度的控制,例如"更新状态并立即跳转到节点 X",或者"更新状态并结束图"。
实现原理
节点可以返回一个特殊的 graph.Command 对象。运行时会优先处理这个对象中的指令(如 Goto,
Update),覆盖默认的路由逻辑。
代码展示
func myNode(ctx context.Context, state interface{}) (interface{}, error) {
// ... 逻辑判断 ...
// 动态跳转
return graph.Command{
Goto: "node_c", // 强制跳转到 node_c
Update: map[string]interface{}{"key": "value"}, // 同时更新状态
}, nil
}