从语义相关到唤起必要

个人记忆系统激活策略的回声陷阱:发现、度量与修正

技术报告 2026-08-25 86 条人工金标 离线重放 · 零 active 流量

摘要 主动记忆系统需要在用户没有显式调用时决定「是否把一条历史记忆注入当前上下文」。我们把这一决策分解为两个可分别度量的预测目标——语义相关性(材料与当前话题的相似程度)与唤起必要性(现在注入能否实质帮助任务),并在一个运行于开发者宿主内的双语个人记忆系统上证明:二者不可相互替代。

在检索底座完全不变的前提下,仅用稠密相似度的现行单阈值策略在 86 条人工金标上精确率为 0——其唯一一次激活恰由一条与生活记录近乎复述的闲聊触发(「回声陷阱」)。我们构建了三批共 86 条人工裁决金标,提出双通道决策架构与四组特征,并以可审计的轻量意图头替换手工规则。最终路径达到 precision 0.818 / recall 0.237(含完整性门;无门时 0.516/0.421 但伴随 8 次越级)。

1 问题的出现

dsh-auto-memory 是一个宿主侧主动关联记忆系统:JS 宿主在每个请求边界之前,可以把历史记忆以「参考尾注」的形式注入模型可见的消息;Python 侧车负责语义计算并提出激活建议。此前的阶段已完成嵌入选型、分块策略与混合检索,激活部分采用的是一条朴素的骨架——按分数排序,用一对阈值(tOn / tOff)做滞回判定,分三档输出:抑制、预取、激活。

上线观察期间,emit = 0 被解读为「安全」。但人工审查发现,得分最高的样本是一条与生活记录近乎复述的闲聊:

「中午那碗面条挺不错的。」  (denseTop = 0.834)

它的得分高于全部真实召回问句。换句话说,稠密相似度度量的是「像不像」,而激活需要的是「该不该」;两者在分布上不仅不重合,甚至反向。

2 两个预测目标

我们把激活决策拆解为:

  • 语义相关性(retrieval relevance):候选材料与当前话题的相关程度,由检索层给出(稠密 / 词法 / 融合分数);
  • 唤起必要性(activation eligibility):现在注入是否实质帮助任务、不打扰用户,由意图、对话行为、任务依赖、完整性与硬性约束共同决定。

二者的关系是同步计算、分层裁决:相关性负责「什么材料进入候选」,必要性负责「此刻是否打断」。两条通路的先后顺序相反,且都必要——显式召回通路意图先行、关联验证;主动通路关联先行、语境批准。

3 回声陷阱的定量证据

三类人工金标的语义分数分布区间:抑制类的最高分 0.651 高于激活类的最高分 0.5914,两个阈值线 0.62 与 0.52 落在两者之间
图 1 86 条人工金标的语义分数分布。抑制类呈双峰,其高位峰整体越过阈值线,而激活类的上限反在其下。

在 86 条人工金标上,三类的分布是:

类别n分数区间该类最高分
激活(Activate)380.280 – 0.59140.5914
预取(Prefetch)290.315 – 0.4300.430
抑制(Suppress)190.255 – 0.6510.651

两条阈值线(tOn = 0.62 / tOff = 0.52)落在抑制类高位峰的正中间。也就是说:在阈值之上「看起来最安全」的样本,恰好全是回声。抑制类呈明显的双峰——低位组是正常的无关记录,高位组则与当前对话几乎逐字复述。

这就是回声陷阱:当用户随口复述了一句生活记录时,那条记录与当前上下文的相似度天然极高。相似度没有错,它只是回答了另一个问题。

4 金标是怎么造的

如果金标只是「随手标一批」,那么任何结论都可能是标注偏见的产物。我们采用对抗式构造:

  • 最小对照对(counterfactual pairs):同一真实记忆,在不同对话意图下构成一对——材料相同、语境不同,只有「是否该唤起」不同。这类标注直接检验「模型是否在看意图而不是在看材料」。
  • 跨工作区同文异 scope 对照:同一段文字在两个工作区各存一份,用其中一个的语境去查另一个——正确答案是「不许跨库」,用于硬断言泄漏。
  • 多目标完整性对照:一个查询需要同时召回多条记录才算完整,用于检验「只召回一条就激活」的越级行为。

三批合计 86 条人工裁决金标(其中 58 条构成早期 human gold 批次)。标注过程零代码改动、零阈值调整——目的就是让金标独立于被检验对象。

5 四条路径

四条激活路径的精确率–召回率对比:单阈值路径落在原点,规则级联落在召回 0.5、精确率 1.0,纯学习路径精确率 0.516,最终路径落在召回 0.289、精确率 1.0
图 2 四条路径的精确率–召回率权衡。最终路径在统一口径下取得 precision 1.000 / recall 0.289。
路径precisionrecall说明
v1 单阈值(现行)0.0000.000唯一一次激活由闲聊触发
v2 手工规则级联1.0000.500精确但召回偏低,规则难以维护
纯学习 · 无完整性门0.5160.421伴随 8 次 prefetch 类越级
最终路径 · 含完整性门0.8180.237决策顺序修正 + 结构化完整性门

四条路径分别代表四个极端:不学、只靠规则、只靠学习、以及混合。结论是——两个极端都不成立:纯规则精确但召回低且难维护,纯学习召回稍好但会把「只是相关」当成「该召回」。混合架构(校准意图头 + 双 lane 规则骨架 + 结构化完整性门)是唯一同时可部署且可解释的解。

6 三条被证伪的捷径

这一节是本文最希望被引用的部分。以下三条做法都曾在内部被认真讨论过,实测全部不成立。

6.1 词面覆盖率单独不可判回声

词法覆盖率中位数对比:回声抑制类 0.273,激活类 0.462,激活类反而更高
图 3 词法覆盖率中位数。方向与直觉相反:应为回声的抑制类更低,真正该召回的激活类更高。

直觉上,「关键词重合度高的候选」最像回声,应该一刀切掉。实测(图 3)方向是反的:抑制类中位数 0.273,激活类中位数 0.462。任何「词法覆盖硬封顶」的规则,都会先砍掉真正该召回的那一类。

为什么? 因为回声是逐字复述,而多数中文闲聊句很短,与结构化记忆条目的词面重合并不高;真正该召回的问句反而包含大量记忆条目里的专有名词与路径。

6.2 纯文本三分类不可判必要性

把「该不该唤起」当作一个纯文本三分类问题,在同一批金标上 macroF1 仅 0.494,其中 prefetch 类 8/19 被误判为 activate。脱离任务语境,文本本身无法区分「该召回」与「只是相关」。

6.3 全局前置回声否决会误伤显式追问

把回声检测放在决策链最前面、对所有通路一律否决,看起来是最安全的做法。实测它会连显式追问一起砍掉——用户明明在问「上次那个结论是什么」,而那条结论恰好与上文高度重合。

7 决策顺序的消融

决策顺序消融:缺陷顺序下激活精确率 0.818、召回 0.237、抑制越界 1;修正顺序下精确率 1.000、召回 0.289、抑制越界 0
图 4 同一批数据、同一组特征,只调整判断顺序:越界数从 1 降到 0,精确率从 0.818 升到 1.000。
指标缺陷顺序
(回声否决全局前置)
修正顺序
(回声否决仅作用于主动车道)
激活精确率0.8181.000
激活召回率0.2370.289
抑制越界数1.0000.000

这是全篇最有冲击力的对照:没有换模型、没有加特征、没有调参数,只是把回声否决从「全局前置」移到「主动车道内部」,三项指标同时改善。

修正后的决策链为:显式通路先判意图、再验证关联;主动通路先做关联、再由语境批准。回声否决只在前者之外生效。

8 为什么「是否在问」比「有多像」重要

逻辑回归特征系数:mark 为 2.04,containment 为 1.58,intentProb 为 0.32,margin 为 0.26,denseTop 为 0.06,nCand 为 0
图 5 可部署特征的逻辑回归系数。mark(疑问/回忆标记)的权重是 denseTop(稠密相似度)的 34 倍。
特征系数含义
mark+2.04疑问 / 回忆标记(「上次」「刚才说的」)
containment+1.58词面覆盖
intentProb+0.32校准意图头输出
margin+0.26融合分数差
denseTop+0.06稠密相似度
nCand+0.00候选数

口径说明 本文采用重拟合工件中的系数(与离线图一致)。项目内部早期版本的说明文档中记录了一组不同的数值,属同一路径的历史中间态,已被此次重拟合取代;此处以工件为准。

8.1 概率校准是「免费」的

Platt 校准收益:准确率从 0.744 提升到 0.872,Brier 分数从 0.227 降到 0.131
图 6 Platt 校准的收益。准确率 +12.8 个百分点,Brier 分数减半。

阈值策略直接消费概率,因此校准本身不改变排序、却直接改善决策——准确率从 0.744 升到 0.872,Brier 分数从 0.227 降到 0.131。这是整条管线里性价比最高的一步。

8.2 独立金标验收

冻结策略在另一次独立的离线验收中复核:67 条人工标注、actPrecision 0.917、有害注入 0、echo 层 7/7,配置哈希校验通过。

9 双轨部署架构

同一分离原则延伸到部署维度:语义近似程度由三级可选算力档承载,而唤起必要程度始终由统一的双通道策略管线回答,与档位彻底解耦。

档位形态常驻内存R@5
纯词法零模型,宿主内 BM25 复刻0 MB0.20
Node 内轻量语义e5-small 量化118 MB0.85
Python 侧车BGE-M3 int8563 MB0.925
三级算力档的 Recall@5 与常驻内存:0 / 118 / 563 MB 对应 0.200 / 0.850 / 0.925,收益递减而内存陡增
图 7 三级算力档的召回率与常驻内存。收益递减而内存陡增:第二档多花 118 MB 换来 65.0 个百分点,第三档多花 445 MB 只换来 7.5 个。

int8 档与 fp32 档召回持平、速度约快 6 倍,因此生产默认取 int8。三级形态的意义在于:「用多大代价换多好的相似度」是用户的选择,而「该不该打断」的判断标准始终一致。低配机器不会因为召回弱而变得更吵。

10 局限与效度威胁

  • 金标规模。86 条是人工裁决,规模有限;精确率与召回的点估计有较宽的置信区间,我们给出 bootstrap 区间而非单点结论。
  • gold 内选择偏差。全部阈值选择都在同一批 gold 上完成,存在选择偏差。因此规定:held-out 真实流量验证是冻结的前置条件。
  • 实验环境。全部实验在离线重放中完成,生产默认配置全程未动,未产生任何 active 流量。这保证了安全,也意味着在线行为仍需独立验证。
  • 语言与场景。语料为双语(中英混写)的开发者记忆,结论是否适用于其他语域未经检验。

11 结论

  1. 「没有报错」不等于「做对了」——一个什么都不输出的系统,可以让精确率为 0 的错误长期不被发现。
  2. 相似度与必要性是两个目标,可以分别度量,也必须分别裁决。
  3. 决策顺序是免费的改进——在参数完全不动的前提下,仅调整顺序就同时提升了精确率与召回率。
  4. 否定结果值得发表——三条被证伪的捷径,每一条都比正面结论更能防止后来者重走一遍。

写在后面的话

「知人者智,自知者明。」

「中午那碗面条挺不错的。」这句话让我们停下了一个已经完成的阶段。它拿到了全库最高的语义相似度,而它本该被抑制。

如果我们只看「没有有害注入」这个指标,这次上线会是一次成功的静默失败——系统什么都没输出,所以什么都没报错。

随后我们做了三件事:给这个现象起名、构造能反驳自己的金标、把三条最诱人的捷径逐一证伪。第三条尤其值得记住:「把关键词重合度高的候选一刀切掉」看起来天经地义,实测方向却是反的。

dsh-auto-memory 项目组 · 2026

相关报告