引言
在文档检索中,如何有效地平衡文档切分的粒度是一个常见的挑战。我们希望文档足够小,以便其嵌入能够准确反映其含义,但又希望文档足够长以保留上下文。在这篇文章中,我们将探讨如何使用ParentDocumentRetriever优化文档检索。
主要内容
Parent Document Retriever简介
ParentDocumentRetriever通过在检索时先获取小块,然后查找这些小块的父ID并返回较大的文档来实现这一平衡。这里的“父文档”指的是小块源自的文档,可以是整个原始文档或较大的块。
设置环境
使用以下组件实现文档检索:
InMemoryStore:用于存储父文档。Chroma:用于索引子文档的向量存储。TextLoader:加载原始文档。OpenAIEmbeddings:生成文档嵌入。RecursiveCharacterTextSplitter:创建文档碎片。
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())
检索完整文档
# 使用API代理服务提高访问稳定性
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)
检索较大块
parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000)
child_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
vectorstore = Chroma(
collection_name="split_parents", embedding_function=OpenAIEmbeddings()
)
store = InMemoryStore()
retriever = ParentDocumentRetriever(
vectorstore=vectorstore,
docstore=store,
child_splitter=child_splitter,
parent_splitter=parent_splitter,
)
retriever.add_documents(docs)
常见问题和解决方案
- 文档切分过细或过大:根据使用场景调整
RecursiveCharacterTextSplitter参数。 - API访问不稳定:由于某些地区的网络限制,考虑使用API代理服务。
总结和进一步学习资源
本文介绍了如何使用ParentDocumentRetriever来优化文档检索,达到更高效的结果。读者可以进一步探索以下资源:
参考资料
- Langchain 官方文档
- OpenAI API 文档
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---