用户说“忘掉它”,为什么模型回答失败也不能撤销这次遗忘?
内容主线:模块精讲;兼线:系统架构与工程观点。本文讨论应用层长期记忆的持久效果,不涉及模型训练参数中的遗忘。
2026 年 10 月,我们给 ETF Agent 的长期记忆做了一次真实链路验收:先让用户明确要求遗忘一条记忆,再观察 Agent 的后续行为。结果出了个很别扭的问题——遗忘已经提交到数据库,紧接着的模型回答却失败了。
如果只看聊天窗口,这次操作似乎失败了;如果只看持久化记录,遗忘已经发生。最危险的处理方式,是把后面的回答失败当成前面操作没有发生,再重新执行一次。
这件事让我们重新确定了 Memory 的责任:模型可以解释用户的意思、选择应该记住什么,但记忆是否保存、更正、遗忘,必须由应用的持久记录和效果回执来证明。回答有没有送达、下一次会话有没有使用记忆,是另外两件事。
一、我们不是从零开始造 Memory
最初也很容易以为,长期记忆就是“把用户偏好存起来,下次用向量检索找回来”。但真正检查 ETF Agent 的旧代码时,我们已经拥有相当多的基础:记忆候选和确认状态、分类、作用范围、同族版本、过期与遗忘、PostgreSQL 仓库、管理 API,还有有界召回和同族去重逻辑。
2026 年 9 月 30 日的基线核对却发现,当时生产 Research Runtime 并没有真正沿正常研究路径消费已有的记忆召回。管理记忆的组件存在,不意味着下一次研究已经用上它。要解决的不是“再引入一个记忆数据库”,而是把已有应用事实接回 Native 研究流程。
我们因此保留了两层明确分工。
应用记忆仓库持有当前事实:属于哪个账户范围、何时确认、哪个版本有效、哪条已被替代、哪条已遗忘。语义适配器只负责提出候选或提供检索线索;它的相似度排序没有资格让一条已撤销记录重新生效。
这不只是权限设计。投资研究中的“我偏好长期持有”与“我目前持有哪些基金”本来就不是同一种事实。前者可能是可更正的偏好,后者需要读取当前获准的持仓。长期记忆不能越俎代庖成为实时账本。
二、三个时点不能再用同一个“成功”表示
考虑一个简化场景。用户先说“我偏好低换手”,后来改为“未来半年需要保留更多现金”,最后又要求忘掉这条临时约束。
第一个时点:写入或更正。 用户发起明确操作后,系统先检查作用范围与旧版本关系,再以持久化效果回执确认提交。模型说“好的,我记住了”不是数据库成功的证据。
第二个时点:下一轮研究。 新会话要重新检查该记忆是否仍属于当前范围、版本是否有效、来源是否仍可使用,随后才能把内容放进真实模型请求。数据库检索命中不等于已注入模型;回答恰巧出现相同措辞,也不等于证明 Memory 被实际消费。
第三个时点:遗忘后的再次披露。 历史摘要、已经保存的报告和派生检索索引可能还保留旧内容。它们可以记录历史,但不能凭“以前读过”取得未来的使用资格。
这里没有一个万能的“memorySuccess”能替代三个时点的核查。持久化提交、后续消费、当前撤权,必须各看自己的证据。
三、真实故障:遗忘落库了,回答却没完成
10 月 9 日的 Memory 验收保留了一个明确反例:遗忘操作已经成功提交,后面的模型终态失败,原计划中的最后一次新会话查询没有执行。
如果把整个流程定义为一条必须全部成功的流水线,这次实验就会被粗暴标成“遗忘失败”。但这既否认了已经发生的持久效果,也可能诱导恢复过程重复副作用。
修正验收方式以后,我们分别检查:提交回执是否存在、目标记录的资格是否变化、后继请求是否真正装入获准记忆、遗忘后的历史是否仍会把旧记录放回来。
这里需要诚实承认两种不同结论:受控的本地跨会话路径已有正证据;那次失败的 live 运行没有因此被追认成成功。 没有执行的第六次查询,不能从数据库状态推算成已经执行。
这不是写作上的保守,而是决定恢复逻辑会不会误操作的事实边界。
四、我们还踩过另一个反方向的坑:撤掉旧内容,却连“已更正”的事实也撤了
假设 Memory V1 已被 V2 替代。V1 的正文不再有当前读取资格,这很好理解。
但当前模型可能需要说明:“刚才的更正已经提交,旧版本现在不再生效。”这句话依据的是版本更正已经发生的合法回执,不是重新读取 V1 的旧摘要。
在 2026 年 10 月 14 日的后续核对里,我们发现历史来源投影容易混淆两者。
一种错误是把所有关联 V1 的信息统统隐藏,连合法更新回执也看不到。另一种错误更危险:只要历史里出现了更正回执,就把 V1 正文重新授权。
最终没有加一句“有回执就放行”的宽松规则。只有在 Memory 归属方已经留下可见、完整的成功更新回执,而且同一个 family、准确的 supersedes 关系和递增 revision 都吻合时,才能用旧版本身份说明这次更正的发生事实。
至于旧版本的内容本身,仍然不能重新读取。回执缺失、不可读、来源被普通撤权或者读取者无法判定当前资格时,继续拒绝或保留未知。
这项区分后来有 18 个 Memory history 相关测试用例通过。它检验的是指定来源关系和拒绝分支,不是对任意未来自然语言输出的保证。
五、为什么我们没有为此再造一套记忆执行系统?
这里其实有三个可以选择的方向。
最简单的是让模型自己总结、自己保存在提示词里。实现快,但更正、撤权与作用范围会随会话文本漂移。
第二种是让外部语义记忆引擎自己保存并决定最终可用性。它适合做候选检索,但如果同时与应用数据库争夺当前授权和版本权威,就会有两套“最新记忆”。
我们最终选择复用已有应用仓库。显式保存、更正、遗忘沿正常研究工具同步提交,后台自动学习在回答终态之后单独运行;自动提议、用户明确指令和实际确认分别处理。
这增加了版本与来源校验的工程成本,也要求测试不能只看模型回复。但换来的是:当回答失败时,系统不需要靠猜测决定持久副作用有没有发生。
六、到底验证到了哪一步?
2026 年 10 月 9 日的一期正式关闭,在声明的 provider-free 范围内得到 45 个离线文件、444/444 通过和7 个真实 PostgreSQL 文件、47/47 通过,没有跳过约定断言。六会话本地控制涉及认证 HTTP、跨会话读取、同族更正和遗忘,也保留了“提交后模型失败”的对照。
这些结果支持限定范围内的 Memory 运行合同,却不代表所有真实模型都会准确措辞,更不证明可选外部 Hindsight、全部 Docker Analysis 旅程和长期生产质量已经验收。相关真实运行中的未知与失败仍在自己的证据记录里。
回头看,Memory 最值得我们分享的不是“Agent 可以记住投资偏好”,而是一个不太直观的工程判断:
用户说“忘掉它”以后,系统要先证明遗忘确实发生,再决定如何回答;不能让一段后来失败的模型文字,推翻已经提交的操作事实。
对一次性聊天,这种复杂度也许不值得。但对需要长期伴随、可更正、可撤权的 Agent,这才是“记忆”能真正交给用户使用的前提。
取材与验证边界
- 2026-10-09 Memory 持久效果与 live 失败复盘
- 一期正式关闭与原始测试证据
- 后续更正来源重绑定与受控验收
以上记录来自不同源码和日期窗口,不能合并为一次全端到端的生产验收。
公开版本说明: 原稿引用的私有项目测试、Spec 与工程日志未随文章公开;本文保留案例及其取材时间、局部验证范围,不将内部验收作为读者可直接访问的外部证据。