如何合并多个FAISS索引为单个检索器且保留单独使用能力
可行方案与替代实现
方案一:使用LangChain的EnsembleRetriever合并检索器
LangChain中不存在MultiIndexRetriever,但可以用EnsembleRetriever组合多个FAISS检索器,同时保留每个原始索引实例,既能满足合并后的问答需求,也支持单独调用索引做相似性搜索。
实现步骤
- 为每个FAISS索引创建独立检索器
- 用
EnsembleRetriever组合检索器(可自定义权重) - 保留原始FAISS索引,用于后续单独搜索
- 开启QA链的源文档返回,获取参考页面信息
完整代码示例
from langchain.retrievers import EnsembleRetriever from langchain.vectorstores import FAISS from langchain.embeddings import OpenAIEmbeddings from langchain.chains import RetrievalQA # 加载并保存索引(原逻辑保留) pdf = load_pdf(help_doc_name) faiss_index_ft9Help = FAISS.from_documents(pdf, OpenAIEmbeddings()) faiss_index_ft9Help.save_local(index_path + "/" + help_doc_name) pdf = load_pdf(newsletters_doc_name) faiss_index_newsletters = FAISS.from_documents(pdf, OpenAIEmbeddings()) faiss_index_newsletters.save_local(index_path + "/" + newsletters_doc_name) pdf = load_pdf(supportCases_doc_name) faiss_index_supportCases = FAISS.from_documents(pdf, OpenAIEmbeddings()) faiss_index_supportCases.save_local(index_path + "/" + supportCases_doc_name) # 为每个索引创建独立检索器,可单独调整返回数量 retriever_help = faiss_index_ft9Help.as_retriever(search_kwargs={"k": 3}) retriever_newsletters = faiss_index_newsletters.as_retriever(search_kwargs={"k": 3}) retriever_support = faiss_index_supportCases.as_retriever(search_kwargs={"k": 3}) # 组合成EnsembleRetriever,权重可按需分配 ensemble_retriever = EnsembleRetriever( retrievers=[retriever_help, retriever_newsletters, retriever_support], weights=[0.4, 0.3, 0.3] ) # 创建QA链,开启源文档返回以获取参考页面 qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=ensemble_retriever, verbose=False, return_source_documents=True ) # 问答交互逻辑(新增参考页面输出) while True: question = input("You: ") if question.lower() == "exit": print("Bot: Goodbye!") break result = qa_chain({"query": question}) response = result["result"] source_docs = result["source_documents"] print("Bot: " + response + "\n") print("参考页面:") for doc in source_docs: # 需确保PDF加载时保留source和page元数据,根据实际情况调整 print(f"- 来源:{doc.metadata.get('source', '未知')},页码:{doc.metadata.get('page', '未知')}") print("\n") # 单独使用单个索引进行相似性搜索示例 def search_single_index(index, query): return index.similarity_search(query, k=3) # 调用示例 help_search_results = search_single_index(faiss_index_ft9Help, "你的问题") news_search_results = search_single_index(faiss_index_newsletters, "你的问题") support_search_results = search_single_index(faiss_index_supportCases, "你的问题")
方案二:手动合并FAISS索引(保留原索引副本)
如果不需要动态调整各索引权重,可以直接合并三个FAISS索引,同时保留原始索引副本用于单独搜索。
实现代码
# 加载并保存原始索引(原逻辑保留) # ...(省略原加载代码) # 创建原始索引副本,用于后续单独搜索 faiss_index_ft9Help_copy = FAISS.from_documents(load_pdf(help_doc_name), OpenAIEmbeddings()) faiss_index_newsletters_copy = FAISS.from_documents(load_pdf(newsletters_doc_name), OpenAIEmbeddings()) faiss_index_supportCases_copy = FAISS.from_documents(load_pdf(supportCases_doc_name), OpenAIEmbeddings()) # 合并三个索引 merged_index = faiss_index_ft9Help.merge_from(faiss_index_newsletters) merged_index.merge_from(faiss_index_supportCases) # 创建合并后的检索器用于QA链 merged_retriever = merged_index.as_retriever(search_kwargs={"k": 9}) qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=merged_retriever, verbose=False, return_source_documents=True ) # 问答交互和单独搜索逻辑同方案一 # ...(省略对应代码)
关键注意事项
- 元数据保留:加载PDF时需确保保留
source(来源文件名)和page(页码)元数据,否则无法获取有效参考页面信息。 - 参数优化:根据业务需求调整检索器的
k值(返回结果数量)和EnsembleRetriever的权重,提升问答准确性。 - 索引复用:后续可直接用
FAISS.load_local()加载已保存的索引,避免重复创建,提升运行效率。
内容的提问来源于stack exchange,提问作者Pasindu Lakshan
相关产品推荐
相关产品推荐

