[LangGraph] 短期记忆
这节课我们来介绍一下记忆。在 langgraph 中,记忆分为两种:
- 短期记忆:Short-term Memory
- 长期记忆:Long-term Memory
基本概念
所谓短期记忆,指的就是在某一个 thread 内持续演化的 State。只要 State 在同一个 thread_id 下被反复传入和更新,agent 就具备了多轮对话的能力。
举个例子,假设我们在 StateGraph 里定义了一个 State:
type State = {
messages: Message[];
topic?: string;
plan?: string;
}
State 里装的内容,本身就是短期记忆。多轮对话能成立,靠的是这三件事一起配合:
- State 会在同一个 thread_id 下持续存在
- 每一轮执行,都会把上一次的 State 传进来
- 新节点在旧 State 的基础上继续改
例如:
// 第 1 轮
State.messages = ["你好"]
// 第 2 轮
State.messages = ["你好", "你是谁"]
// 第 3 轮
State.messages = ["你好", "你是谁", "我们刚刚聊了什么"]
另外,这里一定要注意,短期记忆是和 thread 绑定的,也就是说:
thread_id = A有一份独立的 Statethread_id = B是另一份完全不同的 State
只要 thread 不同:短期记忆就不共享。这也是为什么官网说它是 short-term,因为它的生命周期是:
从 thread 开始 → 到 thread 结束
而不是:
- 跨会话
- 跨线程
- 跨用户
快速上手
下面我们通过一个快速上手示例来验证:
- 不同用户 → 不同 thread
- 切换用户 → 短期记忆立即切换
- 不使用 Store(长期记忆)
- 只使用 State + MemorySaver
用户设计
| 用户名 | 密码 | thread_id |
|---|---|---|
| aaa | 111 | thread-aaa |
| bbb | 222 | thread-bbb |
每个用户固定使用一个 thread_id
import "dotenv/config";
import { ChatOpenAI } from "@langchain/openai";
import {
MemorySaver,
StateGraph,
START,
END,
MessagesZodMeta,
} from "@langchain/langgraph";
import { z } from "zod/v4";
import readline from "readline-sync";
import { HumanMessage, BaseMessage } from "@langchain/core/messages";
import { registry } from "@langchain/langgraph/zod";
// 用户系统
const users = {
aaa: { password: "111", thread_id: "thread-aaa" },
bbb: { password: "222", thread_id: "thread-bbb" },
};
const Schema = z.object({
messages: z.array(z.custom<BaseMessage>()).register(registry, {
...MessagesZodMeta,
default: () => [],
}),
});
type TState = z.infer<typeof Schema>;
const model = new ChatOpenAI({
model: "gpt-4o",
temperature: 0.5,
});
// 聊天的节点
async function chatNode(state: TState): Promise<Partial<TState>> {
const res = await model.invoke(state.messages);
return {
messages: [res],
};
}
const checkpointer = new MemorySaver();
// 图
const graph = new StateGraph(Schema)
.addNode("chatNode", chatNode)
.addEdge(START, "chatNode")
.addEdge("chatNode", END)
.compile({ checkpointer });
async function main() {
while (true) {
console.log("\n--- 登录 ---");
const username = readline.question("请输入用户名:");
const password = readline.question("请输入密码:", {
hideEchoBack: true,
});
const user = users[username];
if (!user || user.password !== password) {
console.log("登录失败☹️");
continue;
}
// 登录成功
console.log(`✅ 登录成功,当前用户:${username}`);
console.log("输入 /switch 可切换用户\n");
const config = {
configurable: {
thread_id: user.thread_id, // 这个非常重要,这个保证了不同的用户拥有不同的state
},
};
// 处理用户的对话
while (true) {
const input = readline.question(`${username}>`);
if (input === "/switch") {
console.log("切换用户中...");
break;
}
// 这里只需要传入当前这一轮的输入消息
const result = await graph.invoke(
{
messages: [new HumanMessage(input)],
},
config,
);
// 返回的结果就是完整的状态
const aiMsg = result.messages.at(-1);
console.log(`AI> ${aiMsg?.content}`);
}
}
}
main();
-EOF-

浙公网安备 33010602011771号