Appearance
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
- 构建有上下文记忆的智能助手
学习要点
MemorySaver从@langchain/langgraph导入(不是langchain主入口)createAgent的checkpointer参数开启状态持久化config.configurable.thread_id标识会话,相同 thread_id 共享状态,不同 thread_id 独立- agent 在第 2 轮能看到第 1 轮的完整消息历史(这就是"记忆"的本质)
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