04. Skills、Memory、Backend 与持久化#
前一篇解决“怎样完成任务”,本篇解决“知识和状态放在哪里”。很多 Agent 项目的问题不是模型不会推理,而是把所有规则、历史、文件和长期记忆都塞进一条消息,最后既贵又难以隔离。
1. 四种上下文载体#
| 载体 | 生命周期 | 典型内容 |
|---|---|---|
| 对话消息 | 当前交互 | 用户问题、模型回答、工具结果 |
| checkpoint | 一次 thread 运行 | 中断位置、state、恢复信息 |
AGENTS.md memory | Agent 启动时始终相关 | 项目规则、长期约定 |
| Store / 持久文件 | 跨 thread | 用户偏好、研究资料、共享知识 |
不要把对话历史当长期记忆,也不要把所有文档都塞入 AGENTS.md。先根据生命周期选择载体。
2. Skills:按需加载知识#
Skill 适合“只在特定任务出现”的流程和知识,例如 API 审查、PDF 处理、研究报告或部署。目录:
skills/
└── research-report/
├── SKILL.md
└── references/
└── source-rubric.mdSKILL.md 使用 frontmatter:
---
name: research-report
description: 当用户要求基于来源撰写研究报告时使用;要求保存证据并标注不确定性。
---
# Research report
1. 读取 `references/source-rubric.md`。
2. 将原始结果和去重证据分开保存。
3. 在最终报告中列出来源和限制。description 是路由信号,必须说明做什么、什么时候使用。渐进式披露的顺序是 metadata → SKILL.md → supporting files;不要把参考资料一次塞进 system prompt。
3. 接入 Skills 和 Memory#
import { createDeepAgent, FilesystemBackend } from "deepagents";
const backend = new FilesystemBackend({
rootDir: "/absolute/path/to/research-agent",
virtualMode: true,
});
const agent = createDeepAgent({
model,
backend,
skills: ["/skills/"],
memory: ["/AGENTS.md"],
});路径相对于 backend root,并使用 POSIX 虚拟路径。默认 StateBackend 没有真实磁盘文件;如果使用它,需要在 invoke state 中按当前 FileData 结构提供 AGENTS.md 和 Skill 文件。
4. AGENTS.md 应该写什么#
始终加载的 memory 应该短、稳定、可执行:
# Project rules
- 使用 TypeScript ESM,公共函数必须有测试。
- 外部来源必须保留 URL;没有来源时标记未核验。
- 不读取或写入 `.env`、凭据和用户 home。
- 发布、删除和发信必须等待人工审批。不要把一次性任务、长篇产品文档或频繁变化的搜索结果放入其中。Skill 文件和 memory 都能指导模型,但都不能授予新的文件、网络或 shell 权限。
5. Backend 选择矩阵#
| Backend | 生命周期 | 适合场景 |
|---|---|---|
StateBackend | 当前 thread state | 临时计划、scratchpad、工具结果卸载 |
StoreBackend | LangGraph Store | 用户记忆、跨 thread 资料 |
FilesystemBackend | 本地磁盘 root | 受控 CLI、项目工作区 |
CompositeBackend | 按路径分流 | 把工作区落盘、内部产物留在 state |
默认 StateBackend 类似线程级 scratchpad,不等于 Node.js fs。Store 需要 namespace;Filesystem 需要 root、权限和隔离;Composite 需要稳定的路径前缀协议。
6. 当前推荐的实例化方式#
import {
CompositeBackend,
FilesystemBackend,
StateBackend,
} from "deepagents";
const backend = new CompositeBackend(
new StateBackend(),
{
"/workspace/": new FilesystemBackend({
rootDir: "/absolute/path/to/project",
virtualMode: true,
}),
},
);/workspace/ 下的项目文件落到磁盘,内部临时路径仍留在 StateBackend。较旧教程中的 backend factory 写法要根据当前版本迁移,推荐以官方当前实例化 API 为准。
7. Store 和 namespace#
import { InMemoryStore } from "@langchain/langgraph";
import { StoreBackend } from "deepagents";
const store = new InMemoryStore();
const backend = new StoreBackend({
namespace: () => ["users", currentUserId],
});
const agent = createDeepAgent({ model, store, backend });InMemoryStore 只适合演示,重启后数据消失。生产环境按用户、租户、assistant 设计 namespace,不能把所有用户放进默认命名空间。namespace 的顺序和版本也要固定,否则迁移后历史数据会“看起来丢失”。
8. Checkpoint 和 Store 的配合#
checkpoint 保存“这次运行走到哪里”,Store 保存“跨运行要复用什么”。恢复 interrupt 需要 checkpoint;让用户下周继续使用研究资料,需要 Store 或持久文件系统。二者混成一个概念会导致清理策略和权限边界模糊。
9. 路径契约和读写冲突#
CompositeBackend 可以定义:
/workspace/ → 受限项目目录
/user-memory/ → StoreBackend
/tmp/ → StateBackend
/report/ → 经过权限策略的工作区前缀不能由用户输入随意拼接。路径要先规范化,再由 backend、permissions 和 rootDir 重复校验。多个 Agent 写同一文件时,最后写入者可能覆盖前者;更安全的方式是每个子 Agent 写独立 artifact,由父 Agent 聚合。
10. 迁移与测试#
更换 backend 时检查路径、编码、旧 thread 可读性、权限规则、清理任务和二进制 mime type。为文件工作流写集成测试:缺少 evidence.md 时不得生成已核验结论;草稿存在但检查失败时不得生成 final.md;A 用户的数据不能被 B namespace 读取。
本章练习
- 创建一个
research-reportSkill 和一个短AGENTS.md。 - 用 StateBackend 运行两个 thread,确认临时文件不共享。
- 将用户偏好迁移到 Store,并用不同 namespace 验证隔离。
- 用 CompositeBackend 映射
/workspace/,测试路径之外的访问。
验收标准:能区分对话、checkpoint、memory 和 Store;知道何时使用真实磁盘;能解释 namespace 和路径前缀如何影响多租户安全。