在 LangChain 中,检索器是一个遵循统一接口的组件:输入一个查询(字符串),输出一个文档(Document)列表 。
这个简单的接口极大地简化了信息检索的复杂性。你可以将任何能够返回相关文档的系统(如搜索引擎、数据库、向量存储)包装成一个检索器,然后在你的 LangChain 应用中以统一的方式调用它。
什么是检索器 在 LangChain 中,检索器是一个遵循统一接口的组件:输入一个查询(字符串),输出一个文档(Document)列表 。
这个简单的接口极大地简化了信息检索的复杂性。你可以将任何能够返回相关文档的系统(如搜索引擎、数据库、向量存储)包装成一个检索器,然后在你的 LangChain 应用中以统一的方式调用它。
LangChain 的检索器是 RAG(检索增强生成)系统的核心组件,它提供了一套统一的接口来连接各种不同的数据源。无论是向量数据库、搜索引擎,还是传统的数据库,都可以通过这个接口被 LLM 应用轻松调用。
常见检索器类型及使用方法 LangChain 支持多种检索器,以满足不同的应用场景。以下是一些最常用和高级的类型:
检索器类型
核心概念
适用场景
向量存储检索器
基于语义相似度 进行检索,将文本转换为向量后计算距离。
语义搜索、问答系统、知识库检索。
父文档检索器
索引小块(如句子)以获得高精度,但返回大块(段落)以提供完整上下文。
文档问答、法律合同分析、技术手册查询。
多查询检索器
使用 LLM 对用户问题生成多个不同视角的变体,分别检索后融合结果。
处理复杂、模糊的问题,提高召回率。
自查询检索器
让 LLM 从自然语言中提取出语义部分 用于向量搜索,并提取出过滤条件 用于元数据过滤。
数据分类清晰、需结构化筛选的场景,如电商、内容库。
集成检索器
结合多个检索器(如 BM25 + 向量搜索)的结果,使用加权或 RRF 算法重新排名。
需要兼顾关键词匹配 和语义理解 的搜索系统。
API/搜索引擎检索器
直接包装外部API(如搜索引擎、第三方数据服务)作为检索器,返回实时信息。
实时信息查询、联网搜索。
调用代码示例 向量存储检索器 :
1 retriever = vectorstore.as_retriever(search_kwargs={"k" : 3 })
父文档检索器
1 retriever = ParentDocumentRetriever(vectorstore=..., docstore=..., child_splitter=..., parent_splitter=...)
多查询检索器
1 retriever = MultiQueryRetriever.from_llm(retriever=..., llm=...)
自查询检索器
1 retriever = SelfQueryRetriever.from_llm(llm, vectorstore, document_content_description, metadata_field_info)
集成检索器
1 retriever = EnsembleRetriever(retrievers=[bm25_retriever, vector_retriever], weights=[0.4 , 0.6 ])
API/搜索引擎检索器
1 retriever = LinkupSearchRetriever(depth="deep" )
详细使用指南与示例 向量存储检索器 这是最基础的检索器类型,几乎所有的向量数据库都支持将它转换为检索器。
使用步骤:
加载和分割 文档。
生成嵌入向量 并存入向量库 。
通过 as_retriever() 方法创建检索器。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 from langchain_community.document_loaders import TextLoaderfrom langchain_text_splitters import RecursiveCharacterTextSplitterfrom langchain_community.vectorstores import FAISSfrom langchain_openai import OpenAIEmbeddingsloader = TextLoader("state_of_the_union.txt" ) documents = loader.load() text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000 , chunk_overlap=200 ) docs = text_splitter.split_documents(documents) embeddings = OpenAIEmbeddings() vectorstore = FAISS.from_documents(docs, embeddings) retriever = vectorstore.as_retriever(search_kwargs={"k" : 3 }) query = "What did the president say about Ketanji Brown Jackson?" relevant_docs = retriever.invoke(query) for doc in relevant_docs: print (doc.page_content[:200 ])
父文档检索器 这种方法解决了检索精度 与上下文完整性 之间的矛盾。
工作原理:
将大文档分割成较大的“父文档”(如段落)。
再将父文档分割成很小的“子文档”(如句子)。
检索时,用子文档 去匹配查询(精度高),但返回时返回其对应的父文档 (上下文完整)。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 from langchain.retrievers import ParentDocumentRetrieverfrom langchain.storage import InMemoryStorefrom langchain_text_splitters import RecursiveCharacterTextSplitterparent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000 , chunk_overlap=200 ) child_splitter = RecursiveCharacterTextSplitter(chunk_size=400 , chunk_overlap=0 ) docstore = InMemoryStore() retriever = ParentDocumentRetriever( vectorstore=vectorstore, docstore=docstore, child_splitter=child_splitter, parent_splitter=parent_splitter, ) retriever.add_documents(docs) retrieved_parent_docs = retriever.invoke("your query here" )
自查询检索器 它让你可以用自然语言实现复杂的、带筛选条件的查询。
工作原理:
你定义好元数据字段的信息(如 year、genre)。
用户输入:"Find movies made before 1960 that are rated higher than 8"。
LLM 将这句话解析成一个结构化查询,包含 query 部分(”movies”)和 filter 部分(year < 1960 and rating > 8)。
示例代码(基于 MongoDB):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from langchain_mongodb.retrievers import MongoDBAtlasSelfQueryRetrieverfrom langchain.chains.query_constructor.base import AttributeInfometadata_field_info = [ AttributeInfo(name="year" , description="The year the movie was released" , type ="integer" ), AttributeInfo(name="rating" , description="A 1-10 rating for the movie" , type ="float" ), ] retriever = MongoDBAtlasSelfQueryRetriever.from_llm( llm=llm, vectorstore=vectorstore, metadata_field_info=metadata_field_info, document_contents="Descriptions of movies" ) result = retriever.invoke("Movies made before 1960 that are rated higher than 8" )
集成检索器 混合检索是目前提升召回率的主流方法,通常将基于关键词 (如BM25)和基于语义 (向量)的检索器结合。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from langchain.retrievers import EnsembleRetrieverfrom langchain_community.retrievers import BM25Retrieverensemble_retriever = EnsembleRetriever( retrievers=[bm25_retriever, vector_retriever], weights=[0.4 , 0.6 ] ) docs = ensemble_retriever.invoke("What did the president say about Justice Breyer?" )
完整的问答系统示例 最后,让我们看一个完整的例子,它使用向量存储检索器 构建一个可以直接使用的问答链:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 from langchain.chains import RetrievalQAfrom langchain_openai import ChatOpenAIfrom langchain_community.vectorstores import FAISSfrom langchain_openai import OpenAIEmbeddingsembeddings = OpenAIEmbeddings() vectorstore = FAISS.from_documents(docs, embeddings) retriever = vectorstore.as_retriever(search_kwargs={"k" : 4 }) llm = ChatOpenAI(model="gpt-3.5-turbo" , temperature=0 ) qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff" , retriever=retriever, return_source_documents=True ) query = "What did the president say about Ketanji Brown Jackson?" result = qa_chain.invoke({"query" : query}) print ("Answer:" , result["result" ])print ("\nSources:" )for doc in result["source_documents" ]: print (f"- {doc.metadata.get('source' , 'Unknown' )} " )