状态管理 (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
}