召回引擎:BM25 + 向量 + RRF 混合检索


文档摘要

召回引擎:BM25 + 向量 + RRF 混合检索 本节摘要:前几节讲记忆如何「长出来」,本节讲记忆如何被「取出来」——召回引擎。系统同时跑两路检索:BM25(关键词,擅长精确命中)与向量(语义,擅长模糊近似),再用 RRF(排名倒数融合)把两路结果按排名加权合并。本节讲清这三者各自的擅长场景、RRF 为什么是好的融合策略、以及混合检索相对单一检索的优势。这是「召回准不准」的核心机制,也是排查「该召回的没召回」的关键参考。

召回引擎:BM25 + 向量 + RRF 混合检索

本节摘要:前几节讲记忆如何「长出来」,本节讲记忆如何被「取出来」——召回引擎。系统同时跑两路检索:BM25(关键词,擅长精确命中)与向量(语义,擅长模糊近似),再用 RRF(排名倒数融合)把两路结果按排名加权合并。本节讲清这三者各自的擅长场景、RRF 为什么是好的融合策略、以及混合检索相对单一检索的优势。这是「召回准不准」的核心机制,也是排查「该召回的没召回」的关键参考。

一、两路检索:BM25 与向量各擅什么

召回引擎不是单路,而是 BM25 + 向量双路并行,因为它们各有所长:

检索方式 原理 擅长 弱项
BM25 关键词词频+反文档频率 精确命中(专有名词、代码符号) 不懂同义、语义近似
向量 语义嵌入的相似度 语义近似、同义改写 精确术语可能漂移
两路擅长的场景对照 问题:「我们的 JWT 密钥在哪?」 BM25 路命中:含「JWT」「密钥」字面的 L1 → 精确 向量路命中:语义相近的「认证凭据存储位置」→ 模糊 问题:「怎么处理那种上线就崩的情况?」 BM25 路:可能命不中(没原词) 向量路:命中「发布事故」「回滚流程」→ 懂语义

关键概念:单路检索都有盲区——BM25 不懂同义,向量在精确术语上可能漂移。双路并行恰好互补:BM25 兜住精确,向量兜住语义。这就是为什么是「混合」检索而非单路。

二、RRF 融合:为什么按「排名倒数」加权

两路结果怎么合成一路?系统用 RRF(Reciprocal Rank Fusion,排名倒数融合):

RRF 的原理(概念) BM25 路结果(按相关度排序): 1. L1_A 2. L1_B 3. L1_C 向量路结果(按相似度排序): 1. L1_B 2. L1_D 3. L1_A RRF 融合(每条 L1 的分数 = Σ 1/(rank+k)): L1_A: 1/(1+k) [BM25第1] + 1/(3+k) [向量第3] = 较高 L1_B: 1/(2+k) [BM25第2] + 1/(1+k) [向量第1] = 最高(两路都靠前) L1_D: 1/(2+k) [向量第2] = 中 L1_C: 1/(3+k) [BM25第3] = 低 融合后排序: L1_B > L1_A > L1_D > L1_C

注意 L1_B——它在两路里都靠前(BM25 第 2、向量第 1),RRF 给它最高分。这就是 RRF 的精髓:两路都认可的结果排最前

融合策略 RRF 的特点
按排名(非分数) 不受两路分数量纲不同的影响
倒数加权 排名越靠前权重越高,但尾部仍有贡献
k 参数 调节头部与尾部的相对权重

💡 技巧:为什么用 RRF 而非「加权求和」?因为 BM25 分数和向量相似度的量纲不同(BM25 可能是几十,向量是 0-1),直接相加会被量纲大的那路主导。RRF 只看「排名」不看「分数」,天然规避量纲问题——这是它在混合检索里被广泛采用的原因。

三、混合检索 vs 单一检索:优势在哪

把混合检索与单一检索对比,优势更清晰:

单一 BM25 的问题 问题:「禁止 ORM」召回吗? → 若记忆里是「不用对象关系映射」,BM25 命不中(没原词) → 漏召回 单一向量的问题 问题:「PostgreSQL 的配置」 → 向量可能把「MySQL 配置」「数据库配置」都召回来(语义相近) → 精确性差,可能召回到错误数据库 混合(BM25 + 向量 + RRF) → BM25 保证 PostgreSQL 精确命中 → 向量补充同义表述 → RRF 让两路都认可的排前面 → 既精确又全面

这就是混合检索的核心收益:降低「该召回的没召回」(向量补语义)+ 降低「不该召回的召回了」(BM25 锚精确)。两路互补 + RRF 融合,比任何单路都稳。

四、召回的输入:已经被装配过滤过

要注意,召回引擎跑在「装配过滤之后」——它检索的不是全量记忆,而是第 3 章讲的「缩小后的候选集」:

召回的完整流程(接第 3 章装配机制) 全部资产 ├─ Team/User/Agent/可见性/生命周期 过滤 ▼ 候选集(已缩小) │ ├─ BM25 检索(在候选集内) ├─ 向量检索(在候选集内) ├─ RRF 融合 ▼ 融合结果(按相关度排序) │ ├─ 召回预算闸门(下一节讲) ▼ 最终注入上下文的记忆

这个顺序很关键:先过滤权限,再检索内容。如果反过来(先在全量检索再过滤),既慢又可能把不该看的先检索出来——第 3 章讲过的「先过滤后召回」原则。召回引擎只负责「在候选集里找相关」,权限过滤是它之前的事。

⚠️ 注意:排查「该召回的没召回」时,先确认候选集里有没有这条记忆——可能它被装配过滤掉了(没绑定、可见性不允许、状态非可用),根本没进候选集,检索再强也找不到。这种「漏召回」是装配问题,不是检索问题,排查方向完全不同。

五、混合检索的工程权衡

这套混合检索有几个工程权衡点:

权衡点 取舍
双路成本 双路比单路贵(算两次),但召回质量提升值得
RRF 的 k 参数 k 大则尾部影响大,k 小则头部主导,需调
候选集大小 太小可能漏,太大检索慢,要平衡
向量索引 实时更新 vs 检索速度的取舍

这些权衡里,最常调的是「候选集大小」和「RRF 的 k」。候选集太小(装配太严)会漏召回,太大(装配太松)会拖慢检索且引入噪音——这与第 5 章 Loadout 设计直接相关,好的 Loadout 让候选集「精且准」。

本节要点回顾

  1. 双路互补:BM25 擅精确(术语/符号),向量擅语义(同义/改写),单路都有盲区。
  2. RRF 融合:按排名倒数加权,两路都认可的排最前;只看排名不看分数,规避量纲问题。
  3. 混合优势:向量补「该召回的没召回」,BM25 锚「不该召回的别召回」,既精确又全面。
  4. 检索在过滤后:召回引擎只检索候选集(已装配过滤),权限是它之前的事。
  5. 排查方向:漏召回先查装配(候选集有没有),再查检索;两者排查方向不同。

召回结果出来了,但还不能直接注入——下一节看三道召回预算闸门,如何防止记忆占满上下文。


发布者: 作者: 灏天文库 转发
评论区 (0)
U