如何让基于LangChain的自定义数据聊天机器人具备联网访问能力?
问题分析
你的代码存在几个核心问题导致错误提示出现:
- 无效的文档传入逻辑:
ConversationalRetrievalChain不会使用你传入的documents参数,它完全依赖初始化时指定的retriever来获取相关文档,你手动合并本地文档和搜索结果的操作没有任何作用。 - 聊天历史格式错误:
chat_history要求每个元素是(用户问题, 助手回答)的元组,你当前用("system", query)的格式会导致链无法正确识别历史上下文。 - 多余的Embedding生成代码:
DocArrayInMemorySearch.from_documents会自动处理文档的Embedding生成,你手动循环生成Embedding的代码属于冗余操作,且没有被使用。 - 缺少本地检索失败后的降级逻辑:当前链只会从本地检索结果生成回答,没有设置当本地无相关信息时自动调用互联网搜索的机制。
解决方案
以下是修正后的完整代码,实现优先查询本地自定义数据,本地无结果时自动联网补充的逻辑:
from langchain.chains import ConversationalRetrievalChain, RetrievalQA from langchain.memory import ConversationBufferMemory from langchain.vectorstores import DocArrayInMemorySearch from langchain.embeddings.openai import OpenAIEmbeddings from langchain.document_loaders import ( UnstructuredWordDocumentLoader, TextLoader, UnstructuredPowerPointLoader, ) from langchain.utilities import GoogleSearchAPIWrapper from langchain.chat_models import ChatOpenAI from langchain.tools import Tool from langchain.agents import initialize_agent, AgentType import os import sys from dotenv import load_dotenv, find_dotenv sys.path.append('../..') _ = load_dotenv(find_dotenv()) # 初始化环境变量 openai.api_key = os.environ['OPENAI_API_KEY'] os.environ["LANGCHAIN_TRACING_V2"] = "true" os.environ["LANGCHAIN_ENDPOINT"] = "https://api.langchain.plus" os.environ["LANGCHAIN_API_KEY"] = os.environ['LANGCHAIN_API_KEY'] os.environ["GOOGLE_API_KEY"] = os.environ.get("GOOGLE_API_KEY") os.environ["GOOGLE_CSE_ID"] = os.environ.get("GOOGLE_CSE_ID") # 加载本地文档 folder_path_docx = "DB\\DB VARIADO\\DOCS" folder_path_txt = "DB\\BLOG-POSTS" folder_path_pptx_1 = "DB\\PPT JUNIO" folder_path_pptx_2 = "DB\\DB VARIADO\\PPTX" loaded_content = [] # 加载DOCX for file in os.listdir(folder_path_docx): if file.endswith(".docx"): loader = UnstructuredWordDocumentLoader(os.path.join(folder_path_docx, file)) loaded_content.extend(loader.load()) # 加载TXT for file in os.listdir(folder_path_txt): if file.endswith(".txt"): loader = TextLoader(os.path.join(folder_path_txt, file), encoding='utf-8') loaded_content.extend(loader.load()) # 加载PPTX for folder in [folder_path_pptx_1, folder_path_pptx_2]: for file in os.listdir(folder): if file.endswith(".pptx"): loader = UnstructuredPowerPointLoader(os.path.join(folder, file)) loaded_content.extend(loader.load()) # 创建本地向量库与检索器 embedding = OpenAIEmbeddings() db = DocArrayInMemorySearch.from_documents(loaded_content, embedding) retriever = db.as_retriever(search_type="similarity", search_kwargs={"k": 3}) # 初始化本地检索链 local_chain = RetrievalQA.from_llm( llm=ChatOpenAI(model_name="gpt-4", temperature=0), retriever=retriever, return_source_documents=True ) # 初始化谷歌搜索工具 search = GoogleSearchAPIWrapper() search_tool = Tool( name="Google Search", func=search.run, description="当本地文档无法回答问题时,使用该工具联网搜索最新信息" ) # 初始化对话记忆 memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True) # 初始化代理,整合本地检索和搜索工具 agent = initialize_agent( tools=[search_tool], llm=ChatOpenAI(model_name="gpt-4", temperature=0), agent=AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION, memory=memory, verbose=True ) # 对话循环 while True: query = input("Hola, soy Chatbot. ¿Qué te gustaría saber? ") # 先尝试本地检索 local_response = local_chain({"query": query}) local_answer = local_response["result"] # 判断本地是否给出有效回答(根据错误提示关键词判断) if "The text does not provide information on" in local_answer: # 本地无结果,调用代理使用搜索工具 final_answer = agent.run(f"回答以下问题:{query}") else: # 本地有结果,直接使用 final_answer = local_answer print(final_answer)
关键改进点
- 移除冗余代码:删除了手动生成Embedding的循环,简化文档加载逻辑。
- 新增本地-搜索降级逻辑:先调用本地检索链,通过错误关键词判断是否需要触发联网搜索。
- 使用Agent整合工具:通过
ChatConversationalAgent实现工具的智能调用,同时保留对话记忆。 - 修正历史格式:使用
ConversationBufferMemory自动管理对话历史,无需手动维护元组列表。
内容的提问来源于stack exchange,提问作者Zaesar
相关产品推荐
相关产品推荐

