在构建检索增强生成(RAG)系统时,Retriever(检索器)是连接用户查询与知识库的关键桥梁。它决定了AI应用能否准确理解用户意图,并从海量文档中找到最相关的信息。LangChain框架提供了丰富多样的Retriever类型,每种都针对特定的使用场景和性能需求进行了优化。理解这些不同类型的特点和适用场景,对于构建高效的RAG系统至关重要。
基础Retriever类型
1. VectorStoreRetriever(向量存储检索器)
核心特点:
- 语义搜索能力:基于嵌入向量进行相似度计算,能够理解查询的语义含义
- 通用性强:支持所有主流向量数据库(Chroma、FAISS、Pinecone、Milvus等)
- 配置灵活:支持多种检索参数调优
工作原理:
VectorStoreRetriever是最基础也是最常用的检索器类型。它将用户查询通过嵌入模型转换为向量,然后在向量数据库中执行近似最近邻(ANN)搜索,返回最相似的文档片段。
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_core.retrievers import BaseRetriever
# 创建向量存储
vectorstore = Chroma.from_documents(
documents=docs,
embedding=OpenAIEmbeddings()
)
# 创建基础向量检索器
retriever = vectorstore.as_retriever(
search_type="similarity", # 相似度搜索
search_kwargs={"k": 4} # 返回4个最相关文档
)
# 使用检索器
results = retriever.invoke("什么是注意力机制?")
适用场景:
- 通用的语义搜索需求
- 需要理解查询意图而非关键词匹配
- 大多数RAG应用的基础检索组件
局限性:
- 对于精确关键词匹配效果不如稀疏检索
- 可能返回冗余或不相关的文档
- 向量计算成本较高
2. BM25Retriever(稀疏检索器)
核心特点:
- 关键词精确匹配:基于传统的TF-IDF算法,擅长处理精确关键词查询
- 无需向量化:直接基于文本内容进行检索,计算成本低
- 互补性强:与向量检索形成良好互补
工作原理:
BM25Retriever实现了经典的BM25算法,这是一种改进的TF-IDF算法,能够更好地处理词频和文档长度的影响。它特别适合处理包含具体术语、代码、数字等精确信息的查询。
from langchain.retrievers import BM25Retriever
# 创建BM25检索器
bm25_retriever = BM25Retriever.from_documents(
documents=docs,
k=4 # 返回4个最相关文档
)
# 使用BM25检索器
results = bm25_retriever.invoke("Python中的list comprehension语法")
适用场景:
- 包含具体技术术语、代码片段的查询
- 需要精确关键词匹配的场景
- 作为向量检索的补充,提高检索覆盖率
局限性:
- 无法理解语义相似性
- 对同义词、近义词处理能力有限
- 不适合处理自然语言的模糊查询
高级Retriever类型
3. MultiQueryRetriever(多查询检索器)
核心特点:
- 查询扩展:自动生成多个相关查询,扩大检索范围
- 提高召回率:减少因查询表述不当导致的漏检
- 智能重写:利用LLM理解查询意图并生成变体
工作原理:
MultiQueryRetriever通过LLM分析原始查询,生成多个语义相关的查询变体,然后对每个变体执行检索,最后合并和去重结果。这种方法有效解决了用户查询表述不准确或过于简单的问题。
from langchain.retrievers.multi_query import MultiQueryRetriever
from langchain_openai import ChatOpenAI
# 创建多查询检索器
llm = ChatOpenAI(temperature=0)
multi_query_retriever = MultiQueryRetriever.from_llm(
retriever=base_retriever, # 基础检索器
llm=llm
)
# 配置生成查询的数量
multi_query_retriever = MultiQueryRetriever.from_llm(
retriever=base_retriever,
llm=llm,
include_original=True, # 是否包含原始查询
prompt=prompt_template # 自定义提示词模板
)
适用场景:
- 用户查询表述模糊或不完整
- 需要提高检索召回率的场景
- 处理复杂或多方面的查询需求
局限性:
- 增加了LLM调用成本
- 可能生成不相关或重复的查询
- 执行时间相对较长
4. ContextualCompressionRetriever(上下文压缩检索器)
核心特点:
- 结果精炼:对检索到的文档进行相关性过滤和内容压缩
- 提高精度:去除不相关或冗余的信息
- 节省token:减少传递给LLM的上下文长度
工作原理:
ContextualCompressionRetriever首先使用基础检索器获取候选文档,然后通过压缩器(Compressor)对每个文档进行相关性评估和内容提取。只有与查询高度相关的文档片段才会被保留。
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor
# 创建LLM压缩器
compressor = LLMChainExtractor.from_llm(ChatOpenAI())
# 创建上下文压缩检索器
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=base_retriever
)
# 使用压缩检索器
results = compression_retriever.invoke("解释Transformer架构的核心组件")
适用场景:
- 检索结果包含大量无关信息
- 需要控制上下文长度以节省token成本
- 提高回答质量和相关性的场景
局限性:
- 增加了额外的LLM调用开销
- 可能过度压缩重要信息
- 对压缩器的质量依赖较大
5. EnsembleRetriever(集成检索器)
核心特点:
- 混合检索策略:同时使用多种检索方法
- 优势互补:结合不同检索器的优点
- 鲁棒性强:降低单一检索方法的失败风险
工作原理:
EnsembleRetriever将多个不同的检索器组合在一起,对每个检索器的结果进行加权融合。通常会结合向量检索和稀疏检索,既保证语义理解能力,又保持关键词匹配的精确性。
from langchain.retrievers import EnsembleRetriever
# 创建集成检索器
ensemble_retriever = EnsembleRetriever(
retrievers=[vector_retriever, bm25_retriever],
weights=[0.5, 0.5] # 权重分配
)
# 使用集成检索器
results = ensemble_retriever.invoke("机器学习中的梯度下降算法")
适用场景:
- 需要兼顾语义搜索和关键词匹配
- 提高检索系统的整体鲁棒性
- 处理多样化的查询类型
局限性:
- 计算成本较高(需要执行多次检索)
- 权重调优需要经验和实验
- 结果融合策略可能影响最终效果
6. ParentDocumentRetriever(父文档检索器)
核心特点:
- 分块策略优化:小块用于检索,大块用于上下文
- 保持上下文完整性:避免因分块过小丢失重要上下文
- 灵活性强:支持不同的分块大小配置
工作原理:
ParentDocumentRetriever采用两层分块策略:将文档分割成较小的子块用于向量检索,但存储和返回的是较大的父块。这样既能保证检索的精确性,又能提供足够的上下文信息。
from langchain.retrievers import ParentDocumentRetriever
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 创建不同大小的文本分割器
child_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=20)
parent_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
# 创建父文档检索器
parent_retriever = ParentDocumentRetriever(
vectorstore=vectorstore,
docstore=InMemoryStore(), # 存储父文档
child_splitter=child_splitter,
parent_splitter=parent_splitter
)
# 添加文档
parent_retriever.add_documents(docs)
适用场景:
- 文档内容较长且需要保持上下文完整性
- 小块检索但大块使用的场景
- 技术文档、法律文件等结构化内容
局限性:
- 存储开销较大(需要存储两种粒度的文档)
- 配置复杂度较高
- 对内存要求较高
特殊用途Retriever类型
7. TimeWeightedVectorStoreRetriever(时间加权检索器)
核心特点:
- 时间衰减:较新的文档获得更高权重
- 动态更新:支持文档的时间戳管理
- 时效性优先:适合处理时效性强的内容
工作原理:
这种检索器在计算相似度时,除了考虑向量距离外,还考虑文档的时间戳。较新的文档会获得更高的最终得分,确保用户优先看到最新的信息。
8. SelfQueryRetriever(自查询检索器)
核心特点:
- 元数据过滤:自动从查询中提取过滤条件
- 结构化查询:支持基于元数据的复杂查询
- 智能解析:利用LLM理解查询中的结构化信息
工作原理:
SelfQueryRetriever能够分析用户查询,自动识别其中的元数据过滤条件(如日期范围、作者、类别等),并将这些条件应用到检索过程中。
from langchain.retrievers.self_query.base import SelfQueryRetriever
# 定义文档元数据结构
metadata_field_info = [
AttributeInfo(
name="category",
description="文档类别",
type="string"
),
AttributeInfo(
name="date",
description="发布日期",
type="integer"
)
]
# 创建自查询检索器
self_query_retriever = SelfQueryRetriever.from_llm_and_vectorstore(
llm=llm,
vectorstore=vectorstore,
document_contents="文档内容",
metadata_field_info=metadata_field_info
)
适用场景:
- 文档具有丰富的元数据信息
- 用户查询包含明确的过滤条件
- 需要支持复杂的结构化查询
Retriever选择与优化策略
性能对比与选择指南
| Retriever类型 | 语义理解 | 关键词匹配 | 计算成本 | 适用场景 |
|---|---|---|---|---|
| VectorStoreRetriever | ⭐⭐⭐⭐⭐ | ⭐⭐ | 中等 | 通用RAG应用 |
| BM25Retriever | ⭐ | ⭐⭐⭐⭐⭐ | 低 | 精确匹配需求 |
| MultiQueryRetriever | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | 高 | 模糊查询场景 |
| ContextualCompression | ⭐⭐⭐⭐ | ⭐⭐⭐ | 高 | 结果精炼需求 |
| EnsembleRetriever | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 高 | 综合性能要求 |
| ParentDocumentRetriever | ⭐⭐⭐⭐ | ⭐⭐ | 中等 | 长文档处理 |
组合使用最佳实践
在实际应用中,往往需要组合多种Retriever来达到最佳效果:
# 复合检索策略示例
def create_optimized_retriever():
# 基础向量检索器
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 10})
# 多查询扩展
multi_query_retriever = MultiQueryRetriever.from_llm(
retriever=vector_retriever,
llm=ChatOpenAI(temperature=0)
)
# 集成BM25检索
bm25_retriever = BM25Retriever.from_documents(docs, k=10)
ensemble_retriever = EnsembleRetriever(
retrievers=[multi_query_retriever, bm25_retriever],
weights=[0.7, 0.3]
)
# 上下文压缩
compressor = LLMChainFilter.from_llm(ChatOpenAI())
final_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=ensemble_retriever
)
return final_retriever
这种复合策略结合了多种Retriever的优势:多查询扩展提高了召回率,集成检索保证了语义和关键词的双重覆盖,上下文压缩确保了结果的精确性。