AI Agent 工程课程

候选记忆怎样准入、更新和撤回

一句话收获:长期记忆必须有主体、来源、准入和撤回证据。

这个场景在解决什么问题

Agent 用久了,你会希望它"记住"用户的偏好、发生过的事实、重要的决定。但"记住"这件事不能是模型在对话里随手写一条就完事——那样会记住错误信息、记住过时信息,而且删都删不干净。

这个场景的目标(goal)是:实现独立记忆写入路径和派生失效。观察点(observation)是:让模型推断经历候选、确认、冲突和撤回——也就是记忆不是一步到位,而是要经过"提取候选 → 确认 → 冲突更新 → 撤回传播"的完整生命周期。

它值得单独学,因为它回答了长期记忆最核心的问题:一条记忆凭什么可信、凭什么有效、凭什么能被安全地撤回

先理清这条判断链(文字版)

记忆的生命周期是一条链,先看"能不能进",再看"怎么存",再看"变了怎么办",最后看"删了干不干净":

  1. 先看提取候选——任务结束后,独立步骤从轨迹里提取候选,主 Agent 不直接写记忆,候选先等着准入。
  2. 再看确认与表示——确认过的东西,按未来用途存成字段、卡片或摘要,表示方式服从读取和更新需求。
  3. 然后看冲突更新——新旧来源冲突时,保留旧值、进入"待确认",不能直接最后写入覆盖。
  4. 最后看撤回传播——主记录、索引、摘要、缓存、新任务全部失效,撤回的标准是"未来不再使用"。

逐层详解

第 1 步:提取候选

原文:任务结束后,独立步骤从轨迹提取偏好、事实和事件候选。

白话:一次任务干完后,由一个"独立的步骤"(不是主 Agent 边干活边写)去翻这次任务的完整轨迹,从中提取出候选的记忆——可能是用户的偏好、一个事实、一个事件。注意这些都是"候选",不是直接生效的记忆。

类比:像会议结束后,专人整理会议纪要,先把"可能值得记下来"的点列出来当草稿,而不是边开会边直接写进制度文档。

举例:Agent 帮 summer 订了一次出差机票,任务结束后,独立步骤从轨迹里提取候选:偏好"夏天出差喜欢靠过道座位"、事实"summer 常驻上海"、事件"本周完成了深圳出差"。这些先作为候选,等准入。

为什么重要:主 Agent 不直接写入长期记忆。因为主 Agent 正在干活的上下文里充满了假设和推断,直接写会把"它猜的"当成"事实"存进去,所以写入要交给独立路径。

怎么验证(证据点)

  • 来源轨迹:每条候选能指回它来自哪段轨迹。
  • 主体明确:能说清这条记忆是关于谁的(哪个用户、哪个对象)。
  • 敏感等级:标注了这条信息的敏感程度。

别踩的坑(边界):模型推断不能直接成为事实。模型从对话里"推断"出某个结论,不等于这个结论就是事实,候选只是"待确认",不能跳过确认直接生效。

落地检查:候选先等待准入。落地时要有一个明确的"候选区",所有提取出的内容先待在候选区,经过下一步确认才能转正。

第 2 步:确认与表示

原文:已确认内容按未来用途进入字段、卡片或摘要。

白话:确认过的内容,要根据"未来怎么用"来决定存成什么形式——如果是高频查询的固定属性,就存字段;如果是一段结构化记录,就存卡片;如果是大段背景,就存摘要。

类比:像整理客户资料,固定要查的(电话、地址)存成表单字段,一次性的合作过程存成档案卡片,长篇背景写成一段摘要,按"以后怎么查"来定格式。

举例:确认"summer 常驻上海"后,存成用户档案里的一个字段(base_city=上海),方便以后订票、约会议时直接调用;而"本周完成深圳出差"存成一条事件卡片,方便以后问"最近去过哪"时召回。

为什么重要:表示方式服从读取和更新需求。存成什么形式,不是随便选的,而是由"以后怎么读、怎么改"决定的——形式错,后续读取和更新就都别扭。

怎么验证(证据点)

  • 确认依据:这条记忆是基于什么依据被确认的。
  • 用途明确:能说清存成这个形式是给哪个用途服务的。
  • 权限明确:谁能读、谁能改这条记忆是清楚的。

别踩的坑(边界):结构化存储不证明事实永远有效。把一条记忆存成漂亮的字段/卡片,不代表它以后一直对——人搬家了、政策变了,记忆就可能过期。

落地检查:生命周期仍需管理。落地时不能只做"存进去",还得管它什么时候过期、什么时候该更新、什么时候该撤回。

第 3 步:冲突更新

原文:新旧来源冲突时保留历史并进入待确认。

白话:当新的来源和旧记忆冲突时,不能直接拿新值覆盖旧值,而是要把旧值保留下来、标记成"待确认",让人或流程来裁决到底哪个对。

类比:像系统改用户手机号,不能直接覆盖掉旧的然后旧的就没了,而是保留历史记录、标个"待确认",避免手滑把正确信息覆盖成错的。

举例:记忆里存了"summer 常驻上海",新轨迹里出现"summer 最近搬到杭州了"。这时不能直接把"上海"改成"杭州",而要保留"上海"作为历史值,新增"杭州"作为新来源,标记为冲突待确认,等确认后再更新。

为什么重要:最后写入覆盖会掩盖不确定性。如果每次都"谁后写谁赢",那一旦后来的信息是错的,就再也看不出"这里曾经有过分歧",不确定性被悄悄抹掉了。

怎么验证(证据点)

  • 旧值保留:被替换前的旧值还能查到。
  • 新来源:新值来自哪里、依据是什么。
  • 冲突状态:这条记忆当前是不是处于"待确认"状态。

别踩的坑(边界):更新时间晚不等于来源更权威。新来的信息时间更晚,不代表它更靠谱——新信息也可能是错的,权威性要看来源,不能只看时间戳。

落地检查:按信息类型处理更新。落地时不同类型的记忆要有不同的更新策略:偏好、事实、事件各有各的冲突处理规则,不能一刀切。

第 4 步:撤回传播

原文:主记录、索引、摘要、缓存和新任务全部失效。

白话:撤回一条记忆,不是把主表里那一行删掉就完了,而是要让它所有"派生出来的东西"一起失效——索引、摘要、缓存、以及未来新任务都不能再引用它。

类比:像撤回一份文件,不能只删原稿,还要让所有复印件、索引卡片、缓存页面、以及以后要引用它的人全都失效,否则原稿删了,复印件还在流传。

举例:发现"summer 常驻上海"这条记忆是错的(其实是杭州),撤回时不只是删主表那条记录,还要让"上海"相关的检索索引失效、让相关摘要失效、清掉缓存,并确保下一次新任务不会再装载"上海"这条信息。

为什么重要:撤回的标准是未来不再使用。撤回是否成功,不看"主表删没删",而看"未来还有没有地方会用到它"——只要还有地方能命中,撤回就没完成。

怎么验证(证据点)

  • 主记录失效:主表里的记录已标记失效。
  • 检索不再命中:再去检索,不会再命中这条内容。
  • 新任务不再装载:新建的任务不会再把这条记忆装进上下文。

别踩的坑(边界):删除主表记录不证明撤回完成。只删主表那一行,索引、缓存、摘要里可能还留着它,删主表只是第一步,不是全部。

落地检查:检查所有派生入口。落地时要系统性地排查所有派生物——索引、摘要、缓存、预装载逻辑——逐个确认它们都不再返回这条已撤回的内容。

落地可行性小结

本场景涉及的核心技术栈:长期记忆(Long-term Memory)轨迹(trace)提取记忆准入(admission)冲突处理(conflict resolution)派生失效(derived invalidation)

真实落地要检查的事:

  • 记忆写入必须走独立路径,主 Agent 运行循环里不允许直接写长期记忆。
  • 每条记忆要带元信息:主体(谁的)、来源(哪条轨迹)、敏感等级、状态(候选/已确认/冲突/已撤回)。
  • 更新不能覆盖式写入,要保留历史版本和冲突标记。
  • 撤回要有一张"派生清单"(索引、摘要、缓存、预装载),逐项失效。

常见坑:

  • 让模型在对话里直接写记忆,导致推断当事实。
  • 更新时直接覆盖,丢掉了冲突历史。
  • 撤回只删主表,索引/缓存里还在命中,出现"删了还能搜到"的灵异现象。
  • 没有敏感等级和权限,敏感信息混在普通记忆里。

回顾

  • 长期记忆必须有主体、来源、准入和撤回证据,不能是模型随手写的黑箱。
  • 记忆写入走独立路径,主 Agent 不直接写,候选先等待准入。
  • 冲突更新要保留旧值、进入待确认,不能用"最后写入覆盖"。
  • 撤回的标准是"未来不再使用",要检查所有派生入口(索引、摘要、缓存、新任务)。
  • 模型推断不能直接成为事实,确认依据和来源是记忆可信的根基。