检索器 API

BaseRetriever 与文档检索

概述

检索器是 LangChain 中获取相关文档的标准接口,通常基于向量存储实现语义搜索。

graph TD
                    A[BaseRetriever] --> B[VectorStoreRetriever]
                    A --> C[BM25Retriever]
                    A --> D[MultiQueryRetriever]
                    A --> E[ContextualCompressionRetriever]
                    A --> F[EnsembleRetriever]
                    A --> G[ParentDocumentRetriever]
                    A --> H[SelfQueryRetriever]

                    B --> I[相似度检索]
                    B --> J[MMR 检索]

                    style A fill:#e1f5fe
                    style B fill:#c8e6c9

基类

BaseRetriever

所有检索器的抽象基类。

from langchain_core.retrievers import BaseRetriever

class BaseRetriever(Runnable[str, List[Document]], ABC):
    """检索器基类"""

    # 必须实现的方法
    @abstractmethod
    def _get_relevant_documents(
        self,
        query: str,
        *,
        run_manager: Optional[CallbackManagerForRetrieverRun] = None,
        **kwargs: Any,
    ) -> List[Document]:
        """
        获取相关文档(子类实现)

        Args:
            query: 查询文本
            run_manager: 回调管理器
            **kwargs: 额外参数

        Returns:
            相关文档列表
        """

    async def _aget_relevant_documents(
        self,
        query: str,
        *,
        run_manager: Optional[CallbackManagerForRetrieverRun] = None,
        **kwargs: Any,
    ) -> List[Document]:
        """
        异步获取相关文档(子类可选实现)

        默认调用 _get_relevant_documents
        """
        return await asyncio.to_thread(
            self._get_relevant_documents,
            query,
            run_manager=run_manager,
            **kwargs
        )

    # 公共接口
    def get_relevant_documents(
        self,
        query: str,
        **kwargs: Any,
    ) -> List[Document]:
        """
        获取相关文档

        Args:
            query: 查询文本
            **kwargs: 额外参数

        Returns:
            相关文档列表
        """

    async def aget_relevant_documents(
        self,
        query: str,
        **kwargs: Any,
    ) -> List[Document]:
        """异步获取相关文档"""

    # Runnable 接口实现
    def invoke(
        self,
        input: str,
        config: Optional[RunnableConfig] = None,
        **kwargs: Any,
    ) -> List[Document]:
        """
        调用检索器(Runnable 接口)

        Args:
            input: 查询文本
            config: 运行配置
            **kwargs: 额外参数

        Returns:
            相关文档列表
        """

    async def ainvoke(
        self,
        input: str,
        config: Optional[RunnableConfig] = None,
        **kwargs: Any,
    ) -> List[Document]:
        """异步调用检索器"""

    def bind(self, **kwargs: Any) -> "BaseRetriever":
        """
        绑定参数

        Args:
            **kwargs: 要绑定的参数

        Returns:
            绑定参数后的检索器
        """

    def with_config(
        self,
        config: RunnableConfig,
    ) -> "BaseRetriever":
        """
        绑定配置

        Args:
            config: 运行配置

        Returns:
            带配置的检索器
        """

检索器类型

VectorStoreRetriever

向量存储检索器。

from langchain_core.vectorstores import VectorStoreRetriever

class VectorStoreRetriever(BaseRetriever):
    """向量存储检索器"""

    vectorstore: VectorStore
    """关联的向量存储"""

    search_type: Literal["similarity", "mmr"] = "similarity"
    """搜索类型"""

    search_kwargs: Dict[str, Any] = {}
    """搜索参数"""

    # 常用搜索参数:
    # k: 返回文档数量
    # score_threshold: 相似度阈值
    # fetch_k: MMR 候选数量
    # lambda_mult: MMR 平衡参数
    # filter: 元数据过滤条件

    def _get_relevant_documents(
        self,
        query: str,
        **kwargs: Any,
    ) -> List[Document]:
        """
        获取相关文档

        Args:
            query: 查询文本
            **kwargs: 临时覆盖 search_kwargs

        Returns:
            相关文档列表
        """

使用示例

python
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings

# 创建向量存储
vectorstore = Chroma.from_texts(
    texts=["文档1", "文档2", "文档3"],
    embedding=OpenAIEmbeddings()
)

# 转换为检索器
retriever = vectorstore.as_retriever()

# 自定义检索器
retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 3}
)

# MMR 检索器
retriever = vectorstore.as_retriever(
    search_type="mmr",
    search_kwargs={
        "k": 3,
        "fetch_k": 10,
        "lambda_mult": 0.5
    }
)

# 使用检索器
docs = retriever.invoke("查询文本")

BM25Retriever

BM25 关键词检索器。

from langchain_community.retrievers import BM25Retriever

class BM25Retriever(BaseRetriever):
    """BM25 检索器"""

    def __init__(
        self,
        documents: List[Document],
        k: int = 4,
        bm25_params: Optional[Dict[str, Any]] = None,
    ):
        """
        初始化 BM25 检索器

        Args:
            documents: 文档列表
            k: 返回文档数量
            bm25_params: BM25 参数
                - k1: 词频饱和参数 (默认 1.5)
                - b: 长度归一化参数 (默认 0.75)
                - epsilon: IDF 下界 (默认 0.25)
        """

使用示例

python
from langchain_community.retrievers import BM25Retriever
from langchain_core.documents import Document

documents = [
    Document(page_content="Python 是一种编程语言"),
    Document(page_content="JavaScript 也是一种编程语言")
]

retriever = BM25Retriever.from_documents(
    documents,
    k=2,
    bm25_params={"k1": 1.5, "b": 0.75}
)

docs = retriever.invoke("编程语言")

MultiQueryRetriever

多查询检索器。

from langchain.retrievers import MultiQueryRetriever

class MultiQueryRetriever(BaseRetriever):
    """多查询检索器"""

    retriever: BaseRetriever
    """底层检索器"""

    llm_chain: Runnable
    """生成查询的 LLM 链"""

    parser_key: str = "lines"
    """解析键"""

    include_original: bool = True
    """是否包含原始查询"""

    def _get_relevant_documents(
        self,
        query: str,
        **kwargs: Any,
    ) -> List[Document]:
        """
        使用多个查询检索
        """

使用示例

python
from langchain.retrievers import MultiQueryRetriever
from langchain_openai import ChatOpenAI
from langchain_chroma import Chroma

# 创建基础检索器
vectorstore = Chroma.from_texts(
    texts=["文档1", "文档2"],
    embedding=OpenAIEmbeddings()
)
base_retriever = vectorstore.as_retriever()

# 创建多查询检索器
llm = ChatOpenAI(model="gpt-4o", temperature=0)
retriever = MultiQueryRetriever.from_llm(
    retriever=base_retriever,
    llm=llm,
    include_original=True
)

docs = retriever.invoke("查询文本")

ContextualCompressionRetriever

上下文压缩检索器。

from langchain.retrievers import ContextualCompressionRetriever

class ContextualCompressionRetriever(BaseRetriever):
    """上下文压缩检索器"""

    base_compressor: BaseDocumentCompressor
    """文档压缩器"""

    base_retriever: BaseRetriever
    """基础检索器"""

    def _get_relevant_documents(
        self,
        query: str,
        **kwargs: Any,
    ) -> List[Document]:
        """
        检索并压缩文档
        """

使用示例

python
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor
from langchain_openai import ChatOpenAI

# 基础检索器
vectorstore = Chroma.from_texts(
    texts=["长文档1...", "长文档2..."],
    embedding=OpenAIEmbeddings()
)
base_retriever = vectorstore.as_retriever()

# 压缩器
llm = ChatOpenAI(model="gpt-4o")
compressor = LLMChainExtractor.from_llm(llm)

# 压缩检索器
retriever = ContextualCompressionRetriever(
    base_compressor=compressor,
    base_retriever=base_retriever
)

docs = retriever.invoke("查询文本")
# 返回压缩后的相关片段

EnsembleRetriever

集成检索器(合并多个检索器)。

from langchain.retrievers import EnsembleRetriever

class EnsembleRetriever(BaseRetriever):
    """集成检索器"""

    retrievers: List[BaseRetriever]
    """检索器列表"""

    weights: Optional[List[float]] = None
    """权重列表"""

    ranking_key: str = "score"
    """排序键"""

使用示例

python
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
from langchain_chroma import Chroma

# 向量检索器
vectorstore = Chroma.from_texts(
    texts=["文档1", "文档2"],
    embedding=OpenAIEmbeddings()
)
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 3})

# 关键词检索器
bm25_retriever = BM25Retriever.from_texts(
    texts=["文档1", "文档2"],
    k=3
)

# 集成检索器
ensemble_retriever = EnsembleRetriever(
    retrievers=[vector_retriever, bm25_retriever],
    weights=[0.5, 0.5]
)

docs = ensemble_retriever.invoke("查询文本")

ParentDocumentRetriever

父子文档检索器。

from langchain.retrievers import ParentDocumentRetriever

class ParentDocumentRetriever(BaseRetriever):
    """父子文档检索器"""

    vectorstore: VectorStore
    """子文档向量存储"""

    docstore: BaseStore[str, Document]
    """父文档存储"""

    child_splitter: TextSplitter
    """子文档分割器"""

    parent_splitter: Optional[TextSplitter] = None
    """父文档分割器"""

    id_key: str = "doc_id"
    """ID 键名"""

使用示例

python
from langchain.retrievers import ParentDocumentRetriever
from langchain.storage import InMemoryStore
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 分割器
parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000)
child_splitter = RecursiveCharacterTextSplitter(chunk_size=400)

# 创建检索器
retriever = ParentDocumentRetriever(
    vectorstore=Chroma(embedding_function=OpenAIEmbeddings()),
    docstore=InMemoryStore(),
    child_splitter=child_splitter,
    parent_splitter=parent_splitter
)

# 添加文档
retriever.add_documents([Document(page_content="长文档...")])

# 检索(返回父文档)
docs = retriever.invoke("查询文本")

SelfQueryRetriever

自查询检索器。

from langchain.retrievers import SelfQueryRetriever

class SelfQueryRetriever(BaseRetriever):
    """自查询检索器"""

    vectorstore: VectorStore
    """向量存储"""

    llm_chain: Runnable
    """查询理解链"""

    structured_query_translator: BaseStructuredQueryTranslator
    """查询转换器"""

使用示例

python
from langchain.retrievers import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo
from langchain_openai import ChatOpenAI

# 定义元数据字段
metadata_field_info = [
    AttributeInfo(
        name="source",
        description="文档来源",
        type="string"
    ),
    AttributeInfo(
        name="year",
        description="文档年份",
        type="integer"
    )
]

# 创建检索器
retriever = SelfQueryRetriever.from_llm(
    llm=ChatOpenAI(model="gpt-4o"),
    vectorstore=vectorstore,
    document_contents="文档内容描述",
    metadata_field_info=metadata_field_info
)

# 自然语言查询
docs = retriever.invoke("2023年关于 Python 的文档")

TimeWeightedVectorStoreRetriever

时间加权检索器。

from langchain.retrievers import TimeWeightedVectorStoreRetriever

retriever = TimeWeightedVectorStoreRetriever(
    vectorstore=vectorstore,
    decay_rate=0.01,  # 衰减率
    k=3
)

使用示例

python
# ========== 示例1: 基础检索器 ==========
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings

vectorstore = Chroma.from_texts(
    texts=["文档1", "文档2", "文档3"],
    embedding=OpenAIEmbeddings()
)
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})

docs = retriever.invoke("查询文本")

# ========== 示例2: 自定义检索器 ==========
from langchain_core.retrievers import BaseRetriever

class CustomRetriever(BaseRetriever):
    def _get_relevant_documents(self, query: str) -> List[Document]:
        # 自定义检索逻辑
        return [Document(page_content=f"关于 {query} 的结果")]

retriever = CustomRetriever()
docs = retriever.invoke("查询")

# ========== 示例3: 与链集成 ==========
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_template("""
基于以下上下文回答问题:
{context}

问题: {question}
""")

llm = ChatOpenAI(model="gpt-4o")

# RAG 链
rag_chain = (
    {"context": retriever, "question": lambda x: x["question"]}
    | prompt
    | llm
    | StrOutputParser()
)

result = rag_chain.invoke({"question": "什么是 LangChain?"})

# ========== 示例4: 过滤检索 ==========
retriever = vectorstore.as_retriever(
    search_kwargs={
        "k": 3,
        "filter": {"source": "python_docs"}
    }
)

# ========== 示例5: 带分数阈值的检索 ==========
retriever = vectorstore.as_retriever(
    search_kwargs={
        "score_threshold": 0.8,
        "k": 5
    }
)

# ========== 示例6: 流式检索 ==========
async for chunk in retriever.astream("查询"):
    print(chunk)

# ========== 示例7: 批量检索 ==========
queries = ["查询1", "查询2", "查询3"]
results = retriever.batch(queries)

相关 API