基于LangChain/LlamaIndex实现仅依赖输入文档的带记忆聊天机器人咨询
实现符合要求的ChatBot:LangChain方案指南
一、LangChain确实更易实现"仅依赖文档回答"的需求
不用修改源码文件,直接通过自定义prompt和配置检索链就能灵活实现,比改内置prompt文件靠谱得多,步骤也更清晰。
二、具体实现步骤
1. 文档加载与预处理
先把目标文档加载进来,分割成合适的文本块,再存入向量数据库方便检索:
from langchain.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.vectorstores import Chroma from langchain.embeddings import OpenAIEmbeddings # 加载PDF文档(其他格式可换对应Loader) loader = PyPDFLoader("你的文档路径.pdf") documents = loader.load() # 分割文本块,兼顾上下文连贯性 text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200) text_chunks = text_splitter.split_documents(documents) # 存入Chroma向量库,用OpenAI嵌入模型生成向量 vector_store = Chroma.from_documents(documents=text_chunks, embedding=OpenAIEmbeddings()) retriever = vector_store.as_retriever(search_kwargs={"k": 3}) # 每次取3个最相关的文本块
2. 配置对话记忆
用LangChain的记忆组件实现对话上下文留存,这里用最基础的ConversationBufferMemory:
from langchain.memory import ConversationBufferMemory memory = ConversationBufferMemory( memory_key="chat_history", return_messages=True # 以消息列表形式返回历史对话,适配Chat模型 )
3. 构建带严格约束的对话检索链
核心是自定义prompt,明确告诉模型只能用检索到的上下文回答,没信息就返回"I don't know",同时把记忆和检索器整合起来:
from langchain.chains import ConversationalRetrievalChain from langchain.chat_models import ChatOpenAI from langchain.prompts import PromptTemplate # 自定义prompt模板,把约束写死 custom_prompt = PromptTemplate( input_variables=["chat_history", "context", "question"], template=""" 历史对话记录:{chat_history} 参考上下文:{context} 用户问题:{question} 请严格按照以下规则回答: 1. 只能使用上面提供的参考上下文信息,绝对不能编造内容; 2. 如果上下文里完全找不到和问题相关的内容,直接回复"I don't know"; 3. 回答要简洁准确,不要冗余。 """ ) # 初始化对话链,把所有组件拼起来 qa_chain = ConversationalRetrievalChain.from_llm( llm=ChatOpenAI(temperature=0), # 温度设0,最大程度减少模型编造 retriever=retriever, memory=memory, combine_docs_chain_kwargs={"prompt": custom_prompt}, verbose=True # 可选,打印链的运行过程方便调试 ) # 测试对话 result = qa_chain({"question": "文档里关于XX的说明是什么?"}) print(result["answer"])
4. 为啥改prompt.py没生效?
LangChain的agent/链初始化时,默认会加载内置的prompt模板,但直接修改源码文件可能因为虚拟环境缓存、动态加载逻辑等原因不生效。正确做法是在代码里自定义prompt并传入组件,而不是改底层文件。
三、如果你想继续用LlamaIndex实现第三点
其实也不用换框架,给LlamaIndex的QueryEngine加个自定义的回答模板就行:
from llama_index import ResponseSynthesizer from llama_index.prompts import PromptTemplate # 定义约束性的回答模板 response_template = PromptTemplate( "请根据以下上下文回答问题,只能使用上下文里的信息,没有相关内容请回复'I don't know'。\n上下文:{context_str}\n问题:{query_str}\n回答:" ) # 初始化ResponseSynthesizer,把模板传进去 response_synthesizer = ResponseSynthesizer.from_args( text_qa_template=response_template, response_mode="compact" ) # 把自定义的synthesizer绑定到你的QueryEngine query_engine = index.as_query_engine(response_synthesizer=response_synthesizer) # 测试查询 response = query_engine.query("文档里有没有提到XX?") print(response)
内容的提问来源于stack exchange,提问作者Carlo
相关产品推荐
相关产品推荐

