详细解释
**Hybrid Search(混合检索,简称 Hybrid)**一句话:你的 RAG 系统里,用户搜「如何申请 2025 年深圳高新技术企业认定的第 3 条条件」这种带具体文号/专有名词的精确查询时,纯向量语义检索经常因为把「2025」「深圳」「高新技术企业认定第 3 条」这些字面信号稀释掉、召回一堆看起来语义相关但文号不对的文档,纯关键词 BM25 刚好反过来能精确命中文号但搜「企业资质申请流程」这种概括性语义查询时就不行;Hybrid Search 就是两路一起搜(向量一路、关键词一路),然后把两路的排序结果智能合并,最后返回一个综合 Top K。2025 年工业界落地 RAG 的共识是:纯向量检索已经是历史产物,任何生产级 RAG 必须上混合检索,单独任何一路的召回率都比 Hybrid 低 20% 至 40%。
混合检索的标准 Pipeline 有 5 步:(1)Query 预处理——分词、同义词扩展、缩写还原、去停用词(给 BM25 用的纯文本版本) + Query Embedding(给向量检索用的 embedding 向量);(2)两路并行检索——关键词倒排检索(BM25 / Elasticsearch / OpenSearch)取 Top 200 候选项,向量 ANN 检索(向量库)同样取 Top 200;(3)结果去重合并(两边都命中的文档只保留一条);(4)分数融合——两路的排名/分数统一成一个综合分数,经典方法是 Reciprocal Rank Fusion(RRF,简单且稳,不需要调参);(5)(可选)交叉编码器 Rerank 做最后一步精排,从融合后的 Top 50 再排到 Top 5-10。
唯元智创 的 RAG 产品线默认就是 Hybrid Search,无需你额外搭建双路索引:上传文档时系统自动生成 BM25 倒排 + 向量 ANN 双索引;查询时默认的融合算法是 RRF(不需要设置权重,对不同类型 Query 都稳),但也允许你在 API 里传 vector_weight 和 keyword_weight 两个可调参数手动控制两路比例(比如精确查询场景给 keyword_weight=0.8 偏关键词、开放式问答场景给 vector_weight=0.7 偏语义)。
融合算法对比:RRF vs 加权线性融合 vs Reranker(2025 年选型)
| 融合方法 | 核心思想 | 需要调参吗 | 对 Query 类型的鲁棒性 | 最终 NDCG@10 提升(相对纯向量) | 延迟开销 | 推荐度 |
|---|---|---|---|---|---|---|
| RRF(Reciprocal Rank Fusion) | 每篇文档的最终分 = 1/(k+rank_vec) + 1/(k+rank_kw),k=60 默认;只看两路的排名位置,不关心原始分数 | ❌ 不需要,固定 k=60 基本最优 | ✅ 极强,不同类型 Query 都稳 | +18% 至 +25% | +0ms(纯计算) | ⭐⭐⭐⭐⭐ 默认首选 |
| 加权线性融合(Weighted Sum) | final_score = α × norm(vector_score) + β × norm(keyword_score),α + β = 1 | ✅ 要,得拿业务数据找最优 α/β | ⚠️ 一般——α/β 调好的 Query 好,没覆盖到的会崩 | +10% 至 +20%(调得好的);-5%(调不好) | +0ms(纯计算) | ⭐⭐⭐ 你有大量标注数据能调参才用 |
| RRF 后 + CrossEncoder Rerank | 先用 RRF 取 Top 50,再用交叉编码器给 50 条精排到 Top 10 | ❌ 基本不需要,Rerank 端到端学 | ✅ 最好,比纯 RRF 再涨 10% | +30% 至 +40% | +50ms 至 +200ms(7B CrossEncoder 单条耗时) | ⭐⭐⭐⭐⭐ 追求最高质量的生产 RAG 必上 |
落地混合检索的 6 条踩坑经验(2025 年最新工业实践)
- 两路各自的 TopK 不能太小——每路至少取 Top 100-200,再做融合后取 Top 50 给 Reranker;很多人图省事每路只取 Top 20,融合之后还是 20 条,但向量检索排 30 多位刚好 BM25 排第一位的那条黄金结果直接就丢了,召回率损失 15% 以上。
- Query 预处理一定要把「专有名词 / 文号 / 代码编号」这类字面强信号保留给 BM25——分词器别激进地把「粤府〔2025〕12 号」「GB/T 2025-3 标准」这种专有名词拆成碎 token;用自定义词典把专有名词、文号、标准号、客户内部代码全部加进分词白名单,让 BM25 能精确命中这些强字面信号;这一条能让精确查询的召回率涨 30%。
- Query 扩展(同义词/缩写/中英对照)只应用于关键词检索侧,向量侧不要扩展——向量检索本身已经能泛化同义词,扩展后反而会稀释 Query 的语义向量(比如本来搜「高血压」扩展到「原发性高血压+继发性高血压+血压高」三个词混在一起),召回反而变差;BM25 侧必须做扩展,不然「冠心病」搜不到「冠状动脉粥样硬化性心脏病」的文档。
- Chunk 级去重要按「原始文档 ID + 原始段落 ID」双重去重——很多混合检索的两路召回是同一个 Chunk 被两边各命一次名(比如向量侧叫 docid=1234,BM25 侧索引里 docid=1234_v1),你只按内容去重就会漏掉;建索引的时候统一生成一个「Chunk Key = sha256(原始文档路径 + 起始偏移)」,不管哪一路召回来的 Chunk Key 相同就是同一条,fuse 时只保留一个,取两路里排名靠前的那个位置参与 RRF。
- 冷启动时用 RRF,积累了 1 万条标注数据再换 Learned 融合——刚开始业务没数据,RRF 是无参最优,别上来就训复杂的融合模型;等你有了 1 万条以上的「Query + Chunk + 是否相关」的人工标注数据后,可以训一个简单的 LambdaMART / LightGBM 的融合排序模型,拿两路分数 + 各种 handcrafted 特征(Query 和 Chunk 的字符重叠比例、BM25 分数、向量余弦、Chunk 长度、是否命中专有名词)作为特征,AUC 比 RRF 还能再涨 5-8%。
- 用 Query 分类器动态决定融合权重或是否直接跳过某一路——先训一个超轻量 2 分类 Query 分类器(0.1M 参数的 tiny BERT 就行)判断当前 Query 是「精确类(带文号/编号/专有名词/代码)」还是「语义类(开放式问题)」,精确类直接把 BM25 权重拉到 80% 甚至只跑 BM25,语义类反过来;这个动态路由能让混合检索的准确率再涨 5%,而且几乎没额外延迟。