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
相关产品推荐
相关产品推荐

