前几天翻到 Giulio D'Erme 那篇 "The Answerability Problem" 系列第四篇,讲一个叫 RE-call 的开源记忆层。这东西有个很挑衅的设计:写入的时候一个 LLM 都不调。零次。
作为对比,同样跑一遍 benchmark 的记忆库构建,Mem0 调了 272 次 LLM,烧了 2.6M token,花了七块二毛九,跑了将近五分钟。RE-call 呢?零次调用,零 token,六十七秒灌完。
我第一反应是:爽。
第二反应是:这么爽的事,底下一定压着什么。
先停一下,问个问题:Mem0 写入时调那 272 次 LLM 到底在干嘛?它在做"提炼"——把原始对话喂进去,让模型吐出干净的结构化记忆条目。逻辑是:原始对话太脏太长,写入时花成本蒸馏,换取检索时的高信噪比。RE-call 反过来:原始对话原样存,不蒸馏,检索的时候再说。
这两条路线吵的不是省钱。吵的是:你愿意在写入时做不可逆的决定,还是在检索时带着上下文做可逆的决定?蒸馏不可逆——模型一旦在写入时决定"这句话的语义核心是 X",被丢掉的细节就回不来了。
但我想说的不是这层。我想说的是下面这个。
benchmark 里有个类别叫 abstention——"不会答就别说"。Mem0 在七十道不可回答的题里,正确弃答了三十八道,均分 0.974。剩下三十二道,它硬编了答案,均分 0.016。也就是说,46% 的情况下它在没答案的时候一本正经地胡说。
有个具体例子。语料里只有一句助手在猜的话——"动态语言切换可能会让用户满意"。到了 Mem0,直接变成了"用户测试显示 90% 满意度"。从推测变成了数据。编的。
为什么会这样?
往下剥。模型在写入时做的事情,本质是"预测下一个 token"。那它吐出来的"记忆",是什么?是"长得像正确记忆的文字"。因为训练数据里正确的结构化记忆就长那样——干净、有数字、有结论。当它遇到模糊的、推测性的、不确定的输入,它会往"更像一条正经记忆"的方向走,因为那才是高概率输出。
这么说吧:它分不清自己是在提炼还是在编造,这两件事在生成机制里是同一件事。模型不知道边界在哪——它只会往"看起来更合理"的方向滑。输入越模糊,滑得越远。
那七块二毛九买到的,包含了这个。
RE-call 不调 LLM,所以它不编。它的弃答策略纯靠检索的 cos 相似度阈值——检索不到就是不到,它不会帮你"推断一个合理的答案出来"。粗暴,但诚实。
代价是 RE-call 的弃答在 LongMemEval 上翻车了:48.1% 的误弃率。因为那个数据集检索命中率到 0.970,但问题太碎,相似度阈值挡掉了一半合法问题。
所以 trade-off 摆在这里:写入时调 LLM 做蒸馏,你能拿到更聪明的弃答,但那个 LLM 同时在帮你编记忆。不调,你诚实,但粗糙。
还有一条让我卡了一下的数据。BEAM 的不可回答问题,top-1 cos 相似度中位数是 0.676——比可回答问题的 0.641 还高。最像有答案的问题,恰恰最可能没答案。你的相似度阈值越高,误杀越多;越低,漏网越多。这条曲线没有甜点,只有你愿意吃哪边的亏。
再往下呢?如果"看起来合理"和"是对的"在模型脑子里是同一件事,那所有让 LLM 在写入时做语义判断的设计,都背着这个风险——不只是 Mem0,是整条路线。你花在蒸馏上的钱,有一部分买的是"把不确定的东西冻成确定的样子"。
RE-call 那个零成本,真正省掉的不是七块二毛九。是那 272 次"帮你把脏对话变成干净记忆"的调用里,藏着的编造概率。
再往下就是"怎么在不调 LLM 的前提下做语义理解"这个更难的问题了。这个我还没想明白,先放这儿。
