主题
09. 长期记忆:让代理"记住"你
从"金鱼"到"老朋友"的进化
引言
普通的 AI 助手像一条"金鱼"——每次对话都是全新的开始,它不记得你是谁、你喜欢什么、你们之前聊过什么。
长期记忆让代理变成"老朋友":
- 记住你的名字和偏好
- 积累使用中学到的知识
- 在新对话中应用过去的经验
- 随着时间推移变得更了解你

┌─────────────────────────────────────────────────────────────┐
│ │
│ 对话 1 对话 2 对话 3 │
│ ┌───────┐ ┌───────┐ ┌───────┐ │
│ │ 你好 │ │ 天气?│ │ 写代码│ │
│ └───┬───┘ └───┬───┘ └───┬───┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ 长期记忆 │ │
│ │ • 用户:张三,前端工程师 │ │
│ │ • 偏好:简洁回复,TypeScript │ │
│ │ • 项目:正在开发电商网站 │ │
│ └───────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘实现原理
DeepAgents 通过 CompositeBackend + StoreBackend 实现长期记忆:
- 代理将记忆写入特定路径(如
/memories/) - CompositeBackend 将该路径路由到 StoreBackend
- StoreBackend 使用 LangGraph 的 BaseStore 跨线程持久化
- 新对话时,代理从持久化存储中读取记忆

┌─────────────────────────────────────────────────────────────┐
│ CompositeBackend │
│ │
│ write_file("/memories/prefs.md") │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 路由规则:/memories/* → StoreBackend │ │
│ └─────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ LangGraph Store │ │
│ │ (跨线程持久化存储) │ │
│ └─────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘基础配置
步骤 1:创建 Store
typescript
import { InMemoryStore } from "@langchain/langgraph";
const store = new InMemoryStore();注意:
InMemoryStore适合开发测试,生产环境应使用PostgresStore等持久化实现。
步骤 2:配置 CompositeBackend
typescript
import { createDeepAgent } from "deepagents";
import { CompositeBackend, StateBackend, StoreBackend } from "deepagents/backends";
const agent = createDeepAgent({
backend: (rt) => new CompositeBackend(
new StateBackend(rt), // 默认后端:临时存储
{
"/memories/": new StoreBackend(rt), // 记忆路径 → 持久化
}
),
store: store, // 必须提供!
});步骤 3:指导代理使用记忆
typescript
const agent = createDeepAgent({
backend: (rt) => new CompositeBackend(
new StateBackend(rt),
{ "/memories/": new StoreBackend(rt) }
),
store: store,
systemPrompt: `你是一个具有长期记忆能力的助手。
## 记忆系统
你可以在 /memories/ 目录下保存和读取跨会话持久化的信息。
### 记忆文件
- /memories/user_profile.md - 用户基本信息
- /memories/preferences.md - 用户偏好设置
- /memories/notes.md - 重要笔记
### 工作流程
1. **对话开始时**:
- ls("/memories/") 检查是否有现有记忆
- read_file 加载相关记忆
2. **对话过程中**:
- 发现用户新偏好 → 更新 preferences.md
- 用户提到重要信息 → 更新 user_profile.md
- 完成重要任务 → 记录到 notes.md
3. **记忆原则**:
- 只保存真正有价值的信息
- 避免重复存储相同内容
- 定期整理和更新
`
});
记忆类型

1. 用户档案
存储用户的基本信息:
markdown
# 用户档案
## 基本信息
- 姓名:张三
- 职业:前端工程师
- 公司:ABC科技
## 技术背景
- 主要语言:TypeScript, JavaScript
- 框架:React, Next.js
- 工具:VS Code, Git
## 联系方式
- 时区:Asia/Shanghai2. 用户偏好
存储用户的使用偏好:
markdown
# 用户偏好
## 回复风格
- 简洁明了
- 包含代码示例
- 使用中文
## 代码风格
- 函数式编程优先
- 使用 TypeScript 类型
- ESLint + Prettier
## 其他偏好
- 不喜欢长篇大论
- 喜欢用表格对比3. 项目笔记
存储项目相关信息:
markdown
# 项目笔记
## 当前项目:电商网站
### 技术栈
- 前端:Next.js 14 + TypeScript
- 后端:Node.js + Prisma
- 数据库:PostgreSQL
### 进度
- [x] 用户认证模块
- [ ] 商品列表页
- [ ] 购物车功能
### 注意事项
- API 路径规范:/api/v1/...
- 组件命名:大驼峰4. 历史摘要
存储对话历史的摘要:
markdown
# 对话历史
## 2024-01-15
- 帮助用户配置 ESLint
- 解决了 TypeScript 类型报错问题
## 2024-01-14
- 讨论了项目架构
- 推荐使用 Next.js App Router记忆协议
为了让代理有效地使用记忆系统,建议在系统提示词中定义清晰的"记忆协议":

启动检查协议
typescript
systemPrompt: `...
## 启动协议
每次对话开始时,执行以下步骤:
1. 检查记忆目录
ls("/memories/")
2. 如果存在记忆,按优先级加载:
- read_file("/memories/user_profile.md") // 必读
- read_file("/memories/preferences.md") // 必读
- read_file("/memories/current_project.md") // 如果讨论项目
3. 根据记忆调整行为
- 使用用户偏好的回复风格
- 引用相关的项目背景
- 避免询问已知信息
`记忆更新协议
typescript
systemPrompt: `...
## 记忆更新协议
在对话过程中,当发现以下情况时更新记忆:
### 触发条件
- 用户明确告知个人信息 → 更新 user_profile.md
- 用户表达偏好("我喜欢..."、"我不喜欢...") → 更新 preferences.md
- 完成重要任务 → 记录到 notes.md
- 对话有价值的结论 → 追加到 history.md
### 更新方式
- 使用 edit_file 进行精确修改
- 避免覆盖现有重要信息
- 添加时间戳便于追踪
### 示例
当用户说:"我喜欢简洁的回复"
→ edit_file("/memories/preferences.md", {
old_string: "## 回复风格",
new_string: "## 回复风格\\n- 简洁明了"
})
`完整示例
带记忆的个人助手
typescript
import { createDeepAgent } from "deepagents";
import { CompositeBackend, StateBackend, StoreBackend } from "deepagents/backends";
import { InMemoryStore, MemorySaver } from "@langchain/langgraph";
import { v4 as uuidv4 } from "uuid";
const store = new InMemoryStore();
const checkpointer = new MemorySaver();
const assistant = createDeepAgent({
backend: (rt) => new CompositeBackend(
new StateBackend(rt),
{ "/memories/": new StoreBackend(rt) }
),
store,
checkpointer,
systemPrompt: `你是一个具有长期记忆能力的个人助手。
## 核心能力
你可以记住用户的信息、偏好和历史交互,在后续对话中提供个性化服务。
## 记忆系统
### 目录结构
- /memories/user_profile.md - 用户基本信息
- /memories/preferences.md - 用户偏好
- /memories/notes.md - 重要笔记
### 启动协议
1. ls("/memories/") 检查现有记忆
2. 如果有记忆,读取并加载
3. 根据记忆调整回复风格
### 记忆原则
- 只保存有价值的信息
- 用户明确告知的信息优先保存
- 推断的信息标记为 [推测]
- 定期整理,避免冗余
### 记忆格式
使用 Markdown 格式,包含:
- 清晰的分类标题
- 时间戳(必要时)
- 来源标注
## 行为准则
1. 不要重复询问已知信息
2. 主动应用用户偏好
3. 在合适时机引用历史交互
4. 保护用户隐私
`
});
async function chat(message: string, threadId: string) {
const config = { configurable: { thread_id: threadId } };
const result = await assistant.invoke(
{ messages: [{ role: "user", content: message }] },
config
);
return result.messages[result.messages.length - 1].content;
}
async function main() {
// 第一次对话:自我介绍
const thread1 = uuidv4();
console.log(await chat("你好,我是张三,我是一名前端工程师", thread1));
// 代理会创建 /memories/user_profile.md 保存信息
// 继续第一次对话:表达偏好
console.log(await chat("我喜欢简洁的回复,代码用 TypeScript", thread1));
// 代理会创建/更新 /memories/preferences.md
// 新的对话(不同线程):测试记忆
const thread2 = uuidv4();
console.log(await chat("你还记得我是谁吗?", thread2));
// 代理会读取 /memories/ 下的文件,识别用户身份
// 测试偏好应用
console.log(await chat("帮我写一个 Hello World", thread2));
// 代理会根据偏好,使用 TypeScript 编写简洁代码
}
main();
预期交互
用户: 你好,我是张三,我是一名前端工程师
助手: 你好张三!很高兴认识你。我已经记下你是一名前端工程师了。
有什么我可以帮你的吗?
[内部操作: write_file("/memories/user_profile.md", ...)]
用户: 我喜欢简洁的回复,代码用 TypeScript
助手: 明白了,我会尽量简洁,代码示例用 TypeScript。
[内部操作: write_file("/memories/preferences.md", ...)]
--- 新对话 ---
用户: 你还记得我是谁吗?
助手: 当然记得,张三!你是一名前端工程师,喜欢简洁的回复和 TypeScript。
[内部操作: ls("/memories/"), read_file("/memories/user_profile.md"), ...]
用户: 帮我写一个 Hello World
助手: ```typescript
console.log("Hello World");
```
[根据偏好:简洁 + TypeScript]记忆 vs 技能

| 特性 | 记忆 (Memory) | 技能 (Skills) |
|---|---|---|
| 来源 | 代理从交互中学习 | 开发者预定义 |
| 内容 | 用户偏好、事实、历史 | 操作指南、模板、知识 |
| 可修改 | ✅ 代理可读写 | ❌ 通常只读 |
| 作用域 | 特定用户/线程 | 全局共享 |
| 存储 | StoreBackend (持久化) | 文件系统或嵌入 |
| 加载时机 | 对话开始时 | 按需加载 |
何时用记忆 vs 技能
┌───────────────────────────────────────────────────────────┐
│ 信息类型 │
│ │
│ 用户偏好 ──────────────────────────────→ 记忆 │
│ 用户信息 ──────────────────────────────→ 记忆 │
│ 项目约定 ──────────────────────────────→ 记忆 │
│ 对话历史 ──────────────────────────────→ 记忆 │
│ │
│ 编程指南 ──────────────────────────────→ 技能 │
│ 代码模板 ──────────────────────────────→ 技能 │
│ API 文档 ──────────────────────────────→ 技能 │
│ 最佳实践 ──────────────────────────────→ 技能 │
│ │
└───────────────────────────────────────────────────────────┘生产环境配置
使用 PostgresStore
typescript
import { PostgresStore } from "@langchain/langgraph-checkpoint-postgres";
const store = new PostgresStore({
connectionString: process.env.DATABASE_URL
});
const agent = createDeepAgent({
backend: (rt) => new CompositeBackend(
new StateBackend(rt),
{ "/memories/": new StoreBackend(rt) }
),
store,
});部署到 LangSmith
部署到 LangSmith 时,Store 会自动配置:
typescript
const agent = createDeepAgent({
backend: (rt) => new CompositeBackend(
new StateBackend(rt),
{ "/memories/": new StoreBackend(rt) }
),
// store 会自动配置,无需手动指定
});最佳实践
1. 结构化记忆格式
使用一致的 Markdown 格式:
markdown
---
updated: 2024-01-15T10:30:00Z
confidence: high
source: user_stated
---
# 用户偏好
## 回复风格
- 简洁明了
- 包含代码示例
## 代码风格
- TypeScript
- 函数式编程2. 记忆分类

将不同类型的记忆存储在不同文件:
/memories/
├── user_profile.md # 用户基本信息
├── preferences.md # 用户偏好
├── projects/ # 项目相关
│ ├── project_a.md
│ └── project_b.md
├── notes.md # 通用笔记
└── history.md # 对话历史摘要3. 定期整理
指导代理定期整理记忆:
typescript
systemPrompt: `...
## 记忆维护
### 整理触发条件
- 记忆文件超过 2000 字
- 发现重复或过时信息
- 用户明确要求整理
### 整理操作
1. 读取现有记忆
2. 删除过时信息
3. 合并重复内容
4. 重新组织结构
`4. 隐私保护
typescript
systemPrompt: `...
## 隐私原则
- 不保存密码、密钥等敏感信息
- 不保存用户明确要求不记录的内容
- 敏感信息只保存在当前会话
`小结
本文介绍了 DeepAgents 长期记忆的实现原理和使用方法:
| 概念 | 说明 |
|---|---|
| CompositeBackend | 路径路由,将 /memories/ 导向持久化存储 |
| StoreBackend | 使用 LangGraph Store 跨线程持久化 |
| 记忆协议 | 指导代理何时读取/更新记忆 |
| 记忆类型 | 用户档案、偏好、笔记、历史 |
关键步骤:
- 创建 Store(InMemoryStore 或 PostgresStore)
- 配置 CompositeBackend 路由
- 在 systemPrompt 中定义记忆协议
- 让代理在对话中读取和更新记忆
与技能的区别:
- 记忆 = 代理学习的个人信息
- 技能 = 开发者预定义的专业知识
下一步
在下一篇文章中,我们将学习技能系统——如何为代理添加可复用的专业能力。
实践任务
- 创建一个带长期记忆的助手,让它能记住你的名字和偏好
- 测试跨线程记忆:在不同对话中验证记忆是否保留
- 设计一个记忆协议,定义什么信息应该保存、什么不应该