AI 技术
#RAG#RRF#混合检索#重排序#BM25#向量检索

RAG-Fusion 与混合检索:多路召回如何通过倒数排名融合提升检索质量?

以企业知识库问答为场景,解释 RAG-Fusion 如何结合向量检索与 BM25 等多路召回,通过倒数排名融合(RRF)合并结果,并对比重排序(Rerank)的差异。分析 RRF 的数学原理、参数敏感性(k 值)、融合策略对召回率和精度的影响,讨论在 RAG 流水线中的部署位置与性能开销。

为什么两路召回合并后反而变差

企业知识库问答系统里,检索环节直接决定大模型回答的上限。一个常见的做法是同时部署向量检索和关键词检索:向量检索用 Embedding 模型把 query 和文档映射到高维空间,按余弦相似度召回语义相近的片段;关键词检索用 BM25 这类基于词频统计的算法,按字面匹配召回包含精确术语的文档。两路各有盲区,向量检索对 CVE 编号、产品型号这类字符串不敏感,BM25 则对同义替换和口语化提问无能为力。

直觉上,把两路结果合并应该能互补短板。但直接拼接往往适得其反。问题出在评分体系不一致:向量检索给出的是余弦相似度,取值在 0~1 之间;BM25 分数理论上没有上界,可能是 3.2,也可能是 27.8。两个不同量纲的分数直接比大小,就像拿身高的厘米数和体重的公斤数排序,谁排在前面全看运气。结果就是模型上下文里塞进一堆重复甚至矛盾的片段,回答质量没提升,token 成本反而涨了。

RAG-Fusion 的核心思路是避开原始分数,只看排名。排名是天然可比的——第 1 名无论在哪一路都是“最好”。通过倒数排名融合(Reciprocal Rank Fusion,RRF),把多路召回结果按排名合并,再交给大模型。这个方案在 2024 年由 Zackary Rackauckas 在英飞凌的工程场景中做了评估,论文标题为《RAG-Fusion: A New Take on Retrieval-Augmented Generation》。作者通过人工评估答案的准确性、相关性和全面性,发现 RAG-Fusion 能提供准确且全面的回答,原因是生成的多个查询从不同角度对原始查询进行了语境化。但论文也指出,当生成的查询与原始查询相关性不足时,部分答案会偏离主题。

RRF 的数学原理:排名如何变成分数

RRF 的公式非常简洁:

[ \text{RRF}(d) = \sum_{i=1}^{N} \frac{1}{k + \text{rank}_i(d)} ]

其中 (d) 是文档,(\text{rank}_i(d)) 是文档 (d) 在第 (i) 路召回结果中的排名(从 1 开始),(k) 是平滑常数,(N) 是召回路数。对每个文档,把它在每一路中的排名代入公式,累加得到融合分数。

这个公式的工程含义很直观:排名越靠前,(1/(k+\text{rank})) 越大,贡献越高。一篇文档如果同时在向量检索和关键词检索中都排前几名,它的融合分数会明显高于只在一路中靠前的文档——这正是想要的效果:两路都认可的结果,可信度更高。

实现 RRF 不需要任何机器学习组件,代码逻辑简单:遍历每一路结果,按排名累加分数,最后按分数降序排序。下面是一个两路融合的伪代码示意:

def rrf_fusion(vector_results, bm25_results, k=60):
    scores = {}
    for rank, doc_id in enumerate(vector_results, start=1):
        scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank)
    for rank, doc_id in enumerate(bm25_results, start=1):
        scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank)
    return sorted(scores.items(), key=lambda x: x[1], reverse=True)

这段代码的关键状态变化是:scores 字典累积每个文档的融合分数,最终排序后返回。边界条件包括:某文档只出现在一路中,则只累加一次;两路结果长度不一致时,较短的列表遍历完即止,不影响其他文档的分数。

k 值:平滑常数的敏感性

k 值控制排名权重的衰减速度,直接影响融合结果。k 太小(比如 k=1),排名第 1 和第 2 之间的分数差会被放大得离谱,几乎变成“赢家通吃”——只有每路的第一名才能获得显著分数,其他文档被压制。k 太大(比如 k=1000),所有文档的分数差都被压平,融合基本等于随机排序。

业界经验值 k=60 来自信息检索领域的大量实验,没有特殊场景不建议改。这个值在 RRF 的原始论文《Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods》(Cormack et al., SIGIR 2009)中被提出,作者通过实验证明 RRF 在多个数据集上优于 Condorcet 融合和单个排序学习方法。

在实际项目中,k 值的选择需要结合召回路数和候选集大小。如果每路只取 Top 10,k=60 意味着第一名贡献约 0.0164 分,第十名贡献约 0.0143 分,差距不大,融合结果更依赖“多路共识”。如果每路取 Top 100,k=60 会让前几名权重相对突出,但整体仍保持平滑。生产环境中,通常用一个小型验证集扫描 k 值(如 30、60、90),观察 Recall@5 或 MRR 的变化,选择稳定区间内的值。

融合策略对比:RRF 与加权得分

除了 RRF,另一种常见的融合策略是加权得分:最终得分 = α × 向量分 + β × BM25 分,其中 α 和 β 是权重。这种方法的缺点是需要反复调参,且分数归一化困难。向量分数和 BM25 分数分布不同,即使归一化到 0~1,两者的信息量也不一致,权重很难找到最优解。

RRF 的优势在于无需调参,不受不同模型分数尺度影响,稳定性高。下表从多个维度对比两种策略:

维度RRF加权得分
输入依赖仅依赖排名,不需原始分数依赖原始分数,需归一化
调参成本只需设定 k(通常取 60)需调 α、β,且对分数分布敏感
跨路可比性排名天然可比,无量纲问题分数量纲不一致,需额外处理
鲁棒性对异常分数不敏感异常分数会直接扭曲加权结果
实现复杂度低,几行代码中,需设计归一化逻辑
适用场景多路召回结果合并单路分数可信且可归一化时

从工程决策角度看,RRF 几乎总是优于加权得分,除非有强理由相信某一路的分数质量明显更高,且归一化方法经过验证。

部署位置:RRF 在 RAG 流水线中的角色

RRF 在 RAG 流水线中位于召回和重排序之间。一个典型的三路并行召回架构如下:用户 Query 并行分发到向量检索(Top 30)、BM25 检索(Top 30)和知识图谱检索(Top 10),三路结果汇总后经过 RRF 融合,再交给 Reranker 精排,最后取 Top 5 送入大模型。

下面用 Mermaid 流程图展示这个数据流:

flowchart TD
    A[用户 Query] --> B[并行分发]
    B --> C[向量检索 Top 30]
    B --> D[BM25 检索 Top 30]
    B --> E[知识图谱检索 Top 10]
    C --> F[RRF 融合]
    D --> F
    E --> F
    F --> G[Reranker 精排]
    G --> H[Top 5 送入 LLM]

RRF 的部署位置决定了它的性能开销。RRF 本身只是内存中的排序和累加,时间复杂度 O(N log N),N 是候选文档总数,通常几十到几百,延迟可忽略。真正的开销在召回阶段(多路并行)和 Reranker 阶段。

与 Reranker 相比,RRF 不引入额外模型推理。Reranker 需要把 query 和每个候选文档拼接后输入 Cross-Encoder 模型,计算量比 Bi-Encoder 高一个量级。因此,RRF 适合作为轻量级融合层,Reranker 则作为精排层,两者职责不同。

RRF 与 Reranker 的差异:为什么 RRF 之后还需要 Rerank

RRF 本质上是在“拼凑”多个独立打分系统的排名,它并不真正理解 query 和文档之间的语义关系,只是在做“投票”——两路都排前面的文档得票高,但两路排名本身的质量它无法校正。例如,如果向量检索和 BM25 都因为某种原因把一篇不相关文档排得很靠前,RRF 会把它融合成高分。

Reranker 解决的正是在这个问题:它是一个专门训练用来判断“query 和某段文档到底有多相关”的模型,直接吃 query 和候选文档的原始文本,输出一个精确的相关性分数,不依赖任何召回阶段的排名信息。

两者在架构上的差异是根本性的。Embedding 模型(用于向量检索)是 Bi-Encoder 架构:query 和文档分别独立编码成向量,之后算余弦相似度。这种架构可以提前把文档向量算好存库,检索时只需编码 query,速度极快,能支撑百万级候选集。但代价是 query 和文档在编码阶段互相看不到对方,模型只能靠两个独立向量的几何距离去近似相关性,精度有损失。

Reranker 用的是 Cross-Encoder 架构:query 和文档拼接成一个整体输入模型,在自注意力层里充分交互,逐词判断相关性,精度明显更高。代价是没法预计算,每个候选文档都要跟 query 现场拼接一次做推理,计算量比 Bi-Encoder 高一个量级,所以只能用在粗筛之后的少量候选上。

下表对比 RRF 与 Reranker 的关键差异:

维度RRFReranker
输入多路排名列表query 和候选文档原始文本
机制基于排名累加分数Cross-Encoder 模型推理
是否理解语义否,仅投票是,逐词交互
计算开销极低(内存排序)高(每个候选一次推理)
适用阶段粗融合精排
是否需要训练是(预训练或微调)

端到端效果:从单路到混合检索的收益

一个实际的客服问答场景中,团队用 300 条标注数据做了端到端对比,结果如下:

方案Recall@5MRRP99 延迟
纯向量检索76.2%0.6845ms
纯 BM25 检索71.5%0.6320ms
双路 + RRF 融合87.0%0.7970ms
双路 + RRF + Reranker96.7%0.94155ms

从单路到“双路 + RRF + Reranker”,Recall@5 提升了 20 个百分点,MRR 提升了近 40%,代价是延迟从 45ms 涨到 155ms。对大多数知识库问答场景,多出的 110ms 用户几乎感知不到,但检索质量的提升会直接反映在大模型回答的准确率上。

这个数据来自腾讯云开发者社区的一篇实战文章,作者陆业聪在文中详细描述了他们的 A/B 测试结果。虽然具体数字可能因场景而异,但趋势是明确的:混合检索 + Reranker 是生产级 RAG 系统的标配。

失败模式与调优方向

RRF 融合并非没有失败模式。最典型的是分布偏移:如果某一路召回结果质量明显下降(例如向量模型未覆盖新领域术语),RRF 会放大这一路的错误排名,导致融合结果变差。另一种情况是长尾输入:用户提问包含罕见实体或混合语言,BM25 可能召回大量无关文档,RRF 的投票机制会让这些噪声文档获得不应有的高分。

RAG-Fusion 论文还指出,当生成的查询与原始查询相关性不足时,答案会偏离主题。这意味着多路召回中的“多路”如果包含低质量查询生成,反而会引入噪声。

调优方向包括:

  • 监控每路召回的独立质量指标(如 Recall@K),及时发现单路退化。
  • 对 RRF 的 k 值做敏感性分析,选择稳定区间。
  • 在 Reranker 阶段引入业务数据微调,让模型学习特定领域的相关性判断。
  • 对高频重复问题使用语义缓存,减少重复计算。

结论与适用边界

RRF 解决了多路召回中分数不可比的问题,通过排名融合提升召回质量,且实现简单、开销极低。但 RRF 不替代 Reranker,两者在流水线中分工明确:RRF 负责粗融合,Reranker 负责精排。

适用边界:当知识库超过几千篇文档、用户提问方式多样时,混合检索 + Reranker 几乎是必选项。唯一需要犹豫的场景是超低延迟要求(如语音实时交互,容不下 100ms 以上的检索环节),此时才值得牺牲一部分精度去换速度。

RRF 的 k 值、融合路数、是否引入 Reranker,都需要结合具体业务数据验证。没有放之四海而皆准的参数,只有通过持续评测和迭代,才能让检索系统在质量和延迟之间找到平衡。

资料来源

  1. RAG-Fusion: A New Take on Retrieval-Augmented Generation
  2. Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods
  3. 混合检索RAG:多路召回+Reranker重排模型实战-腾讯云开发者社区-腾讯云
  4. RAG 多路召回:原理、组件与融合策略 - 菠萝包与冰美式 - 博客园