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

Langchain ConversationalRetrievalChain无法兼顾上下文与对话记忆问题

问题描述

我要做一个基于PDF上下文的HR领域ConversationalRetrievalChain聊天机器人,遇到两个矛盾问题:

  • 版本V1:能正常调用vectorstore里的上下文回答问题,但对话记忆失效,问「我上一个问题是什么」时返回「我不知道」。原因是每次循环都重新创建memory和conv_chain,之前的对话记录被覆盖。
  • 版本V2:把memory和conv_chain移到函数外后,对话记忆生效了,但机器人没法再用vectorstore的上下文回答问题。
问题根源
  1. V1中每次调用querying_V1都重新初始化ConversationBufferMemory和ConversationalRetrievalChain,对话记忆无法持久化。
  2. V2中同时手动维护chat_history列表和使用内置memory,两者冲突;且get_chat_history的lambda函数未正确格式化对话历史,导致prompt无法读取有效历史内容。
  3. 手动传入chat_history参数会覆盖memory中的内容,导致chain无法同时利用vectorstore上下文和对话历史。
解决方案

核心思路:让ConversationalRetrievalChain的内置memory自动管理对话历史,无需手动维护chat_history;同时确保prompt能正确读取context和chat_history变量。

修正后的代码

from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationalRetrievalChain
from langchain.prompts import PromptTemplate
import sys

# 调整prompt模板,适配对话历史的格式化输出
template2 = """
Your name is Bot.
You are a chatbot specialized in human resources. 
Use the following context (delimited by <ctx></ctx>) to answer the questions.
Use the previous conversation history (delimited by <hs></hs>) to understand context and answer follow-up questions.
If you don't know the answer just answer that you don't know. 
------
<ctx>
{context}
</ctx>
------
<hs>
{chat_history}
</hs>
------
Question:
{question} 
"""

prompt2 = PromptTemplate(
    template=template2, 
    input_variables=["context", "chat_history", "question"]
)

# 将memory和conv_chain初始化放在循环外部,避免每次重置
memory = ConversationBufferMemory(
    memory_key="chat_history", 
    return_messages=True, 
    output_key='answer'
)

conv_chain = ConversationalRetrievalChain.from_llm(
    llm=llm,
    chain_type="stuff",
    retriever=vectorstore.as_retriever(search_kwargs={"k": 2}), 
    memory=memory,
    combine_docs_chain_kwargs={"prompt": prompt2},
    output_key='answer',
    # 自定义历史格式化函数,把Message对象转换成易读的对话格式
    get_chat_history=lambda h: "\n".join([f"Human: {msg.content}" if msg.type == "human" else f"Bot: {msg.content}" for msg in h]),
    verbose=False
)

def querying_V3(query: str):
    # 无需手动传入chat_history,memory会自动处理历史记录
    result = conv_chain({"question": query})
    return result["answer"].strip()

# 主循环:不再手动维护chat_history列表
while True:
    query = input("Prompt: ")
    if query == "q":
         sys.exit()
    result = querying_V3(query)
    print("\n" + result)

关键修正点

  • Memory持久化:把memory和conv_chain的初始化放到循环外部,确保对话历史不会每次被重置。
  • 移除手动历史维护:取消手动创建和appendchat_history列表,让ConversationBufferMemory自动管理对话记录。
  • 历史格式适配:自定义get_chat_history函数,将memory存储的Message对象转换成「Human: XXX\nBot: XXX」的字符串格式,让prompt能正确识别对话历史。
  • prompt逻辑优化:调整模板中对对话历史的描述,明确告知LLM要结合历史和上下文回答问题。
验证效果
  1. 先问一个基于PDF的问题(比如「公司的年假政策是什么?」),机器人会调用vectorstore上下文给出答案。
  2. 再问「我刚才问了什么?」,机器人能正确回忆起上一个问题,对话记忆生效。
  3. 后续跟进问题(比如「这个政策适用于新员工吗?」)会同时结合之前的对话历史和vectorstore上下文回答。

内容的提问来源于stack exchange,提问作者Jorge Mendes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 11:54:53