Skip to content

05-stateful-agent.ts

有状态 agent 示例,createAgent + MemorySaver checkpointer,支持跨 invoke 记忆 + thread_id 会话隔离。

功能介绍

这个示例演示了如何用 createAgent + MemorySaver 让 agent 跨多次 invoke() 调用记住对话。MemorySaver 是 LangGraph 的内存检查点保存器,持久化 agent 状态;thread_id 标识会话,相同 thread_id 共享状态,不同 thread_id 独立。3 轮演示验证记忆 + 隔离。

与 06-memory 的边界: 本示例教"如何记住"(checkpointer 跨轮持久化);06-memory(未来重构)教"如何遗忘"(长对话的 trimming / summarization middleware)。两者互补。

使用场景

  • 对话型 agent 需要记住用户信息
  • 多轮对话场景
  • 需要会话隔离的多用户 agent
  • 构建有上下文记忆的智能助手

学习要点

  1. MemorySaver@langchain/langgraph 导入(不是 langchain 主入口)
  2. createAgentcheckpointer 参数开启状态持久化
  3. config.configurable.thread_id 标识会话,相同 thread_id 共享状态,不同 thread_id 独立
  4. agent 在第 2 轮能看到第 1 轮的完整消息历史(这就是"记忆"的本质)
  5. invoke 的第二个参数是 config,传 thread_id

源码

typescript
import "dotenv/config";
import { ChatOpenAI } from "@langchain/openai";
import { createAgent } from "langchain";
import { MemorySaver } from "@langchain/langgraph";
import { tool } from "@langchain/core/tools";
import { z } from "zod";

// 本示例演示 createAgent + MemorySaver 的基础 checkpointer 机制(跨轮持久化 + 会话隔离)。
// 06-memory 模块(未来重构)会教长对话的记忆管理(trimming / summarization middleware)。
// 两者互补:本示例教"如何记住",06-memory 教"如何遗忘"。

if (!process.env.ZHIPUAI_API_KEY) {
  throw new Error("ZHIPUAI_API_KEY is not set in environment variables");
}

// 复用 01-tools 的天气工具定义
const weatherTool = tool(
  async ({ city, unit }) => {
    const weatherData: Record<string, { temp: number; condition: string }> = {
      "北京": { temp: 25, condition: "晴天" },
      "上海": { temp: 22, condition: "多云" },
      "广州": { temp: 28, condition: "小雨" },
    };
    const data = weatherData[city] || { temp: 20, condition: "未知" };
    const temp = unit === "fahrenheit" ? Math.round(data.temp * 9/5 + 32) : data.temp;
    return `${city} 的天气: ${data.condition},${temp}°${unit === "celsius" ? "C" : "F"}`;
  },
  {
    name: "get_current_weather",
    description: "获取指定城市的当前天气",
    schema: z.object({
      city: z.string().describe("城市名称"),
      unit: z.enum(["celsius", "fahrenheit"]).default("celsius").describe("温度单位"),
    }),
  }
);

async function main() {
  try {
    console.log("=== Stateful Agent 示例(createAgent + MemorySaver)===\n");

    const model = new ChatOpenAI({
      model: "deepseek-v3-1",
      temperature: 0,
      configuration: {
        baseURL: "https://ark.cn-beijing.volces.com/api/coding/v3/",
        apiKey: process.env.ZHIPUAI_API_KEY,
      },
    });

    // MemorySaver 是 LangGraph 的内存检查点保存器
    // 跨 invoke() 调用持久化 agent 状态
    const checkpointer = new MemorySaver();
    const agent = createAgent({
      model,
      tools: [weatherTool],
      checkpointer,
    });

    // thread_id 标识会话,相同 thread_id 共享状态
    const config = { configurable: { thread_id: "user-1" } };

    // 第一轮:自我介绍
    console.log("第一轮(thread_id: user-1):");
    const r1 = await agent.invoke(
      { messages: [{ role: "user", content: "我叫张三,我住在北京" }] },
      config
    );
    console.log("用户: 我叫张三,我住在北京");
    console.log("Agent:", r1.messages.at(-1)?.content);
    console.log("消息历史长度:", r1.messages.length);
    console.log("\n---\n");

    // 第二轮:测试记忆(相同 thread_id)
    console.log("第二轮(thread_id: user-1):");
    const r2 = await agent.invoke(
      { messages: [{ role: "user", content: "我叫什么名字?我住哪里?" }] },
      config
    );
    console.log("用户: 我叫什么名字?我住哪里?");
    console.log("Agent:", r2.messages.at(-1)?.content);
    console.log("消息历史长度:", r2.messages.length, "(应大于第一轮,证明状态累积)");
    console.log("\n---\n");

    // 第三轮:不同 thread_id,验证会话隔离
    console.log("第三轮(thread_id: user-2,新会话):");
    const config2 = { configurable: { thread_id: "user-2" } };
    const r3 = await agent.invoke(
      { messages: [{ role: "user", content: "我叫什么名字?" }] },
      config2
    );
    console.log("用户: 我叫什么名字?");
    console.log("Agent:", r3.messages.at(-1)?.content);
    console.log("消息历史长度:", r3.messages.length, "(应为 2,新会话无历史)");
    console.log("(Agent 应该不知道名字,因为是不同会话)");
  } catch (error) {
    console.error("Error during stateful agent example:", error);
    process.exit(1);
  }
}

main().catch(console.error);

运行方式

bash
npm run dev src/05-agents/05-stateful-agent.ts