Skip to content

5.4.4 什么是多路召回(Multi-Retrieval)? ​

先给结论:多路召回可以先理解成:系统不是只走一条固定检索路径,而是同时或按条件走多条召回路径,再把不同路径的候选集合并。

所以它的核心不是“查很多次”,而是:

  • 让不同类型的问题有机会走到更适合它的召回通道

为什么会从“混合检索”继续走到“多路召回” ​

混合检索通常已经是在组合多种信号了,比如:

  • 向量检索 + BM25

但在真实系统里,问题往往比“这两种信号怎么配”更复杂。

因为不同查询还可能需要:

  • 不同 chunk 粒度
  • 不同索引域
  • 不同数据源
  • 不同过滤范围

这时系统就不只是“一个混合检索器”,而更像:

  • 多条并行或分流的召回路径

这就是多路召回的出发点。

多路召回和混合检索是什么关系 ​

你可以先这样理解:

  • 混合检索 更强调多种检索信号融合
  • 多路召回 更强调多条召回路径并行或分工

两者有重叠,但关注点不完全一样。

例如,多路召回可以包括:

  • 向量检索一路
  • BM25 一路
  • FAQ 专用索引一路
  • 文档级检索一路
  • 代码库检索一路

最后把这些路径的结果合并。

所以多路召回往往比“向量 + BM25”再更往前走一步。

什么叫“不同召回路径” ​

所谓不同路径,不一定只是不同算法,也可能是:

1. 不同检索方法 ​

  • 向量检索
  • BM25
  • 规则匹配

2. 不同数据域 ​

  • FAQ 库
  • 产品文档库
  • API 文档库
  • 代码库

3. 不同粒度 ​

  • 文档级召回
  • chunk 级召回
  • 父子块召回

4. 不同查询改写结果 ​

  • 原始问题一路
  • 改写后的关键词查询一路
  • 术语抽取后的一路

所以多路召回的关键不是“多”,而是:

  • 这些路径是否真的互补

一个最小示意 ​

python
results_a = vector_search(embed(user_query), top_k=10)
results_b = bm25_search(user_query, top_k=10)
results_c = faq_search(user_query, top_k=5)

merged = merge_and_deduplicate([results_a, results_b, results_c])
final_results = rerank(merged)[:10]

这段代码想表达的是:

  • 多路召回不是单一路径多跑几次
  • 而是让不同来源、不同逻辑、不同信号都能参与第一轮候选构建

为什么它常常能改善长尾问题 ​

因为长尾问题往往更容易卡在单一路径的盲区里。

比如:

  • 一条路径只擅长自然语言问法
  • 另一条路径更擅长编号和术语
  • 再一条路径只针对 FAQ 做了特别优化

如果系统只走一路,某些长尾问题就会完全撞在盲点上。

而多路召回的价值,往往就是:

  • 不让所有问题都押在同一条路径上

多路召回不代表无脑加路数 ​

这点也很重要。

多路召回不是:

  • 路越多越好

如果路径很多,但彼此高度重复,副作用通常是:

  • 候选暴涨
  • 去重更难
  • 噪声变多
  • 后续重排和生成成本上升

所以更稳的思路通常是:

  • 只保留那些真正补不同盲点的路径

一个常见误区 ​

很多人会把多路召回理解成:

  • 一个高级版的“Top K 调大”

这不一样。

Top K 调大只是同一路径多拿一点候选。
多路召回则是在:

  • 让不同类型的候选源头一起参与

它解决的不是“同一路径拿不够”,而是“同一路径天然有盲区”。

一句话总结 ​

多路召回就是让系统同时或按条件走多条互补召回路径,再把候选集合并。它不只是“多查几次”,而是在用不同方法、不同索引域或不同粒度共同构造更稳的第一轮候选集。