记忆(Memory)
为 Deep Agents 构建的 Agent 添加持久化记忆,使其能够在跨对话中学习和改进
从"无状态的问答机器"到"能记住一切的伙伴"的关键一步为什么需要它
你有没有试过让 Agent 记住用户上次说过的话?
无记忆 Agent 的困境
- 每次对话都是"新来的",不记得用户偏好
- 学到的经验全丢了,同样的错误反复犯
- 上下文一结束就消失,无法跨会话积累知识
- 所有用户看到一样的 Agent,没有个性化体验
- 组织级的合规规则?只能写死在提示词里,无法动态更新
Deep Agents 的解法
- 基于文件系统的记忆机制,Agent 以文件形式读写记忆
- 可插拔后端控制记忆存储位置(内存、Store、磁盘)
- 记忆分作用域:Agent 级别、用户级别、组织级别
- 支持后台整合:空闲时自动回顾对话、提取关键事实
- 声明式只读控制,防止共享记忆被恶意修改
开始之前
你需要会什么
- 了解 Deep Agents 的基本概念(
createDeepAgent、后端、工具) - 了解 LangGraph 的 State 和 Store 概念
- TypeScript 基础(函数、类型、async/await)
- 了解文件路径和命名空间的概念
读完后你应该能
- 说清短期记忆和长期记忆的区别
- 为 Agent 配置 Agent 级别、用户级别记忆
- 实现跨对话的情景记忆搜索
- 配置后台整合 Agent 和 Cron 定时任务
- 理解只读 vs 可写记忆的安全考量
本章不会深入
- 上下文工程的详细机制(见第 08 章)
- 权限系统的完整配置(见第 13 章)
- 后端的详细实现(见第 09 章)
- 技能(Skills)的深入用法(见第 15 章)
工作原理
三步走:指向记忆文件 → Agent 读取 → Agent 更新
1. 指向记忆文件
创建 Agent 时通过 memory= 参数传入文件路径,通过 skills= 传入技能文件。后端控制文件的实际存储位置。
2. Agent 读取记忆
启动时加载到系统提示,或对话过程中按需读取。技能文件用按需加载:先读描述,匹配到任务时才读全文。
3. Agent 更新记忆
学习到新信息时,用 edit_file 工具更新记忆文件。可在对话中即时更新,也可通过后台整合在对话间更新。
import { createDeepAgent, CompositeBackend, StateBackend, StoreBackend } from "deepagents";
const agent = createDeepAgent({
memory: ["/memories/AGENTS.md"], // Agent 启动时加载到系统提示的记忆文件
skills: ["/skills/"], // 按需加载的技能目录
backend: new CompositeBackend(
new StateBackend(), // 默认后端用于临时状态
{
// 记忆文件路由到 StoreBackend,支持持久化
"/memories/": new StoreBackend({
namespace: (rt) => [rt.serverInfo.assistantId], // 按 Agent ID 隔离
}),
// 技能文件也用 StoreBackend,支持跨线程共享
"/skills/": new StoreBackend({
namespace: (rt) => [rt.serverInfo.assistantId], // 同一 Agent 共享
}),
},
),
});
记忆分类
短期记忆管"这一次对话",长期记忆管"所有对话"
短期记忆(Short-term)
- 范围:单个对话线程(thread)内
- 内容:对话历史、临时文件、中间结果
- 生命周期:对话结束即结束
- 实现:通过 Checkpoint 自动管理
- 类比:你的"工作记忆",打电话时记得对方说了什么
长期记忆(Long-term)
- 范围:跨对话线程、跨会话
- 内容:用户偏好、学到的知识、技能、策略
- 生命周期:永久持久化,直到被删除或更新
- 实现:通过 Memory Store + 文件系统管理
- 类比:你的"笔记本",打电话之前就写好了笔记
记忆的三个子类型
| 类型 | 存什么 | 示例 |
|---|---|---|
| 情景记忆 | 过往经历的完整记录 | 过去的对话、调试过程 |
| 程序性记忆 | 可复用的指令和技能 | Skill 文件、操作流程 |
| 语义记忆 | 事实和偏好 | "用户喜欢简洁回答" |
它们怎么协作
- 情景记忆提供上下文——"上次怎么做的"
- 程序性记忆提供能力——"应该怎么做"
- 语义记忆提供知识——"什么是已知的"
- 三者在 Deep Agents 中都通过文件系统统一管理
作用域
通过命名空间控制记忆的"可见范围"——谁能看到什么
Deep Agents 通过后端的命名空间来控制记忆的作用域。不同的命名空间策略决定了记忆的共享范围:
Agent 级别记忆
所有用户共享同一份记忆文件。Agent 通过每次对话积累个性和知识。
命名空间:(assistant_id,)
适合:Agent 自我改进、积累专业知识
跨用户共享
用户级别记忆
每个用户拥有独立的记忆文件。用户之间完全隔离。
命名空间:(user_id,)
适合:个性化服务、用户偏好管理
按用户隔离
组织级别记忆
组织内所有成员共享的策略和知识。通常设为只读。
命名空间:(org_id,)
适合:合规策略、共享知识库
跨用户共享 + 只读
Agent 级别
赋予 Agent 自己的持久化身份——它随时间不断演进
Agent 级别记忆在所有用户之间共享,因此 Agent 会通过每一次对话积累自己的个性、知识和偏好。随着与用户的交互,它会不断深化专业知识、优化方法,并记住哪些做法有效。命名空间设为 (assistant_id,),意味着该 Agent 的每一次对话都读写同一个记忆文件。当拥有写入权限时,它还可以学习和更新 Skill。
import { createDeepAgent, CompositeBackend, StateBackend, StoreBackend } from "deepagents";
const agent = createDeepAgent({
memory: ["/memories/AGENTS.md"],
skills: ["/skills/"],
backend: new CompositeBackend(
new StateBackend(),
{
"/memories/": new StoreBackend({
// assistantId 作为命名空间,所有用户共享同一份记忆
namespace: (rt) => [rt.serverInfo.assistantId],
}),
"/skills/": new StoreBackend({
// 同理,所有用户共享同一份技能
namespace: (rt) => [rt.serverInfo.assistantId],
}),
},
),
});
rt.serverInfo 需要 deepagents >= 1.9.0。在较旧版本中,请从 getConfig().metadata.assistantId 读取 assistant ID。
初始化记忆内容
import { InMemoryStore } from "@langchain/langgraph";
import { createFileData } from "deepagents";
const store = new InMemoryStore();
// 向 Store 中写入初始记忆
await store.put(
["my-agent"],
"/memories/AGENTS.md",
createFileData(`## Response style
- Keep responses concise
- Use code examples where possible
`),
);
跨线程验证记忆
// 线程 1:Agent 学习偏好
const config1 = { configurable: {
thread_id: uuidv4()
}};
await agent.invoke({
messages: [{
role: "user",
content: "I prefer detailed explanations."
}],
}, config1);
// 线程 2:Agent 记住了偏好
const config2 = { configurable: {
thread_id: uuidv4()
}};
await agent.invoke({
messages: [{
role: "user",
content: "Explain transformers."
}],
}, config2);
用户级别
为每个用户提供独立的记忆文件——个性化服务的基石
命名空间设为 (user_id,),每个用户获得一份隔离的记忆文件副本。用户 A 的偏好永远不会泄露到用户 B 的对话中。
import { createDeepAgent, CompositeBackend, StateBackend, StoreBackend } from "deepagents";
const agent = createDeepAgent({
memory: ["/memories/preferences.md"],
skills: ["/skills/"],
backend: new CompositeBackend(
new StateBackend(),
{
"/memories/": new StoreBackend({
// user.identity 作为命名空间,每个用户独立一份记忆
namespace: (rt) => [rt.serverInfo.user.identity],
}),
"/skills/": new StoreBackend({
// 同理,每个用户独立一份技能
namespace: (rt) => [rt.serverInfo.user.identity],
}),
},
),
});
Alice 的记忆
await store.put(
["user-alice"],
"/memories/preferences.md",
createFileData(`## Preferences
- Likes concise bullet points
- Prefers Python examples
`)
);
Bob 的记忆
await store.put(
["user-bob"],
"/memories/preferences.md",
createFileData(`## Preferences
- Likes detailed explanations
- Prefers TypeScript examples
`)
);
rt.serverInfo.user.identity 解析为调用用户。Alice 只能看到自己的偏好,Bob 也一样。核心指令保持不变,只有记忆文件因人而异。
高级维度
记忆不只是"存取"——六个维度决定你的记忆策略
| 维度 | 回答的问题 | 可选值 |
|---|---|---|
| 持续时间 | 记忆保持多久? | 短期(单次对话) / 长期(跨对话) |
| 信息类型 | 存储什么类型的信息? | 情景(过往经历) / 程序性(指令技能) / 语义(事实) |
| 作用域 | 谁可以查看和修改? | 用户级别 / Agent 级别 / 组织级别 |
| 更新策略 | 记忆何时写入? | 对话过程中(默认) / 对话之间(后台整合) |
| 检索方式 | 记忆如何读取? | 加载到提示中(默认) / 按需读取(如 Skill) |
| Agent 权限 | Agent 是否可以写入? | 读写(默认) / 只读(共享策略) |
情景记忆
让 Agent 回忆"过去是怎么解决问题的"——不只是学到了什么
情景记忆存储完整的对话上下文:发生了什么、顺序如何、结果怎样。Deep Agents 已通过 Checkpoint 机制自动保存每一段对话。要让过去的对话可搜索,可以把线程搜索封装为一个工具:
import { Client } from "@langchain/langgraph-sdk";
import { tool } from "@langchain/core/tools";
const client = new Client({ apiUrl: "" });
const searchPastConversations = tool(
async ({ query }, runtime) => {
// 从运行时上下文获取用户 ID,而非作为参数传入——防止用户伪造身份
const userId = runtime.serverInfo.user.identity;
// 按用户 ID 搜索历史对话线程,最多返回 5 条
const threads = await client.threads.search({
metadata: { userId },
limit: 5,
});
const results = [];
for (const thread of threads) {
const history = await client.threads.getHistory(thread.threadId);
results.push(history);
}
return JSON.stringify(results);
},
{
name: "search_past_conversations",
description: "Search past conversations for relevant context.",
}
);
按用户搜索
const userThreads = await client.threads.search({
metadata: { userId },
limit: 5,
});
按组织搜索
const orgThreads = await client.threads.search({
metadata: { orgId },
limit: 5,
});
user_id 从运行时上下文中获取,而非作为参数传入——防止用户伪造身份访问他人记忆。
组织级记忆
跨用户共享的策略和知识——通常是只读的
组织级别记忆使用组织范围的命名空间,用于对组织内所有用户和 Agent 生效的策略或知识。它通常是只读的,以防止提示注入。
const agent = createDeepAgent({
memory: [
"/memories/preferences.md", // 用户级:按用户隔离,可读写
"/policies/compliance.md", // 组织级:所有人共享,通常只读
],
backend: new CompositeBackend(
new StateBackend(),
{
// 用户偏好:按用户身份隔离存储
"/memories/": new StoreBackend({
namespace: (rt) => [rt.serverInfo.user.identity],
}),
// 组织策略:按组织 ID 共享,通过权限配置为只读
"/policies/": new StoreBackend({
namespace: (rt) => [rt.context.orgId],
}),
},
),
});
写入组织记忆
import { Client } from "@langchain/langgraph-sdk";
import { createFileData } from "deepagents";
const client = new Client({
apiUrl: ""
});
await client.store.putItem(
[orgId],
"/compliance.md",
createFileData(`## Compliance policies
- Never disclose internal pricing
- Always include disclaimers
on financial advice
`),
);
读写 vs 只读
| 权限 | 场景 | 方式 |
|---|---|---|
| 读写 | 用户偏好、Agent 自学 | Agent 通过内置 edit_file 工具更新文件 |
| 只读 | 组织策略、合规规则 | 通过应用代码或 Store API 填充;使用权限(Permissions)拒绝特定路径写入,或使用策略钩子(Policy Hooks)进行自定义验证逻辑 |
(user_id);(2) 共享策略用只读记忆(通过应用代码填充,而非 Agent);(3) 在 Agent 写入共享记忆之前添加人工审核——使用中断(interrupt)来要求人工批准对敏感路径的写入。对于自定义验证逻辑(速率限制、审计日志、内容检查),可使用后端策略钩子(Policy Hooks)。
后台整合
让 Agent 在"空闲时"回顾对话、提取关键事实——零延迟记忆升级
默认方式是热路径(对话中即时写入记忆)。另一种方式是后台整合——有时也被称为休眠期计算(sleep time compute):一个独立的 Deep Agent 在对话之间审查最近的对话,提取关键事实并合并到记忆中。
热路径(默认)
- 优点:记忆立即可用,对用户透明
- 缺点:增加延迟,Agent 需要多任务处理
- 适合:大多数应用场景
后台整合
- 优点:无面向用户的延迟,可综合多次对话
- 缺点:记忆要下次对话才可用,需要额外 Agent
- 适合:需要降低延迟或提高记忆质量时
图:后台整合工作流
工作流程说明:
- Cron 定时任务(紫色,定时触发)按固定计划驱动整合流程
- 整合 Agent(蓝色,处理核心)被触发后,从 Memory Store 读取近期对话(Conversation 1、Conversation 2)的历史记录
- 整合 Agent 审查对话内容,提取关键事实,合并去重后写入 Memory Store(橙色,记忆存储)
- 下一次用户对话时,Agent 从 Store 中读取更新后的记忆,立即可用
整个过程对用户透明——用户在对话中零延迟,记忆在"休眠期"自动完成升级。
整合 Agent
一个独立的 Deep Agent——读取最近对话、提取事实、合并到记忆
// src/consolidation-agent.ts
import { createDeepAgent } from "deepagents";
import { Client } from "@langchain/langgraph-sdk";
import { tool } from "@langchain/core/tools";
const sdkClient = new Client({ apiUrl: "" });
const searchRecentConversations = tool(
async ({ query }, runtime) => {
const userId = runtime.serverInfo.user.identity;
// 回溯 6 小时内的对话,与 Cron 间隔匹配
const since = new Date(Date.now() - 6 * 60 * 60 * 1000).toISOString();
const threads = await sdkClient.threads.search({
metadata: { userId }, // 按用户筛选
updatedAfter: since, // 只查找最近 6 小时内更新的线程
limit: 20, // 最多获取 20 条
});
// 遍历每个线程,获取完整对话历史
const conversations = [];
for (const thread of threads) {
const history = await sdkClient.threads.getHistory(thread.threadId);
conversations.push(history.values.messages);
}
return JSON.stringify(conversations);
},
{
name: "search_recent_conversations",
description: "Search this user's conversations updated in the last 6 hours.",
}
);
const agent = createDeepAgent({
model: "google-genai:gemini-3.1-pro-preview",
systemPrompt: `Review recent conversations and update the user's memory file.
Merge new facts, remove outdated information, and keep it concise.`,
tools: [searchRecentConversations],
});
export { agent };
langgraph.json 配置
{
"dependencies": ["."],
"graphs": {
"agent": "./src/agent.ts:agent",
"consolidation_agent":
"./src/consolidation-agent.ts:agent"
},
"env": ".env"
}
Cron 定时触发
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({
apiUrl: ""
});
const cronJob = await client.crons.create(
"consolidation_agent",
{
schedule: "0 */6 * * *", // 每 6 小时
input: { messages: [{
role: "user",
content: "Consolidate recent memories."
}] },
},
);
0 */6 * * *),Agent 回溯 6 * 60 * 60 * 1000(6 小时)。如果 Cron 运行频率高于回溯窗口,会重复处理;低于则遗漏记忆。
并发与隔离
多线程写入和多 Agent 共存的注意事项
并发写入
多个线程可以并行写入记忆,但对同一文件的并发写入可能导致"最后写入胜出"冲突。
- 用户级记忆冲突率低(用户通常一次一个对话)
- Agent/组织级记忆可用后台整合序列化写入
- 按主题拆分为独立文件可减少争用
- LLM 通常能从写入失败中恢复
多 Agent 隔离
共享部署中为每个 Agent 提供独立记忆,在命名空间中添加 assistant_id:
new StoreBackend({
// 多维度命名空间:先按 Agent 再按用户隔离
// 避免不同 Agent 的记忆互相污染
namespace: (rt) => [
rt.serverInfo.assistantId,
rt.serverInfo.user.identity,
],
})
如果只需按 Agent 隔离,单独使用 assistant_id 即可。
动手练习
设计一个带记忆的技术支持 Agent——综合运用作用域、情景记忆和后台整合
现在轮到你了。停下来,思考如何用 Deep Agents 构建一个带持久化记忆的技术支持 Agent。需求如下:
智能体应该:
1. 记住每个用户的偏好(语言、回答风格、常见问题)
2. 搜索过去的对话历史来回答重复问题
3. 从每次对话中学习新的解决方案
4. 每个用户的记忆完全隔离
5. 组织级的合规策略不可被 Agent 修改
6. 每 4 小时自动整合最近的对话
任务 1:设计作用域
- 哪些记忆用用户级别?哪些用组织级别?
- 命名空间应该怎么设置?
- 哪些记忆需要设为只读?
任务 2:配置后端
- 需要几个 StoreBackend?各自用什么命名空间?
- CompositeBackend 的路径映射怎么设计?
- 初始记忆文件包含什么内容?
任务 3:设计整合
- 整合 Agent 的回溯窗口设多久?
- Cron 的执行频率怎么匹配?
- 整合 Agent 的系统提示词应该怎么写?
参考答案
一种可行的设计方案——三级作用域 + 后台整合
import { v4 as uuidv4 } from "uuid";
import { createDeepAgent, CompositeBackend, StateBackend, StoreBackend, createFileData } from "deepagents";
import { InMemoryStore } from "@langchain/langgraph";
const store = new InMemoryStore();
// 初始化组织级只读策略(由应用代码写入,Agent 不可修改)
await store.put(
["my-org"], // 组织级命名空间
"/policies/compliance.md", // 文件路径
createFileData(`## Support Policies
- Never share user data between accounts
- Always include SLA timelines in responses
- Escalate billing issues to human agents
`),
);
const agent = createDeepAgent({
memory: [
"/memories/preferences.md", // 用户级:按用户隔离,可读写
"/policies/compliance.md", // 组织级:只读策略,需配合权限配置
],
backend: new CompositeBackend(
new StateBackend(),
{
// 用户偏好:按用户身份隔离
"/memories/": new StoreBackend({
namespace: (rt) => [rt.serverInfo.user.identity],
}),
// 组织策略:按组织 ID 共享
"/policies/": new StoreBackend({
namespace: (rt) => [rt.context.orgId],
}),
},
),
store,
});
作用域设计
| 路径 | 作用域 | 权限 | 内容 |
|---|---|---|---|
/memories/ | 用户级 | 读写 | 偏好、历史学习 |
/policies/ | 组织级 | 只读 | 合规策略 |
整合 Agent 配置
// Cron:每 4 小时运行
await client.crons.create(
"consolidation_agent",
{
schedule: "0 */4 * * *",
input: { messages: [{
role: "user",
content: "Consolidate."
}] },
},
);
// 回溯窗口:4 小时(与 Cron 匹配)
const since = new Date(
Date.now() - 4 * 60 * 60 * 1000
);
本章回顾
到这里,你已经掌握了 Deep Agents 记忆系统的完整用法
你学到了什么
- 记忆的本质是Agent 可读写的文件,通过后端控制存储
- 短期记忆(单次对话)vs 长期记忆(跨对话持久化)
- 三种记忆类型:情景、程序性、语义
- 三种作用域:Agent 级别、用户级别、组织级别
- 通过命名空间控制记忆的可见范围
- 后台整合让 Agent 在空闲时回顾对话、提取事实
- 共享记忆务必设为只读,防止提示注入
- Cron 间隔必须与整合 Agent 的回溯窗口匹配
后续章节预告
- 技能(Skills) — 可复用的程序性记忆模块
- 沙箱 — 隔离执行代码的安全环境
- 解释器 — 在内存中运行 JavaScript
- 上线生产 — 部署、监控、扩展最佳实践
- 前端集成 — 在 Web 应用中使用 Deep Agents
延伸阅读
继续本课程
- 下一章:技能(Skills) — 程序性记忆的深入用法
- 权限系统 — 只读控制的声明式配置
- 后端详解 — StoreBackend 的完整参数
官方文档
- deepagents npm 包 — 安装和 API 参考
- GitHub 仓库 — 源码和示例
- LangSmith — 追踪记忆写入的审计平台
相关概念
- LangGraph 持久化 — Checkpoint 和 Store 机制
- LangGraph Cron Jobs — 定时任务配置
- 上下文工程 — 短期记忆的详细管理策略