为什么记忆「注进去了」,模型却用错了

记忆该不该注、注多少、注错了怎么办——七维透镜做决策,三层分工避免重复灌,相反本能让你别把记忆当圣旨。

Module E · 第 3 讲

立靶:你以为注入了记忆就万事大吉,模型偏要用错

做一个有记忆的 Agent,最直觉的想法是:把用户的历史档案查出来、拼进 prompt,模型自然就「记得」这个人了。于是你写了一段加载逻辑,把用户画像 .format() 进系统提示,自测一遍——开场果然能叫出名字、续上上次的话题,看起来很聪明。

可上线一阵后,三种事故会陆续找上门。

第一种:注错人。两个用户的标识串了,把 A 的画像注给了 B,Agent 张口就「您上次说想换城市对吧」,B 一脸懵——这比干脆不注入更糟,因为模型会信以为真、基于错信息行动。第二种:重复灌。本轮已经问过的信息下一轮又问一遍,或者把用户全部历史逐字塞进上下文,token 爆掉、延迟飙高、模型还抓不住重点。第三种最隐蔽:注进去了,模型却死咬旧偏好。画像里写「上次想找司机岗」,这通用户明明说想换方向,模型却揪着司机不放——你以为「记住」就是好事,模型却把历史记忆当成了不可违抗的圣旨。

这一讲要解决的,正是这三件事背后的同一个核心问题:模型这一轮,要不要给它喂一段「它本来不知道、但这轮可能用得上」的外部知识或历史记忆?喂哪条、喂多少、什么时候喂、喂错了怎么办? 这就是七层装配图里的 L6——RAG 与记忆。

框架:先认清 L6 是什么,再用七维透镜做决策

L6 装的是「按当前用户、当前轮检索出来、它本来不在模型脑子里」的知识或记忆,两个子类:

子类是什么典型场景
RAG(检索增强)从知识库捞相关片段FAQ 库、文档库、按 query 动态召回
记忆(memory)跨会话 / 跨轮的用户状态用户画像、上次聊到哪、长期偏好

命门一:层按「内容来源」分,不按「物理拼在哪」分

这是 L6 最反直觉、也最容易判错的一条。设想某用户档案最终是 .format() 填进系统提示那段字符串里的——物理上它躺在 L1 的文本里,但它的逻辑归属仍然是 L6。

为什么?因为分层看的是这段内容怎么来的

  • L1 系统提示:静态人设,每个用户、每轮都一样,不查任何东西就有。
  • L6 记忆:按「这个人是谁」检索某用户档案才有,不同用户注入的内容不同。

它最后被拼进了 L1 的字符串 ≠ 它就是 L1。物理位置 ≠ 逻辑归属。 审计上下文时要追内容的来源链,不能只看它落在哪段文本里。一个配套的速判:这条信息是本轮产生的,还是上一轮 / 库里带来的——本轮产生的算 L7(状态与历史),带过来的算 L6。L7 是本会话内累积、框架托管、每轮自动增长;L6 是跨会话检索来的、相对静态地在开场注入。

命门二:七维透镜做「注入决策」

注入记忆本质是回答一句话:「在对的时刻、用对的判断、在预算内、把对的知识塞进去、还不能塞错。」把这句话拆成七个维度,就是一张可以逐项填空的决策表:

维度要回答的问题记忆场景的典型答案
When 何时注loop 哪个节点注入会话开始时一次性注入,不是每轮检索
Signal 什么触发用什么信号决定注哪条强标识(如唯一 ID)命中某用户档案 / 命中上次断点
Rank 多条怎么排多候选如何排序取舍画像简单时不涉及;真 RAG 多片段召回才需要
Budget token 预算注入占多少 token、怎么压压成结构化摘要而非全部历史;进静态前缀者考虑 cache
Guardrail 怎么防错怎么防注错 / 过度注入身份校验防张冠李戴;认「注错 > 不注」,拿不准就别注
State 状态注入是否依赖会话状态续接断点需读会话状态,纯画像较弱
Observe 可观测注了什么、用没用对,可见吗打印每轮注入的记忆 token,对账

记忆场景的重头戏在 When + Budget + Guardrail:开场注一次(When)、压缩别全灌(Budget)、注错比不注更糟(Guardrail)。Rank / State / Observe 在简单画像场景偏弱,要等真 RAG 重场景才吃重。

命门三:记忆三层分工,避免重复灌

「重复灌」之所以反复发生,是因为没把记忆分清谁管哪一段时间尺度。把记忆切成三层、各管一段,问题自然消失:

存什么作用
会话内当前已采集的槽位 / slots本轮已问过的不再重问
会话结束一句话摘要 + 下次续接 hint(强压缩)下次不必从头探一遍
跨会话长期 profile 画像老用户回来直接注入,不重建

一句话:会话内靠当前 slots 不重问、会话间靠 hint 不重探、长期靠 profile 不重建。 三层各守一段时间尺度,重复灌就没了立足之地。

命门四:按新鲜度分档注入

老用户 ≠ 全量注入画像,因为记忆会过时,越旧越不可信。正确做法是按距上次交互的时间分档:

距上次策略注入什么
较近(如 ≤ N 天)直接续上跳过自我介绍,记忆新鲜信得过
半新(如 ≤ M 天)注入但先确认注画像但先核身份,记忆可能过时
太久当新用户几乎不注入,重新探

口诀:记忆不是全有全无,按新鲜度分档——越新越敢用、越旧越要确认或丢弃。 这其实是 Budget(不浪费预算注过时记忆)和 Guardrail(旧记忆可能错,先确认防注错)两维的合体。注入粒度的总判据是「刚好够这轮用」——一个积累了几十次交互的超级老用户,注入的是压缩后的 profile + 最近一次 hint,不是逐字记录。

命门五:相反本能——注进去 ≠ 模型会恰当使用

这是全讲最该刻进反射的一条。你把记忆塞进上下文,潜意识以为模型会「适度参考」,但模型有一种相反本能:过度使用注入的记忆。画像说用户上次想找司机岗,这通用户说想换方向,模型很可能死咬司机不放。

防法是双管:① prompt 里显式声明优先级——「画像是历史参考,一切以本轮用户意图为准,冲突时跟随本轮」;② 注入时用降权表述——「上次曾提到……,本次请重新确认」,让注入的记忆是参考而不是圣旨。

这条本能不止出现在记忆这一层。凡是「把 X 塞进上下文 / 给模型一项能力」,都要立即反问一句:模型有没有相反本能会用错它?该冲突时跟随谁、还是该并存? 把能力给出去和把能力用对,是两件事。

数据 / case:三种事故,三种修法

下面是脱敏后的典型手感,对应立靶里的三种事故:

  • 注错人比不注更糟(某语音 Agent,身份串号):某 Agent 用某标识匹配用户档案,一次数据串号,把 A 的画像注给了 B。Agent 开场就「您上次想找司机对吧」——B 从没说过,体验和信任同时崩。而如果当时压根没注入,Agent 只会正常问「您想找什么」,毫无伤害。结论:记忆系统的 Guardrail 取向应当保守,拿不准就别注;并且 Signal 必须用强标识 + 身份校验。
  • 每轮重检索拖垮延迟(某实时 Agent,注入时机错位):一版实现把画像改成「每轮根据用户当前说的话实时检索注入」,结果三个代价齐发:每轮多一次检索 = 延迟(实时场景的红线)、反复注入相似内容 = token 重复浪费、注入内容每轮抖动 = 破坏 cache、模型困惑。修法:画像是跨会话静态记忆,开场注一次就够。判据很清晰——静态记忆开场注一次,只有随 query 变化的知识(真 RAG)才值得每轮检索
  • 静态画像没进 cache,每轮全价重发(某 Agent,Budget 暗账):画像 .format() 进 L1 后,它就和系统人设一起成了每轮重发的静态前缀。画像越长,每轮重发的 token 越多,单次成本被悄悄推高。这和工具 schema、L1 人设是同一块暗物质:所有「开场注入、整通不变」的记忆都属静态前缀,该进 prompt cache 只发一次、后续命中缓存。 若有人把几十次历史逐字塞进画像,不仅 token 可能撑爆上限,cache 也救不了这么大的前缀——唯一出路是压缩成结构化摘要。

三个案例指向同一句话:记忆的难,不在「查得到」,在「何时注、注多少、会不会注错、模型会不会用错」

可操作做法:怎么把这套用起来

PM 视角——用它做判断和沟通:

  1. 评审一个记忆功能,先用七维透镜逐项问一遍:When 在哪注?Signal 靠什么?Budget 多少 token、压不压?Guardrail 怎么防注错? 答不上来的那一维,就是设计还没做完的地方。
  2. 和工程师对齐用层号说话:「这是 L6 注错了记忆」「这是 L7 历史膨胀」,比「它老是出错」精准得多。
  3. 守住「注错 > 不注」这条价值取向:在体验评审里,把「张冠李戴」列为比「没记住」更高优先级的缺陷。
  4. 要求每个记忆功能都回答「按新鲜度分档了吗」——别让团队默认「老用户就全量注入」。

工程视角——用它做架构决策:

  1. 把记忆切成三层落地:会话内 slots(不重问)、会话结束摘要 + hint(不重探)、跨会话 profile(不重建),各管一段时间尺度。
  2. 静态记忆开场注一次,只有随 query 变化、且无法预先全量注入的知识才走每轮检索(真 RAG)。
  3. 画像这类「开场注入、整通不变」的记忆,和 L1 人设、tool schema 一起放进静态前缀做 cache,逐字节稳定、追求高命中。
  4. 注入粒度做到「刚好够这轮用」:profile 存提炼后的画像 + 最近一次 hint,不堆逐字历史;按新鲜度分档,越旧越简或丢。
  5. 在 prompt 里显式写明优先级——「注入的记忆是参考,以本轮为准」+ 降权表述,防模型死咬旧偏好。
  6. 加观测:打印每轮注入了哪条记忆、占多少 token,让「设计账本」和「运行日志」能对上账。

收口

记忆系统真正难的从来不是「查得到」,而是「何时注、注多少、会不会注错、模型会不会用错」。注进去 ≠ 模型会恰当使用——给注入的记忆写明「以本轮为准」,让它是参考,不是圣旨。