bge-m3 等稠密向量对 ORD-48207 这类精确 token 检索失效,文章通过 max(模型得分, 词法得分) 混合策略解决。
我维护着 Agent Brain Hub,一个多个 AI Agent 共享的开源记忆层。上个版本我加入了真正的 embedding 模型,基准测试的召回率从 88.5% 跃升到了 100%。然而当我写了一个更难的测试后,模型在任何一个关键词搜索都能答对的事情上摔了跟头。
一位客户有十二段购物对话,每个订单一段:
My order ORD-48200 for a blue backpack hasn't arrived yet
My order ORD-48201 for running shoes hasn't arrived yet
…
My order ORD-48211 for a water bottle hasn't arrived yet
随后另一个 Agent 向记忆层提问:"order 48207 怎么了"。
对这十二段对话,embedding 模型给出的含义完全相同(都是"一个延迟的订单"),因此得分几乎一模一样,最终由近因效应决定哪四个被塞进上下文。那个唯一能区分它们的 token——48207——恰恰是密集 embedding 最容易模糊掉的部分。哈希向量虽然粗糙,但它们能精准匹配精确 token。
我的第一个修复方案是取两者中更强的信号:max(model, lexical)。但还是失败了。因为模型对每个订单的评分(约 0.6)都高于正确答案的词汇评分,所以 max 处处都取了模型评分,什么都没变。
// Hybrid (CombSUM): meaning + wording
const lexical = Math.max(0, cosine(qHash, item.hashVec));
return modelVecAvailable ? Math.max(0, dot(qVec, item.vec)) + lexical : lexical;
既在语义上匹配、又在措辞上匹配的条目,现在击败了那些只是沾边的话题的条目。求和后的值永远不会低于任一信号,所以 paraphrase 匹配("Can I drive to the airport?" → "no car for 3 days")依然保持了让它们能work的分数。我在基准测试中加入了一个 exact_match 类别,包含那些仅相差一位数字的订单号(带和不带 ORD- 前缀的情况都有),以及设备型号名。一个单元测试证明了这次修复有效:如果你回滚它,测试就会失败。
在全部 25 个场景上用 bge-m3 测试:通过率 96%,召回率 100%,泄漏率 0%。
我自己的场景只能比较我自己项目的不同版本。所以 v0.4.0 也跑了 LongMemEval-S(MIT):470 个问题,每个问题藏在大约 50 段过往聊天记录中。持有答案的那段会话能排到前列吗?
坦诚的结论:大约有一半的情况正确答案会话落在 top 4,而偏好类问题表现很差。这个数字就是为什么要有一个公开基准测试的理由:它告诉我接下来该在哪里发力,而不是告诉我大功告成。(embedding 模型的运行需要 GPU;在 CPU 上跑要好几天,所以留到下次。)
检索曾经是扫描每一位客户的记忆,然后过滤。改为按客户建索引后,尾延迟大幅改善:
git clone https://github.com/leluong141996-dev/Agent-Brain-Hub && cd Agent-Brain-Hub
docker compose up -d # http://localhost:4317
npm run bench -- --url http://localhost:4317 # benchmark your own running hub
如果你的 Agent 记忆曾经以类似方式失效过(比如一个编码、一个名字、一个检索器看不到的日期),我很乐意把它作为一个基准测试场景。就是一个 JSON 文件,而每个未来的版本都必须通过它。
👉 https://github.com/leluong141996-dev/Agent-Brain-Hub
部分评论可能仅对登录访客可见。登录后查看所有评论。部分评论已被文章作者隐藏