引言
在处理大型文档数据时,通常会面临一个两难选择:是将文档拆分为小块,以便其嵌入准确地反映其意义,还是保持块足够大以保留上下文?ParentDocumentRetriever
在检索过程中通过先提取小块数据,然后根据这些块的父ID返回较大的文档,巧妙地解决了这一问题。
本篇文章将深入讲解如何使用ParentDocumentRetriever
,并提供详细代码示例。
主要内容
1. Parent Document Retriever概述
ParentDocumentRetriever
通过将文档拆分为较小的块进行存储,并在检索时返回较大文档来实现高效的文档检索。这个过程涉及两个主要步骤:
- 拆分文档:将文档拆分成小块以便存储和索引。
- 检索父文档:在需要时检索并返回原始较大文档。
2. 支持的组件与功能
在实现这一功能时,使用了以下组件:
- InMemoryStore:一个简单的内存存储,用来存储父文档。
- Chroma:一个用于存储和索引文档新区块的向量存储。
- OpenAIEmbeddings:用于创建文本的嵌入表示。
- RecursiveCharacterTextSplitter:用于根据字符长度递归拆分文档的文本拆分器。
代码示例
下面的代码示例演示了如何使用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()
)
store = InMemoryStore()
# 创建检索器实例
retriever = ParentDocumentRetriever(
vectorstore=vectorstore,
docstore=store,
child_splitter=child_splitter,
)
# 添加文档
retriever.add_documents(docs, ids=None)
# 检索示例
retrieved_docs = retriever.invoke("justice breyer")
print(retrieved_docs[0].page_content)
常见问题和解决方案
挑战1:网络访问限制
在某些地区,直接访问API可能受到限制,建议使用API代理服务提高访问稳定性。
挑战2:文档过大
如果返回的文档过大,可以优化拆分策略,先拆分为较大块,然后再细化为小块。
总结与进一步学习资源
ParentDocumentRetriever
提供了一种平衡精确性和上下文保留的文档检索方法。通过拆分和索引较小的文档块,我们可以实现更高效的检索和信息获取。
进一步学习资源
参考资料
- LangChain Documentation: https://www.langchain.com/docs/
- Chroma Vector Store: https://www.chroma.com/tutorials
- OpenAI Embeddings: https://www.openai.com/blog/openai-embeddings/
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
—END—