You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Langchain ParentDocumentRetriever保存加载与检索链集成问题

如何加载ParentDocumentRetriever实例并用于RetrievalQA链

我使用Langchain的ParentDocumentRetriever构建了向量数据库,已将Chroma数据库保存至chroma_db目录,但未保存ParentDocumentRetriever实例(big_chunks_retriever)。现在需要在构建RetrievalQA链的代码中加载该实例,并将其设置为retriever参数,请问该如何实现?

数据库构建代码

# =========================
#  Module: Vector DB Build
# =========================
import box
import yaml
from langchain.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.document_loaders import PyPDFLoader, DirectoryLoader
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.storage import InMemoryStore
from langchain.retrievers import ParentDocumentRetriever
from langchain.vectorstores import Chroma

# Import config vars
with open('config/config.yml', 'r', encoding='utf8') as ymlfile:
    cfg = box.Box(yaml.safe_load(ymlfile))

# Build vector database
def run_db_build():
    loader = DirectoryLoader(cfg.DATA_PATH,
                             glob='*.pdf',
                             loader_cls=PyPDFLoader)
    documents = loader.load()
    
    embeddings = HuggingFaceEmbeddings(model_name=cfg.EMBEDDING_MODEL_NAME,
                                       model_kwargs={'device': 'mps'}, encode_kwargs={'device': 'mps', 'batch_size': 32})
    
    parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000, chunk_overlap=200)
    child_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
    store = InMemoryStore()

    vectorstore = Chroma(collection_name="split_parents", embedding_function=embeddings,
                         persist_directory="chroma_db/") 
    big_chunks_retriever = ParentDocumentRetriever(
        vectorstore=vectorstore,
        docstore=store,
        child_splitter=child_splitter,
        parent_splitter=parent_splitter,
    )
    big_chunks_retriever.add_documents(documents)

if __name__ == "__main__":
    run_db_build()

检索链构建代码

def build_retrieval_qa(llm, prompt, vectordb):
    chain_type_kwargs={
        #"verbose": True,
        "prompt": prompt,
        "memory": ConversationBufferMemory(
            memory_key="history",
            input_key="question")}
    
    dbqa = RetrievalQA.from_chain_type(llm=llm,
                                       chain_type='stuff',
                                       retriever="HOW TO SET PARENTDOCUMENTRETRIEVER HERE?",                                       
                                       return_source_documents=cfg.RETURN_SOURCE_DOCUMENTS,
                                       chain_type_kwargs=chain_type_kwargs,
                                      )
    return dbqa

解决方案

关键问题说明

原代码使用InMemoryStore存储父文档,这是内存级存储,程序重启后数据会丢失。要实现Retriever实例的复用,必须先将父文档存储替换为持久化的本地存储。

步骤1:修改数据库构建代码,改用持久化存储

导入LocalFileStore替换InMemoryStore,指定本地存储目录(如./docstore/):

# 新增导入
from langchain.storage import LocalFileStore

# 修改run_db_build函数中的store初始化
store = LocalFileStore("./docstore/")  # 替换原来的InMemoryStore()

修改后的完整构建代码:

# =========================
#  Module: Vector DB Build
# =========================
import box
import yaml
from langchain.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.document_loaders import PyPDFLoader, DirectoryLoader
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.storage import LocalFileStore  # 替换InMemoryStore
from langchain.retrievers import ParentDocumentRetriever
from langchain.vectorstores import Chroma

# Import config vars
with open('config/config.yml', 'r', encoding='utf8') as ymlfile:
    cfg = box.Box(yaml.safe_load(ymlfile))

# Build vector database
def run_db_build():
    loader = DirectoryLoader(cfg.DATA_PATH,
                             glob='*.pdf',
                             loader_cls=PyPDFLoader)
    documents = loader.load()
    
    embeddings = HuggingFaceEmbeddings(model_name=cfg.EMBEDDING_MODEL_NAME,
                                       model_kwargs={'device': 'mps'}, encode_kwargs={'device': 'mps', 'batch_size': 32})
    
    parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000, chunk_overlap=200)
    child_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
    store = LocalFileStore("./docstore/")  # 持久化存储父文档

    vectorstore = Chroma(collection_name="split_parents", embedding_function=embeddings,
                         persist_directory="chroma_db/") 
    big_chunks_retriever = ParentDocumentRetriever(
        vectorstore=vectorstore,
        docstore=store,
        child_splitter=child_splitter,
        parent_splitter=parent_splitter,
    )
    big_chunks_retriever.add_documents(documents)
    vectorstore.persist()  # 确保Chroma向量库数据持久化

if __name__ == "__main__":
    run_db_build()

步骤2:编写加载ParentDocumentRetriever的函数

创建函数重新初始化所有组件,恢复Retriever实例:

def load_parent_retriever():
    # 加载配置和依赖模块
    import box
    import yaml
    from langchain.embeddings import HuggingFaceEmbeddings
    from langchain.storage import LocalFileStore
    from langchain.text_splitter import RecursiveCharacterTextSplitter
    from langchain.vectorstores import Chroma
    from langchain.retrievers import ParentDocumentRetriever

    with open('config/config.yml', 'r', encoding='utf8') as ymlfile:
        cfg = box.Box(yaml.safe_load(ymlfile))
    
    # 初始化embeddings(参数需和构建时一致)
    embeddings = HuggingFaceEmbeddings(model_name=cfg.EMBEDDING_MODEL_NAME,
                                       model_kwargs={'device': 'mps'}, encode_kwargs={'device': 'mps', 'batch_size': 32})
    
    # 初始化分割器(参数需和构建时完全一致)
    parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000, chunk_overlap=200)
    child_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
    
    # 加载持久化的存储和向量库
    store = LocalFileStore("./docstore/")
    vectorstore = Chroma(collection_name="split_parents", embedding_function=embeddings,
                         persist_directory="chroma_db/")
    
    # 重新创建ParentDocumentRetriever实例
    retriever = ParentDocumentRetriever(
        vectorstore=vectorstore,
        docstore=store,
        child_splitter=child_splitter,
        parent_splitter=parent_splitter,
    )
    return retriever

步骤3:修改检索链构建代码,传入加载的Retriever

更新build_retrieval_qa函数,加载Retriever实例并赋值给retriever参数:

def build_retrieval_qa(llm, prompt):
    # 加载ParentDocumentRetriever实例
    retriever = load_parent_retriever()
    
    chain_type_kwargs={
        #"verbose": True,
        "prompt": prompt,
        "memory": ConversationBufferMemory(
            memory_key="history",
            input_key="question")}
    
    dbqa = RetrievalQA.from_chain_type(llm=llm,
                                       chain_type='stuff',
                                       retriever=retriever,  # 传入加载后的实例
                                       return_source_documents=cfg.RETURN_SOURCE_DOCUMENTS,
                                       chain_type_kwargs=chain_type_kwargs,
                                      )
    return dbqa

注意事项

  • 分割器的chunk_size和chunk_overlap参数必须和构建数据库时完全一致,否则无法正确匹配父文档。
  • 确保chroma_db和docstore目录存在且有读写权限。
  • 若在不同文件中调用,需确保所有依赖模块已正确导入。

内容的提问来源于stack exchange,提问作者Maxl Gemeinderat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 03:12:04