在前两篇文章中,我分别实现了可以抓取并总结网页的agent和一个可以管理日程的agent,里面演示了基本agent创建和使用流程,也为agent添加了特殊的功能。但你仔细观察就会发现,我们的两个agent都是只支持单轮对话,也就是你之前和它说过什么,它不知道。 有些时候其实多轮对话的能力还是很重要的,比如在网页总结的agent中,如果它总结的格式不是我们想要的,我们就可以重新让他汇总整理下,显然这个功能在这里是不支持的。所以我们今天就来看下,如何让agent具备记忆的功能。
LangChain在早期曾推迟过Memory模块,但Memory模块目前被官方标记为beta版本,说是并为这边好投入生产,而且也不支持最新的LCEL语法,但是ChatMessageHistory这个功能是个例外,它已经支持LCEL并且基本可以用在生产上了,所以我们今天说下如何使用ChatMessageHistory让我们的agent记录下对话历史,实现多轮对话。
首先还是来创建基本的agent,这里我们就创建一个简单的对话agent,如果你想创建具备某些功能的复杂agent,可以参考我之前两篇实践文章 抓取并总结网页的agent,管理日程的agent。
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.runnables.history import RunnableWithMessageHistory,BaseChatMessageHistory
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai.chat_models import ChatOpenAI
llm = ChatOpenAI(model="gpt-3.5-turbo", max_tokens=4096)
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"你是一个智能聊天机器人,名字叫二狗,请用markdown格式回答任何问题",
),
MessagesPlaceholder(variable_name="history"),
("human", "{input}"),
]
)
chain = prompt | llm
要注意的是,上面的prompt中必须要留下历史消息history的占位符,这样agent才能在每次调用llm的时候将历史消息传递过去。
然后就是创建agent了,当然这里和普通的agent创是有区别的,需要通过RunnableWithMessageHistory()来创建,其中有个特殊的参数,就是需要传入一个能根据session_id获取历史信息的方法,这里我们就先用最简单纯内存的实现方式,完整的创建代码如下:
store = {}
def get_session_history(session_id: str) -> BaseChatMessageHistory:
if session_id not in store:
store[session_id] = ChatMessageHistory()
return store[session_id]
with_message_history = RunnableWithMessageHistory(
chain,
get_session_history,
input_messages_key="input",
history_messages_key="history",
)
当然调用的agent时候,也需要新增一个config参数。
res = with_message_history.invoke(
{"input": "我刚说过什么??"},
config={"configurable": {"session_id": "你的session_id"}} # 主要是用来不同的聊天上下文
)
res
其中ChatMessageHistory是最基本的聊天历史记录实现,LangChain也提供很多具备持久化能力的实现,比如基于Redis的RedisChatMessageHistory……,具体可以看下官方文档https://python.langchain.com/v0.1/docs/integrations/memory/。