基准答案中 6.4% 的错误率,教会我如何信任 Agent 记忆
索引丢失了一半内容,却仍然在回答问题
--
Listen
Share
几个月前,我自己那个业余项目的检索层挂了,可我整整四天都没发现。
我一直反复提到的那个多仓库工单生成工具 Featpilot,背后挂着一个小型混合检索索引。一边是 BM25,用来处理精确匹配(类名、配置项、每个代码库都会积累的那些古怪内部缩写);另一边是 pgvector 嵌入,用来应对那种模糊的“帮我找一下大致做这件事的东西”的查询。两份排序结果用倒数排名融合(Reciprocal Rank Fusion)合并,排在前面的若干片段被送进提示词里。都是些标准操作。我还挺得意这套东西做得如此无聊。
后来我改了切分策略,星期四很晚的时候启动了一次全量重建索引。嵌入那边跑完了。关键词那边处理到一半时锁住了表,任务记了一条谁也不会看的警告,然后因为我一年前写的那层包装脚本吞掉了错误,就以状态码 0 正常退出了。关键词索引里大约一半的仓库就这样凭空消失了。
真正让我到现在都耿耿于怀的是:这东西看起来没有任何异常。每一次查询都返回了结果。工单不断生成出来,带着看着挺合理的验收标准。倒数排名融合的设计目标,就是在某一路召回很弱的时候优雅降级,它也确实完全按设计的那样运转了:当 BM25 对某个查询毫无结果时,向量那一路就悄悄承担起了整个排序。系统并没有崩溃。它只是开始从一个更小、更模糊的文档池里找答案,而给出的回答看起来像是模型正常波动,稍微多了一点泛泛的意味。
我是周一才发现的,发现的原因仅仅是因为某张工单里引用了一个三个月前就已经被改过名的配置项。精确匹配那一路本可以立刻认出新名字;嵌入那一路则找到了一份“语义上差不多”的旧 README。
Rick Hightower 最近在他的 Harness 工程系列里也写了几乎一模一样的故障,他总结里有一句话我一直记着:检索是唯一一个失败了看起来像成功的子系统。Agent 记忆的全部问题,用这一句话就能概括。崩溃是个礼物。一个自信地返回第二优事实的记忆系统,只是一次缓慢的渗漏。
我提起这件事,是因为我之所以发现 bug,是靠运气、靠肉眼盯输出,而我们对记忆系统所做的大多数评测,眼下也基本就是这种状态。我们很多人倚重的那套基准,结果也有它自己静悄悄的渗漏。
构建时“智能体记忆”的真正含义
在进入基准测试之前,先坦诚地谈谈“记忆”这个词究竟涵盖了多大范围是值得的,因为我认为围绕排行榜数字的大量困惑正是从这里开始的。
一端是检索增强类方法:存储文档或对话片段,对它们建立索引,在查询时将最相关的内容拉入上下文。工程的取舍主要围绕索引展开:
另一端是专用记忆系统,它们增加了带有“主张”的写入路径:
下面是我在自己笔记中区分它们的方式:
最后一列才是关键。上面每一种方式都可能以一种仍然能产生流畅、自信答案的方式失败。JIN 在我本周读到的一篇文章中也提到了类似的观点:智能体可以找到写有“Database: MySQL”的文档,却仍然给出错误的建议,因为它检索到的只是某个决定的残留信息,而非其背后的推理过程。检索“成功”了,记忆却失败了。
因此,如果失败是悄无声息的,那么评估就必须是响亮的。这正是基准测试登场的时刻,也正是在这里,我开始对它们失去一些信心。
基准本身也有"静默失败"
LoCoMo(Maharana 等人,ACL 2024)是被引用最多的长程对话记忆基准之一。它包含若干段长篇多会话对话、一组针对这些对话的问题以及一份标准答案。如果你过去一年读过任何一篇记忆系统的发布博客,那篇文章里很可能就出现过一个 LoCoMo 分数。
今年早些时候,Penfield Labs 的一个团队发布了对这份标准答案的系统性审计。他们逐一检查了全部 1,540 道非对抗性问题,标记出其中 99 处会真正影响得分的错误,也就是 6.4%。这些错误的类别,足以让任何在做记忆系统的人感到紧张:标准答案中出现了源对话里根本不存在的"事实"、错误的时间推理,以及张冠李戴的说话人。
我最喜欢审计报告里的一个例子,因为它实在太稀松平常了:某道题的期望答案给出了一个具体的跑车型号。而对话里从头到尾只出现过"这辆漂亮的车"之类的说法,配图说明也只是写着"一辆红色跑车"。这个车型名只存在于一个内部标注字段里,那是标注员用来检索配图的搜索字符串,而任何记忆系统都不会去摄取这个字段。一个回答"一辆红色跑车"的系统其实是正确的,却被判成错误;一个不知怎么恰好说出正确型号名的系统,要么是运气极好,要么就是见过标准答案。
6.4% 这个数字听上去不大,但一旦你算一下就会发现:既然标准答案里有 99 道题是错的,那这个基准的真实上限其实只有大约 93.6%,而不是 100%。而一些已发布的系统,如今报告的分数正好就在 90 出头。处在那个区间时,你测的其实已经不是记忆能力了,而是在测某个系统"碰巧与标准答案里的错误一致到什么程度"。
再来说说裁判(judge)。现代的 LoCoMo 评测已经不再使用精确匹配(exact-match)评分了——那种方式太苛刻,因为"7 May 2023"和"May 7th, 2023"会被算成不同答案。它们改用 LLM 作为裁判,通常是 gpt-4o-mini,让它拿系统的回答与参考答案做比对。审计人员针对每道题都生成了一些"故意写错但话题相邻"的答案,然后把它们丢进已发布评测中使用的同一套裁判流程。结果,裁判大约接受了其中 63%。
请你把这一句读两遍。具体的事实性错误,比如错的名字或错的日期,多数时候还是会被抓住,大约 89% 的比例。真正漏过去的,是那些模糊的回答——答案落在了正确的话题上,却一个具体细节都没有。而这恰恰就是"弱检索"的样子:找到了正确的对话,从里面却抽不出任何精确的东西,于是你对一片大致区域给出一段胸有成竹的转述。这个基准不仅不会惩罚这种失败模式,它还在奖励它。
当你把同一份审计里的其他发现叠在一起看,情况会更糟。不存在一套标准化的流程,所以每个系统都用自己的摄入方式、自己的回答 prompt,有时甚至用自己的一套回答模型,然后这些数字被塞进同一张比较表里。部分类别的样本量小到审计人员发现,类别内超过一半的相邻两两比较在统计上无法区分。也有独立研究者公开表示,复现已发布的结果很困难。而经常被推荐作为替代方案的 LongMemEval-S,它的每道题里待检索段落(haystack)小到可以直接塞进现代模型的上下文窗口里,因此它更像是一个长上下文测试,而不是一个记忆测试。
我得承认,我的第一反应有点沾沾自喜,就是那种"我就知道排行榜水得很"的反应。但我的第二反应就没那么自在了。我自己也曾引用过 LoCoMo 的数字——在一份设计文档里——用来为某个原型挑选一种记忆方案而非另一种。我没打开过这个数据集,也没看过哪怕一道题。我之所以相信一个数字,仅仅因为它出现在一张表里,而那张表又出现在一篇论文里。
我在 Rick 那篇文章下面留言问,有没有人在修正过的标准答案上重跑过那些主流系统,得到的诚实答案是"部分做过"。审计仓库里包含对几个已发布系统的"调整后分数"分析,这项工作相当出色。但它只能针对它拿到的那份标准答案做修正。它无法告诉你,这些系统里有没有谁真能记住你的用户实际上会告诉你的智能体(agent)的事情。
关于基准测试能告诉你什么、不能告诉你什么
我不想矫枉过正地说"基准测试毫无用处"。LoCoMo 仍然有用,至少能用来发现一个严重跑偏的系统。如果某个系统只拿到 30% 的分数,你确实能从中看出问题。问题出在分辨力上:一旦各系统的分数在顶端扎堆,答案键本身的噪声以及评判标准的宽松程度,就会大于你想要观察的那些差异。
上面提到的最后那一行规则,已经成为我自己评测集中的固定判据,我会在下文中贴出对应的代码。