混合检索 Hybrid Search

Hybrid Search (Dense + Sparse / Vector + Keyword)

混合检索是在 RAG 中同时使用向量语义检索(Dense / Dense Embedding)和关键词检索(Sparse / BM25 / TF-IDF / 倒排索引),再用 Reciprocal Rank Fusion 或 Reranker 合并两路结果的技术,能在字面匹配和语义匹配两类 Query 上同时保持高召回率。

详细解释

**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 年最新工业实践)

  1. 两路各自的 TopK 不能太小——每路至少取 Top 100-200,再做融合后取 Top 50 给 Reranker;很多人图省事每路只取 Top 20,融合之后还是 20 条,但向量检索排 30 多位刚好 BM25 排第一位的那条黄金结果直接就丢了,召回率损失 15% 以上。
  2. Query 预处理一定要把「专有名词 / 文号 / 代码编号」这类字面强信号保留给 BM25——分词器别激进地把「粤府〔2025〕12 号」「GB/T 2025-3 标准」这种专有名词拆成碎 token;用自定义词典把专有名词、文号、标准号、客户内部代码全部加进分词白名单,让 BM25 能精确命中这些强字面信号;这一条能让精确查询的召回率涨 30%。
  3. Query 扩展(同义词/缩写/中英对照)只应用于关键词检索侧,向量侧不要扩展——向量检索本身已经能泛化同义词,扩展后反而会稀释 Query 的语义向量(比如本来搜「高血压」扩展到「原发性高血压+继发性高血压+血压高」三个词混在一起),召回反而变差;BM25 侧必须做扩展,不然「冠心病」搜不到「冠状动脉粥样硬化性心脏病」的文档。
  4. Chunk 级去重要按「原始文档 ID + 原始段落 ID」双重去重——很多混合检索的两路召回是同一个 Chunk 被两边各命一次名(比如向量侧叫 docid=1234,BM25 侧索引里 docid=1234_v1),你只按内容去重就会漏掉;建索引的时候统一生成一个「Chunk Key = sha256(原始文档路径 + 起始偏移)」,不管哪一路召回来的 Chunk Key 相同就是同一条,fuse 时只保留一个,取两路里排名靠前的那个位置参与 RRF。
  5. 冷启动时用 RRF,积累了 1 万条标注数据再换 Learned 融合——刚开始业务没数据,RRF 是无参最优,别上来就训复杂的融合模型;等你有了 1 万条以上的「Query + Chunk + 是否相关」的人工标注数据后,可以训一个简单的 LambdaMART / LightGBM 的融合排序模型,拿两路分数 + 各种 handcrafted 特征(Query 和 Chunk 的字符重叠比例、BM25 分数、向量余弦、Chunk 长度、是否命中专有名词)作为特征,AUC 比 RRF 还能再涨 5-8%。
  6. 用 Query 分类器动态决定融合权重或是否直接跳过某一路——先训一个超轻量 2 分类 Query 分类器(0.1M 参数的 tiny BERT 就行)判断当前 Query 是「精确类(带文号/编号/专有名词/代码)」还是「语义类(开放式问题)」,精确类直接把 BM25 权重拉到 80% 甚至只跑 BM25,语义类反过来;这个动态路由能让混合检索的准确率再涨 5%,而且几乎没额外延迟。

常见问题

ES/OpenSearch 已经自带 Hybrid Search(knn + match 组合查询),还需要单独部署一套向量数据库吗?
分规模:100 万 Chunk 以内用 ES/OpenSearch 自带的 knn + match 完全够用,不要再额外部署一套向量库(多一套组件多一套故障域);超过 100 万 Chunk 或者 QPS 超过 200 时,独立向量库(Milvus / Qdrant / Weaviate)的性能和成本会更优。具体选型时看三个关键指标:(1)你的 Chunk 总量——如果只是企业内部知识库几万到几十万篇文档 Chunk 后几十万元组,ES 自带的 lucene HNSW 实现完全能hold住,延迟(p95 30-50ms)和召回率(95%+)和独立向量库没明显差距;(2)QPS 和 SLA 要求——如果你的 RAG 是 ToC 面向几十万用户高峰 QPS 500+,ES 的 knn 在这种高并发下会把整个集群的 CPU 打满严重影响写入,这时候应该把向量检索单独 offload 到 Milvus/Qdrant,ES 只负责倒排和结构化过滤;(3)是否需要高级向量功能(Scalar Quantization、DiskANN、稀疏注意力的 Sparse Vector、GPU 加速索引)——ES 原生 HNSW 不支持这些,需要这些高级功能时也得换独立向量库。Graph RAG 这种有图谱关系的复杂 RAG,强烈建议向量库和图谱数据库 + ES 倒排三路并行,别全塞 ES 里。
中文场景下混合检索效果总是不如预期,是不是分词器的问题?怎么调?
中文混合检索 80% 的效果问题出在倒排侧的分词和词典配置,剩下 20% 才是 embedding 模型选型;按下面四步调,90% 的中文 RAG 效果能从及格提到优秀。(1)第一步:分词器切到「细粒度 + 自定义业务词典」——不要用 ES 默认的 IK Smart(粗粒度),用 IK Max Word(细粒度)或者结巴细粒度 + 自己的业务词典(把行业术语、客户内部名词、产品名、缩写、文号、标准号全部加进去),业务词典的质量直接决定了 BM25 的上限;(2)第二步:在 BM25 侧打开「NGram/拼音/同义词」三向扩展——对专有名词做 2-Gram 索引(「深高认定」同时能命中「深圳高新技术企业认定」的 2Gram 倒排)、拼音扩展(搜「gaoxin」也能命中「高新」)、同义词扩展(行业专业词的不同写法全部映射到标准词);(3)第三步:中文专用 Embedding 模型,别用英文模型中文 SFT 的版本——目前 2025 年中文 Embedding 效果排序是:bge-m3 / bge-large-zh-v1.5 第一梯队(NDCG@10 70+),text-embedding-3-large 中文版本第二梯队(65+),其他开源的在 60 左右徘徊;(4)第四步:中文专用 Reranker,别用英文 CrossEncoder——BAAI/bge-reranker-large-v2 是目前中文 Rerank 的王者,比通用 CrossEncoder 中文效果高 10+ 个百分点,这一步不换,前面三路怎么调都是白搭。(5)额外加分项:中文 Query 纠错 + 改写,用户输入的错别字/口语化缩写先纠错再检索,又能涨 5%。
结构化字段过滤(时间范围、部门、文档类别这种)应该放在检索前还是检索后?会影响混合检索效果吗?
标准答案:结构化过滤一定要放在检索之前做(Pre-filtering),让检索引擎直接在过滤后的子集合里找 TopK,绝对不要先检索再事后过滤;事后过滤的「先取 1000 条再筛」这条路,在极端过滤比例下(比如你要查 2025 年内部财务文档,100 万里只有 100 条)会把召回率直接打到 10% 以下——因为那 100 条真实命中的可能在向量检索里本来排 1000+,取 Top1000 根本拿不到。但要注意两个坑:(1)超严格过滤(过滤完只剩 50 条以内)的时候,直接跳过向量 ANN 走纯 BM25 倒排,不然 ANN 索引里候选集合太小距离估算不准,召回会抖;(2)一定要确认你的向量库/ES 原生支持「先过滤后 ANN」的 Pre-filtering 且过滤之后 ANN 召回率没崩——很多向量库支持 Pre-filter 但实现很差,过滤到 1% 子集时 ANN 召回率直接从 95% 崩到 60%;做上线前必须单独做「过滤比例 50%/10%/1%/0.1% 四档下的 ANN 召回率测试」,1% 档召回率还能在 90% 以上才能放心用。ANN 里关于过滤和索引协同优化的内容直接适用,把过滤条件当软约束不行,必须是硬前置过滤。