使用LangChain实现PDF对话时的历史上下文记忆问题求助
解决FastAPI接口对话上下文记忆问题
核心思路
要处理“我之前问了什么?”这类跟进问题,关键是给每个请求绑定对话历史,把历史上下文和当前问题拼接后,再送入模型生成回答。可以通过会话ID区分不同用户的对话,把历史暂存到内存(生产环境建议用Redis这类持久化存储)中。
具体修改步骤
1. 新增对话历史存储结构
用Python字典存储会话ID对应的对话历史,每条历史包含用户提问和AI回答:
# 全局内存存储对话历史,生产环境建议替换为Redis/MongoDB conversation_history = {}
2. 修改/process接口的请求参数
新增session_id参数(可用UUID或用户自定义标识),用来关联同一用户的对话:
from pydantic import BaseModel, Field from fastapi import FastAPI, File, UploadFile, HTTPException import faiss from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.embeddings.openai import OpenAIEmbeddings from langchain.vectorstores import FAISS from langchain.chat_models import ChatOpenAI from langchain.chains import RetrievalQA from PyPDF2 import PdfReader import uuid app = FastAPI() # 全局变量存储FAISS索引和对话历史 db = None conversation_history = {} class ProcessRequest(BaseModel): # 可选:自动生成UUID作为默认会话ID,降低前端传参成本 session_id: str = Field(default_factory=lambda: str(uuid.uuid4())) question: str
3. 拼接上下文并更新对话历史
处理问题前,先取出对应会话的历史,把历史格式化成上下文文本,和当前问题组合后再查询模型:
@app.post("/process") async def process_request(req: ProcessRequest): global db if not db: raise HTTPException(status_code=400, detail="还未上传PDF文件") # 初始化新会话的历史 if req.session_id not in conversation_history: conversation_history[req.session_id] = [] # 拼接对话上下文 context_content = "" if conversation_history[req.session_id]: for turn in conversation_history[req.session_id]: context_content += f"用户:{turn['user']}\nAI:{turn['answer']}\n" # 组合带上下文的完整问题 full_question = f"之前的对话历史:\n{context_content}\n当前用户问题:{req.question}\n请结合对话历史和已上传的PDF内容回答,不要脱离上下文。" # 调用RetrievalQA生成回答 qa_chain = RetrievalQA.from_chain_type( llm=ChatOpenAI(temperature=0), chain_type="stuff", retriever=db.as_retriever(search_kwargs={"k": 3}), return_source_documents=True ) result = qa_chain({"query": full_question}) answer = result["result"] # 更新当前会话的历史 conversation_history[req.session_id].append({ "user": req.question, "answer": answer }) return {"answer": answer}
4. (可选)新增会话历史清理接口
如果需要手动清理指定会话的历史,可添加以下接口:
@app.delete("/clear-history") async def clear_history(session_id: str): if session_id in conversation_history: del conversation_history[session_id] return {"message": f"会话{session_id}的历史已清理"} else: raise HTTPException(status_code=404, detail="该会话不存在")
5. 生产环境注意事项
- 内存存储的对话历史仅适用于单进程单实例服务,分布式场景必须用Redis、MongoDB这类外部存储,避免重启服务丢失数据。
- 要限制对话历史的最大轮数(比如只保留最近5轮),防止上下文过长导致模型处理效率下降。
内容的提问来源于stack exchange,提问作者Parth Adhikari
相关产品推荐
相关产品推荐

