代码中使用了 langchain.memory.ConversationBufferMemorylangchain.chains.ConversationalRetrievalChain 来实现带有对话历史的检索问答(Retrieval-Augmented Generation, RAG),会触发 LangChainDeprecationWarning,提示 ConversationBufferMemory 已废弃,并建议参考迁移指南。本文基于 LangChain 0.3.x,详细解释如何迁移到推荐的对话历史管理方式(langchain_core.runnables.history.RunnableWithMessageHistory),并提供代码示例(结合 ChatOpenAI 和向量存储实现 RAG)。

代码废弃告警:
LangChainDeprecationWarning: Please see the migration guide at: https://python.langchain.com/docs/versions/migrating_memory/
memory = ConversationBufferMemory(memory_key = “chat_history”, return_messages = True) ……


为什么触发 LangChainDeprecationWarning

langchain.memory.ConversationBufferMemorylangchain.chains.ConversationalRetrievalChain 是 LangChain 早期(0.1.x 及之前)的 API,用于管理对话历史和构建检索问答链。然而,随着 LangChain 0.2.x 和 0.3.x 的发展,这些类被废弃,原因包括:

  1. 模块化重构:LangChain 引入了 LangChain Expression Language(LCEL),提供更灵活、统一的链构建方式(如 Runnable)。
  2. 现代化接口RunnableWithMessageHistory 取代 ConversationBufferMemory,支持更强大的历史管理和 LCEL 集成。
  3. 性能与可维护性:旧链(如 ConversationalRetrievalChain)代码复杂,LCEL 链更简洁且易于调试。
  4. 废弃计划ConversationBufferMemoryConversationalRetrievalChain 将在 LangChain 1.0 中移除。

根据迁移指南(LangChain 文档),推荐:

  • 使用 langchain_core.runnables.history.RunnableWithMessageHistory 替代 ConversationBufferMemory
  • 使用 LCEL 组合 ChatPromptTemplateChatOpenAI、向量存储检索器和 StrOutputParser,替代 ConversationalRetrievalChain

迁移目标

假如原始代码实现了一个 RAG 系统:

  • 使用 ConversationBufferMemory 存储对话历史(memory_key="chat_history"return_messages=True 返回消息对象)。
  • 使用 ConversationalRetrievalChain 结合 ChatOpenAI 和向量存储检索器(vectorstore.as_retriever),基于检索到的上下文和历史回答问题。
  • verbose=True 启用日志,方便调试。

迁移后,我们将:

  1. 替换 ConversationBufferMemoryRunnableWithMessageHistoryChatMessageHistory
  2. 替换 ConversationalRetrievalChain 为 LCEL 链,结合 ChatPromptTemplate 和向量存储检索器。
  3. 保持功能等效:支持对话历史、上下文检索和问答。

迁移步骤

以下是将代码从 ConversationBufferMemoryConversationalRetrievalChain 迁移到 LCEL 和 RunnableWithMessageHistory 的详细步骤,假设你使用 OpenAI 的嵌入模型和 Chroma 向量存储。

1. 分析原始代码

代码如下:

import os
os.environ["OPENAI_API_KEY"] = "Your OpenAI API Key"

from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationalRetrievalChain
from langchain_openai import ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings

# 初始化嵌入模型和向量存储
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_texts(
    ["人工智能(AI)是计算机科学的一个分支,专注于创建智能系统。", 
     "机器学习是 AI 的子领域,涉及从数据中学习模型。"],
    embeddings
)

# 初始化对话历史
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)

# 创建 RAG 链
qa = ConversationalRetrievalChain.from_llm(
    ChatOpenAI(temperature=0),
    vectorstore.as_retriever(),
    memory=memory,
    verbose=True
)

# 调用链
result = qa({"question": "什么是人工智能?"})
print(result["answer"])

result = qa({"question": "它包含哪些子领域?"})
print(result["answer"])

输出示例

人工智能(AI)是计算机科学的一个分支,专注于创建能够执行需要人类智能的任务的系统,例如学习、推理和决策。
人工智能包含子领域,如机器学习,涉及从数据中学习模型。

问题

  • from langchain.memory import ConversationBufferMemory 已废弃,需替换为 langchain_community.chat_message_histories.ChatMessageHistorylangchain_core.runnables.history.RunnableWithMessageHistory
  • from langchain.chains import ConversationalRetrievalChain 已废弃,需使用 LCEL 构建等效链。
  • 需要安装 langchain-communitylangchain-core
  • 确保 OPENAI_API_KEY 有效,支持嵌入模型和 LLM。
2. 安装必要依赖

确保安装 LangChain 0.3.x 及其相关依赖:

pip install --upgrade langchain langchain-community langchain-openai langchain-core chromadb

确认 OPENAI_API_KEY 已配置,支持 text-embedding-3-smallgpt-4o-mini

3. 迁移到 LCEL 和 RunnableWithMessageHistory

以下是迁移后的代码,使用 LCEL 和 RunnableWithMessageHistory 重现原功能:

import os
os.environ["OPENAI_API_KEY"] = "Your OpenAI API Key"

from langchain_community.vectorstores import Chroma
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough, RunnableWithMessageHistory
from langchain_community.chat_message_histories import ChatMessageHistory
from operator import itemgetter

# 初始化嵌入模型和向量存储
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_texts(
    ["人工智能(AI)是计算机科学的一个分支,专注于创建智能系统。", 
     "机器学习是 AI 的子领域,涉及从数据中学习模型。"],
    embeddings
)
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})

# 初始化 LLM
llm = ChatOpenAI(temperature=0, model="gpt-4o-mini")

# 定义提示模板
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个助手,根据以下上下文和对话历史回答问题:\n上下文:{context}"),
    MessagesPlaceholder(variable_name="history"),
    ("human", "{question}")
])

# 创建 LCEL 链
runnable = (
    {
       "context": itemgetter("question") | retriever,  # 提取 question 并传递给 retriever
       "question": itemgetter("question"),  # 提取 question 传递给 prompt
       "history": itemgetter("history") | RunnablePassthrough()  # 传递 history
    }
    | prompt
    | llm
    | StrOutputParser()
)

# 初始化消息历史存储
store = {}
def get_session_history(session_id: str) -> ChatMessageHistory:
    if session_id not in store:
        store[session_id] = ChatMessageHistory()
    return store[session_id]

# 创建带历史的链
qa = RunnableWithMessageHistory(
    runnable,
    get_session_history,
    input_messages_key="question",
    history_messages_key="history"
)

# 调用链
session_id = "user1"
response = qa.invoke(
    {"question": "什么是人工智能?"},
    config={"configurable": {"session_id": session_id}}
)
print(response)

response = qa.invoke(
    {"question": "它包含哪些子领域?"},
    config={"configurable": {"session_id": session_id}}
)
print(response)

输出示例

人工智能(AI)是计算机科学的一个分支,专注于创建能够执行需要人类智能的任务的系统,例如学习、推理和决策。
人工智能包含子领域,如机器学习,涉及从数据中学习模型。
代码说明
  1. OpenAI API 密钥
    • 通过 os.environ["OPENAI_API_KEY"] 设置,替换为实际密钥。
    • 确保密钥支持嵌入模型(text-embedding-3-small)和 LLM(gpt-4o-mini)。
  2. 导入替换
    • 使用 langchain_community.chat_message_histories.ChatMessageHistorylangchain_core.runnables.history.RunnableWithMessageHistory 替代 ConversationBufferMemory
    • 使用 LCEL(RunnablePassthrough, ChatPromptTemplate, StrOutputParser)替代 ConversationalRetrievalChain
  3. 向量存储
    • Chroma.from_texts 创建向量存储,retriever 搜索相关文档(k=2 返回 2 个结果)。
  4. 提示模板
    • ChatPromptTemplate 包含系统消息(带上下文)、历史消息(MessagesPlaceholder)和用户问题。
    • MessagesPlaceholder(variable_name="history") 插入对话历史。
  5. LCEL 链
    • { "context": itemgetter("question") | retriever,"question": itemgetter("question"),"history": itemgetter("history") | RunnablePassthrough() } 并行检索上下文和传递问题。
    • prompt | llm | StrOutputParser 生成回答并解析为字符串。
  6. 对话历史
    • ChatMessageHistory 存储消息,storesession_id 区分会话。
    • RunnableWithMessageHistory 包装链,自动管理历史。
  7. 调用
    • 输入为字典({"question": "..."}),session_id 保持会话一致。
    • 输出为字符串,与原代码的 result["answer"] 等效。
  8. 调试
    • 原代码的 verbose=True 效果可通过设置 langchain.debug = True 或自定义日志实现:
      import langchain
      langchain.debug = True
      
4. 功能等效性
  • 对话历史RunnableWithMessageHistory 完全替代 ConversationBufferMemory,支持 return_messages=True 的消息格式。
  • RAG 功能:LCEL 链通过 retrieverprompt 实现与 ConversationalRetrievalChain 相同的检索问答逻辑。
  • 输入/输出:新链接受 {"question": "..."} 输入,返回字符串输出,与原代码一致。
  • 上下文管理MessagesPlaceholderChatMessageHistory 确保历史和上下文正确传递。
5. 自动迁移(可选)

LangChain 提供 CLI 工具自动升级废弃导入和内存管理:

  1. 安装 LangChain CLI:
    pip install langchain-cli
    
  2. 运行迁移命令:
    langchain migrate
    
  3. 按提示扫描代码,工具会将 ConversationBufferMemoryConversationalRetrievalChain 替换为新 API。

注意

  • 迁移工具可能无法完全处理复杂链(如 ConversationalRetrievalChain 的逻辑),建议手动迁移并验证。
  • 确保安装 langchain-communitylangchain-core 以支持新 API。
6. 测试与验证
  • 依赖
    • 确认已安装 langchain, langchain-community, langchain-openai, langchain-core, 和 chromadb
    • 验证 OPENAI_API_KEY 有效,支持嵌入模型和 LLM。
  • 运行
    • 测试向量存储创建,确认文档嵌入正确。
    • 测试多轮问答,验证对话历史保留(例如第二轮问题依赖第一轮上下文)。
    • 比较输出与原代码,确保功能一致。
  • Chroma 配置
    • 默认使用内存存储,生产环境可设置持久化路径:
      vectorstore = Chroma.from_texts(texts, embeddings, persist_directory="./chroma_db")
      

注意事项

  1. API 密钥安全
    • 避免硬编码密钥,推荐使用 .env 文件:
      from dotenv import load_dotenv
      load_dotenv()  # 加载 OPENAI_API_KEY
      
    • 确保密钥支持嵌入模型(text-embedding-3-small)和 LLM(gpt-4o-mini)。
  2. 嵌入模型选择
    • text-embedding-3-small:1536 维,成本低,适合大多数场景。
    • text-embedding-3-large:3072 维,精度更高,成本更高。
    • text-embedding-ada-002:旧模型,仍广泛使用。
  3. 对话历史管理
    • ChatMessageHistory 是内存存储,生产环境可替换为持久化存储(如 SQLChatMessageHistory):
      from langchain_community.chat_message_histories import SQLChatMessageHistory
      def get_session_history(session_id: str) -> SQLChatMessageHistory:
          return SQLChatMessageHistory(session_id=session_id, connection_string="sqlite:///history.db")
      
  4. 性能
    • 检索速度依赖文档数量和 Chroma 配置,优化 search_kwargs(如 k)可平衡精度和速度。
    • LLM 调用速度依赖 API,批量处理可提高效率。
  5. Ollama 替代
    • 若想避免 OpenAI API 费用,可使用 langchain_ollama
      from langchain_ollama import ChatOllama, OllamaEmbeddings
      embeddings = OllamaEmbeddings(model="nomic-embed-text")
      llm = ChatOllama(model="qwen3:1.7b")
      

常见问题

Q1:可以继续使用 ConversationBufferMemoryConversationalRetrievalChain 吗?
A:可以,但不建议。它们已废弃,迁移到 LCEL 和 RunnableWithMessageHistory 更安全且现代化。

Q2:新旧 API 功能有差异吗?
A:功能等效,新 API(LCEL 和 RunnableWithMessageHistory)更灵活,支持流式、异步和复杂链。

Q3:如何调试 LCEL 链?
A:设置 langchain.debug = True 查看详细日志,或单独调用链的组件(如 retriever.invoke(), prompt.invoke())检查中间输出。

Q4:如何优化 RAG 性能?
A:调整检索器的 k 参数、使用更高效的嵌入模型(如 text-embedding-3-small)、优化提示模板,或启用流式输出(chain.stream())。


总结

ConversationBufferMemoryConversationalRetrievalChain 迁移到 LCEL 和 RunnableWithMessageHistory 的步骤包括:

  1. 安装 langchain, langchain-community, langchain-openai, langchain-core, 和 chromadb
  2. 替换 ConversationBufferMemoryChatMessageHistoryRunnableWithMessageHistory
  3. 替换 ConversationalRetrievalChain 为 LCEL 链(retriever | prompt | llm | StrOutputParser)。
  4. 设置 OPENAI_API_KEY,确保支持嵌入模型和 LLM。
  5. 使用 ChatPromptTemplateMessagesPlaceholder 管理上下文和历史。
  6. 可选使用 LangChain CLI(langchain migrate)自动升级导入。
  7. 可选使用 langchain_ollama 替代 OpenAI 模型。
Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐