20-Memory-Retrieval-Context官方深读
核对日期:2026-05-18
官方资料:Short-term memory https://docs.langchain.com/oss/javascript/langchain/short-term-memory;Long-term memory https://docs.langchain.com/oss/javascript/langchain/long-term-memory;Retrieval https://docs.langchain.com/oss/javascript/langchain/retrieval;Context engineering https://docs.langchain.com/oss/javascript/langchain/context-engineering。
官方概念
官方短期记忆文档强调 thread-level persistence:同一会话中的消息和状态通过 checkpointer 保存,使 Agent 可以在不同步骤和多轮调用间恢复上下文。长对话会受到上下文窗口、成本和注意力分散影响,因此需要 trim、delete、summarize 等策略。
官方长期记忆文档把 long-term memory 建在 LangGraph stores 上,以 JSON document 形式按 namespace 和 key 组织。工具可以通过 runtime.store 读取和写入长期记忆。
官方 context engineering 文档给出一个关键判断:Agent 失败往往不是模型完全不行,而是没有传入“正确上下文”。上下文分成 model context、tool context 和 life-cycle context;数据源包括 runtime context、state 和 store。
机制
Short-term Memory 深读
| 官方点 | 工程解释 |
|---|---|
checkpointer | 创建 Agent 时传入,用于保存 graph state |
thread_id | 调用时传入,用于区分会话线程 |
| state 持久化 | 每次 invoke 或工具步骤完成后更新 |
| production checkpointer | 生产应使用数据库后端,而不是内存 |
| trim messages | 调模型前裁剪历史,控制 token |
| delete messages | 从 graph state 永久删除 |
| summarize messages | 将早期历史总结成摘要,保留信息但降低长度 |
| tools access state | 工具可通过 runtime 读取或写短期状态 |
短期记忆不是“把所有聊天都塞回 prompt”。可用策略:
| 策略 | 适用 | 不适用 |
|---|---|---|
| Trim | 最近上下文最重要 | 早期约束不能丢的任务 |
| Delete | 用户要求删除、清理错误消息 | 需要审计的消息不能直接物理删除 |
| Summarize | 长对话、信息仍有价值 | 事实精度要求极高时必须保留引用 |
| Custom filter | 去掉 tool noise、重复系统消息 | 规则太复杂会难复现 |
Long-term Memory 深读
长期记忆应按 namespace/key 设计:
const namespace = ["users", userId, "learning"];
await store.put(namespace, "profile", {
goal: "掌握 LangChain Agent 工程化",
preferredLanguage: "TypeScript",
});
官方 store 支持 get/put/search,生产可换 Postgres 等持久后端。向量化 search 依赖 index 配置,因此要记录 embedding 模型、dims 和重建版本。
记忆类型建议:
| 类型 | 内容 | 写入策略 |
|---|---|---|
| Semantic | 用户偏好、稳定事实 | 需要来源和更新时间 |
| Episodic | 历史任务、交互事件 | 适合回顾和复盘 |
| Procedural | 用户偏好的工作流、格式 | 需要显式确认 |
Retrieval 与 Context Engineering
Retrieval 是 context engineering 的一部分,不只是 RAG 章节。它解决“模型本轮需要什么外部资料”。官方 context engineering 将可控项拆成:
| 上下文类型 | 控制对象 | 例子 |
|---|---|---|
| Model context | system prompt、messages、tools、model、response format | 动态系统提示、裁剪消息、工具过滤 |
| Tool context | 工具能读写什么 | state、store、runtime context、外部 API |
| Life-cycle context | 调用前后发生什么 | summarization、guardrails、logging、retry |
这意味着 RAG 文档、长期记忆、runtime 权限和工具列表都不应随意拼成一个大 prompt,而要按来源、用途、持久性和风险分层。
TypeScript 落地模板
const contextSchema = z.object({
userId: z.string(),
role: z.enum(["employee", "manager"]),
tenantId: z.string(),
});
const injectContext = createMiddleware({
name: "InjectContext",
contextSchema,
wrapModelCall: async (request, handler) => {
const { userId, role } = request.runtime.context;
const userPrefs = await request.runtime.store?.get(["users"], userId);
const filteredTools = request.tools.filter((tool) =>
role === "manager" ? true : !tool.name.startsWith("admin_"),
);
return handler({
...request,
tools: filteredTools,
// messages 可在这里短暂注入偏好,但不要把敏感 runtime 信息直接塞给模型。
});
},
});
Python 差异
Python 侧同样有 checkpointer/store/context engineering 概念,但代码形态常与 LangGraph 更贴近。TypeScript 侧 contextSchema 与 zod 更适合和 API 层共享。跨语言时必须统一 namespace、thread id、memory key 和 RAG metadata schema。
工程边界
- runtime context 是给工具和 middleware 的,不一定给模型看。
- short-term memory 是线程级;long-term memory 是跨线程级。
- RAG 文档不是长期记忆;长期记忆也不一定进入每次 prompt。
- summarize 会丢细节,关键事实必须保留引用或原始事件。
- store search 的向量维度和 embedding 版本要可追溯。
常见反模式
| 反模式 | 后果 |
|---|---|
| 所有信息都进 prompt | token 成本高、注意力分散、泄露风险 |
| 不区分 state/store/runtime | 上下文生命周期混乱 |
| 长期记忆自动写入一切 | 隐私和错误记忆累积 |
| RAG 检索不带权限和版本 | 越权、旧文档、不可审计 |
| 摘要替代事实来源 | 复盘时无法定位证据 |
练习任务
- 给
InMemoryLongTermStore增加 namespace search 的过滤条件,模拟官方 store search。 - 给个人学习助手增加 semantic/episodic/procedural 三类 memory key。
- 为企业知识库 Agent 增加
tenantId,要求 RAG 检索前过滤租户。 - 写一条测试:runtime context 里的
tenantId不应该出现在最终用户答案中。