使用 LangChain 从短暂记忆到持久记忆

在聊天机器人中构建长期记忆:详细介绍如何将简单的聊天机器人转变为具有长期记忆和上下文理解能力的复杂 AI 助手

     欢迎来到雲闪世界。在聊天机器人中构建长期记忆详细介绍如何将简单的聊天机器人转变为具有长期记忆和上下文理解能力的复杂 AI 助手

     在之前的一篇文章中,我写了如何使用 OpenAI 创建对话聊天机器人。但是,如果您使用过 ChatGPT 或 Claude 等聊天机器人接口,您会注意到,当会话关闭并重新打开时,记忆会被保留,您可以从上次中断的地方继续对话。这正是我想在本文中创造的体验。

我将使用 LangChain 作为基础,它提供了管理对话历史的出色工具,而且如果你想通过构建链转向更复杂的应用程序,它也非常有用。

代码可用性

可以联系博主找到重新创建本文中所有内容的代码。

使用 LangChain 和 OpenAI 的单一问答机器人

我将首先创建一个循环,让用户输入聊天机器人的问题。我将把它分配给变量humaninput。现在,我将把用户输入的内容分配给变量,而不是 LLM 输出,result然后打印出result。之后,我将连接 OpenAI API 以获取结果,然后更新此 while 循环以从客户端打印出结果。

while True:
    humaninput = input(">> ")
    result = humaninput    
    print(result)

设置环境

我将使用 安装以下包之后导入它们pip install package_name

from langchain_openai import ChatOpenAI
import os
import dotenv

与 OpenAI 联系

我将在OpenAI 平台上建立一个帐户并生成一个唯一的 API 密钥。我将把此 API 密钥存储在我的 .env 文件中以便OPENAI_API访问它。

我现在将连接 OpenAI 客户端,开始创建聊天机器人的骨架。

dotenv.load_dotenv()
llmclient = ChatOpenAI(openai_api_key=os.getenv("OPENAI_API"))

创建聊天提示

我现在将创建一个聊天提示模板,该模板接收人类消息并将其转换为模板,然后传递给 llm 客户端以获取答案。聊天提示将为我发送给模型的输入提供上下文、说明和结构。提示模板是可重复使用的结构,因此它们可以轻松保持对话之间的一致性以及将动态内容添加到提示中。

在这里我将创建一个简单的ChatPromptTemplate,它需要一个名为的变量humaninput。在messages列表中,我将包括一个HumanMessagePromptTemplate ,它代表来自对话中用户的消息。

from langchain_core.prompts import HumanMessagePromptTemplate, ChatPromptTemplate

prompt = ChatPromptTemplate(
    input_variables=["humaninput"],  
    messages=[
        HumanMessagePromptTemplate.from_template("{humaninput}") 
    ]
)

創建一條鏈

考虑将链视为 LangChain 的基本构建块。它允许将多个组件组合成一个单一、有凝聚力的工作流程。虽然对于这个场景,我正在创建一个简单的链,但它们确实可以帮助创建复杂的多步骤流程,同时保持易于重复使用的模块化结构。

在我的特定场景中,我的链由三个部分组成:

  1. 我之前创建的提示模板
  2. 将收到提示并生成响应的 LLM。
  3. 字符串输出解析器期望使用一致的输出格式。

现在链条看起来应该是这样的:

应用提示 -> 聊天模型 -> 字符串输出

from langchain_core.output_parsers import StrOutputParser

chain = prompt | llmclient | StrOutputParser()

更新结果

现在我有了链,我可以调用它来获取输出。chain.invoke()运行humaninput我在链中定义的整个组件序列。 因此,我现在将打印从 LLM 客户端收到的答案,而不是打印人工输入。

while True:
    humaninput = input(">> ")
    result = chain.invoke({"humaninput": humaninput})   
    print(result)

整合在一起

现在代码看起来就是这样的。当我运行它时,我可以与客户端交互并直接从客户端获取答案。创建单个对话聊天机器人的代码位于名为的文件中main_base.py

from langchain_openai import ChatOpenAI
from langchain_core.prompts import HumanMessagePromptTemplate, ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
import os
import dotenv

dotenv.load_dotenv()
llmclient = ChatOpenAI(openai_api_key=os.getenv("OPENAI_API"))

prompt = ChatPromptTemplate(
    input_variables=["humaninput"],  
    messages=[
        HumanMessagePromptTemplate.from_template("{humaninput}")  
    ]
)

chain = prompt | llmclient | StrOutputParser()

while True:
    humaninput = input(">> ")
    result = chain.invoke({"humaninput": humaninput})   
    print(result)

它正确地回答了第一个问题,这是一个很好的开始。当我问第二个问题(第一个问题的后续问题)时,它编造了一个随机答案,因为它没有任何历史记录。接下来让我们创建一个可以解决这个问题的对话机器人。

对话机器人

初始化内存

LangChain 提供了几个记忆类。我将用它ConversationBufferMemory来保留所有之前的交互,但不做任何总结。术语memory_key="messagememory"设置访问记忆的密钥,return_messages=True参数告诉记忆以消息列表的形式返回历史记录。

from langchain.memory import ConversationBufferMemory

memory = ConversationBufferMemory(memory_key="messagememory", return_messages=True)

请注意,ConversationBufferMemory存储整个对话历史记录,这可能并不总是适合长时间的对话,并且可能导致性能问题。还有其他类可用于存储对话摘要,这可能适用于特定场景。

使用消息占位符更新提示模板

我现在将在我的提示模板中引入对话历史记录的消息占位符。我将使用MessagesPlaceholder它允许提示随着对话的进展而动态调整。

<span style="color:rgba(0, 0, 0, 0.8)"><span style="background-color:#ffffff"><span style="background-color:#f9f9f9"><span style="color:#242424"><span style="color:#aa0d91">从</span>langchain_core.prompts<span style="color:#aa0d91">导入</span>MessagesPlaceholder 

prompt = ChatPromptTemplate( 
    input_variables=[ <span style="color:#c41a16">"humaninput"</span> ], 
    messages=[ 
        MessagesPlaceholder(variable_name= <span style="color:#c41a16">"messagememory"</span> ),   
        HumanMessagePromptTemplate.from_template( <span style="color:#c41a16">"{humaninput}"</span> )   
    ] 
)</span></span></span></span>

更新链以加载内存

现在需要将记忆注入提示链中。我将使用它RunnablePassthrough来检索对话历史记录,将其合并到提示中,将其发送到语言模型,然后格式化输出。链现在应该是这样的:

加载内存 -> 应用提示 -> 聊天模型 -> 字符串输出

from langchain_core.prompts import MessagesPlaceholder

prompt = ChatPromptTemplate(
    input_variables=["humaninput"],
    messages=[
        MessagesPlaceholder(variable_name="messagememory"),  
        HumanMessagePromptTemplate.from_template("{humaninput}")  
    ]
)

将交互保存到内存中

现在在 while 循环中,每次发生交互时,我都会将其保存到内存中。我将使用memory.save_context()将交互保存到ConversationBufferMemory

while True:
    humaninput = input(">> ")
    result = chain.invoke({"humaninput": humaninput})   
    print(result)
    memory.save_context({"humaninput": humaninput}, {"output": result})

整合在一起

现在代码看起来就是这样的。当我运行它时,我可以进行交互并进行持续对话。创建持续对话聊天机器人的代码位于名为main_conversation.py

from langchain_openai import ChatOpenAI
from langchain_core.prompts import HumanMessagePromptTemplate, ChatPromptTemplate, MessagesPlaceholder
from langchain_core.output_parsers import StrOutputParser
from langchain.memory import ConversationBufferMemory
from langchain_core.runnables import RunnablePassthrough
import os
import dotenv

dotenv.load_dotenv()
llmclient = ChatOpenAI(openai_api_key=os.getenv("OPENAI_API"))

memory = ConversationBufferMemory(memory_key="messagememory", return_messages=True)

prompt = ChatPromptTemplate(
    input_variables=["humaninput"],
    messages=[
        MessagesPlaceholder(variable_name="messagememory"),  
        HumanMessagePromptTemplate.from_template("{humaninput}")  
    ]
)

chain = (
    RunnablePassthrough.assign(
        messagememory=lambda x: memory.load_memory_variables({})["messagememory"]
    ) 
    | prompt  
    | llmclient 
    | StrOutputParser()  
)

while True:
    humaninput = input(">> ")
    result = chain.invoke({"humaninput": humaninput})   
    print(result)
    memory.save_context({"humaninput": humaninput}, {"output": result}) 

它正确回答了每个问题。现在让我关闭此会话并通过重新运行代码重新启动会话。

显然,它不记得过去的会话。但如果你考虑任何可用的人工智能聊天机器人,期望是能够在你返回会话时继续对话。所以,让我们接下来尝试实现这一点。

跨会话的持久内存

我现在要导入FileChatMessageHistory所有聊天内容,将其存储到名为messagememory.json“本地保存”的外部 JSON 文件中,保存在同一文件夹中。当我重新打开会话时,我将使用此文件重新加载聊天内容并从那里开始。

from langchain_community.chat_message_histories import FileChatMessageHistory

memory = ConversationBufferMemory(
    chat_memory=FileChatMessageHistory("messagememory.json"),
    memory_key="messagememory",
    return_messages=True
)

这个简单的功能将过去的交互转变为可以跨会话进行的持久交互,从而提供长期背景。

但是,如果您要处理多个用户或非常长的对话,则需要注意这些注意事项,因为可能需要管理这些 JSON 文件。考虑使用数据库存储以获得更好的性能和可扩展性可能是一个好主意。将对话存储在文件中可能还需要额外的安全层。

整合在一起

现在代码看起来就是这样的。当我运行它时,我可以交互并在多个会话中进行持续对话。创建持久对话聊天机器人的代码位于名为main_persistence.py

from langchain_openai import ChatOpenAI
from langchain_core.prompts import HumanMessagePromptTemplate, ChatPromptTemplate, MessagesPlaceholder
from langchain_core.output_parsers import StrOutputParser
from langchain.memory import ConversationBufferMemory
from langchain_core.runnables import RunnablePassthrough
from langchain_community.chat_message_histories import FileChatMessageHistory
import os
import dotenv

dotenv.load_dotenv()
llmclient = ChatOpenAI(openai_api_key=os.getenv("OPENAI_API"))

memory = ConversationBufferMemory(
    chat_memory=FileChatMessageHistory("messagememory.json"),
    memory_key="messagememory",
    return_messages=True
)

prompt = ChatPromptTemplate(
    input_variables=["humaninput"],
    messages=[
        MessagesPlaceholder(variable_name="messagememory"),  
        HumanMessagePromptTemplate.from_template("{humaninput}")  
    ]
)

chain = (
    RunnablePassthrough.assign(
        messagememory=lambda x: memory.load_memory_variables({})["messagememory"]
    ) 
    | prompt  
    | llmclient 
    | StrOutputParser()  
)

while True:
    humaninput = input(">> ")
    result = chain.invoke({"humaninput": humaninput})   
    print(result)
    memory.save_context({"humaninput": humaninput}, {"output": result})    

它正确回答了每个问题。现在让我关闭此会话并通过重新运行代码重新启动会话。

即使重新启动会话后也能够继续对话。

下一步是什么!

在本文中,我介绍了使用 LangChain 和 OpenAI 构建简单问答机器人的过程,将其发展为具有记忆功能的对话机器人,最后将其转变为可跨会话保留对话的持久机器人。从这里开始,您可以通过以下方式扩展其功能:

我希望本教程能让您感受到 LangChain 的强大功能,它能大大简化构建具有长期记忆的对话机器人的过程。祝您编码愉快!

感谢关注雲闪世界。(亚马逊aws谷歌GCP服务协助解决云计算及产业相关解决方案)

订阅频道(https://t.me/awsgoogvps_Host)
TG交流群(t.me/awsgoogvpsHost)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值