从 ConversationBufferMemory 或 ConversationStringBufferMemory 迁移
ConversationBufferMemory 和 ConversationStringBufferMemory 用于跟踪人类与 AI 助手之间的对话,而无需任何额外处理。
ConversationStringBufferMemory
相当于 ConversationBufferMemory
,但针对的是不是聊天模型的大型语言模型(LLMs)。
使用现有现代原语处理对话历史的方法有:
- 使用 LangGraph 持久化 以及对消息历史的适当处理
- 使用 LCEL 与 RunnableWithMessageHistory 结合对消息历史的适当处理。
大多数用户会发现 LangGraph 持久化 比等效的 LCEL 更易于使用和配置,特别是对于更复杂的用例。
设置
%%capture --no-stderr
%pip install --upgrade --quiet langchain-openai langchain
import os
from getpass import getpass
if "OPENAI_API_KEY" not in os.environ:
os.environ["OPENAI_API_KEY"] = getpass()
与LLMChain / ConversationChain的使用
本节展示如何从与LLMChain
或ConversationChain
一起使用的ConversationBufferMemory
或ConversationStringBufferMemory
迁移。
旧版
以下是ConversationBufferMemory
与LLMChain
或等效的ConversationChain
的示例用法。
Details
<!--IMPORTS:[{"imported": "LLMChain", "source": "langchain.chains", "docs": "https://python.langchain.com/api_reference/langchain/chains/langchain.chains.llm.LLMChain.html", "title": "Migrating off ConversationBufferMemory or ConversationStringBufferMemory"}, {"imported": "ConversationBufferMemory", "source": "langchain.memory", "docs": "https://python.langchain.com/api_reference/langchain/memory/langchain.memory.buffer.ConversationBufferMemory.html", "title": "Migrating off ConversationBufferMemory or ConversationStringBufferMemory"}, {"imported": "SystemMessage", "source": "langchain_core.messages", "docs": "https://python.langchain.com/api_reference/core/messages/langchain_core.messages.system.SystemMessage.html", "title": "Migrating off ConversationBufferMemory or ConversationStringBufferMemory"}, {"imported": "ChatPromptTemplate", "source": "langchain_core.prompts", "docs": "https://python.langchain.com/api_reference/core/prompts/langchain_core.prompts.chat.ChatPromptTemplate.html", "title": "Migrating off ConversationBufferMemory or ConversationStringBufferMemory"}, {"imported": "ChatPromptTemplate", "source": "langchain_core.prompts.chat", "docs": "https://python.langchain.com/api_reference/core/prompts/langchain_core.prompts.chat.ChatPromptTemplate.html", "title": "Migrating off ConversationBufferMemory or ConversationStringBufferMemory"}, {"imported": "HumanMessagePromptTemplate", "source": "langchain_core.prompts.chat", "docs": "https://python.langchain.com/api_reference/core/prompts/langchain_core.prompts.chat.HumanMessagePromptTemplate.html", "title": "Migrating off ConversationBufferMemory or ConversationStringBufferMemory"}, {"imported": "MessagesPlaceholder", "source": "langchain_core.prompts.chat", "docs": "https://python.langchain.com/api_reference/core/prompts/langchain_core.prompts.chat.MessagesPlaceholder.html", "title": "Migrating off ConversationBufferMemory or ConversationStringBufferMemory"}, {"imported": "ChatOpenAI", "source": "langchain_openai", "docs": "https://python.langchain.com/api_reference/openai/chat_models/langchain_openai.chat_models.base.ChatOpenAI.html", "title": "Migrating off ConversationBufferMemory or ConversationStringBufferMemory"}]-->
from langchain.chains import LLMChain
from langchain.memory import ConversationBufferMemory
from langchain_core.messages import SystemMessage
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.prompts.chat import (
ChatPromptTemplate,
HumanMessagePromptTemplate,
MessagesPlaceholder,
)
from langchain_openai import ChatOpenAI
prompt = ChatPromptTemplate(
[
MessagesPlaceholder(variable_name="chat_history"),
HumanMessagePromptTemplate.from_template("{text}"),
]
)
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
legacy_chain = LLMChain(
llm=ChatOpenAI(),
prompt=prompt,
memory=memory,
)
legacy_result = legacy_chain.invoke({"text": "my name is bob"})
print(legacy_result)
legacy_result = legacy_chain.invoke({"text": "what was my name"})
{'text': 'Hello Bob! How can I assist you today?', 'chat_history': [HumanMessage(content='my name is bob', additional_kwargs={}, response_metadata={}), AIMessage(content='Hello Bob! How can I assist you today?', additional_kwargs={}, response_metadata={})]}
legacy_result["text"]
'Your name is Bob. How can I assist you today, Bob?'
请注意,单个内存对象中不支持分离对话线程
LangGraph
下面的示例展示了如何使用LangGraph实现带有ConversationBufferMemory
的ConversationChain
或LLMChain
。
本示例假设您对LangGraph
已有一定了解。如果您不熟悉,请参阅LangGraph快速入门指南以获取更多详细信息。
LangGraph
提供了许多额外功能(例如,时间旅行和中断),并且适用于其他更复杂(和现实)的架构。
Details
<!--IMPORTS:[{"imported": "HumanMessage", "source": "langchain_core.messages", "docs": "https://python.langchain.com/api_reference/core/messages/langchain_core.messages.human.HumanMessage.html", "title": "Migrating off ConversationBufferMemory or ConversationStringBufferMemory"}]-->
import uuid
from IPython.display import Image, display
from langchain_core.messages import HumanMessage
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import START, MessagesState, StateGraph
# Define a new graph
workflow = StateGraph(state_schema=MessagesState)
# Define a chat model
model = ChatOpenAI()
# Define the function that calls the model
def call_model(state: MessagesState):
response = model.invoke(state["messages"])
# We return a list, because this will get added to the existing list
return {"messages": response}
# Define the two nodes we will cycle between
workflow.add_edge(START, "model")
workflow.add_node("model", call_model)
# Adding memory is straight forward in langgraph!
memory = MemorySaver()
app = workflow.compile(
checkpointer=memory
)
# The thread id is a unique key that identifies
# this particular conversation.
# We'll just generate a random uuid here.
# This enables a single application to manage conversations among multiple users.
thread_id = uuid.uuid4()
config = {"configurable": {"thread_id": thread_id}}
input_message = HumanMessage(content="hi! I'm bob")
for event in app.stream({"messages": [input_message]}, config, stream_mode="values"):
event["messages"][-1].pretty_print()
# Here, let's confirm that the AI remembers our name!
input_message = HumanMessage(content="what was my name?")
for event in app.stream({"messages": [input_message]}, config, stream_mode="values"):
event["messages"][-1].pretty_print()
================================[1m Human Message [0m=================================
hi! I'm bob
==================================[1m Ai Message [0m==================================
Hello Bob! How can I assist you today?
================================[1m Human Message [0m=================================
what was my name?
==================================[1m Ai Message [0m==================================
Your name is Bob. How can I help you today, Bob?
LCEL RunnableWithMessageHistory
或者,如果您有一个简单的链,可以将链的聊天模型包装在 RunnableWithMessageHistory 中。
有关更多信息,请参阅以下 迁移指南。
与预构建代理的使用
此示例展示了如何使用使用 create_tool_calling_agent 函数构建的预构建代理的代理执行器。
如果您正在使用其中一个 旧的 LangChain 预构建代理,您应该能够 用新的 langgraph 预构建代理 替换该代码,该代理利用 聊天模型的原生工具调用能力,并且可能会更好地开箱即用。
旧版用法
Details
<!--IMPORTS:[{"imported": "AgentExecutor", "source": "langchain.agents", "docs": "https://python.langchain.com/api_reference/langchain/agents/langchain.agents.agent.AgentExecutor.html", "title": "Migrating off ConversationBufferMemory or ConversationStringBufferMemory"}, {"imported": "create_tool_calling_agent", "source": "langchain.agents", "docs": "https://python.langchain.com/api_reference/langchain/agents/langchain.agents.tool_calling_agent.base.create_tool_calling_agent.html", "title": "Migrating off ConversationBufferMemory or ConversationStringBufferMemory"}, {"imported": "ConversationBufferMemory", "source": "langchain.memory", "docs": "https://python.langchain.com/api_reference/langchain/memory/langchain.memory.buffer.ConversationBufferMemory.html", "title": "Migrating off ConversationBufferMemory or ConversationStringBufferMemory"}, {"imported": "tool", "source": "langchain_core.tools", "docs": "https://python.langchain.com/api_reference/core/tools/langchain_core.tools.convert.tool.html", "title": "Migrating off ConversationBufferMemory or ConversationStringBufferMemory"}, {"imported": "ChatOpenAI", "source": "langchain_openai", "docs": "https://python.langchain.com/api_reference/openai/chat_models/langchain_openai.chat_models.base.ChatOpenAI.html", "title": "Migrating off ConversationBufferMemory or ConversationStringBufferMemory"}]-->
from langchain import hub
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain.memory import ConversationBufferMemory
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
model = ChatOpenAI(temperature=0)
@tool
def get_user_age(name: str) -> str:
"""Use this tool to find the user's age."""
# This is a placeholder for the actual implementation
if "bob" in name.lower():
return "42 years old"
return "41 years old"
tools = [get_user_age]
prompt = ChatPromptTemplate.from_messages(
[
("placeholder", "{chat_history}"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
]
)
# Construct the Tools agent
agent = create_tool_calling_agent(model, tools, prompt)
# Instantiate memory
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
# Create an agent
agent = create_tool_calling_agent(model, tools, prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
memory=memory, # Pass the memory to the executor
)
# Verify that the agent can use tools
print(agent_executor.invoke({"input": "hi! my name is bob what is my age?"}))
print()
# Verify that the agent has access to conversation history.
# The agent should be able to answer that the user's name is bob.
print(agent_executor.invoke({"input": "do you remember my name?"}))
{'input': 'hi! my name is bob what is my age?', 'chat_history': [HumanMessage(content='hi! my name is bob what is my age?', additional_kwargs={}, response_metadata={}), AIMessage(content='Bob, you are 42 years old.', additional_kwargs={}, response_metadata={})], 'output': 'Bob, you are 42 years old.'}
{'input': 'do you remember my name?', 'chat_history': [HumanMessage(content='hi! my name is bob what is my age?', additional_kwargs={}, response_metadata={}), AIMessage(content='Bob, you are 42 years old.', additional_kwargs={}, response_metadata={}), HumanMessage(content='do you remember my name?', additional_kwargs={}, response_metadata={}), AIMessage(content='Yes, your name is Bob.', additional_kwargs={}, response_metadata={})], 'output': 'Yes, your name is Bob.'}
LangGraph
您可以按照标准 LangChain 教程 构建代理 来深入了解其工作原理。
这个示例在这里明确展示,以便用户更容易比较传统实现与相应的LangGraph实现。
这个示例展示了如何在LangGraph中为预构建的React代理添加记忆。
有关更多详细信息,请参阅LangGraph中的如何为预构建的ReAct代理添加记忆指南。
Details
<!--IMPORTS:[{"imported": "HumanMessage", "source": "langchain_core.messages", "docs": "https://python.langchain.com/api_reference/core/messages/langchain_core.messages.human.HumanMessage.html", "title": "Migrating off ConversationBufferMemory or ConversationStringBufferMemory"}, {"imported": "tool", "source": "langchain_core.tools", "docs": "https://python.langchain.com/api_reference/core/tools/langchain_core.tools.convert.tool.html", "title": "Migrating off ConversationBufferMemory or ConversationStringBufferMemory"}, {"imported": "ChatOpenAI", "source": "langchain_openai", "docs": "https://python.langchain.com/api_reference/openai/chat_models/langchain_openai.chat_models.base.ChatOpenAI.html", "title": "Migrating off ConversationBufferMemory or ConversationStringBufferMemory"}]-->
import uuid
from langchain_core.messages import HumanMessage
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.checkpoint.memory import MemorySaver
from langgraph.prebuilt import create_react_agent
@tool
def get_user_age(name: str) -> str:
"""Use this tool to find the user's age."""
# This is a placeholder for the actual implementation
if "bob" in name.lower():
return "42 years old"
return "41 years old"
memory = MemorySaver()
model = ChatOpenAI()
app = create_react_agent(
model,
tools=[get_user_age],
checkpointer=memory,
)
# The thread id is a unique key that identifies
# this particular conversation.
# We'll just generate a random uuid here.
# This enables a single application to manage conversations among multiple users.
thread_id = uuid.uuid4()
config = {"configurable": {"thread_id": thread_id}}
# Tell the AI that our name is Bob, and ask it to use a tool to confirm
# that it's capable of working like an agent.
input_message = HumanMessage(content="hi! I'm bob. What is my age?")
for event in app.stream({"messages": [input_message]}, config, stream_mode="values"):
event["messages"][-1].pretty_print()
# Confirm that the chat bot has access to previous conversation
# and can respond to the user saying that the user's name is Bob.
input_message = HumanMessage(content="do you remember my name?")
for event in app.stream({"messages": [input_message]}, config, stream_mode="values"):
event["messages"][-1].pretty_print()
================================[1m Human Message [0m=================================
hi! I'm bob. What is my age?
==================================[1m Ai Message [0m==================================
Tool Calls:
get_user_age (call_oEDwEbIDNdokwqhAV6Azn47c)
Call ID: call_oEDwEbIDNdokwqhAV6Azn47c
Args:
name: bob
=================================[1m Tool Message [0m=================================
Name: get_user_age
42 years old
==================================[1m Ai Message [0m==================================
Bob, you are 42 years old! If you need any more assistance or information, feel free to ask.
================================[1m Human Message [0m=================================
do you remember my name?
==================================[1m Ai Message [0m==================================
Yes, your name is Bob. If you have any other questions or need assistance, feel free to ask!
如果我们使用不同的线程ID,它将开始一个新的对话,机器人将不知道我们的名字!
config = {"configurable": {"thread_id": "123456789"}}
input_message = HumanMessage(content="hi! do you remember my name?")
for event in app.stream({"messages": [input_message]}, config, stream_mode="values"):
event["messages"][-1].pretty_print()
================================[1m Human Message [0m=================================
hi! do you remember my name?
==================================[1m Ai Message [0m==================================
Hello! Yes, I remember your name. It's great to see you again! How can I assist you today?
下一步
探索与LangGraph的持久性:
使用简单的 LCEL 添加持久性(对于更复杂的用例,建议使用 langgraph):
处理消息历史: