LangChain入门:17.使用 ConversationChain实现对话记忆功能

在默认情况下,无论是 LLM 还是代理都是无状态的,每次模型的调用都是独立于其他交互的。也就是说,我们每次通过 API 开始和大语言模型展开一次新的对话,它都不知道你其实昨天或者前天曾经和它聊过天了。
你肯定会说,不可能啊,每次和 ChatGPT 聊天的时候,ChatGPT 明明白白地记得我之前交待过的事情。
的确如此,ChatGPT 之所以能够记得你之前说过的话,正是因为它使用了记忆(Memory)机制,记录了之前的对话上下文,并且把这个上下文作为提示的一部分,在最新的调用中传递给了模型。在聊天机器人的构建中,记忆机制非常重要。
使用 ConversationChain
不过,在开始介绍 LangChain 中记忆机制的具体实现之前,先重新看一下我们上一节课曾经见过的 ConversationChain。
这个 Chain 最主要的特点是,它提供了包含 AI 前缀和人类前缀的对话摘要格式,这个对话格式和记忆机制结合得非常紧密。让我们看一个简单的示例,并打印出 ConversationChain 中的内置提示模板,你就会明白这个对话格式的意义了。

#初始化语言模型
from langchain_openai import ChatOpenAI
llm=ChatOpenAI(
    openai_api_key='替换为你的API密钥',  
    base_url='https://api.chatanywhere.tech/v1',
    model='gpt-3.5-turbo',
    temperature=0.7,
)

#初始化对话链
from langchain.chains import ConversationChain
conv_chain = ConversationChain(
    llm=llm,
)

#打印对话的模型
print(conv_chain.prompt.template)

在这里插入图片描述
使用 ConversationBufferMemory
在 LangChain 中,通过 ConversationBufferMemory(缓冲记忆)可以实现最简单的记忆机制。

#使用 ConversationBufferMemory在 LangChain 中,
#通过 ConversationBufferMemory(缓冲记忆)可以实现最简单的记忆机制。
from langchain.chains.conversation.memory import ConversationBufferMemory
conversation = ConversationChain(
    llm=llm,
    memory=ConversationBufferMemory()
)

#第一天的对话
#回合1
conversation("我姐姐明天要过生日,我需要一束生日花束。")
print("第一次对话后的记忆:", conversation.memory.buffer,"\n")

# 回合2
conversation("她喜欢粉色玫瑰,颜色是粉色的。")
print("第二次对话后的记忆:", conversation.memory.buffer,"\n")

# 回合3 (第二天的对话)
conversation("我又来了,还记得我昨天为什么要来买花吗?")
print("\n第三次对话后时提示:\n",conversation.prompt.template)
print("\n第三次对话后的记忆:\n", conversation.memory.buffer,"\n")

实际上,这些聊天历史信息,都被传入了 ConversationChain 的提示模板中的 {history} 参数,构建出了包含聊天记录的新的提示输入。
有了记忆机制,LLM 能够了解之前的对话内容,这样简单直接地存储所有内容为 LLM 提供了最大量的信息,但是新输入中也包含了更多的 Token(所有的聊天历史记录),这意味着响应时间变慢和更高的成本。而且,当达到 LLM 的令牌数(上下文窗口)限制时,太长的对话无法被记住(对于 text-davinci-003 和 gpt-3.5-turbo,每次的最大输入限制是 4096 个 Token)。

使用 ConversationBufferWindowMemory
ConversationBufferWindowMemory 是缓冲窗口记忆,它的思路就是只保存最新最近的几次人类和 AI 的互动。因此,它在之前的“缓冲记忆”基础上增加了一个窗口值 k。这意味着我们只保留一定数量的过去互动,然后“忘记”之前的互动。


#使用 ConversationBufferWindowMemory。ConversationBufferWindowMemory 是缓冲窗口记忆,
#它的思路就是只保存最新最近的几次人类和 AI 的互动。
from langchain.chains.conversation.memory import ConversationBufferWindowMemory
conversation = ConversationChain(
    llm=llm,
    memory=ConversationBufferWindowMemory(k=1)
)

# 第一天的对话
# 回合1
result = conversation("我姐姐明天要过生日,我需要一束生日花束。")
print(result)
# 回合2
result = conversation("\n她喜欢粉色玫瑰,颜色是粉色的。")

# 第二天的对话
# 回合3
result = conversation("\n我又来了,还记得我昨天为什么要来买花吗?")
print(result)

在给定的例子中,设置 k=1,这意味着窗口只会记住与 AI 之间的最新的互动,即只保留上一次的人类回应和 AI 的回应。

使用 ConversationSummaryMemory
上面说了,如果模型在第二轮回答的时候,能够说出“我可以帮你为你姐姐找到…”,那么在第三轮回答时,即使窗口大小 k=1,还是能够回答出正确答案。
这是为什么?因为模型在回答新问题的时候,对之前的问题进行了总结性的重述。ConversationSummaryMemory(对话总结记忆)的思路就是将对话历史进行汇总,然后再传递给 {history} 参数。这种方法旨在通过对之前的对话进行汇总来避免过度使用 Token。

ConversationSummaryMemory 有这么几个核心特点。

  1. 汇总对话:此方法不是保存整个对话历史,而是每次新的互动发生时对其进行汇总,然后将其添加到之前所有互动的“运行汇总”中。
  2. 使用 LLM 进行汇总:该汇总功能由另一个 LLM 驱动,这意味着对话的汇总实际上是由 AI 自己进行的。
  3. 适合长对话:对于长对话,此方法的优势尤为明显。虽然最初使用的 Token
    数量较多,但随着对话的进展,汇总方法的增长速度会减慢。与此同时,常规的缓冲内存模型会继续线性增长。
#使用 ConversationSummaryMemory
#ConversationSummaryMemory(对话总结记忆)的思路就是将对话历史进行汇总,
#然后再传递给 {history} 参数。这种方法旨在通过对之前的对话进行汇总来避免过度使用 Token。
from langchain.chains.conversation.memory import ConversationSummaryMemory

# 初始化对话链
conversation = ConversationChain(
    llm=llm,
    memory=ConversationSummaryMemory(llm=llm)
)

# 第一天的对话
# 回合1
result = conversation("我姐姐明天要过生日,我需要一束生日花束。")
print(result)
# 回合2
result = conversation("\n她喜欢粉色玫瑰,颜色是粉色的。")

# 第二天的对话
# 回合3
result = conversation("\n我又来了,还记得我昨天为什么要来买花吗?")
print(result)

ConversationSummaryMemory 的优点是对于长对话,可以减少使用的 Token 数量,因此可以记录更多轮的对话信息,使用起来也直观易懂。不过,它的缺点是,对于较短的对话,可能会导致更高的 Token 使用。
另外,对话历史的记忆完全依赖于中间汇总 LLM 的能力,还需要为汇总 LLM 使用 Token,这增加了成本,且并不限制对话长度。通过对话历史的汇总来优化和管理 Token 的使用,ConversationSummaryMemory 为那些预期会有多轮的、长时间对话的场景提供了一种很好的方法。然而,这种方法仍然受到 Token 数量的限制。在一段时间后,我们仍然会超过大模型的上下文窗口限制。

使用 ConversationSummaryBufferMemory
我要为你介绍的最后一种记忆机制是 ConversationSummaryBufferMemory,即对话总结缓冲记忆,它是一种混合记忆模型,结合了上述各种记忆机制,包括 ConversationSummaryMemory 和 ConversationBufferWindowMemory 的特点。
这种模型旨在在对话中总结早期的互动,同时尽量保留最近互动中的原始内容。它是通过 max_token_limit 这个参数做到这一点的。当最新的对话文字长度在 300 字之内的时候,LangChain 会记忆原始对话内容;当对话文字超出了这个参数的长度,那么模型就会把所有超过预设长度的内容进行总结,以节省 Token 数量。

#使用 ConversationSummaryBufferMemory
#ConversationSummaryBufferMemory,即对话总结缓冲记忆,它是一种混合记忆模型,结合了上述各种记忆机制,
#包括 ConversationSummaryMemory 和 ConversationBufferWindowMemory 的特点。
#这种模型旨在在对话中总结早期的互动,同时尽量保留最近互动中的原始内容。
from langchain.chains.conversation.memory import ConversationSummaryBufferMemory

# 初始化对话链
conversation = ConversationChain(
    llm=llm,
    memory=ConversationSummaryBufferMemory
    (
        llm=llm,
        max_token_limit=300
    )
)
# 第一天的对话
# 回合1
result = conversation("我姐姐明天要过生日,我需要一束生日花束。")
print(result)
# 回合2
result = conversation("\n她喜欢粉色玫瑰,颜色是粉色的。")

# 第二天的对话
# 回合3
result = conversation("\n我又来了,还记得我昨天为什么要来买花吗?")
print(result)

不难看出,在第二回合,记忆机制完整地记录了第一回合的对话,但是在第三回合,它察觉出前两轮的对话已经超出了 300 个字节,就把早期的对话加以总结,以节省 Token 资源。ConversationSummaryBufferMemory 的优势是通过总结可以回忆起较早的互动,而且有缓冲区确保我们不会错过最近的互动信息。当然,对于较短的对话,ConversationSummaryBufferMemory 也会增加 Token 数量。
总体来说,ConversationSummaryBufferMemory 为我们提供了大量的灵活性。它是我们迄今为止的唯一记忆类型,可以回忆起较早的互动并完整地存储最近的互动。在节省 Token 数量方面,ConversationSummaryBufferMemory 与其他方法相比,也具有竞争力。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/531166.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

3.2.k8s搭建-kubeadm

目录 一、虚拟机准备 二、所有节点环境准备 1.所有节点做hosts解析 2.所有节点重新命名 3.所有节点安装docker 4.所有节点为docker做linux内核转发 5.所有节点配置docker 6.所有节点关闭swap分区 7.所有节点验证网卡硬件编号是否冲突 8.所有节点配置允许iptables桥接…

【HTML】简单制作一个分形动画

目录 前言 开始 HTML部分 效果图 ​编辑​编辑​编辑​编辑总结 前言 无需多言,本文将详细介绍一段代码,具体内容如下: 开始 首先新建文件夹,创建一个文本文档,其中HTML的文件名改为[index.html]&a…

【原创教程】Smart200通过Modbus RTU实现V90位置控制的方法

1 绪论 1.1 本文的目的 S7-200Smart 可通过标准的 Modbus 功能块发送伺服驱动器的控制指令及读写驱动器的参数。本文详细叙述了 S7-200 SMART PLC 通过 Modbus RTU 通信连接 SINAMICS V90 实现内部位置的 MDI 功能。(MDI(Manual Data Input)称为设定值直接给定运行方式。…

岛屿个数c++

参考文章 岛屿个数1岛屿个数2 题目 输入样例: 2 5 5 01111 11001 10101 10001 11111 5 6 111111 100001 010101 100001 111111输出样例: 1 3样例解释 对于第一组数据,包含两个岛屿,下面用不同的数字进行了区分: 0…

计算机网络-TCP基础、三次挥手、四次握手过程

TCP基础 定义:TCP是面向连接的、可靠的、基于字节流的传输层通信协议。这意味着在发送数据之前,TCP需要建立连接,并且它能确保数据的可靠传输。此外,TCP将数据视为无结构的连续字节流。面向连接:TCP只能一对一进行连接…

Harmony与Android项目结构对比

主要文件对应 Android文件HarmonyOS文件清单文件AndroidManifest.xmlmodule.json5Activity/Fragmententryability下的ts文件XML布局pages下的ets文件resresourcesModule下的build.gradleModule下的build-profile.json5gradlehvigor根目录下的build.gradle根目录下的build-profi…

动态内存管理详解

一.为什么要存在动态内存分配: 下图是不同类型数据在内存中的分配: 上述的开辟空间的⽅式有两个特点: • 空间开辟⼤⼩是固定的。 • 数组在申明的时候,必须指定数组的⻓度,数组空间⼀旦确定了⼤⼩不能调整 但是对…

DeepStream做对象模糊的几种方法

有时候,我们需要对视频的敏感信息做模糊处理,比如模糊人脸,车牌。 有时候,也需要对整帧做模糊,或者遮挡。比如这个例子。 下面介绍几种模糊的办法。 1. 通过nvosd deepstream-test1是DeepStream最简单的一个例子&…

基于SpringBoot的“垃圾分类网站”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“垃圾分类网站”的设计与实现(源码数据库文档PPT) 开发语言:Java 数据库:MySQL 技术:SpringBoot 工具:IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 系统功能界面图 用户登录、用户注…

基于java+springboot+vue实现的人事管理系统(文末源码+Lw)23-242

摘 要 使用旧方法对人事管理系统的信息进行系统化管理已经不再让人们信赖了,把现在的网络信息技术运用在人事管理系统的管理上面可以解决许多信息管理上面的难题,比如处理数据时间很长,数据存在错误不能及时纠正等问题。这次开发的人事管理…

时序预测 | Matlab实现SSA-ESN基于麻雀搜索算法(SSA)优化回声状态网络(ESN)的时间序列预测

时序预测 | Matlab实现SSA-ESN基于麻雀搜索算法(SSA)优化回声状态网络(ESN)的时间序列预测 目录 时序预测 | Matlab实现SSA-ESN基于麻雀搜索算法(SSA)优化回声状态网络(ESN)的时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现SSA-ESN基于麻雀搜索…

SQL 注入之 Windows/Docker 环境 SQLi-labs 靶场搭建!

在安全测试领域,SQL注入是一种常见的攻击方式,通过应用程序的输入执行恶意SQL查询,从而绕过认证和授权,可以窃取、篡改或破坏数据库中的数据。作为安全测试学习者,如果你要练习SQL注入,在未授权情况下直接去…

(2022级)成都工业学院数据库原理及应用实验一:CASE工具概念数据模型建模

写在前面 1、基于2022级软件工程/计算机科学与技术实验指导书 2、代码仅提供参考 3、如果代码不满足你的要求,请寻求其他的途径 运行环境 window11家庭版 PowerDesigner 16.1 实验要求 某医院一个门诊部排班管理子系统涉及如下信息: 若干科室&a…

传输大咖22|如何利用ProtoBuf实现高效的数据传输?

在今日信息技术日新月异的时代,数据传输的速度与安全性无疑成为了软件开发中的重中之重。无论是微服务架构下的服务间交流,还是客户端与服务器间的数据互动,寻求一种既高效又稳妥的数据传输方式已成为共识。尽管传统的数据格式,如…

论文复现 混淆矩阵

概念 参考视频: 使用pytorch和tensorflow计算分类模型的混淆矩阵_哔哩哔哩_bilibili 混淆矩阵是评判模型结果的一种指标,属于模型评估的一部分,常用于评判分类器模型的优劣。 准确率:所有预测正确的验证集样本个数/所有的验证集…

什么是SSL重签(reissue)?具体怎么做?

SSL重签(reissue)是指在SSL/TLS证书到期或需要更新时,证书持有者向证书颁发机构(CA)申请新的证书的过程。这通常是因为原有证书的有效期即将结束,或者证书因为某些原因(如密钥泄露、证书损坏等&…

2024,嵌入式还适合入吗?为什么好多人劝退?

昨几天有个老铁找我,说买了我们的教程。 我有点奇怪,c语言教程我们都是送的。 聊了一会才知道,有人拿我送给粉丝的教程工具资料,到某宝上卖。 他就是买了资料,看我们的教程和经历,找到我的。 他说&#xff…

深入理解LRU缓存算法:原理、应用与优化

LRU算法(Least Recently Used,最近最少使用算法)的思想是基于"时间局部性"原理,即在一段时间内,被访问过的数据在未来仍然会被频繁访问的概率较高。 LRU 原理 LRU算法的主要思想是将最近被使用的数据保留在…

redis的三大模式的演化及集群模式思考和总结

redis的三大模式,也是循序渐进。 1、主从复制 比如一开始的读写分离的,主从复制。 一个master,多个slave。 master进行写和 增量同步,slave负责读,和接收增量同步的信息。 这样压力减轻。 2、哨兵模式 这个推出…

如何通过VPN访问内网?

VPN(Virtual Private Network)是一种通过公共网络建立私有网络连接的技术,可以在不同地点的网络中建立安全通道,实现远程访问内网资源的目的。本文将介绍如何通过VPN访问内网,并介绍一款名为“天联”的VPN服务。 什么是…