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

基于Langchain的ChatPDF应用:历史会话恢复与上下文记忆问题

解决方案:RAG ChatPDF 会话上下文持久化与历史导航实现

一、修复现有两种方法的问题

1. 解决Prompt模板加入历史后的Missing some input keys: {'context'}错误

这个错误的核心是RAG流程中未保证每次请求都检索PDF上下文并传入Prompt。当你把历史加入Prompt后,Chain的输入变量需要包含history、question和context,但二次提问时可能遗漏了触发Retriever获取context的步骤。

修复步骤:

  • 确保Prompt模板明确包含三个变量:history(会话历史)、context(PDF检索结果)、question(当前提问)
  • 构建Chain时,将Retriever的输出与Memory的历史、当前提问串联,保证context始终被传入LLM

示例Prompt模板:

from langchain.prompts import PromptTemplate

prompt = PromptTemplate(
    input_variables=["history", "context", "question"],
    template="""
    你是一个基于PDF文档的问答助手,根据以下信息回答用户问题:
    会话历史:{history}
    PDF文档上下文:{context}
    当前问题:{question}
    请结合会话历史和PDF上下文,给出准确的回答。
    """
)

2. 解决ConversationBufferMemory重启后上下文丢失问题

ConversationBufferMemory是内存存储,重启后数据清空。需要改用持久化的ChatMessageHistory,将会话历史存储到MongoDB中,再关联到Memory类。

示例代码:

from langchain.memory import ConversationBufferMemory
from langchain.mongodb.chat_message_histories import MongoDBChatMessageHistory

# 初始化MongoDB聊天历史存储
chat_history = MongoDBChatMessageHistory(
    session_id="your_session_id",
    connection_string="mongodb://localhost:27017/",
    database_name="chatpdf_db",
    collection_name="chat_histories"
)

# 绑定持久化历史到Memory
memory = ConversationBufferMemory(
    chat_memory=chat_history,
    memory_key="history",
    input_key="question",
    return_messages=False  # 按字符串返回历史,适配Prompt模板
)

二、实现会话历史导航功能

要实现类似ChatGPT的会话恢复,需要完成以下核心步骤:

1. 会话标识管理

为每个会话生成唯一的session_id(比如UUID),前端展示会话列表时,将每个会话名称与对应的session_id绑定。

2. 加载指定会话的历史

当用户选择某条历史会话时,通过session_id从MongoDB加载对应的聊天历史,重新初始化Memory和Chain:

def load_session_history(session_id: str):
    # 根据session_id加载MongoDB中的历史
    chat_history = MongoDBChatMessageHistory(
        session_id=session_id,
        connection_string="mongodb://localhost:27017/",
        database_name="chatpdf_db",
        collection_name="chat_histories"
    )
    # 重新初始化Memory
    memory = ConversationBufferMemory(
        chat_memory=chat_history,
        memory_key="history",
        input_key="question",
        return_messages=False
    )
    return memory

3. 构建完整的RAG Chain

将Retriever、Memory、Prompt模板整合到Chain中,确保每次请求既检索PDF上下文,又加载会话历史:

from langchain.chains import RetrievalQAWithSourcesChain
from langchain.llms import OpenAI
from langchain.vectorstores import Chroma

# 初始化Chroma向量库
chroma_db = Chroma(persist_directory="./chroma_db", embedding_function=your_embedding_func)
retriever = chroma_db.as_retriever()

# 加载指定会话的Memory
memory = load_session_history("target_session_id")

# 构建带Memory的RAG Chain
chain = RetrievalQAWithSourcesChain.from_llm(
    llm=OpenAI(temperature=0),
    retriever=retriever,
    memory=memory,
    prompt=prompt,
    return_source_documents=True
)

# 发起提问,自动携带会话历史和PDF上下文
response = chain({"question": "你的问题"})

4. 会话列表展示

从MongoDB中查询所有session_id及对应会话的第一条/最后一条消息,生成会话列表供用户选择:

from pymongo import MongoClient

client = MongoClient("mongodb://localhost:27017/")
db = client["chatpdf_db"]
collection = db["chat_histories"]

# 查询所有会话的session_id和最近一条消息
sessions = collection.aggregate([
    {"$group": {
        "_id": "$session_id",
        "last_message": {"$last": "$content"},
        "created_at": {"$first": "$created_at"}
    }},
    {"$sort": {"created_at": -1}}
])

# 转换为前端可用的会话列表
session_list = [{"session_id": item["_id"], "last_msg": item["last_message"]} for item in sessions]

关键注意事项

  • 确保每个会话的session_id唯一,避免历史混淆
  • MongoDB存储聊天记录时,需包含session_id、role(user/assistant)、content、created_at等字段
  • 当用户切换会话时,需重新初始化Chain,确保使用对应会话的Memory
  • 大模型的上下文窗口有限,过长的会话历史可能需要做摘要处理,避免超出Token限制

内容的提问来源于stack exchange,提问作者usama hussain

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 03:16:28