首页/AI/RAG 与向量库速查/多路召回合并与去重
Embedding 与检索50 条

多路召回合并与去重

多路召回从不同通道(向量、关键词、字段检索、多模型、查询改写变体)各取候选后合并去重:按内容 hash 与父文档 id 去重,再统一打分或交给重排,避免同一段内容占满上下文。

RAG 与向量库速查AI更新于 2026-10-13

多路召回合并是什么

多路召回从不同通道各取一批候选:稠密向量抓语义、关键词一路抓专名、字段检索抓结构化条件、查询改写变体抓措辞差异。各路分数口径不同、候选高度重叠,直接拼接会让同一段内容的好几个近似版本占满上下文。合并要做三件事:按内容指纹与父文档 id 去重、把不同量纲的分数归一到可比空间(或用只看排名的 RRF 融合)、最后交给重排统一排序。

基本信息

常见通道稠密向量、稀疏/关键词、字段过滤、查询改写变体
去重键chunk_uid 或内容指纹 + 父文档 id
融合方式RRF(按排名)、加权归一化分数、直接交给重排
代价候选量放大数倍,检索与重排开销同步上升
必备动作记录每一路各自的召回结果,便于归因

典型使用场景

  • 中文技术问答:向量一路抓语义、BM25 一路抓型号与命令名
  • 多模型并行:两三个 embedding 模型各取候选,合并后重排
  • 查询改写变体:原问题与改写问题同时检索,提高召回覆盖面
  • 权限与业务过滤:结构化条件走字段检索,语义部分走向量检索
  • 消歧:同一文档的小块密集命中时按父文档聚合选代表块

候选合并去重

候选合并去重
def merge(candidates):
    seen, merged = set(), []
    for c in candidates:
        key = c.meta.get('chunk_uid') or hash(c.text)
        if key in seen:
            continue
        seen.add(key)
        merged.append(c)
    return merged

all_hits = merge(hits_original + hits_rewrite1 + hits_rewrite2)

合并策略

策略适用注意点
按 uid 去重后重排候选来自同一文档的不同路径去重键要稳定,不能用随机 id
RRF 融合排名多路分数不可直接比较只看排名,对量纲不敏感
加权分数融合各路分数已归一化权重需评测确定
按父文档聚合选代表块小块密集命中同一长文代表块选择规则要固定
多路召回会把候选量放大数倍,检索与重排的耗时、费用都要按放大后的规模估算;上线前用压测确认延迟没有突破预算。

易错点

  • 只按文本前若干字符去重,措辞相近的重复段落仍会重复进上下文
  • 多路候选简单相加不去重,同一文档占满全部上下文位置
  • 不同量纲的分数直接相加融合,其中一路被完全压制
  • 去重键用随机 id,同一片段每次合并都被当成新内容
  • 不记录各路单独的召回结果,融合效果差时无法定位是哪一路的问题

数据来源与参考

  • Gao et al., Retrieval-Augmented Generation for Large Language Models: A Survey (arXiv:2312.10997)
  • LlamaIndex 官方文档(QueryFusionRetriever)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌