LangChain VectorStoreRetriever如何加入链?(使用Runnable组合、使用create_retrieval_chain)
prompt| llm将加入链的本质是:把“检索”作为一个 Runnable 节点插入到数据流中。Retriever 是 RunnablePrompt 是 RunnableLLM 是 RunnableParser 也是 Runnable因此所有组件都可以自由组合。使用 LCEL明确分离 retriever 和 combine_docs控制检索策略做好文档格式化。
文章目录
LangChain 中如何将 VectorStoreRetriever 加入到链(Chain)中
在基于 LLM 的问答系统(RAG,Retrieval-Augmented Generation)中,检索器(Retriever) 是关键组件。本文将系统讲解:
- 什么是
VectorStoreRetriever - 它在 LangChain 架构中的位置
- 如何把
VectorStoreRetriever接入到链(Chain)中 - 常见的组合模式与最佳实践
本文基于 LangChain v0.1+ 以及 LCEL(LangChain Expression Language)范式。
一、VectorStoreRetriever 是什么?
在 LangChain 中,VectorStoreRetriever 是对向量数据库的抽象封装。
它的职责非常单一:
输入:查询字符串
输出:相关文档列表(List[Document])
其底层通常依赖向量数据库,例如:
- FAISS
- Chroma
- Milvus
- Weaviate
- Pinecone
典型流程:
用户问题
↓
Embedding
↓
向量相似度搜索
↓
返回相关文档
二、创建一个 VectorStoreRetriever
假设我们使用 FAISS:
from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings
# 1. 初始化 embedding
embeddings = OpenAIEmbeddings()
# 2. 构建向量数据库
vectorstore = FAISS.from_texts(
["LangChain is a framework for LLM applications."],
embedding=embeddings
)
# 3. 创建 retriever
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 3}
)
此时,retriever 已经是一个 VectorStoreRetriever 实例。
三、将 VectorStoreRetriever 加入到链中(核心部分)
在 LangChain 中,推荐使用 LCEL(| 管道操作符)构建链。
目标结构:
用户问题
↓
Retriever
↓
拼接上下文
↓
PromptTemplate
↓
LLM
↓
输出
方法一:使用 Runnable 组合(推荐方式)
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnablePassthrough
from langchain.schema.output_parser import StrOutputParser
llm = ChatOpenAI()
prompt = ChatPromptTemplate.from_template("""
请根据以下上下文回答问题:
{context}
问题:
{question}
""")
# 构建 RAG 链
rag_chain = (
{
"context": retriever,
"question": RunnablePassthrough()
}
| prompt
| llm
| StrOutputParser()
)
调用:
rag_chain.invoke("什么是 LangChain?")
解释:
RunnablePassthrough()保留原始问题- retriever 自动接收 question 作为输入
- 返回的文档会被自动格式化为字符串拼入 prompt
这是最清晰、可扩展性最强的方式。
方法二:使用 create_retrieval_chain
LangChain 提供了高级封装:
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
llm = ChatOpenAI()
prompt = ChatPromptTemplate.from_template("""
根据上下文回答问题:
{context}
问题:
{input}
""")
combine_docs_chain = create_stuff_documents_chain(llm, prompt)
retrieval_chain = create_retrieval_chain(
retriever,
combine_docs_chain
)
retrieval_chain.invoke({"input": "什么是 LangChain?"})
优点:
- 更模块化
- 清晰分离“检索”和“生成”
四、VectorStoreRetriever 在链中的数据流解析
在 LCEL 里,retriever 本质是:
Callable[str] → List[Document]
当你写:
{
"context": retriever,
"question": RunnablePassthrough()
}
LangChain 会自动:
- 把输入字符串传给 retriever
- 把返回的 Document 列表转成字符串
- 填充到 prompt 中的
{context}
这就是 LangChain 的 Runnable 设计优势 —— 所有组件都是可组合的。
五、高级用法
1️⃣ 控制检索策略
retriever = vectorstore.as_retriever(
search_type="mmr",
search_kwargs={"k": 5, "lambda_mult": 0.7}
)
支持:
- similarity
- mmr
- similarity_score_threshold
2️⃣ 自定义文档格式化
可以插入一个格式化步骤:
from langchain.schema.runnable import RunnableLambda
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
rag_chain = (
{
"context": retriever | RunnableLambda(format_docs),
"question": RunnablePassthrough()
}
| prompt
| llm
)
3️⃣ 多路检索合并
multi_retriever = retriever1 | retriever2
或者使用 EnsembleRetriever。
六、常见问题
❓ Retriever 接收的输入是什么?
默认是:
str
如果你传入 dict,需要:
retriever = retriever.with_config(
run_name="my_retriever"
)
或者手动提取字段。
❓ 为什么推荐 LCEL 而不是传统 Chain?
原因:
- 更灵活
- 可并行
- 可追踪
- 易于调试
- 可组合
传统 RetrievalQA 已经逐步被 LCEL 方式替代。
七、完整示例(生产可用版本)
from langchain.chat_models import ChatOpenAI
from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings
from langchain.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnablePassthrough
from langchain.schema.output_parser import StrOutputParser
# embedding
embeddings = OpenAIEmbeddings()
# 向量数据库
vectorstore = FAISS.from_texts(
["LangChain 是一个构建 LLM 应用的框架。"],
embedding=embeddings
)
retriever = vectorstore.as_retriever()
# LLM
llm = ChatOpenAI()
# Prompt
prompt = ChatPromptTemplate.from_template("""
根据上下文回答问题:
{context}
问题:
{question}
""")
# 构建 RAG
rag_chain = (
{
"context": retriever,
"question": RunnablePassthrough()
}
| prompt
| llm
| StrOutputParser()
)
print(rag_chain.invoke("LangChain 是什么?"))
八、总结
将 VectorStoreRetriever 加入链的本质是:
把“检索”作为一个 Runnable 节点插入到数据流中。
在 LangChain 新架构中:
- Retriever 是 Runnable
- Prompt 是 Runnable
- LLM 是 Runnable
- Parser 也是 Runnable
因此所有组件都可以自由组合。
如果你正在构建 RAG 系统,建议:
- 使用 LCEL
- 明确分离 retriever 和 combine_docs
- 控制检索策略
- 做好文档格式化
更多推荐



所有评论(0)