1. EnsembleRetriever(混合检索器)

功能:

将多个不同类型的检索器(如 BM25、向量检索等)的结果进行融合,形成一个“合奏”式检索系统。

核心思想:

  • 集成学习:利用不同检索方法的优势(关键词匹配 + 语义相似度)
  • 可配置权重(如 BM25 占 0.4,向量检索占 0.6)

典型用法:

from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
from langchain_community.vectorstores import FAISS

# 向量检索器
vector_retriever = FAISS.from_documents(docs, embeddings).as_retriever()

# BM25 检索器
bm25_retriever = BM25Retriever.from_documents(docs)

# 混合检索器
ensemble_retriever = EnsembleRetriever(
    retrievers=[bm25_retriever, vector_retriever],
    weights=[0.4, 0.6]
)

适用场景:

  • 需要兼顾关键词精确匹配语义泛化能力
  • 提升召回率与排序质量(常用于 RAG 系统主干检索)

2. BM25Retriever(基于 BM25 的稀疏检索器)

功能:

实现经典的 BM25 算法(一种改进的 TF-IDF),用于基于关键词的文档打分与召回。

特点:

  • 稀疏检索:依赖词频统计,不理解语义
  • 对拼写错误、同义词不鲁棒,但对精确关键词匹配效果好
  • 轻量、快速,适合处理短查询或结构化字段

典型用法:

bm25_retriever = BM25Retriever.from_documents(documents, k=5)

适用场景:

  • 查询包含明确关键词(如“API 文档”、“2023 年财报”)
  • 作为混合检索的一部分,弥补向量检索在关键词上的不足

3. MultiQueryRetriever(多查询检索器)

功能:

利用 LLM 自动生成多个相关查询变体,然后用这些变体并行检索,扩大召回范围。

核心思想:

  • 查询扩展(Query Expansion)
  • 解决用户原始查询表述模糊、信息不足的问题

典型用法:

from langchain.retrievers.multi_query import MultiQueryRetriever
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(temperature=0)
multi_query_retriever = MultiQueryRetriever.from_llm(
    retriever=vector_retriever,  # 底层可以是任何 retriever
    llm=llm
)

适用场景:

  • 用户提问简短或模糊(如“怎么用?”、“讲一下这个”)
  • 需要从不同角度理解问题意图
  • 常用于提升召回覆盖率,尤其在知识库问答中效果显著

注意:它本身不是独立检索器,而是对已有检索器(如向量检索)的“增强包装”。


三者对比总结:

组件 类型 是否依赖 LLM 主要作用 优势 局限
BM25Retriever 稀疏关键词检索 精确关键词匹配 快速、可解释 无语义理解
EnsembleRetriever 混合检索框架 否(但可集成 LLM 检索器) 融合多种检索结果 兼顾精度与泛化 需调权重、去重
MultiQueryRetriever 查询扩展增强器 扩展用户查询,提升召回 解决模糊查询 依赖 LLM 成本/质量

实战建议(组合使用):

可以将三者嵌套使用,构建更强大的检索流水线:

# 1. 基础向量检索
vector_retriever = ...

# 2. 用 MultiQuery 扩展查询
multi_retriever = MultiQueryRetriever.from_llm(retriever=vector_retriever, llm=llm)

# 3. 再与 BM25 混合
bm25_retriever = BM25Retriever.from_documents(docs)
final_retriever = EnsembleRetriever(
    retrievers=[bm25_retriever, multi_retriever],
    weights=[0.3, 0.7]
)

这样既扩展了查询意图,又融合了关键词与语义信号,是当前 RAG 系统中的最佳实践之一

高级组合策略:构建“四层”检索流水线

一、SelfQueryRetriever:结构化语义查询

 功能:

允许用户用自然语言提问,自动解析出:

  • 查询语句(query)
  • 元数据过滤条件(metadata filter)

例如:

“2023 年关于气候变化的英文论文”

→ 自动提取:

  • query: “气候变化”
  • filter: {"year": 2023, "language": "en"}

优势:

  • 支持结构化过滤 + 语义检索联合
  • 减少人工构造 filter 的成本
  • 提高检索精准度(尤其在带元数据的知识库中)

用法示例:

from langchain.retrievers.self_query import SelfQueryRetriever
from langchain.chains.query_constructor.schema import AttributeInfo
from langchain_openai import ChatOpenAI

# 定义文档元数据结构
metadata_field_info = [
    AttributeInfo(
        name="year",
        description="The year the document was published",
        type="integer",
    ),
    AttributeInfo(
        name="category",
        description="The category of the document (e.g., 'policy', 'research')",
        type="string",
    ),
]

document_content_description = "Brief summary of a scientific or policy document"

llm = ChatOpenAI(temperature=0)
vectorstore = FAISS.from_documents(docs, embeddings)

self_query_retriever = SelfQueryRetriever.from_llm(
    llm=llm,
    vectorstore=vectorstore,
    document_contents=document_content_description,
    metadata_field_info=metadata_field_info,
    verbose=True
)

要求底层 vectorstore 支持 metadata filtering(如 Chroma、Pinecone、FAISS with custom logic)。

二、bge-reranker:重排序提升 Top-K 质量

功能:

对初步召回的文档(比如 top 20)进行精细语义相关性打分,重新排序,选出最相关的 top 5。

为什么需要?

  • 向量检索(如 cosine similarity)是近似匹配,可能排错顺序
  • BM25 对语义不敏感
  • Reranker 使用交叉编码器(cross-encoder),比双塔模型更准

用法(使用 HuggingFace Transformers):

from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch

# 加载 bge-reranker-large(推荐)
tokenizer = AutoTokenizer.from_pretrained('BAAI/bge-reranker-large')
model = AutoModelForSequenceClassification.from_pretrained('BAAI/bge-reranker-large')
model.eval()

def rerank(query: str, docs: list[str], top_k: int = 5):
    pairs = [[query, doc] for doc in docs]
    with torch.no_grad():
        inputs = tokenizer(pairs, padding=True, truncation=True, return_tensors='pt', max_length=512)
        scores = model(**inputs, return_dict=True).logits.view(-1, ).float()
    # 按分数降序排序
    scored_docs = sorted(zip(docs, scores), key=lambda x: x[1], reverse=True)
    return [doc for doc, _ in scored_docs[:top_k]]

也可使用 FlagEmbedding 库简化:

from FlagEmbedding import FlagReranker
reranker = FlagReranker('BAAI/bge-reranker-large', use_fp16=True)
scores = reranker.compute_score([[query, doc] for doc in retrieved_docs])

三、高级组合策略:构建“四层”检索流水线

所有技术串联成一个多阶段检索增强系统

用户提问
   ↓
[1] MultiQueryRetriever → 生成 3~5 个语义变体
   ↓
[2] EnsembleRetriever → 每个变体同时走 BM25 + Vector 路径,合并去重 → 召回 top 30
   ↓
[3] SelfQueryRetriever(可选)→ 如果有元数据,提前过滤(可在 Ensemble 前或后)
   ↓
[4] bge-reranker → 对 top 30 重排序 → 输出 top 5 最相关文档
   ↓
送入 LLM 生成答案

示例代码骨架(简化版):

# Step 1: 多查询扩展
multi_retriever = MultiQueryRetriever.from_llm(retriever=vector_retriever, llm=llm)

# Step 2: 混合 BM25 + 向量(注意:MultiQueryRetriever 包装的是向量检索器)
bm25_retriever = BM25Retriever.from_documents(docs, k=10)
ensemble_retriever = EnsembleRetriever(
    retrievers=[bm25_retriever, multi_retriever],
    weights=[0.3, 0.7]
)

# Step 3: 执行初步检索(得到 ~20-30 文档)
initial_docs = ensemble_retriever.invoke("用户问题")

# Step 4: 重排序
final_docs = rerank(query="用户问题", docs=[d.page_content for d in initial_docs], top_k=5)

注意:SelfQueryRetriever 通常替代普通向量检索器,而不是叠加。如果你的数据有丰富元数据,建议:

  • 用 SelfQueryRetriever 作为 MultiQueryRetriever 的底层 retriever
  • 或在 Ensemble 中用它替换标准向量检索器

 四、何时用哪种技术?

场景 推荐组件
用户问题模糊、简短 MultiQueryRetriever
文档含年份/类别/作者等元数据 SelfQueryRetriever
需要兼顾关键词和语义 EnsembleRetriever(BM25 + Vector)
初步召回结果排序不准 bge-reranker
构建生产级 RAG 全部组合使用(按需裁剪)

这种架构已在 LlamaIndex、LangChain 生产案例、开源 RAG 评测(如 BEIR、MTEB) 中验证有效。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐