Appearance
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 调大只是同一路径多拿一点候选。
多路召回则是在:
- 让不同类型的候选源头一起参与
它解决的不是“同一路径拿不够”,而是“同一路径天然有盲区”。
一句话总结
多路召回就是让系统同时或按条件走多条互补召回路径,再把候选集合并。它不只是“多查几次”,而是在用不同方法、不同索引域或不同粒度共同构造更稳的第一轮候选集。