人人都会AI编程

多路召回合并去重

更新时间:2026-07-12

在实际的检索系统中,单一召回策略往往难以兼顾不同类型的问题。例如,关键词搜索(如 BM25)擅长匹配精确术语,但在理解语义相近的表达上力不从心;向量检索(Dense Retrieval)能捕捉语义相似性,却可能漏掉罕见但关键的专业缩写或固定编号。为了让最终结果既全面又相关,通常的做法是同时运行多路召回,然后将它们的结果合并去重,再送入后续的重排序或生成环节。

1. 为什么需要多路召回

不同类型的问题对“相关”的定义差异很大:

  • 精确查询:如“合同编号 BG-2024-0882”,要求精确匹配字符串。
  • 概念性查询:如“怎样处理客户投诉”,更依赖语义理解。
  • 混合查询:如“去年Q4华北区的促销政策”,既有时间、地域等筛选条件,又需要理解“促销政策”的语义。

单一召回很难同时在所有这些场景上表现良好。多路召回通过并行使用多种检索器,让系统对不同风格的问题都有基本的应对能力——先“广撒网”把可能相关的候选文档都捞回来,再在后续环节精细筛选。

2. 常见的召回路径

可以根据业务场景选择组合,常见的几类路径包括:

  • 向量语义召回:将问题和文档片段转换为向量,通过余弦相似度等度量查找语义相近的内容。适合捕获改写、同义词、长文本匹配。
  • 全文关键词召回:如 BM25 或 Elasticsearch 的倒排索引搜索,擅长匹配精确术语、代码、缩写、编号。对于包含强标识符的查询非常关键。
  • 元数据过滤:基于文档属性(如时间、分类标签、作者、部门)进行精确筛选。这不是独立的召回通道,但可作为前置过滤条件与上述路径结合,减少无效检索。
  • 细粒度重叠召回(可选):针对某些场景,还可以引入基于 n-gram 或实体的召回,例如对关键人名、地名、产品型号做专门索引。

实用建议:并不是通道越多越好,两到三路高互补性的召回往往性价比最高。典型的组合是“向量检索 + BM25 关键词检索”,辅以必要的元数据过滤。

3. 合并策略

各路召回返回的结果带有各自的分数,但这些分数的量纲和分布不同(例如向量相似度在 0-1 之间,BM25 分数可能大于 100),不能直接比较数值大小。因此合并之前需要进行分数对齐或排名融合

常用的合并策略:

  • RRF(Reciprocal Rank Fusion,倒排秩融合)

不依赖原始分数,只看文档在各路结果中的排名位置。公式为:

  score(d) = Σ 1 / (k + rank_i(d))
  

其中 rank_i(d) 是文档 d 在第 i 路结果中的排名(从1开始),k 是一个常数(通常取 60),用于平滑排名影响。RRF 实现简单,无需调参对齐分数,实践中表现稳定,是首推的合并方式。

  • 线性加权融合

需要先将各路分数归一化到同一尺度(如 Min-Max 归一化或 Z-score),然后根据重要性赋予不同权重求和。这种方法可以灵活调控各通道的贡献,但需要维护归一化逻辑和权重参数,更适合对召回通道理解深入、需要精细控制的团队。

  • 优先级串联

在某些对精度要求极高、但对全量性要求稍低的场景,也可采用“先看第一路,不足时再补第二路”的串行策略。例如优先使用精确的关键词结果,如果返回数量不足,再触发向量召回。这种方式简单,但会增加延迟,不适合实时性要求高的场景。

4. 去重方法

不同召回通道可能返回相同的文档片段,合并后必然出现重复。去重一般在合并之后、排序之前进行,常见的去重维度:

  • 基于文档 ID 去重:以文档切片的唯一标识(如 chunk_id)为准,保留分数最高的那一个副本。这是最基本也是最可靠的方式。
  • 基于内容哈希去重:如果同一知识库可能通过不同来源引入相同内容,但 ID 不同,可对文本内容计算哈希(如 MD5 或 SHA256),将内容完全一致的片段视为重复。不过要注意,内容相同的片段如果来源文档不同,可能会附带不同的元数据(如章节、页码),去重后需要保留最完整的信息。
  • 近似去重(可选):当存在大量相似但不完全相同的片段(如相邻切分时出现重叠),可以根据文本相似度阈值进行去重。但这会增加计算开销,一般通过优化切分策略从源头解决。

实用做法:在大多数情况下,基于 chunk_id 的去重已经足够,因为同一个 chunk 在知识库中通常只有一份。多路召回只是从不同角度找到了它,保留最高分即可。

5. 真实场景配置示例

某公司内部知识库助手采用以下多路召回方案:

  1. 向量检索:基于 OpenAI text-embedding-3-small,召回 Top-20。
  2. BM25 关键词检索:由 Elasticsearch 提供,召回 Top-20,并对“编号”“日期”字段加权。
  3. 合并:使用 RRF(k=60),将两路结果融合,取排名前 30。
  4. 去重:对相同 chunk_id 的记录保留 RRF 排名最高的那条。
  5. 若有特殊过滤需求(如只查最新版本文档),在检索时加元数据过滤,不参与后续合并。

效果上,相比单一向量检索,多路合并后 Top-5 的准确率提升了约 12%,且对包含产品编号的问题几乎不再出现漏答。

6. 注意事项

  • 监控召回质量:定期抽检各路召回的命中情况,特别是关键词召回是否遗漏了术语变体,向量召回是否在冷门术语上表现不足。
  • 通道隔离与容错:各路检索尽可能独立、异步执行,并在代码层面做好超时和异常处理。某一路失败不应影响其他路的服务,保证系统鲁棒性。
  • 避免过度合并:如果初步召回数量过大,合并去重后可能仍超过 LLM 上下文窗口,需要配合重排序模型或截断逻辑,确保送入生成阶段的信息精简且高质。

多路召回合并去重并不是复杂的算法,而是务实的工程方法,通过组合互补的检索策略,以较小的开销显著提升了检索的鲁棒性和覆盖度。从实用性出发,推荐从“向量+关键词+RRF”的基础配置起步,再根据实际反馈逐步调整。