承接上一节的数据库持久化,我们已经实现了单会话内对话历史 的长期保存。但 Checkpointer 是按
thread_id隔离的 ------ 新开一个会话、重启程序后,智能体依然不知道你的使用偏好、项目背景和已知信息,每次都要重新说明。
本节我们学习 Deep Agents 原生的 Memory 记忆机制 ,通过AGENTS.md记忆文件实现跨会话、跨重启的全局长期记忆,让智能体真正做到 "越用越懂你"。
一、认识跨会话长期记忆
1.1 为什么需要跨会话记忆?
Checkpointer 解决的是「同一会话能不能记住刚才说过的话」,而 Memory 解决的是「所有会话能不能记住你的习惯和背景」。
举个例子:
- 你告诉智能体 "我喜欢简洁回答,代码加中文注释"
- 只用 Checkpointer:只有当前会话生效,新开对话就忘了
- 启用 Memory:所有会话、程序重启后都记得,全程遵循你的偏好
1.2 核心概念对比:Checkpointer vs Memory
三者都是 Deep Agents 记忆体系的一部分,但定位和用途完全不同:
| 机制 | 存储内容 | 生效范围 | 加载时机 | 核心用途 |
|---|---|---|---|---|
| Checkpointer | 对话历史、工具调用状态、执行进度 | 同 thread_id 会话内 | 调用时自动加载 | 多轮对话延续、断点续跑 |
| Memory | 用户偏好、项目规范、已知事实 | 全局跨所有会话 | 智能体启动时全量加载 | 统一行为风格、复用背景知识 |
💡 两者互补不冲突,生产环境通常同时启用:Checkpointer 管对话上下文,Memory 管全局偏好。
1.3 AGENTS.md 记忆文件格式
Deep Agents 的 Memory 机制基于约定格式的 Markdown 文件实现,通常命名为 AGENTS.md。它采用结构化的二级标题分类,便于智能体识别、读取和更新。
标准结构示例:
markdown
# Agent Memory
## User Preferences
- 回答风格:简洁明了,避免冗余客套
- 代码风格:使用中文注释,变量命名用英文
- 交流语言:默认使用中文
## Project Context
- 当前项目:DeepAgents 学习教程项目
- 技术栈:Node.js + Deep Agents
## Known Facts
- 用户正在学习 Deep Agents 框架
- 已完成环境配置、工具调用、流式输出、多轮对话章节
官方约定:文件以 # Agent Memory 开头,通过 ## 二级标题 划分板块,内容用列表形式呈现,智能体对这种格式的识别和编辑准确率最高。
二、快速上手跨会话记忆
Memory 是 Deep Agents 的内置能力,不需要安装额外依赖,只需准备记忆文件并在创建智能体时注入即可。
2.1 项目准备
沿用之前的项目目录,新建 06-cross-session-memory.js,模型复用 00-model.js。记忆文件统一存放在 ./workspace/memory/ 目录下。
2.2 核心实现三步法
步骤 1:创建记忆文件与初始内容
通过代码自动创建记忆目录和初始记忆文件,也可以手动创建编辑:
csharp
import fs from "node:fs";
import path from "node:path";
// 准备记忆存储目录
const memoryDir = path.resolve("./workspace/memory");
fs.mkdirSync(memoryDir, { recursive: true });
const memoryFile = path.join(memoryDir, "AGENTS.md");
// 写入初始记忆内容
fs.writeFileSync(
memoryFile,
`# Agent Memory
## User Preferences
- 回答风格:简洁明了,不要啰嗦
- 代码风格:使用中文注释
- 偏好语言:中文交流
## Project Context
- 当前项目:deepagents 学习教程
- 技术栈:Node.js + deepagents
## Known Facts
- 用户正在学习 deepagents 框架
- 已学完基础对话、自定义工具和输出模式
`
);
步骤 2:注入记忆到智能体
通过 memory 参数传入记忆文件路径数组,支持传入多个文件:
javascript
import { createDeepAgent } from "deepagents";
import { model } from "./00-model.js";
const agent = createDeepAgent({
model: model,
// 注入记忆文件,支持传入多个路径
memory: [memoryFile],
systemPrompt: `你是一个智能助手。你有一份记忆文件,其中记录了用户的偏好和项目信息。
请始终遵循记忆文件中的偏好来回答问题。
如果用户告诉你新的偏好或项目信息,可以使用 write_file 工具更新记忆文件。`,
});
✨ 记忆文件会在智能体初始化时自动读取并融入系统提示词,全程生效,不需要每次调用手动传入。
步骤 3:验证记忆生效
调用智能体,询问记忆中的内容,验证是否能正确读取:
javascript
async function main() {
const userInput = "根据你记得的信息,我当前在学什么?用的什么技术栈和模型?";
console.log("🧑 用户:", userInput);
console.log("📄 记忆文件:", memoryFile);
console.log("\n🤖 助手:\n");
const result = await agent.invoke({
messages: [{ role: "user", content: userInput }],
});
console.log(result.messages.at(-1).content);
}
main().catch(console.error);
运行代码后,智能体可以准确说出记忆文件中的项目、技术栈等信息 ------ 即使你换一个 thread_id、重启程序再运行,结果依然一致,说明跨会话记忆生效了。
三、进阶:动态更新与组合使用
3.1 动态更新记忆
Memory 不是静态只读的,智能体可以在对话中根据你的反馈,自动更新记忆文件,实现记忆的持续进化。
Deep Agents 内置了虚拟文件系统工具(read_file、write_file、edit_file),只要在系统提示词中授权,智能体就可以自主修改记忆文件。
典型流程:
- 用户说 "以后回答都尽量简短,不要多余的话"
- 智能体识别为偏好更新,自动调用
edit_file修改AGENTS.md中的User Preferences板块 - 后续所有对话、所有会话都会遵循新的偏好
3.2 多记忆文件组合
memory 参数支持传入数组,可拆分不同维度的记忆文件,按顺序叠加加载:
arduino
const agent = createDeepAgent({
model: model,
memory: [
"./workspace/memory/global-prefs.md", // 全局用户偏好,所有项目通用
"./workspace/memory/project-a.md", // A 项目专属记忆
],
});
加载规则:
- 按数组顺序依次加载,后面文件的内容会补充到前面的内容中
- 适合多项目场景:全局偏好通用,项目记忆独立
3.3 结合 Checkpointer 构建双层记忆
实际使用中,推荐同时启用 Checkpointer + Memory,形成完整的记忆体系:
- Memory:跨会话的偏好、知识、规范(长期不变的内容)
- Checkpointer:单会话的对话上下文、任务进度(短期动态内容)
php
import { SqliteSaver } from "@langchain/langgraph-checkpoint-sqlite";
const checkpointer = SqliteSaver.fromConnString("./workspace/memory/conversations.sqlite");
const agent = createDeepAgent({
model: model,
memory: [memoryFile], // 跨会话长期记忆
checkpointer: checkpointer, // 单会话对话记忆
systemPrompt: "...",
});
四、核心要点与最佳实践
4.1 记忆内容设计原则
- 结构化优先 :严格遵循
# Agent Memory+## 板块+ 列表的格式,提升智能体读写准确率 - 粒度适中:记录偏好、规范、背景类信息,不要记录具体对话内容(那是 Checkpointer 的职责)
- 控制长度:记忆内容会全量进入系统提示词,避免堆砌无关信息,控制 token 占用
- 定期整理:过时的信息及时清理,避免记忆冗余导致智能体混淆
4.2 安全注意事项
- 不要在记忆文件中存放密码、API 密钥、身份证号等敏感信息
- 多用户场景不要共用同一个记忆文件,每个用户独立一份
- 重要的记忆文件建议做好备份,避免误操作被覆盖
4.3 官方底层特性说明
根据 Deep Agents 官方文档,Memory 机制具备以下核心特性:
- 记忆文件始终全量加载,不同于 Skills 的按需渐进式加载
- 记忆内容存储在配置的虚拟文件系统后端中,支持磁盘、内存等多种后端
- 智能体可以基于交互反馈自主更新记忆,无需手动编写更新逻辑
五、完整代码汇总
06-cross-session-memory.js 完整代码如下,包含记忆文件创建、流式输出、工具调用监控、记忆内容展示,可直接运行:
javascript
/**
* Deep Agents 教程 06:跨会话长期记忆(Memory 与 AGENTS.md)
*/
import { createDeepAgent } from "deepagents";
import fs from "node:fs";
import path from "node:path";
import { model } from "./00-model.js";
// ============================================================
// 1. 创建记忆文件与初始内容
// ============================================================
const memoryDir = path.resolve("./workspace/memory");
fs.mkdirSync(memoryDir, { recursive: true });
const memoryFile = path.join(memoryDir, "AGENTS.md");
// 文件不存在时写入初始记忆,避免重复运行被覆盖
if (!fs.existsSync(memoryFile)) {
fs.writeFileSync(
memoryFile,
`# Agent Memory
## User Preferences
- 回答风格:简洁明了,不要啰嗦
- 代码风格:使用中文注释
- 偏好语言:中文交流
## Project Context
- 当前项目:deepagents 学习教程
- 技术栈:Node.js + deepagents + 智谱AI(GLM-4)
- 模型:glm-4-flash-250414
## Known Facts
- 用户正在学习 deepagents 框架
- 已学完基础对话、自定义工具和输出模式
`
);
}
// ============================================================
// 2. 创建带跨会话记忆的智能体
// ============================================================
const agent = createDeepAgent({
model: model,
memory: [memoryFile],
systemPrompt: `你是一个智能助手。你有一份记忆文件,其中记录了用户的偏好和项目信息。
请始终遵循记忆文件中的偏好来回答问题。
如果用户告诉你新的偏好或项目信息,可以使用 write_file 或 edit_file 工具更新记忆文件。`,
});
// ============================================================
// 3. 流式输出辅助函数
// ============================================================
async function streamAgent(input) {
const stream = await agent.streamEvents(
{ messages: [{ role: "user", content: input }] },
{ version: "v3" }
);
await Promise.all([
// 实时打印回答文本
(async () => {
for await (const message of stream.messages) {
const text = await message.text;
if (text) process.stdout.write(text);
}
})(),
// 实时打印工具调用与结果
(async () => {
for await (const call of stream.toolCalls) {
console.log(`\n🔧 [工具调用] ${call.name}(${JSON.stringify(call.input)})`);
const status = await call.status;
if (status === "finished") {
console.log(`📦 [工具结果] ${await call.output}`);
} else if (status === "error") {
console.error(`❌ [工具错误] ${await call.error}`);
}
}
})(),
]);
console.log("\n");
}
// ============================================================
// 4. 主流程
// ============================================================
async function main() {
// 支持命令行传入问题,默认使用测试问题
const userInput =
process.argv.slice(2).join(" ") ||
"根据你记得的信息,我当前在学什么?应该用什么语言和模型?";
console.log("\n🧑 用户:", userInput);
console.log("📄 记忆文件路径:", memoryFile);
console.log("\n🤖 助手:\n");
await streamAgent(userInput);
// 打印当前记忆文件内容,方便对比更新前后的变化
console.log("--- 当前记忆文件内容 ---");
console.log(fs.readFileSync(memoryFile, "utf-8"));
}
main().catch(console.error);
运行方式
bash
# 运行默认测试问题,验证记忆读取
node 06-cross-session-memory.js
# 传入自定义问题,例如让智能体更新记忆
node 06-cross-session-memory.js "记住:我以后的代码都用 TypeScript 编写"
六、常见问题排查
-
智能体 读取不到记忆内容
- 检查记忆文件路径是否正确,文件是否真实存在
- 确认文件开头是
# Agent Memory,格式符合约定结构 - 可在系统提示词中补充说明 "优先参考记忆文件中的信息回答"
-
智能体 不会主动更新记忆文件
- 确认系统提示词中明确授权了更新记忆的权限
- 检查虚拟文件系统工具是否正常可用(默认内置,无需额外配置)
- 用户指令尽量明确,例如 "把这个偏好加到记忆文件里",而非模糊的 "记住"
-
记忆文件被错误覆盖怎么办
- 重要记忆建议定期备份
- 可在系统提示词中约束:更新记忆时只能追加和修改,不能删除原有内容
- 生产环境可以搭配文件权限规则,限制写入范围
-
Memory 和 Checkpointer 同时启用会冲突吗 不会冲突,两者职责完全不同。Memory 提供全局背景偏好,Checkpointer 维护单会话对话上下文,同时启用效果最佳。
下一节我们将介绍 Deep Agents 的虚拟文件系统,学习如何让智能体具备读写本地文件、管理项目目录的能力。