Install
npx skillscat add evanfang0054/cc-system-creator-scripts/langgraph-memory Install via the SkillsCat registry.
About this skill
This skill explains how to implement memory in LangGraph agents using JavaScript or TypeScript, covering both short-term thread-scoped memory via checkpointers and long-term cross-thread memory via stores. It solves the problem of building agents that maintain conversation context within a session while also retaining facts and preferences across sessions. Developers should use it when they need to add stateful behavior to LangGraph workflows, distinguishing between ephemeral dialogue history and persistent user data.
SKILL.md
langgraph-memory (JavaScript/TypeScript)
name: langgraph-memory
description: LangGraph 中的内存 - 短期(线程范围)vs 长期(跨线程)内存,使用检查点器和存储
概述
LangGraph 为 Agent 提供两种类型的内存:
- 短期内存:线程范围,通过检查点器管理
- 长期内存:跨线程,通过存储管理
决策表:内存类型
| 类型 | 范围 | 持久化 | 使用场景 |
|---|---|---|---|
| 短期 | 单个线程 | 通过检查点器 | 对话历史 |
| 长期 | 跨线程 | 通过存储 | 用户偏好、事实 |
代码示例
短期内存(线程范围)
import { MemorySaver, StateGraph, StateSchema, ReducedValue, START, END } from "@langchain/langgraph";
import { z } from "zod";
const State = new StateSchema({
messages: new ReducedValue(
z.array(z.string()).default(() => []),
{ reducer: (current, update) => current.concat(update) }
),
});
const respond = async (state: typeof State.State) => {
// 访问对话历史
const history = state.messages;
return { messages: [`I remember ${history.length} messages`] };
};
const checkpointer = new MemorySaver();
const graph = new StateGraph(State)
.addNode("respond", respond)
.addEdge(START, "respond")
.addEdge("respond", END)
.compile({ checkpointer });
// 第一轮
const config = { configurable: { thread_id: "user-1" } };
await graph.invoke({ messages: ["Hello"] }, config);
// 第二轮 - 记住第一轮
await graph.invoke({ messages: ["How are you?"] }, config);
// 响应: "I remember 3 messages" (Hello, 响应, How are you?)长期内存(跨线程)
import { InMemoryStore } from "@langchain/langgraph";
// 创建长期内存存储
const store = new InMemoryStore();
// 保存用户偏好(在所有线程中可用)
const userId = "alice";
const namespace = [userId, "preferences"];
await store.put(
namespace,
"language",
{ preference: "short, direct responses" }
);
// 在任何线程中检索
const getUserPrefs = async (state, config) => {
const store = config.store;
const userId = state.userId;
const namespace = [userId, "preferences"];
const prefs = await store.get(namespace, "language");
return { preferences: prefs };
};
// 使用存储编译
const graph = builder.compile({
checkpointer,
store,
});
// 在不同线程中使用
const thread1 = { configurable: { thread_id: "thread-1" } };
const thread2 = { configurable: { thread_id: "thread-2" } };
// 两个线程访问相同的长期内存
await graph.invoke({ userId: "alice" }, thread1); // 获取偏好
await graph.invoke({ userId: "alice" }, thread2); // 相同的偏好存储操作
import { InMemoryStore } from "@langchain/langgraph";
const store = new InMemoryStore();
// Put(创建/更新)
await store.put(
["user-123", "facts"],
"location",
{ city: "San Francisco", country: "USA" }
);
// Get
const item = await store.get(["user-123", "facts"], "location");
console.log(item); // { city: 'San Francisco', country: 'USA' }
// 带过滤器搜索
const results = await store.search(
["user-123", "facts"],
{ filter: { country: "USA" } }
);
// Delete
await store.delete(["user-123", "facts"], "location");在节点中访问存储
import { BaseStore } from "@langchain/langgraph";
const myNode = async (state, config: { store: BaseStore }) => {
const store = config.store;
const namespace = [state.userId, "memories"];
// 检索过去的记忆
const memories = await store.search(namespace, { query: "preferences" });
// 保存新记忆
await store.put(
namespace,
"new_fact",
{ fact: "User likes TypeScript" }
);
return { processed: true };
};
const graph = builder.compile({
checkpointer,
store,
});组合短期和长期内存
const smartNode = async (state, config) => {
const store = config.store;
// 短期:对话上下文
const recentMessages = state.messages.slice(-5); // 最近 5 条消息
// 长期:用户档案
const userId = state.userId;
const profile = await store.get([userId, "profile"], "info");
// 使用两者生成个性化响应
const response = await generateResponse(recentMessages, profile);
return { messages: [response] };
};
const graph = new StateGraph(State)
.addNode("respond", smartNode)
.addEdge(START, "respond")
.addEdge("respond", END)
.compile({ checkpointer, store });持久化存储(生产环境)
import { PostgresStore } from "@langchain/langgraph-checkpoint-postgres";
// 在生产环境中使用 PostgreSQL
const store = await PostgresStore.fromConnString(
"postgresql://user:pass@localhost/db"
);
const graph = builder.compile({
checkpointer,
store,
});边界
您能够配置的
✅ 使用检查点器进行短期内存
✅ 使用存储进行长期内存
✅ 命名空间组织
✅ 搜索和过滤记忆
✅ 通过 config 在节点中访问存储
✅ 选择存储后端
您不能配置的
❌ 跨线程共享短期内存
❌ 修改内存序列化格式
❌ 存储机制内部
注意事项
1. 短期需要检查点器
// ❌ 错误 - 没有检查点器,没有内存
const graph = builder.compile(); // 消息丢失!
// ✅ 正确
const checkpointer = new MemorySaver();
const graph = builder.compile({ checkpointer });2. 长期需要存储
// ❌ 错误 - 试图在没有存储的情况下共享数据
// 仅靠检查点器无法访问来自其他线程的数据!
// ✅ 正确 - 使用存储
const store = new InMemoryStore();
const graph = builder.compile({ checkpointer, store });3. 通过 Config 访问存储
// ❌ 错误 - 存储不可用
const myNode = async (state) => {
store.put(...); // ReferenceError!
};
// ✅ 正确 - 通过 config 访问
const myNode = async (state, config) => {
const store = config.store;
await store.put(...);
};4. InMemoryStore 不用于生产环境
// ❌ 错误 - 重启时数据丢失
const store = new InMemoryStore(); // 仅内存!
// ✅ 正确 - 使用持久化后端
import { PostgresStore } from "@langchain/langgraph-checkpoint-postgres";
const store = await PostgresStore.fromConnString("postgresql://...");5. 始终 Await 存储操作
// ❌ 错误
const item = store.get(namespace, key);
console.log(item); // Promise!
// ✅ 正确
const item = await store.get(namespace, key);
console.log(item);