
图 1:Memory 不是聊天历史的自动归档。明确偏好和已验证经验可以进入 Store;工单事实回到事实源,推测与敏感值被拒绝;未来使用前还要再过 Recall Gate。
1. Memory Engineering 到底在工程什么
很多 Memory 教程从 embedding、向量数据库或“语义记忆、情节记忆、程序性记忆”开始。这些概念有用,但第一次搭系统时,更早的问题是:
如果这些问题没有答案,向量数据库只会更高效地检索未经治理的数据。
因此我会把 Memory Engineering 拆成两道门和一个生命周期:
这里有一个重要细节:写入时合格,不代表以后永远合格。 用户偏好会变化,流程会更新,租户会迁移,政策会失效。Memory 既需要写入策略,也需要读取时重新验证。
一个判断是否需要 Memory 的简单问题
先问:
如果这条信息在当前任务结束后消失,下一个独立任务是否会因此重复犯错、重复询问,或失去经过确认的个性化信息?
如果答案是否定的,它大概率只属于当前 Context、RunState 或 Session。
如果答案是肯定的,也仍然不能直接写入。还要判断它是否已有业务事实源、证据是否足够、能否安全持久化,以及是否有明确所有者。
2. 先分清五个状态面
Agent “记得某件事”可能来自完全不同的机制。把它们都叫 Memory,会让恢复、隐私和删除变得混乱。

图 2:越往下生命周期越长,但长期不等于更权威。正式业务事实始终由 Source of Truth 负责;Memory 只是经过策略筛选的跨任务辅助证据。
2.1 Context:当前一次模型调用看到什么
Context 包含系统规则、当前任务、工具定义、检索结果、必要历史和运行摘要。它的目标是让这一次调用获得足够而不过量的信息。
上一篇 Context Architecture 已经把它设计成 Context Packet:每个来源带有来源、新鲜度、权限和预算证据。
Context 可以临时包含一条长期记忆,但 Context 本身不是长期 Memory。
2.2 RunState / Checkpoint:当前任务从哪里继续
RunState 保存:
它服务于“这次任务中断后怎样恢复”,不是“下个月另一个任务要了解用户什么”。
把 Checkpoint 当长期记忆,会让未来任务误读旧的中间状态;把长期 Memory 当 Checkpoint,又无法证明哪些副作用已经发生。
2.3 Session:同一段对话的连续历史
Session 常用于保存同一线程里的消息或运行历史。它让第 12 轮对话能够接上前 11 轮,但不代表所有消息都值得跨 Session 保留。
例如:
第一句离开当前对话就失去指代对象,第二句才可能在未来任务复用。
2.4 Long-term Memory:跨任务复用的受控信息
长期 Memory 保存经策略允许、未来可能复用的记录,例如:
-
用户明确确认的表达偏好; -
经人工验证的工作流经验; -
某项目稳定存在、且没有更正式所有者的约定; -
经过审查的失败模式与处理办法。
它需要命名空间、来源、状态、有效期、更正和删除。
2.5 Source of Truth:正式业务事实
订单状态、工单结果、权限、付款、库存和生效政策应由业务系统负责。
Memory 可以记住“查询退款状态前调用哪个工具”,但不应该长期记住“订单 104 已退款”并在未来绕过订单系统。后者会过期,也缺少正式更新路径。
3. 一条 Memory Record 至少要有什么
纯文本 "用户喜欢先看结论" 不足以成为可治理的记忆。
Memory Lab 使用七个主字段:
3.1 memory_id:稳定引用,不把正文当身份
更正、删除和审计都需要稳定 ID。不要用整段正文充当主键,否则句子稍微改写就会生成无法关联的另一条记忆。
3.2 namespace:先确定“是谁的”
本文示例使用:
生产系统还可能加入环境、区域或数据域。关键不是层数越多越好,而是召回前能用确定性规则回答“这个运行是否有权看”。
3.3 kind:不同类型使用不同策略
偏好、流程经验、任务事件和业务事实不能共用同一套有效期与权限。kind 让 Policy 可以分别处理。
3.4 statement:可使用的最小内容
不要默认保存整轮对话。只保留未来任务真正需要、并已通过策略的最小陈述。必要时同时保存引用,让 Reviewer 可以回到来源,而不是把上下文全部复制进来。
3.5 provenance:为什么应该相信它
来源至少回答:
“模型推测”与“用户明确确认”即使文本一样,也不应拥有同等权威。
3.6 valid_until:什么时候必须重新确认
并非所有记忆都要永久保存。迁移期流程、临时项目约定和阶段性偏好可以设置 TTL。到期后应停止召回,而不是等某次事故才发现它已过时。
3.7 status:当前能否被使用
最小状态包括:
实现里还保存 key、version、创建日期和内容摘要。它们不是为了让 JSON 看起来完整,而是服务于冲突、追溯和删除。
4. Write Gate:什么值得记
Write Gate 是整个系统最重要的一层。一次对话结束后,不应该由模型自由决定“我觉得以后可能有用”。

图 3:六个问题会把候选信息路由到 Store、Source of Truth 或 Reject。拒绝写入不是能力缺失,而是 Memory Policy 正常工作。
4.1 六个问题
我会按下面顺序检查一条候选信息:
- 未来任务会复用吗?
只对当前步骤有用的内容留在 Context 或 RunState。 - 证据是什么?
用户明确表达、人工确认,还是模型推测? - 业务系统是否已经拥有它?
工单、订单和权限回到 Source of Truth。 - 命名空间属于谁?
没有明确租户与主体,不允许写入。 - 是否含敏感或禁止持久化的数据?
密钥、邮箱和受限正文默认拒绝或最小化。 - 怎样过期、更正和删除?
没有退出路径的记忆不应轻易进入长期层。
4.2 工单案例的五种决策
注意,route_to_source 不是把信息丢掉。它表示未来需要这条事实时,重新调用正式系统,而不是相信 Agent 的旧副本。
4.3 模型推测怎样才能升级为记忆
推测可以成为待确认候选,但不能直接成为 active Memory。例如:
这比静默建立画像更准确,也给用户留下知情和更正的机会。
还有一条容易漏掉的信任边界:evidence_type 必须由可信运行时根据真实事件写入,不能让模型自己把候选标成 explicit_user 或 verified_reviewer。模型可以提出 statement,运行时要用当前消息、Reviewer 身份或业务回执确认来源,再生成不可由模型覆盖的 provenance。
5. Recall Gate:什么此刻该想起
写入合格只是第一道门。未来任务召回时,还要重新判断这条记忆是否属于当前运行、是否相关、是否仍有效。

图 4:相关性不是第一道门。当前明确指令与业务事实源是上方锚点,Memory 只能补充上下文,不能覆盖更高权威。
5.1 顺序一:先按命名空间隔离
假设 tenant_acme / user_u17 有一条高度相关的表达偏好,而当前查询来自 tenant_beta / user_u17。即使用户名相同、语义分数接近 1,也必须返回空。
因此正确顺序是:
而不是先在全库做语义搜索,再希望最后一步记得过滤租户。
5.2 顺序二:只取当前任务需要的类型
写技术报告时,可能需要表达偏好和项目约定,不需要把购物偏好、历史工单和所有流程经验一起放进 Context。
召回查询至少应声明 kinds 与任务意图。Memory 的目标是减少重复信息,而不是建立另一种 Context dump。
5.3 顺序三:检查状态、有效期和冲突
只召回 active 且未过期的记录。superseded 保留用于审计,不能继续影响模型;deleted 不保留正文,也不进入检索索引。
5.4 顺序四:重新对照当前锚点
召回结果进入模型前,再与两类更高权威信息对照:
-
当前用户明确指令; -
当前业务 Source of Truth。
例如长期记忆写着“先给结论”,但当前消息明确要求“请先列证据”,当前指令优先。Memory 是默认值,不是不可覆盖的系统规则。
5.5 预算也是 Recall Gate 的一部分
通过 Policy 的记录仍然可能太多。可以按相关性、权威、新鲜度和 token 预算排序,只把最少必要记录放进 Context Packet,并在 Trace 中保存被选中的 memory_id。
6. 更正、过期与删除
长期 Memory 最容易被忽略的不是写入,而是变化。

图 5:更正创建新版本并停用旧版本;删除会清除同一 key 的历史正文与内容摘要,只保留不含原值的审计证据。
6.1 更正:新版本替代旧版本
用户后来明确说:
以后先列证据,最后再给结论。
系统不应该把两句话都标成 active,再让模型自己判断。Memory Lab 会:
同一个 namespace + kind + key 最多只有一个 active 版本。
如果新信息权威更低,例如模型推测与用户明确偏好冲突,应拒绝低权威版本,而不是覆盖用户选择。
6.2 过期:停止召回,不必假装删除
流程经验可以设置 valid_until。过期后它不再进入 Context,但仍可保留受控审计记录,供维护者判断是否续期或替换。
删除和过期目的不同:
6.3 删除:正文、摘要和索引一起处理
只在主表把 status 改为 deleted,却让向量索引、离线报告和缓存继续保存正文,不算完成删除。
本文实验在删除 response_order 时会:
-
清空 v1 和 v2 的 statement; -
将内容哈希改为固定 purged,避免低熵文本被摘要反查; -
将状态设为 deleted; -
把来源替换为不含原值的删除请求证据; -
保留 memory_id,证明删除动作作用于哪些记录。
生产环境还要同步处理数据库副本、搜索索引、对象存储、缓存、日志、备份和保留政策。本文的内存实验不声称覆盖法律意义上的彻底擦除。
7. Memory Lab 0.8.0 怎样实现这些规则
完整代码位于 RalfNick/ai-agent-learn,本篇对应不可变检查点 ddca6ca。
下载 Memory Lab 0.8.0 ZIP
Lab 使用 Python 标准库,不连接模型或数据库。这样可以先验证 Policy 行为,再把同一接口替换成真实存储。
7.1 文件增量
7.2 Candidate Policy
实际实现的判断顺序保持刻意简单:
这里没有让模型给“值得记忆程度”打分。不是因为评分永远没用,而是硬边界应先由确定性策略处理:秘密不能因为模型给了高分就落盘,跨租户数据也不能因为很相关就被召回。
实验中的 JSONL 是可信测试夹具,因此可以直接声明 evidence_type。生产入口不能把这个字段放进模型可自由生成的参数里;它应由 Harness 根据已认证的用户消息、Reviewer 事件或工具回执填充。
7.3 Namespace-first Recall
实验先按精确命名空间过滤,再进入状态、TTL 和相关性:
本地实验用 token overlap 保持结果可预测。生产系统可以替换成倒排、向量或混合检索,但命名空间和权限过滤不能因为更换检索器而消失。
7.4 Review Gate 检查什么
Review Gate 不只统计 8 条 case 是否返回预期 action,还检查:
这些检查分别对应文章前面的 Write Gate、Recall Gate 与生命周期,不是为了凑一张 PASS 截图。
8. 跟着运行 Memory Lab
当前检查点的输出是:

图 6:两个 store 分别是用户明确偏好和 Reviewer 验证经验;三个 reject 包含模型推测、敏感值和跨租户召回。数字只描述本文夹具,不是 Memory 效果指标。
命令生成五份文件:
一个容易误读的地方是:cross-tenant-recall 的实际 action 为 reject,但总 Gate 仍通过。因为这个案例的合同就是“即使其他租户有高度相关记录,也必须拒绝召回”。
8.1 练习一:把推测升级成用户确认
打开 datasets/memory-cases.jsonl,找到 inferred-preference:
把 evidence_type 改为 explicit_user,同时把 source_ref 改成可回查的 message_confirmation_12,重新运行。Review Gate 应失败,因为实现返回 store,但夹具仍期待 reject。
确认行为变化后,再把 expected_action 改成 store,Gate 恢复 PASS。
这个练习说明:数据集声明的是产品策略,不是实现碰巧得到的结果。 策略变化必须显式修改测试合同。
8.2 练习二:让删除选择器指向错误 key
找到 forget-preference,把:
临时改成:
命令应以非零状态退出:系统找不到目标,返回 reject;expected_decisions_matched 与 deleted_content_purged 都会失败,因为没有任何目标记录被清除。
恢复正确 key 后再运行,观察 memory-store.jsonl 中两个版本的:
这一步比只测试“召回不到”更严格,因为后者可能只是索引漏查,正文仍然存在。
9. Session、RAG、Compaction 与 Memory 不要混在一起
9.1 Session 不是长期 Memory
Session 解决对话连续性。它可以在每次运行前取回历史消息,并在运行后追加新消息。长期 Memory 则需要从历史中筛选未来可复用的信息,并应用不同的所有权与保留策略。
把整个 Session 永久保留并不自动得到 Memory Policy。
9.2 RAG 不等于 Memory
RAG 常用于从外部知识库检索文档。Memory 常用于保存交互过程中形成、并经策略允许的跨任务状态。
它们可以共用向量检索基础设施,但数据治理不同:
9.3 Compaction 不是长期 Memory
Compaction 用摘要或重写方式让一段长运行继续装进有限 Context。它主要解决“同一次长任务怎样继续”。长期 Memory 解决“未来独立运行需要复用什么”。
压缩摘要可以成为候选来源,但不能未经 Write Gate 自动获得长期权威。
9.4 Prompt cache 也不是 Memory
缓存减少重复输入的传输或计算成本,不负责信息是否可信、属于谁、何时过期或怎样删除。缓存命中不代表 Agent 形成了长期记忆。
9.5 Memory 不等于模型学习
模型下次看到一条召回记录,只是在当前 Context 中重新读取它。外部 Store 没有改变基础模型权重。若记忆被删除,模型也不会因为曾经看过就自动“反训练”。
10. 记忆类型何时有用
当状态面已经分清,再看常见分类会更容易。
这个分类帮助选择检索和更新方式,但不能替代 Write Gate。一个“情节”仍可能包含个人信息,一个“程序”仍可能已经过期。
11. 映射到 OpenAI、Claude 与 LangGraph
下面只映射当前官方能力,不把框架名当成统一标准。
11.1 OpenAI:Session、Compaction 与 Sandbox Memory 是不同层
OpenAI Agents SDK Sessions 当前用于保存特定 Session 的运行历史:运行前读取历史并加入输入,运行后追加新项。官方文档也明确提醒,同一次 run 不应同时把 Session 与 conversation_id、previous_response_id 或自动 previous response 方式混用,因为它们是不同的状态延续机制。
OpenAI Cookbook 的可靠 Agent Memory / Compaction 示例 将两者区分为:Compaction 帮助同一长运行继续,Memory 帮助未来 sandbox-agent 运行复用已审查的工作流经验;最终经 Review 的产物仍是事实依据。
OpenAI Sandbox Memory 指南 也将 Sandbox Memory 与 SDK Session 分开:Session 保留消息历史,Sandbox Memory 跨运行提炼可复用经验,并通过 memory_summary.md、MEMORY.md 和 rollout summary 做渐进式读取。
这些实现与本文的对应关系是:
11.2 Claude:客户端存储与按需读取
Claude Memory Tool 提供查看、创建、替换、插入、删除和重命名等操作,但存储实现由客户端应用负责。官方示例把记忆限制在 /memories 路径,并建议按需读取,而不是把全部文件预先塞入 Context。
这对应本文的两点:
-
工具能力不等于存储治理,应用仍要负责路径隔离、权限与删除; -
Memory Store 不等于 Context,召回应遵循渐进披露。
Claude Context Editing 处理的是有限上下文中的压缩和选择性清理,仍应与跨任务持久 Memory 区分。
11.3 LangGraph:线程状态与跨线程 Store
LangGraph Memory 概念 将短期记忆放在 Agent State / Checkpoint 中,并按 thread 组织;长期记忆则保存在跨 Session 的自定义 namespace / store 中。官方还使用 semantic、episodic、procedural 三类记忆,并区分 hot path 写入与后台写入。
对应本文:
无论使用哪一种模式,租户隔离、来源、TTL、冲突与删除仍需要项目自己定义。
11.4 Mem0、Letta 与 LangMem:实现参考,不是收益证明
Mem0、Letta 和 LangMem 提供了不同的持久记忆、Agent 状态和提炼方式,适合继续研究具体实现。
但开源项目首页中的 benchmark、成本或提升数字只适用于其声明的数据集与配置,不能直接证明“给任何 Agent 加 Memory 都会更好”。更稳妥的顺序仍然是:
12. 一份可复制的 Memory Policy
下面这份最小模板可以放进项目文档,再逐项落到代码和测试。
Policy 写完后,不要只做文档 Review。至少为每一条允许、拒绝、冲突和删除路径准备一个可重复测试。
13. 收藏清单:第一次给 Agent 加长期记忆
第 1 步:列出五个状态面
-
[ ] 当前 Context 存在哪里 -
[ ] RunState / Checkpoint 存在哪里 -
[ ] Session 保存什么历史 -
[ ] Long-term Memory 允许哪些 kind -
[ ] 哪些业务事实必须实时查询 Source of Truth
第 2 步:只开放一类低风险记忆
先从用户明确偏好或经 Reviewer 验证的流程经验开始,不要第一版就自动提炼全部对话。
第 3 步:给记录补齐治理字段
-
[ ] namespace -
[ ] kind 与 key -
[ ] provenance -
[ ] valid_until -
[ ] status 与 version -
[ ] correction / delete owner
第 4 步:让 Recall namespace-first
先做租户、用户、项目和权限过滤,再做向量或关键词相关性。为跨租户和跨用户准备负向测试。
第 5 步:建立冲突与删除实验
至少验证:
-
[ ] 新显式偏好会 supersede 旧版本 -
[ ] 低权威推测不能覆盖显式偏好 -
[ ] 过期记录不召回 -
[ ] deleted 记录正文和内容摘要已清除 -
[ ] 缓存、索引与报告遵守同一删除路径
第 6 步:再做质量对照
在相同任务、模型、预算和重复次数下比较:
不仅看答案是否更个性化,也要看误召回、越权、冲突、Token 成本和人工纠正率。
结语:可靠的记忆从“允许忘记”开始
Agent Memory 最吸引人的演示,是它隔了几天还能说出用户偏好。但工程上更重要的问题是:
如果只记住一句:
Memory 不是长期 Context,而是一组带所有权、来源、有效期和退出路径的可召回记录。
下一篇进入 Graph Engineering。Memory 解决单个运行怎样复用受控状态;当任务包含真实依赖、并行研究、独立验证和人工闸门时,我们再判断是否需要把多个局部 Loop 组织成工作图。
参考资料
OpenAI 官方
-
OpenAI Agents SDK:Sessions -
OpenAI Cookbook:Building Reliable Agents with Memory and Compaction -
OpenAI Sandbox:Persist memory across runs -
OpenAI Agents SDK:Sandbox memory example
Claude 与 LangGraph 官方
-
Claude Memory Tool -
Claude Context Editing -
LangGraph:Memory concepts -
LangGraph:Add and manage memory
开源实现
-
Mem0 -
Letta -
LangMem
本文代码与证据
-
Agent Reliability Lab ddca6ca -
Memory Policy implementation -
Memory Review report -
Redacted Memory Store
订阅智宅客
AI / 技术 / 数字生活方式,新文章第一时间送到邮箱。









