### [RAG 中的混合检索是什么?为什么要用混合检索而不是纯向量检索?](https://www.isearch.life/article/678) **Published:** 2026-06-18T07:10:37 **Author:** tearell **Excerpt:** 深度解析 一、为什么纯向量检索不够用? 向量检索的原理是把文本通过 Embedding 模型编码成高维向量,然后用余弦相似度或内积来衡量语义相关性。这对 “理解意思” 很在行,但它有一个致命弱点:对精确关键词的匹配能力很弱。 举个实际的例子 ## 深度解析 ### 一、为什么纯向量检索不够用? 向量检索的原理是把文本通过 Embedding 模型编码成高维向量,然后用余弦相似度或内积来衡量语义相关性。这对 “理解意思” 很在行,但它有一个致命弱点:**对精确关键词的匹配能力很弱**。 举个实际的例子。假设你的知识库里有这样一段文档: > “ > > `Spring AI` 整合 `Milvus` 向量数据库时,需要在 `pom.xml` 中引入 `spring-ai-milvus-store` 依赖,版本号 `1.0.0-M4`。 用户提问:”`spring-ai-milvus-store` 的版本号是多少?” 向量检索可能会返回一堆跟 `Spring AI`、`Milvus`、依赖配置语义相关的文档,但精确包含 `spring-ai-milvus-store` 这个 artifactId 的那段文档,排名可能反而靠后——因为 Embedding 模型把这段文本编码后,”精确匹配 artifactId” 这个信号被稀释到整个语义空间里了。 而 BM25 关键词检索呢?它看到 `spring-ai-milvus-store` 这个精确 token,直接就能命中目标文档,简单粗暴但有效。 反过来,用户问:”`Spring AI` 怎么连接向量数据库?”BM25 可能搜不到好结果,因为文档里写的是 “整合 `Milvus`“,没有 “连接” 这个词。但向量检索能理解 “连接” 和 “整合” 在这个语境下是一个意思。 **这就是为什么需要混合检索——两种检索方式是互补的,不是替代关系。** ### 二、混合检索的整体架构 ![](https://www.isearch.life/resources/2026/06/%E9%A2%98%E7%9B%AE1.png) RAG 混合检索 Hybrid Search 架构图 RAG 混合检索 Hybrid Search 架构图 上图是混合检索的完整流程。核心就三步: - **两路并行检索**:用户查询同时进入稠密检索通道和稀疏检索通道,各自返回 Top-K 个结果(通常 K=10~20) - **结果融合**:用 RRF(Reciprocal Rank Fusion)或加权分数融合,把两路结果合并成统一的排序 - **重排序(可选但推荐)**:用 Cross-Encoder 模型对融合后的结果做精排,进一步提升相关性 ### 三、RRF 融合算法——混合检索的核心魔法 混合检索最关键的步骤是**怎么把两路结果合并**。你不能简单地把向量检索的分数和 BM25 的分数相加——因为它们的分数量纲完全不同(向量相似度是 0~1 的余弦值,BM25 是基于词频的评分,可能到几十甚至上百)。 RRF(Reciprocal Rank Fusion)巧妙地避开了分数归一化的问题,它只看**排名位置**,不看原始分数: ``` RRF_score(d) = Σ  1 / (k + rank_i(d)) ``` - `rank_i(d)`:文档 d 在第 i 路检索结果中的排名 - `k`:平滑常数,通常取 60 举个直观的例子:假设文档 A 在向量检索中排第 1 名,在 BM25 中排第 5 名: ``` RRF_score(A) = 1/(60+1) + 1/(60+5) = 1/61 + 1/65 ≈ 0.031 ``` 文档 B 在向量检索中排第 3 名,在 BM25 中排第 1 名: ``` RRF_score(B) = 1/(60+3) + 1/(60+1) = 1/63 + 1/61 ≈ 0.031 ``` RRF 的设计哲学是:**两种检索方式都给高排名的文档,最终得分就高**。即使某一路的分数偏低,只要另一路排名靠前,文档仍然能获得不错的最终分数。这个算法最早由 Cormack, Clarke & Büttcher 在 2009 年提出,到今天已经成为 Elasticsearch、Azure AI Search、OpenSearch 等主流搜索引擎的默认融合策略。 ### 四、代码示例:用 `LangChain4j` + Elasticsearch 实现混合检索 目前 `LangChain4j` 框架中,通过 Elasticsearch 集成实现混合检索是最成熟的方案。以下是基于 Elastic 官方博客(2026 年 3 月发布)的完整示例: **Maven 依赖:** ```                   dev.langchain4j         langchain4j         1.0.0-beta2                        dev.langchain4j         langchain4j-elasticsearch         1.0.0-beta2                        dev.langchain4j         langchain4j-ollama         1.0.0-beta2      ``` **Java 代码:** ``` import dev.langchain4j.data.embedding.Embedding; import dev.langchain4j.data.segment.TextSegment; import dev.langchain4j.model.embedding.EmbeddingModel; import dev.langchain4j.model.ollama.OllamaEmbeddingModel; import dev.langchain4j.rag.content.Content; import dev.langchain4j.rag.content.retriever.ContentRetriever; import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever; import dev.langchain4j.store.embedding.elasticsearch.ElasticsearchEmbeddingStore; import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; import java.util.List; publicclass HybridSearchDemo {     public static void main(String[] args) {         // 1. 配置 Elasticsearch 客户端         RestClientBuilder restClientBuilder = RestClient.builder(             new HttpHost("localhost", 9200, "http")         );         // 2. 配置 Embedding 模型(这里用 Ollama 本地模型)         EmbeddingModel embeddingModel = OllamaEmbeddingModel.builder()                 .baseUrl("http://localhost:11434")                 .modelName("nomic-embed-text")                 .build();         // 3. 创建 Elasticsearch 向量存储         ElasticsearchEmbeddingStore embeddingStore = ElasticsearchEmbeddingStore.builder()                 .restClientBuilder(restClientBuilder)                 .embeddingModel(embeddingModel)                 .indexName("knowledge_base")                 .build();         // 4. 纯向量检索(作为对比)         ContentRetriever vectorRetriever = EmbeddingStoreContentRetriever.builder()                 .embeddingStore(embeddingStore)                 .embeddingModel(embeddingModel)                 .maxResults(5)                 // 默认使用 kNN 向量检索                 .build();         // 5. 混合检索(BM25 + kNN + RRF 融合)         ContentRetriever hybridRetriever = EmbeddingStoreContentRetriever.builder()                 .embeddingStore(embeddingStore)                 .embeddingModel(embeddingModel)                 .maxResults(5)                 // 开启混合检索:自动使用 BM25 + kNN,通过 RRF 融合结果                 .searchType(ElasticsearchEmbeddingStore.SearchType.hybrid())                 .build();         // 6. 执行检索对比         String query = "怎么在 Spring AI 中整合 Milvus 向量数据库?";         System.out.println("=== 纯向量检索结果 ===");         List vectorResults = vectorRetriever.retrieve(query);         vectorResults.forEach(c -> System.out.println(c.textSegment().text()));         System.out.println("\n=== 混合检索结果 ===");         List hybridResults = hybridRetriever.retrieve(query);         hybridResults.forEach(c -> System.out.println(c.textSegment().text()));     } } ``` 这段代码的核心区别就在第 5 步——设置 `.searchType(ElasticsearchEmbeddingStore.SearchType.hybrid())` 就能开启混合检索模式。Elasticsearch 底层会自动执行 BM25 + kNN 双路检索,然后用 RRF 融合排序。 ### 五、主流向量数据库的混合检索支持情况 | 数据库 | 混合检索支持 | 稀疏检索方式 | 融合策略 | | --- | --- | --- | --- | | **Elasticsearch** | 原生支持 | BM25 | RRF(内置) | | **Milvus 2.5+** | 原生支持 | Sparse-BM25 / SPLADE | 加权融合 | | **Weaviate** | 原生支持 | BM25 | 加权融合 | | **Qdrant** | 原生支持 | 稀疏向量 | RRF / 加权 | | **OpenSearch** | 原生支持 | BM25 | RRF(内置) | | **Chroma** | 有限支持 | 需外部配合 | 手动融合 | 如果你用的是 `Milvus 2.5`,它原生支持 Sparse-BM25 全文检索,可以直接在一个 Collection 中同时存储稠密向量和稀疏向量,然后用 `HybridSearchRequest` 执行混合查询。`Spring AI` 框架中通过 `MilvusVectorStore` 可以对接 `Milvus`,不过目前 `Spring AI` 对混合检索的原生抽象还在社区讨论阶段。 ### 六、生产环境的最佳实践 说几个我实际踩过的坑和经验: **1\. 混合检索 + Rerank 是黄金组合** Azure AI Search 做过一组对比实验,结论很明确: | 方案 | 召回准确率 | | --- | --- | | 纯关键词检索(BM25) | 基准 | | 纯向量检索 | +8% | | 混合检索(BM25 + 向量) | +15% | | **混合检索 + Rerank** | **+25%** | 加了 Rerank 之后提升非常明显。推荐用 `bge-reranker-v2-m3` 或 `Cohere Rerank` 这类 Cross-Encoder 模型,在融合结果的基础上做精排。 **2\. 权重需要根据场景调整** 两路检索的权重不是固定的。如果你的知识库中专业术语、编号、代码片段比较多,BM25 的权重应该适当提高;如果是概念性、描述性的内容为主,向量检索的权重可以大一些。一般建议从 0.5:0.5 开始,然后根据实际效果调优。 **3\. Embedding 模型的选择很关键** 中文场景别用英文 Embedding 模型,效果会差很多。推荐 `bge-large-zh-v1.5`、`text-embedding-3-large`(支持中文)或者国产的 `Acme_Embedding`。模型选对了,向量检索这路的基线就稳了。 ### 七、常见误区 - **误区一**:”向量检索已经理解语义了,不需要关键词检索。” 现实是向量检索对精确匹配天然不敏感。用户搜 `ERR-4023` 这种错误码,向量检索很可能给你一堆跟 “错误” 语义相关但完全不包含这个编号的文档。 - **误区二**:”混合检索就是把两路结果拼在一起。” 不是简单拼接,需要通过 RRF 或加权融合来统一排序。直接拼接会导致两路结果各排各的,相关性混乱。 - **误区三**:”混合检索一定比单路检索好。” 不一定。如果查询是纯语义类的(比如 “如何提高团队效率”),向量检索可能就够了。混合检索的价值在于应对**复杂多样的查询场景**,确保 “不管用户怎么问,都能找到相关文档”。 **Categories:** 热门资讯 ---