Skip to content

第 18 章 记忆质量度量与 Badcase 闭环 ​

一家做 SaaS 客服的团队在 2026 年 5 月上线了记忆功能。三个月后,客户成功经理发现一个规律:同一个租户用得越久,助手的回答越差。新租户第一周满意度 4.6 分,用到第十二周掉到 3.9 分。团队的第一反应是「模型退化了」,但模型版本没变。第二反应是「检索变慢了」,延迟确实涨了 40%,但把延迟压回去之后满意度没有恢复。

真正的原因在第三周才被找到:这个租户的记忆库里积累了 2,300 条记忆,其中 400 多条是已经过期的产品政策。检索时这些旧条目与新条目语义相近,一起被召回,注入预算被它们占掉了一半。助手不是记错了,是被自己的历史淹没了。

这个问题在选型阶段完全测不出来。它只在系统运行足够久之后出现,且不伴随任何报错。上一章的自建评测集也无法发现它,因为评测集是静态的,而这个问题是累积性的。

记忆质量的特殊性在于它不是一个指标。召回准确率高可能伴随注入成本失控;拒答正确率高可能伴随召回覆盖率下降;删除彻底率高可能伴随级联失效误伤。六个维度互相拉扯,任何单一指标优化到极致都会破坏另一个。这就是为什么「记忆系统质量」不能被压缩成一个分数。

现有做法的边界也在这里。多数系统只暴露召回准确率与延迟,因为这两项最容易测量。而真正决定长期体验的时效正确率、来源可追溯率、删除彻底率,往往没有测量接口——不是不想测,是没有采集点。

本章按「观测 → 度量 → 归因 → 修复」展开。18.1 拆开六个维度及其冲突关系。18.2 说明 recall_health 能观测什么,特别是它如何回答「召回是否随会话时长退化」。18.3 处理度量系统最容易犯的错:用 0 代替「没有数据」。18.4 给出 Badcase 四步闭环,18.5 是一张可直接使用的归因表,18.6 讨论质量与成本的帕累托边界。

18.1 记忆质量不是单一指标 ​

18.1.1 六个维度及其定义 ​

召回准确率。 给定查询,返回的记忆中有多少与查询相关,且相关的记忆有多少被返回。这是最常被报告的指标,也是最容易被单方面优化的指标——提高返回条数能提升召回率,代价是精度与注入成本。

拒答正确率。 当记忆库中没有相关信息时,系统是否明确表示不知道,而不是用相近内容凑答案。这个维度几乎不被报告,但它是「记错比不记更危险」这一判断的直接体现。

时效正确率。 当同一事实存在多个版本时,返回的是否是当前有效版本。它要求系统能区分「写入时间」与「事实生效时间」,并在检索时做时序判断。

来源可追溯率。 返回的记忆能否回溯到原始对话的具体轮次。它决定了错误能否被归因——一条无法追溯的记忆,出问题时只能整条删除,无法判断是提取错还是判断错。

删除彻底率。 用户要求删除后,该内容是否从所有派生结构中消失,包括摘要、图节点、缓存与压缩胶囊。级联不彻底时,删除是名义上的。

注入成本。 为让模型用上记忆而消耗的 token 数量,以及由此产生的延迟与费用。它与前五项直接冲突:提高召回覆盖率、增加上下文、加入更多历史版本,都会推高成本。

18.1.2 维度之间的冲突是结构性的 ​

六个维度不是并列关系,而是互相拉扯。提升召回准确率最直接的办法是扩大返回集,但这会推高注入成本并降低精度;提升时效正确率需要在检索时加入时序判断,这会增加延迟;提升来源可追溯率需要在每条记忆上保存轮次区间,这会增加存储与写入开销。

一组具体冲突可以说明这种结构性。

维度 A维度 B冲突机制常见误判
召回准确率注入成本扩返回集提召回,占满预算认为成本问题属工程优化
拒答正确率召回覆盖率提高拒答阈值会漏掉真实存在的记忆认为拒答率高是保守
时效正确率延迟时序判断需额外检索与比较认为延迟可事后优化
来源可追溯率写入吞吐保存轮次区间增加写开销认为可追溯性是锦上添花
删除彻底率召回连续性级联删除可能误伤共享摘要认为删除只是标记

表 18-1 六个质量维度之间的结构性冲突

这张表的用法是:在优化任何一项之前,先确认它挤压的是哪一项,以及那一项当前是否已经接近临界。一个召回准确率 92% 但注入成本已占满预算的系统,继续优化召回的收益接近于零,因为新增的召回内容无法被注入。

代价必须说清楚:同时观测六个维度需要六套采集点,工程投入不小。多数团队在早期只应盯住两个——召回准确率与拒答正确率,其余在出现具体问题时再补。全面观测的代价是仪表盘变成没人看的仪表盘。

18.2 recall_health 能观测什么 ​

recall_health 是一个只读工具,它不改检索参数、不触发重算,只报告已经发生的召回行为。这个设计约束很重要:一个会改变系统状态的「健康检查」无法用于生产环境,因为观测行为本身会污染被观测对象。

它报告的内容可以分成四组。

调用量与结果分布。 调用次数、空结果率、平均返回条数、平均 top1 分。空结果率是最容易被忽略的信号:它突然上升通常意味着写入链路出了问题(提取器失效、嵌入不可用),而不是检索变差。

相关性下限的剔除量。 被相关性下限剔除的条数。这个数字与空结果率配合使用能区分两种失效:剔除量高而返回数正常,说明库里有大量边缘相关内容;剔除量高且返回数下降,说明查询与库的语义空间已经偏离。

置信带与通道命中分布。 返回项落在 high / normal / low 三个置信带的分布,以及五路信号(语义、BM25、实体图、时间、标签)各自的命中次数。通道分布是定位退化的关键:如果某段时间语义通道命中骤降而 BM25 命中上升,说明嵌入后端出了问题,而不是记忆内容变差。

后端与异常计数。 向量后端的写入与删除成败、非法字符替换计数、胶囊缓存命中率、图边规模、延迟分位。非法字符替换计数是一个容易被忽略的指标——它上升说明有不可见 Unicode 或编码异常的内容正在进入库中。

这些指标合起来回答一个特定问题:召回是否随会话时长退化。这个问题不能靠单点快照回答,需要看趋势。一个典型的退化曲线是:调用次数稳定、平均返回条数稳定、但平均 top1 分缓慢下降、同时被下限剔除的条数上升。这个组合说明库里的相关内容正在被越来越多的边缘内容稀释——正是本章开头那个客服团队遇到的情况。

最近 20 轮明细是这条曲线的原始数据。它的价值在于让「退化」从统计现象变成可指认的具体查询:哪一轮的 top1 分异常、那一轮召回了什么、其中哪些是过期条目。

需要说明边界:recall_health 观测的是召回侧,它看不到「召回正确但模型没用上」这一类问题。后者需要看注入结果与最终答案的对应关系,属于另一个采集点。

18.3 memory_metrics 的诚实设计 ​

memory_metrics 提供三组指标:Chat 5 项、Working 4 项、Coding 4 项。分组的意义在于不同类型的记忆有不同的质量定义——对话记忆看的是上下文连贯性,任务记忆看的是目标达成,代码记忆看的是意图与约束的保留。

这组指标最重要的设计决定不在指标本身,而在数据不足时的返回值。

当某项指标缺少足够样本时,它返回:

json
{"value": null, "status": "insufficient_data", "need": "at least 5 sessions with pending items"}

而不是返回 0。这个区别看似细节,实际上是度量系统最容易犯的错,值得单独展开。

18.3.1 为什么 0 和「没数据」是两件事 ​

返回 0 会让「未测量」与「测量结果为零」在报表上完全一致。后果沿三个方向扩散。

第一,污染聚合。 一个有 10 项指标的系统,若其中 4 项因为没有数据返回 0,平均分会从真实的 85 掉到 51。这个数字会进入汇报材料,然后被用来判断「系统质量下降」。

第二,掩盖采集故障。 采集点失效时指标归零,运维看到的是「质量下降」而不是「采集坏了」,排查方向从一开始就错了。某家做内部知识助手的团队曾因此浪费两周:Coding 组四项指标全部为 0,他们去查代码记忆的提取器,实际原因是采集脚本的时区参数写错,导致所有事件落在未来时间被过滤掉。

第三,破坏趋势判断。 一个从 0 增长到 60 的曲线,可能是系统从「无数据」变成「有数据」,也可能是从「完全失败」变成「部分成功」。两者的处置完全不同,而报表上看不出区别。

18.3.2 诚实的度量需要三样东西 ​

第一是区分状态。insufficient_data 是一个独立状态,不是 0 的一种。它需要在报表层被显式渲染——显示为空白、显示为「样本不足」,而不是显示为 0。

第二是说明缺口。need 字段说明还差多少样本。这让读者能判断「等一周就有数据」还是「这个采集点根本没接上」。

第三是不估算。数据不足时不要用历史均值填充、不要用同类指标外推。填充会让报表好看,但会让所有下游判断建立在虚构之上。

代价很直接:报表会有大量空白,看起来不完整。一个充满 insufficient_data 的仪表盘在汇报场合不好看,团队会承受「为什么这么多指标没数」的质疑。这个代价必须付,因为另一种选择的代价是决策建立在假数字上。

18.4 Badcase 的四步闭环 ​

Badcase 闭环的价值不在修复单个案例,而在让同类问题不再重复出现。四步的分工是:发现靠采集,归因靠结构,修复靠判断,回归靠纪律。

18.4.1 发现 ​

来源有两类。一是 Trace:检索到的记忆与最终答案之间的对应关系出现异常,例如答案引用了未被召回的内容,或召回了正确内容但答案未使用。二是用户反馈:用户明确说「这不是我说的」「我早就改过了」。

两类来源的可靠性不同。Trace 信号客观但需要建立对应关系;用户反馈直接但稀疏,且只在体验差到一定程度时才出现。只依赖用户反馈的团队,发现问题的时间点通常比实际劣化晚数周。

18.4.2 归因 ​

归因的核心是把问题落到三个环节之一:提取错、检索错、判断错。

提取错:原始对话里有正确信息,但写入时被抽错、抽漏或被合并。检索错:库里有正确信息,但没被召回,或被过期信息挤掉。判断错:正确信息被召回了,模型却没用上或误用。

三者的修复动作完全不同,误判的代价很高。把检索错当成提取错,会导致重复写入(库里堆更多冗余);把判断错当成检索错,会导致不断放宽召回阈值(引入更多噪声)。

区分方法很具体:看库。如果库里根本没有正确信息,是提取错;如果有但没召回,是检索错;如果召回了且内容正确但答案错了,是判断错。

18.4.3 修复 ​

提取错改提取器:调整抽取粒度、补充字段识别、检查分型规则。检索错改检索参数:相关性下限、通道权重、时序判断。判断错改注入方式:调整 prompt 模板、改变记忆的呈现顺序、标注来源与时间。

每次修复只改一个变量。同时改多个变量会让回归结果无法归因——分数上升了,但不知道是哪一项起的作用,下次出问题时也无法回退。

18.4.4 回归 ​

同一批 case 重跑,固定 judge。回归的纪律性体现在两点:case 集不变、judge 版本不变。任何一项变化都会让「修好了」这个结论失去依据。

回归还要检查反向影响:修复 A 类问题是否引入了 B 类问题。方法是在同一批 case 上同时看修复目标项与非目标项的分数变化。只修好目标项却拉低其他项的改动,通常不值得保留。

四步的输入与产出各不相同:发现阶段吃 Trace 与用户反馈、产出可指认的问题条目,最常见的失败是只看反馈、滞后数周;归因阶段吃问题条目与库内实际内容、产出「提取 / 检索 / 判断」三者之一,最常见的失败是跳过查库直接改参数;修复阶段吃归因结论、产出单变量改动,最常见的失败是同时改多项;回归阶段吃固定的 case 集与 judge、产出前后对照与反向检查,最常见的失败是 case 集或 judge 版本漂移。

18.5 归因表 ​

下表把常见现象直接映射到原因、验证方法与修复动作。它的用途是缩短归因时间,不是替代查库。

现象最可能的原因验证方法修复动作
用户说「这不是我说的」提取时把模型推断写成了用户事实查该条记忆的来源轮次,比对原话改提取器:区分陈述与推断,推断降置信度
答案引用了三个月前的政策时效正确率失效,旧版本未被压制查同一事实的版本链改检索:加时序判断,旧版本降权
召回结果为空但库里明显有相关性下限过高或嵌入后端异常看通道命中分布与后端成败先查后端,再调下限
返回条数正常但 top1 分持续下降库被边缘内容稀释看最近 20 轮明细与剔除量跑去重与巩固,清理过期条目
助手自信回答库中没有的信息缺拒答机制,用相近内容凑答案构造无答案查询,看是否拒答加拒答阈值与显式「不知道」路径
删除后仍能召回相关内容级联不彻底,派生结构未清理删除后按语义近邻查询用级联删除,清理摘要与图节点
注入预算被占满但答案没变好注入内容与查询相关性不足看注入文本与答案的对应关系改用渐进式披露,先目录后展开

表 18-2 记忆 Badcase 的现象—原因—验证—修复对照

这张表的一个隐含判断是:七行里有四行的修复动作在检索侧,但验证动作都在库侧。这反映了一个实践规律——检索参数的调整看起来最快,但多数检索问题的根源在库的内容质量。先查库再调参,能避免反复调整阈值却不见效的循环。

18.6 质量与成本的帕累托 ​

三项投入经常被同时考虑:重排器、更强的嵌入模型、更精细的规则提取器。它们不是同一条曲线上的选项,适用条件不同。

什么时候值得上重排器。 当召回阶段的候选集已经包含正确项、但排序靠后时。判据是:看正确项在未重排结果中的排名分布,若多数落在 5 至 20 名之间,重排器收益显著;若多数根本不在候选集里,重排器无用,问题在召回阶段。代价是每次检索增加一次模型调用,延迟上升,且重排器的效果随候选集质量下降而迅速衰减。

什么时候值得配更强的嵌入模型。 当通道命中分布显示语义通道命中率明显低于 BM25 时。这说明当前嵌入对业务语料的区分度不足,换模型是直接解法。判据是看语义通道与 BM25 通道的命中差异是否稳定存在。代价是重建索引的成本与持续的推理费用,且换模型会让历史分数的可比性中断。

什么时候内置规则提取器就够。 当业务事实的结构高度稳定、且对提取延迟敏感时。规则提取器确定性、零模型调用、可离线运行,在这些条件下优于模型提取。判据是:抽样 100 条真实对话,若规则提取的字段覆盖率超过八成且错误率可接受,就不必上模型。代价是规则需要随业务变化维护,且无法处理非结构化表述。

三项投入的决策可以压缩成一张判据表。

投入适用判据主要收益主要代价
重排器正确项多在候选集 5–20 名提升 top1 与 top3每次检索多一次模型调用
更强嵌入语义通道命中显著低于 BM25提升召回覆盖率重建索引、推理费用、分数断代
规则提取器字段覆盖超八成、延迟敏感确定性、零调用、可离线需随业务维护,处理不了自由表述

表 18-3 三项质量投入的决策判据

一个常被忽略的组合是:这三项都不该在系统稳定运行前上。系统还在频繁改提取逻辑时,重排器的收益会被上游噪声掩盖,投入产出比无法测量。先稳定写入,再优化检索,最后才考虑重排——这个顺序的代价是见效慢,但它是唯一能归因的顺序。

18.7 本章小结 ​

本章确立三条判断。第一,记忆质量是六个维度的结构性冲突,不是单一指标;任何一项优化到极致都会挤压另一项,因此优化的第一步是确认当前瓶颈在哪一项,而不是提高最容易测的那一项。第二,度量系统的诚实性体现在数据不足时的返回值上;用 0 代替「没有数据」会同时污染聚合、掩盖采集故障、破坏趋势判断,代价是报表不好看,这个代价必须付。第三,Badcase 闭环的价值在归因而不在修复;把问题落到提取、检索、判断三者之一,是唯一能让修复可归因、可回退的前提。

三条判断各有失效条件。六维观测在团队规模小时投入过高,此时只盯召回准确率与拒答正确率是合理妥协,代价是时效与删除问题会在运行数月后才暴露。诚实度量的代价在汇报场合真实存在,一个充满 insufficient_data 的仪表盘会引来质疑,团队需要有心理准备解释为什么空白比 0 更可信。归因优先的前提是有 Trace 与来源追溯,若系统没有保存轮次区间,查库这一步无法完成,闭环会退化成试错。

本章留下的问题是:这套闭环处理的是已知问题——有人发现、有人归因、有人修复。而记忆系统的能力增长还有另一条路径:让系统从自己的轨迹中提炼可复用的经验,下次遇到同类任务时直接调用。这条路径的效率远高于人工归因,但它引入一个新风险:经验是由模型生成的,模型会抽象错、会过度泛化、会把偶然有效的做法固化成规则。第 19 章处理这个层面:如何让系统自进化,同时保证每一次进化都是受控的候选变更,而不是直接写入组织规则。


Copyright © 2026 胡景堃(Hu Jingkun). 采用 CC BY-NC-ND 4.0 许可。未经授权禁止传播、复制或用于商业化。