纲要
- 检索器概述
Retriever在 RAG 系统中的核心作用- 统一调用接口:
invoke/ainvoke
- 基础检索器与词法检索器
- 向量数据库的一键封装:
as_retriever() - 经典词法检索实现:
BM25Retriever
- 向量数据库的一键封装:
- 查询重写:多重查询(
MultiQueryRetriever)- 原理:利用大语言模型将模糊问题改写为多个精准子问题
- 实现方式:
MultiQueryRetriever.from_llm()与模拟模型
- 查询重构:自然语言转 SQL
- 核心流程:自然语言 → SQL 生成 → SQL 执行 → 答案生成
- 模拟实现:使用
FakeListChatModel模拟 SQL 生成与回答
- 检索策略对比与选型建议
- 完整可运行代码示例(无需 API Key)
引言
在 RAG(Retrieval-Augmented Generation)系统中,检索器(Retriever)承担着将用户自然语言问题与知识库中最相关文档片段进行匹配的核心职责。LangChain 将检索器抽象为标准的 Runnable 组件,不仅支持基础的向量相似度搜索,还内置了查询重写(Query Rewriting)、查询重构(Query Reconstruction)等高级策略,以显著提升召回率(Recall)和答案质量。
本文将从最简单的 as_retriever() 起步,逐步深入到多重查询(MultiQuery)和文本到 SQL 的查询重构,并提供无需外部 API 即可运行的完整示例。
检索器基础
所有向量数据库均可通过 .as_retriever() 方法一键转换为检索器,并直接使用 invoke 方法进行同步查询。以下示例使用 Chroma 内存向量库和 FakeEmbeddings 模拟嵌入过程,适用于 LangChain v0.1.x 及以上版本。
from langchain_community.embeddings import FakeEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_core.documents import Document
# 准备文档
docs = [
Document(page_content="LangChain 是一个强大的 LLM 应用框架。"),
Document(page_content="RAG 结合检索与生成,提升回答准确性。"),
Document(page_content="向量数据库用于存储文档的高维向量表示。"),
]
# 构建向量库
embeddings = FakeEmbeddings(size=128)
vectorstore = Chroma.from_documents(docs, embeddings, collection_name="intro")
# 转换为检索器,指定返回文档数量
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
# 执行检索
results = retriever.invoke("什么是 RAG?")
for doc in results:
print(doc.page_content)
词法检索器:BM25
BM25(Okapi BM25)是一种基于词频(TF)和逆文档频率(IDF)的经典排序算法,适用于精准字面匹配场景。LangChain 社区模块提供了 BM25Retriever,安装依赖后即可使用。
安装依赖:
pip install langchain-community rank_bm25
from langchain_community.retrievers import BM25Retriever
from langchain_core.documents import Document
# 准备文档语料
corpus = [
Document(page_content="LangChain 链式调用"),
Document(page_content="RAG 检索增强生成"),
Document(page_content="向量数据库 Chroma 和 FAISS"),
Document(page_content="BM25 是一种词法检索算法"),
]
# 从文档列表创建 BM25 检索器
bm25_retriever = BM25Retriever.from_documents(corpus)
bm25_retriever.k = 2 # 返回前 2 个结果
# 执行检索
results = bm25_retriever.invoke("检索算法")
for doc in results:
print(doc.page_content)
BM25Retriever.from_documents() 方法接受一个 Document 列表,并返回一个 BM25Retriever 实例。k 参数用于控制返回的文档数量,默认值为 4。
查询重写:多重查询(MultiQueryRetriever)
用户的问题往往表述模糊或不够精确。多重查询技术会先用大语言模型将原始问题改写为多个不同角度的子问题,再对每个子问题分别执行检索,最后合并去重返回结果。这一策略能有效提升召回率。
实现时,我们使用 FakeListChatModel 模拟大模型的改写能力,无需真实 API 密钥。FakeListChatModel 是 LangChain 提供的用于测试目的的模拟聊天模型,按顺序返回预设的响应列表。
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import FakeEmbeddings
from langchain_core.documents import Document
from langchain.retrievers.multi_query import MultiQueryRetriever
from langchain_community.chat_models.fake import FakeListChatModel
# 构建知识库
docs = [
Document(page_content="LangChain 提供了丰富的组件用于构建 RAG 应用。"),
Document(page_content="查询重写技术可以将一个笼统的问题拆解为多个子问题。"),
Document(page_content="MultiQueryRetriever 利用 LLM 生成多个查询变体。"),
Document(page_content="向量检索基于余弦相似度或欧氏距离。"),
]
embeddings = FakeEmbeddings(size=128)
vectorstore = Chroma.from_documents(docs, embeddings, collection_name="mq")
# 基础检索器
base_retriever = vectorstore.as_retriever(search_kwargs={"k": 1})
# 模拟大模型:预设三行改写结果(每行一个子问题)
# MultiQueryRetriever 使用 LineListOutputParser 解析按换行符分隔的查询列表
fake_llm = FakeListChatModel(
responses=[
"如何提高检索准确性?\n有哪些检索优化方法?\nMultiQueryRetriever 的工作原理"
]
)
# 创建多重查询检索器
multi_retriever = MultiQueryRetriever.from_llm(
retriever=base_retriever,
llm=fake_llm
)
# 执行查询
results = multi_retriever.invoke("如何让搜索更准?")
for doc in results:
print(doc.page_content)
运行后,原始问题将被扩展为多个子问题,从而检索到更全面的相关文档。
注意:MultiQueryRetriever.from_llm() 方法接受一个 BaseRetriever 和一个 BaseLLM 实例,内部使用默认的提示模板生成查询变体。FakeListChatModel 的 responses 参数是一个字符串列表,每个字符串代表一次模型调用的完整输出。
查询重构:自然语言转 SQL
另一种常见的检索优化策略是将自然语言问题重构为精确的 SQL 语句,尤其适用于结构化数据查询场景。以下示例展示了一个完整的处理流程:用户提问 → 生成 SQL → 执行 SQL → 生成自然语言答案。
from langchain_community.chat_models.fake import FakeListChatModel
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
# 模拟数据库查询函数
def execute_sql(sql: str) -> str:
# 实际环境中应连接数据库执行 SQL,此处返回模拟结果
if "销售额" in sql:
return "员工A: 100万, 员工B: 80万"
return "无数据"
# 模拟大模型:第一次调用返回 SQL,第二次调用返回自然语言答案
fake_llm = FakeListChatModel(
responses=[
"SELECT employee, revenue FROM sales ORDER BY revenue DESC LIMIT 2;",
"销售额最高的员工是员工A(100万)和员工B(80万)。"
]
)
# 第一步:生成 SQL
sql_prompt = ChatPromptTemplate.from_template(
"将以下问题转换为 SQL 语句(仅返回 SQL):\n{question}"
)
sql_chain = sql_prompt | fake_llm | StrOutputParser()
# 第二步:生成最终答案
answer_prompt = ChatPromptTemplate.from_template(
"根据 SQL 查询结果回答问题:\n问题: {question}\nSQL 结果: {result}"
)
answer_chain = answer_prompt | fake_llm | StrOutputParser()
# 完整链:自然语言 -> SQL -> 执行 -> 答案
def full_chain(question: str):
sql = sql_chain.invoke({"question": question})
result = execute_sql(sql)
answer = answer_chain.invoke({"question": question, "result": result})
return {"sql": sql, "result": result, "answer": answer}
response = full_chain("哪两位员工的销售额最高?")
print("生成的 SQL:", response["sql"])
print("执行结果:", response["result"])
print("最终答案:", response["answer"])
此流程清晰展示了查询重构如何将自然语言映射为结构化查询语言,显著简化了数据访问层的交互复杂度。
检索策略对比
| 策略 | 适用场景 | 典型组件 | 特点 |
|---|---|---|---|
| 向量检索(Dense Retrieval) | 通用 RAG,语义搜索 | vectorstore.as_retriever() | 基于语义相似度,泛化能力强 |
| 词法检索(BM25) | 精准关键词匹配 | BM25Retriever | 基于词频统计,字面匹配精准 |
| 多重查询(MultiQuery) | 用户问题模糊,需多角度覆盖 | MultiQueryRetriever | 查询扩展,提升召回率 |
| 文本到 SQL(Text-to-SQL) | 结构化数据库查询 | 自定义链 + SQL 执行 | 将自然语言转为精确查询语句 |
| 混合检索(Hybrid Search) | 兼顾语义与关键词匹配 | 需向量库原生支持(如 Pinecone、Weaviate) | 综合 dense + sparse 检索优势 |
参考文档
官方文档
- LangChain MultiQueryRetriever API Reference
- LangChain BM25Retriever API Reference
- LangChain FakeEmbeddings API Reference
- LangChain FakeListChatModel API Reference
总结
检索器是 RAG 系统的核心组件,LangChain 不仅提供了统一的 invoke 调用接口,还封装了多种检索优化策略。从基础的向量检索到智能的查询重写(MultiQueryRetriever)与查询重构(Text-to-SQL),开发者可以根据业务场景灵活组合这些能力。
通过本文提供的模拟示例,开发者可以在无需外部 API 的情况下快速验证这些高级检索特性,为实际项目落地奠定坚实基础。
398



被折叠的 条评论
为什么被折叠?



