You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 20:12:39