它的优化对象是「检索召回的结果」,核心逻辑是对多路不同检索引擎的召回结果做融合重排,全程不修改用户的原始查询语句,和查询转换阶段"改写查询文本"的核心定位有本质区别。
1.3.1 集成检索器与混合检索策略
1.3.1.1 核心原理与优势
集成检索器的核心思想是多路召回、优势互补:接入多种不同检索逻辑的检索器,对同一个查询分别执行召回,再通过融合算法将多路结果合并排序,最终输出统一的文档列表,整体效果优于任意单一检索器。
单一检索算法都存在天然的能力边界:
- 稀疏检索(如BM25关键词检索):擅长字面精确匹配,对专有名词、专业术语、数字、缩写的匹配度高,但无法理解语义、同义词、上下文关联;
- 密集检索(如向量相似度检索):擅长语义模糊匹配,能理解同义词、句式变化、隐含语义,但对精确关键词、专有名词的匹配弱于字面检索。
将二者结合的混合检索(Hybrid Search) 是工业界生产级RAG的标准配置,能够同时覆盖字面匹配与语义匹配,大幅提升召回的准确率与全面性,也是Dify、Coze等主流AI应用平台的默认检索方案。
1.3.1.2 LangChain 内置实现:EnsembleRetriever
LangChain 官方封装了 EnsembleRetriever 集成检索器,原生支持多路检索器结果融合,默认基于RRF倒数排名融合算法做结果重排,可接入任意符合标准的Retriever实现。
1.3.1.2.1 核心构造参数
| 参数名 | 类型 | 说明 |
|---|---|---|
| retrievers | ListBaseRetriever | 检索器列表,支持任意数量、任意类型的检索器组合 |
| weights | Listfloat | 对应检索器的权重列表,长度与retrievers一致,权重越高对应检索器的结果优先级越高 |
1.3.1.2.2 基础实现示例(BM25+FAISS混合检索)
最经典的落地方案是「BM25关键词稀疏检索 + FAISS向量密集检索」的双路组合,实现完整的混合检索能力。
python
import dotenv
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
from langchain_community.vectorstores import FAISS
from langchain_core.documents import Document
from langchain_openai import OpenAIEmbeddings
dotenv.load_dotenv()
# 1. 准备知识库文档
documents = [
Document(page_content="笨笨是一只很喜欢睡觉的猫咪", metadata={"page": 1}),
Document(page_content="我喜欢在夜晚听音乐,这让我感到放松。", metadata={"page": 2}),
Document(page_content="猫咪在窗台上打盹,看起来非常可爱。", metadata={"page": 3}),
Document(page_content="学习新技能是每个人都应该追求的目标。", metadata={"page": 4}),
]
# 2. 构建BM25关键词检索器(稀疏检索)
bm25_retriever = BM25Retriever.from_documents(documents)
bm25_retriever.k = 4
# 3. 构建FAISS向量检索器(密集检索)
faiss_db = FAISS.from_documents(
documents,
embedding=OpenAIEmbeddings(model="text-embedding-3-small")
)
faiss_retriever = faiss_db.as_retriever(search_kwargs={"k": 4})
# 4. 初始化集成检索器,两路检索权重各占0.5
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, faiss_retriever],
weights=[0.5, 0.5],
)
# 5. 执行混合检索
docs = ensemble_retriever.invoke("除了猫,你养了什么宠物呢?")
1.3.1.2.3 运行时动态配置
生产环境支持通过 configurable_fields 实现检索参数的动态调整,无需重启服务即可修改单路检索器的召回数量、匹配阈值等配置。
python
# 为向量检索器配置可动态修改的搜索参数
faiss_retriever = faiss_db.as_retriever(search_kwargs={"k": 4}).configurable_fields(
search_kwargs=ConfigurableField(
id="search_kwargs_faiss",
name="搜索参数",
description="FAISS检索器的搜索参数配置",
)
)
# 调用时传入配置,动态调整召回数量
config = {"configurable": {"search_kwargs_faiss": {"k": 1}}}
docs = ensemble_retriever.invoke("苹果", config=config)
1.3.1.3 融合算法逻辑
EnsembleRetriever 底层基于加权版RRF(倒数排名融合) 算法实现结果合并,核心执行逻辑:
- 并行调用所有检索器,分别获取各自的文档排名列表;
- 对每个文档,按其在各路检索器中的排名,结合对应检索器的权重,累计计算融合得分;
- 按总得分降序排列,去重后输出最终的融合结果。
与标准RRF算法相比,加权RRF支持人为调整不同检索通道的优先级:比如精确查询占比高的业务场景,可将BM25权重设为0.6、向量检索设为0.4,灵活适配业务偏好。
1.3.1.4 与RAG Fusion的边界区分
二者都使用了RRF融合算法,但所属阶段、解决的问题完全不同,是极易混淆的两个方案,核心区别如下:
| 方案 | 所属阶段 | 核心逻辑 | 差异来源 | 核心目标 |
|---|---|---|---|---|
| 集成检索器(混合检索) | 检索阶段 | 同一个查询,多路不同检索引擎召回,结果融合 | 检索算法/引擎不同 | 兼顾字面匹配与语义匹配 |
| RAG Fusion | 查询转换+检索融合 | 多个改写查询,同一路检索器召回,结果融合 | 查询语句不同 | 提升召回的语义全面性 |
工业界最佳实践通常是二者叠加使用:先通过查询转换生成多个子查询,再对每个子查询执行混合检索,最后对所有结果做统一RRF融合,实现最大化的召回效果。
1.3.1.5 落地最佳实践
- 权重调优:默认两路各0.5是通用基线,需结合业务场景调优。事实类、精确查询多的场景调高BM25权重,语义类、咨询类查询多的场景调高高向量检索权重。
- 召回数量配置:单路检索器的召回数量建议略大于最终目标数量,保证融合后有足够的候选池做排序。例如最终返回4条结果,单路可各召回4~6条。
- 中文分词适配:原生BM25检索器默认按空格分词,不适合中文文本。生产环境需替换为Jieba等中文分词器,否则关键词检索效果会严重下降。
- 可扩展组合:不仅限于BM25+向量,还可接入图检索、SQL检索、知识库目录检索等多路通道,通过统一的RRF框架融合,适配复杂的多数据源RAG系统。
- 性能权衡:每增加一路检索器,检索耗时会相应增加,需在效果与性能之间做平衡。通用场景两路混合即可覆盖绝大多数需求,不建议堆砌超过三路检索器。