状态管理详解

深入理解 LangGraph 的状态更新机制:Reducer 和默认值

📚 学习目标

学完这篇文章后,你将能够:

  • 理解为什么需要 Reducer
  • 掌握如何配置 Default Value(默认值)
  • 实现历史记录追加(Append)模式
  • 实现数值累加(Increment)模式

前置知识

在开始学习之前,建议先阅读:


1️⃣ 为什么简单的覆盖是不够的?

在上一节中,我们看到节点返回的对象会与当前状态进行“合并”。对于简单的字段(如 stringboolean),这种默认的覆盖行为通常没问题——新的值替换旧的值。

但是,如果我们想要:

  • 保留所有历史消息(而不是只保留最后一条)?
  • 统计执行步骤(每次 +1,而不是固定的值)?

这时我们就需要更强大的工具:Reducer

2️⃣ 使用 Reducer 和 Default

Annotation 允许我们通过配置对象来定义字段的行为:

import { Annotation } from '@langchain/langgraph';

const StateAnnotation = Annotation.Root({
    // 1. 数组追加模式
    history: Annotation<string[]>({
        // reducer: 定义如何合并旧值(old)和新值(new)
        reducer: (oldState, newState) => {
            return [...oldState, ...newState]; // 将新值追加到旧数组后
        },
        // default: 定义初始值
        default: () => ['系统启动']
    }),

    // 2. 数值累加模式
    step: Annotation<number>({
        reducer: (oldState, newState) => {
            return oldState + newState; // 旧值 + 新值
        },
        default: () => 0
    }),

    // 3. 普通覆盖模式(默认行为)
    input: Annotation<string>(),
});

代码解析

  1. history: 使用 spread operator [...old, ...new] 实现追加。这在聊天应用中非常常用,用于累积对话历史。
  2. step: 实现累加器。如果节点返回 step: 1,状态中的 step 就会增加 1。
  3. default: 这是一个工厂函数,当图启动且没有提供该字段的初始值时,会调用它来生成默认值。

3️⃣ Reducer 实战

让我们看看节点是如何与这些 Reducer 交互的。

输入节点

const inputNode = (state: typeof StateAnnotation.State) => {
    return {
        step: 1,               // 触发 reducer: 0 + 1 = 1
        history: [state.input] // 触发 reducer: 追加到 history 数组末尾
    }
}

验证节点

const validateOutputNode = (state: typeof StateAnnotation.State) => {
    return {
        step: 1,  // 再次触发 reducer: 1 + 1 = 2
        // history 这里没有返回,所以保持不变
    }
}

4️⃣ 运行效果

当我们运行这个图时,状态的变化如下:

  1. 初始状态history 默认为 ['系统启动']step 默认为 0
  2. inputNode 执行后
    • step: 0 + 1 = 1
    • history: ['系统启动', '用户输入']
  3. validateOutputNode 执行后
    • step: 1 + 1 = 2
    • history: 保持不变

💡 练习题

  1. 选择题:如果 step 的 reducer 定义为 (old, new) => new,那么连续两个节点都返回 step: 1,最终结果是多少?

    • A. 1
    • B. 2
    • 提示:这是覆盖模式的行为。
  2. 代码题:修改 reducer,使得 history 数组最多只保留最近的 3 条记录。


📚 参考资源

项目代码


✅ 总结

核心要点

  • Reducer 赋予了你控制状态更新方式的能力。
  • 最常用的 Reducer 模式是数组追加(用于消息历史)和数值累加(用于计数)。
  • Default 保证了状态字段在未初始化时也有安全的值。

下一步:在下一篇文章《LLM 节点集成》中,我们将引入真正的大脑——大语言模型,让我们的图变得智能起来。

登录以继续阅读

解锁完整文档、代码示例及更多高级功能。

立即登录

On this page