首页 > 其他分享 >使用 LangChain 从短暂记忆到持久记忆

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

时间:2024-07-23 23:55:17浏览次数:11  
标签:result 持久 messagememory LangChain 记忆 langchain memory import humaninput

在聊天机器人中构建长期记忆:详细介绍如何将简单的聊天机器人转变为具有长期记忆和上下文理解能力的复杂 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)

标签:result,持久,messagememory,LangChain,记忆,langchain,memory,import,humaninput
From: https://blog.csdn.net/2401_85233349/article/details/140648834

相关文章

  • redis的使用场景和持久化方式
    redis的使用场景热点数据的缓存。热点:频繁读取的数据。限时任务的操作:短信验证码。完成session共享的问题完成分布式锁。redis的持久化方式什么是持久化:把内存中的数据存储到磁盘的过程,同时也可以把磁盘中的数据加载到内存中。redis持久化分为两种:RDB和AOFRDB:什......
  • langchain:ModuleNotFoundError:没有名为“langchain_community”的模块
    尝试执行此代码:fromlangchain_community.vectorstoresimportFAISS显示错误:ModuleNotFoundError:没有名为“langchain_community”的模块我已经执行了命令:pipinstalllangchain-社区遇到的错误是因为没有名为“langchain-community”......
  • 使用 Langchain 和 OpenAI 将矢量嵌入数据从 PDF 添加到 PineCone
    我不确定PineCone和Langchain的.get()替代方案是什么。我希望运行此代码,但我不断收到错误消息,指出.get不是Pinecone的属性。我不确定有什么替代方案可以替代它。defadd_to_pinecone(chunks:list[Document]):VectorStore=Pinecone(index='portfolio-assistan......
  • 登陆京东(滑块验证),验证码识别,Scrapy框架介绍及其使用,持久化存储到本地
    Ⅰ案例登陆京东(滑块验证)【一】下载opencv库pipinstallopencv-python【二】数据准备先将京东的滑块图片下载到本地背景图background.png滑块图tag.png【三】展示获取滑块的移动数据importos.path#使用opencv识别图像计算滑块之间的距离importcv2impo......
  • 使用 LCEL 链接 langchain 响应
    我已经开始与Langchain合作来感受它,很多视频似乎已经过时了。经过一些研究,我了解到LCEL正在被使用,因为其他方法似乎已被弃用。在我的代码中,我尝试使用一个链的输出作为另一个链的输入,但它似乎不起作用。defmain():prompt1=ChatPromptTemplate.from_messages([......
  • 深入浅出分析最近火热的Mem0个性化AI记忆层
    最近Mem0横空出世,官方称之为PA的记忆层,ThememorylayerforPersonalizedAI,有好事者还称这个是RAG的替代者,Mem0究竟为何物,背后的原理是什么,我们今天来一探究竟。Mem0介绍开源地址:https://github.com/mem0ai/mem0官方介绍为:Mem0providesasmart,self-improvingmemory......
  • 【搜索】【模板】记忆化搜索
    记忆化搜索思想是实现DP的一种手段。优点:不关心递推顺序;对于两维及以上的DP,方便处理初始状态和无效状态。缺点:无法使用滚动数组。注意事项:要什么状态搜什么状态;所有的状态转移都要采取直接搜索的数据很傻。越界的状态不能赋值。实现步骤:先判断是否越界,如果越......
  • 【故障诊断】基于斑马优化算法ZOA优化长短记忆网络LSTM实现故障诊断附matlab代码
    %导入数据集load(‘fault_diagnosis_data.mat’);%假设故障诊断数据保存在fault_diagnosis_data.mat文件中%数据预处理%这里省略了数据预处理的步骤,包括数据归一化、特征提取等%划分训练集和测试集train_ratio=0.8;%训练集占总数据的比例train_size=round......
  • 如何使用ngrok url运行LangChain Ollama?
    我运行了一个脚本来获取ngrokurl:importasyncio#SetLD_LIBRARY_PATHsothesystemNVIDIAlibraryos.environ.update({'LD_LIBRARY_PATH':'/usr/lib64-nvidia'})asyncdefrun_process(cmd):print('>>>starting',*cmd)p......
  • Redis7(二)Redis持久化双雄
    持久化之RDBRDB的持久化方式是在指定时间间隔,执行数据集的时间点快照。也就是在指定的时间间隔将内存中的数据集快照写入磁盘,也就是Snapshot内存快照,它恢复时再将硬盘快照文件直接读回到内存里面。RDB保存的是dump.rdb文件。自动触发默认redis是有三种自动触发的规则,在配置......