使用 LangChain 开发 LLM 应用(3):记忆

news2024/11/17 13:54:56

注:

  1. 本文是基于吴恩达《LangChain for LLM Application Development》课程的学习笔记;
  2. 完整的课程内容以及示例代码/Jupyter笔记见:LangChain-for-LLM-Application-Development;

课程大纲

目前 LLM 基本上都有最大 Token 的限制,即限制每次对话中输入的最长的文字个数。目前常见的 gpt-3.5-turbo 模型支持的最大 Token 数是 4096,最强的 gpt-4 模型支持的最大 Token 数是 8192 。

本课程主要讲解 LangChain 中的以下几种 memory 方式:

  • ConversationBufferMemory:对话内容缓存,方便存储对话内容;
  • ConversationBufferWindowMemory:根据对话的次数来控制记忆长度;
  • ConversationTokenBufferMemory:根据 Token 数量来控制记忆长度;
  • ConversationSummaryMemory:总结对话内容来减少token占用,从而有更长的记忆;

主要内容如下图:

Memory.png

初始化设置

首先会初始化/读取环境变量信息,代码大致如下:

import os

from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file

import warnings
warnings.filterwarnings('ignore')

ConversationBufferMemory

from langchain.chat_models import ChatOpenAI
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory

llm = ChatOpenAI(temperature=0.0)
memory = ConversationBufferMemory()
# 创建一个对话,并传入 memory
conversation = ConversationChain(
    llm=llm, 
    memory = memory,
    # 会打印 LangChain 的 Prompt 信息,自己尝试时可以打开此选项
    verbose=False
)

下面是使用 conversation 进行的三次对话,其中最后一句会询问第一句中的姓名信息,根据输出可知对话过程中是可以记住上下文信息的。

# 使用 predict 函数开始对话
conversation.predict(input="Hi, my name is Andrew")
conversation.predict(input="What is 1+1?")
conversation.predict(input="What is my name?")

'Your name is Andrew, as you mentioned earlier.'

我们使用 memory.buffer 获取对话的上下文信息,打印出的信息如下:

print(memory.buffer)

Human: Hi, my name is Andrew
AI: Hello Andrew, it's nice to meet you. My name is AI. How can I assist you today?
Human: What is 1+1?
AI: The answer to 1+1 is 2.
Human: What is my name?
AI: Your name is Andrew, as you mentioned earlier.

也可用通过 load_memory_variables 函数,获取对话历史,如下:

memory.load_memory_variables({})

{'history': "Human: Hi, my name is Andrew\nAI: Hello Andrew, it's nice to meet you. My name is AI. How can I assist you today?\nHuman: What is 1+1?\nAI: The answer to 1+1 is 2.\nHuman: What is my name?\nAI: Your name is Andrew, as you mentioned earlier."}

自定义 ConversationBufferMemory

上面是真实的对话过程中产生的是对话记录,我们也可以通过 save_context 函数来预设一些对话内容,如下:

memory = ConversationBufferMemory()
memory.save_context({"input": "Hi"}, 
                    {"output": "What's up"})
print(memory.buffer)

Human: Hi
AI: What's up

也可以不停的进行追加对话内容,如下:

memory.save_context({"input": "Not much, just hanging"}, 
                    {"output": "Cool"})
print(memory.buffer)

Human: Hi
AI: What's up
Human: Not much, just hanging
AI: Cool

ConversationBufferMemory 可以很方便的记录对话的内容,在使用的时候会很方便。由于对话内容的不断增加以及 LLM 模型有最大 Token 的限制,所以对话不会无限制的传递给 LLM 进行使用。按照什么策略选取对话内容就变得比较重要了,下面就先介绍下滑动窗口的方式来记录对话内容了。

ConversationBufferWindowMemory

以滑动窗口的方式来记录对话内容,可以设置记忆对话的轮数。

from langchain.memory import ConversationBufferWindowMemory

# 创建 ConversationBufferWindowMemory 示例,并且设置记忆窗口为 1,及只能记住一次对话内容
memory = ConversationBufferWindowMemory(k=1)         

memory.save_context({"input": "Hi"},
                    {"output": "What's up"})
memory.save_context({"input": "Not much, just hanging"},
                    {"output": "Cool"})
# 只会打印最近一次的对话内容
memory.load_memory_variables({})

{'history': 'Human: Not much, just hanging\nAI: Cool'}

下面在与 LLM 模型结合看一下是否会记住上下文的对话内容,还是上面和 Andrew 对话的内容,代码如下:

# 初始化
llm = ChatOpenAI(temperature=0.0)
memory = ConversationBufferWindowMemory(k=1)
conversation = ConversationChain(
    llm=llm, 
    memory = memory,
    verbose=False
)

# 多轮对话,并不会记住 Andrew 的名字
conversation.predict(input="Hi, my name is Andrew")
conversation.predict(input="What is 1+1?")
conversation.predict(input="What is my name?")

"I'm sorry, I don't have access to that information. Could you please tell me your name?"

你可以通过修改 K 的值,来体验一下 LLM 能记住的内容。当然,你也可以将 verbose 设置为 Ture 来看一下 LangChain 内部是如何设计 Prompot 的。开启后,输出如下:

Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.

Current conversation:

Human: Hi, my name is Andrew
AI:

ConversationTokenBufferMemory

除了使用 ConversationBufferWindowMemory 方式之外,还可以 Token 的数量来限制记忆的大小。

# 安装 tiktoken
!pip install tiktoken

from langchain.memory import ConversationTokenBufferMemory
from langchain.llms import OpenAI

# 初始化 llm
llm = ChatOpenAI(temperature=0.0)
# 初始化 ConversationTokenBufferMemory,设置只能记忆 30 个 Token 以内的对话
memory = ConversationTokenBufferMemory(llm=llm, max_token_limit=30)

# 构造对话历史
memory.save_context({"input": "AI is what?!"},
                    {"output": "Amazing!"})
memory.save_context({"input": "Backpropagation is what?"},
                    {"output": "Beautiful!"})
memory.save_context({"input": "Chatbots are what?"}, 
                    {"output": "Charming!"})

# 打印对话记忆
memory.load_memory_variables({})

{'history': 'AI: Beautiful!\nHuman: Chatbots are what?\nAI: Charming!'}

通过日志输出可以看出,只记录了下半段的对话内容。

ConversationSummaryMemory

上面两种的记忆方式都是很精准的,但是能记录的内容有限。参考人类的记忆方式,我们很难完整详细的记住一件事情的所有细节,就像我们很难叙述今天一天完整的流水一样。我们通常只会记忆一次很长的对话的总结内容,ConversationSummaryMemory 就是做这件事情的。

当对话的 Token 数量超限制的时候,就会将上述的对话内容进行总结,并且把总结的内容当作上下文,并进行下一次的对话请求。

from langchain.memory import ConversationSummaryBufferMemory

# 一段超长的对话内容,超过了设置的 100 最大 Token 数
schedule = "There is a meeting at 8am with your product team. \
You will need your powerpoint presentation prepared. \
9am-12pm have time to work on your LangChain \
project which will go quickly because Langchain is such a powerful tool. \
At Noon, lunch at the italian resturant with a customer who is driving \
from over an hour away to meet you to understand the latest in AI. \
Be sure to bring your laptop to show the latest LLM demo."

memory = ConversationSummaryBufferMemory(llm=llm, max_token_limit=100)
memory.save_context({"input": "Hello"}, {"output": "What's up"})
memory.save_context({"input": "Not much, just hanging"},
                    {"output": "Cool"})
memory.save_context({"input": "What is on the schedule today?"}, 
                    {"output": f"{schedule}"})

# 打印 memory 中的信息
memory.load_memory_variables({})

{'history': "System: The human and AI engage in small talk before discussing the day's schedule. The AI informs the human of a morning meeting with the product team, time to work on the LangChain project, and a lunch meeting with a customer interested in the latest AI developments."}

通过日志可以看出,总结的内容会放在 System 中而非之前的 Human 和 AI 字段中。

conversation = ConversationChain(
    llm=llm, 
    memory = memory,
    verbose=True
)
conversation.predict(input="What would be a good demo to show? in Chinese")

[1m> Entering new ConversationChain chain...[0m
Prompt after formatting:
[32;1m[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.

Current conversation:
System: The human and AI discuss their schedule for the day, including a morning meeting with the product team, time to work on the LangChain project, and a lunch meeting with a customer interested in AI developments. The AI suggests showcasing their latest natural language processing capabilities and machine learning algorithms to the customer, and offers to prepare a demo for the meeting. The human asks what would be a good demo to show.
AI: Based on our latest natural language processing capabilities and machine learning algorithms, I suggest showcasing our chatbot that can understand and respond to complex customer inquiries in real-time. We can also demonstrate our sentiment analysis tool that can accurately predict customer emotions and provide personalized responses. Additionally, we can showcase our language translation tool that can translate text from one language to another with high accuracy. Would you like me to prepare a demo for each of these capabilities?
Human: What would be a good demo to show? in Chinese
AI:[0m

[1m> Finished chain.[0m

'对于我们最新的自然语言处理能力和机器学习算法,我建议展示我们的聊天机器人,它可以实时理解和回答复杂的客户查询。我们还可以展示我们的情感分析工具,它可以准确预测客户的情绪并提供个性化的回应。此外,我们还可以展示我们的语言翻译工具,它可以高精度地将文本从一种语言翻译成另一种语言。您想让我为每个功能准备一个演示吗?(Translation: 对于我们最新的自然语言处理能力和机器学习算法,我建议展示我们的聊天机器人,它可以实时理解和回答复杂的客户查询。我们还可以展示我们的情感分析工具,它可以准确预测客户的情绪并提供个性化的回应。此外,我们还可以展示我们的语言翻译工具,它可以高精度地将文本从一种语言翻译成另一种语言。您想让我为每个功能准备一个演示吗?)'

通过日志可以看出,LLM 返回的内容也已经超出最大 Token 数的限制,这个时候 ConversationSummaryMemory 还是会对对话内容进行再次总结,可以通过 load_memory_variables 输出对应的信息:

memory.load_memory_variables({})

{'history': 'System: The human and AI discuss their schedule for the day, including a morning meeting with the product team, time to work on the LangChain project, and a lunch meeting with a customer interested in AI developments. The AI suggests showcasing their latest natural language processing capabilities and machine learning algorithms to the customer, and offers to prepare a demo for the meeting. The AI recommends demonstrating their chatbot, sentiment analysis tool, and language translation tool, and offers to prepare a demo for each capability. The human asks for a demo in Chinese.'}

课程小结

本课程主要讲解 LangChain 中的以下几种 memory 方式:

  • ConversationBufferMemory:
    • 对历史对话消息的一个包装器,用于提取变量中的对话历史消息。
  • ConversationBufferWindowMemory:
    • 这种记忆保存了一段时间内对话的交互列表。它只用最后k个相互作用。
  • ConversationTokenBufferMemory:
    • 此内存在内存中保留最近交互的缓冲区,并使用令牌长度而不是交互次数来确定何时刷新交互。
  • ConversationSummaryMemory:
    • 随着时间的推移,这个记忆创建了对话的摘要。

除了上述提到的 memory 方式之外,LangChain 的官方网站中还提供了一些其他的记忆方式:

  • 矢量数据存储器
    • 存储文本(从对话或其他地方)矢量数据库和检索最相关的文本块。
  • 实体记忆
    • 使用LLM,它可以记住特定实体的细节。

除了上述的记忆方式之外,还可以同时使用多个内存。例如,会话记忆+实体记忆来回忆个体。当然,可以将会话存储在常规数据库中(例如键值存储或sql)或者向量数据库中。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IEEE计算智能学会深圳分会线上讲座 22-01期: 金耀初教授的科研经验分享

IEEE计算智能学会深圳分会线上讲座 22-01期: 金耀初教授的科研经验分享_哔哩哔哩_bilibili 非限定性定语从句,使用逗号和which、动名词搭配使用, 尽量避免使用被动语态。 obviously- 使用clearly,apparently感觉上更好。 In this study/work 后面的交…

C++重载左移运算符

通过重载左移运算符&#xff0c;可以实现cout << p;直接输出类对象的各个属性。 其只能使用全局函数重载。 注意cout的定义如下&#xff1a; _EXPORT_STD extern "C" __PURE_APPDOMAIN_GLOBAL _CRTDATA2_IMPORT ostream cout; 也就是说我们一直用来输出的c…

VirtualFlow案例 | 油箱燃油晃动模拟,高效分析管路及油箱内油面变化

在探索流体行为模拟的领域&#xff0c;CFD技术为油箱燃油晃动模拟带来了革命性的转变。通过高精度的数值模拟&#xff0c;它不仅揭示了燃油在不同工况下的复杂动态&#xff0c;还为油箱设计的优化提供了关键洞察。这一技术在航空航天、汽车制造、船舶与海洋工程等多个行业中展现…

Diffree - AI一键P图,告别P图困扰,只需要输入一段文字就能轻松玩转P图的神器 本地一键整合包下载

在这个AI技术飞速发展的时代&#xff0c;我们见证了许多神奇的创新&#xff0c;比如最近火遍朋友圈的“Diffree”。这可不是一款新推出的手机游戏&#xff0c;而是一项能让设计师和摄影师们欢呼雀跃的AI图像处理技术。 它能够根据你的文字描述&#xff0c;在图片中“无痕迹”地…

1_初识pytorch

之前完全没有了解过深度学习和pytorch&#xff0c;但现在因为某些原因不得不学了。不得不感叹&#xff0c;深度学习是真的火啊。纯小白&#xff0c;有错的欢迎指正~ 参考视频&#xff1a;PyTorch深度学习快速入门教程&#xff08;绝对通俗易懂&#xff01;&#xff09;【小土堆…

企业官网后台管理|网站后台管理系统PHP源码 开源

效果展示 提交反馈 获得更多开源资料 技术交流

在 Google Cloud 上大规模部署 dbt 项目

使用 Artifact Registry、Cloud Composer、GitHub Actions 和 dbt-airflow 容器化并运行 dbt 项目 欢迎来到雲闪世界。&#xff0c;大规模管理数据模型是使用dbt&#xff08;数据构建工具&#xff09;的数据团队面临的常见挑战。最初&#xff0c;团队通常从易于管理和部署的简单…

【日记】9 个发箍只有 2 个能压住头发……(513 字)

正文 今天下午实在有些受不了&#xff0c;从正大门外走了出去。抬头望着天空&#xff0c;望着那些悠然自在纯白无暇的云&#xff0c;竟然有些眼睛疼&#xff0c;刺激到想要流泪。 我在室内待得太久太久了。似乎很久没有在这种时间段出来过了。 下午快下班的时候&#xff0c;有个…

前端面试宝典【设计模式】【2】

欢迎来到《前端面试宝典》,这里是你通往互联网大厂的专属通道,专为渴望在前端领域大放异彩的你量身定制。通过本专栏的学习,无论是一线大厂还是初创企业的面试,都能自信满满地展现你的实力。 核心特色: 独家实战案例:每一期专栏都将深入剖析真实的前端面试案例,从基础知…

二进制部署k8s集群之cni网络插件flannel和calico工作原理

3、部署 CNI 网络组件 在 master01 节点上操作 上传flannel-v0.21.5.zip并解压 unzip flannel-v0.21.5.zipscp flannel*.tar 192.168.80.20:/opt/k8s/ scp flannel*.tar 192.168.80.30:/opt/k8s/ node两个节点操作 cd /opt/k8s/ docker load -i flannel.tar docker load -i …

Vue3开源Tree组件研发:节点勾选支持v-model

自研Tree组件有两个原因&#xff1a;1. 目前开源UI对Tree组件的用户API不太友好&#xff0c;2. 提升Vue3组件自研能力。 目前已实现的功能见上面思维导图。想象Tree组件的一个使用场景&#xff1a;后台管理员通过Tree组件来完成用户角色授权&#xff0c;同时支持对权限进行新增…

自动化测试概念篇

目录 一、自动化 1.1 自动化概念 1.2 自动化分类 1.3 自动化测试金字塔 二、web自动化测试 2.1 驱动 2.2 安装驱动管理 三、selenium 3.1 ⼀个简单的web自动化示例 3.2 selenium驱动浏览器的工作原理 一、自动化 1.1 自动化概念 在生活中&#xff1a; 自动洒水机&am…

cv::convexityDefects异常

cv::convexityDefects捕捉到cv::Exception OpenCV(4.8.0) C:\GHA-OCV-1\_work\ci-gha-workflow\ci-gha-workflow\opencv\modules\imgproc\src\convhull.cpp:360: error: (-5:Bad argument) The convex hull indices are not monotonous, which can be in the case when the inp…

拓扑排序(初中组)

有向无环图 定义 边有向&#xff0c;无环。英文名叫 Directed Acyclic Graph&#xff0c;缩写是 DAG。一些实际问题中的二元关系都可使用 DAG 来建模。 性质 能 拓扑排序 的图&#xff0c;一定是有向无环图&#xff1b; 如果有环&#xff0c;那么环上的任意两个节点在任意序…

特征构造和降维

特征构造&#xff08;Feature Engineering&#xff09; 特征构造是从现有数据中创建新的特征&#xff0c;以揭示数据中的隐藏关系&#xff0c;从而提高模型表现。这是数据预处理中一个关键步骤&#xff0c;可以显著提升模型的性能。 原理 通过特征构造&#xff0c;我们可以利…

“云计算环境下的等保测评要点分析“

随着云计算技术的广泛应用&#xff0c;企业越来越多地将业务迁移到云端&#xff0c;这不仅带来了灵活性和效率的提升&#xff0c;也对信息安全提出了新的挑战。等保测评作为我国信息安全等级保护制度的重要组成部分&#xff0c;其在云计算环境下的实施具有特殊性。本文将围绕“…

nginx 简单使用方法

nginx是用于 Web 服务、反向代理、内容缓存、负载均衡、媒体流传输等场景的开源软件。 主要作用有三个&#xff1a;1、反向代理 负载均衡动静分离 下载地址&#xff1a;nginx: download nginx执行命令及启动 //假设安装在E:\server\nginx-1.20.0目录下 //cmd命令进入安装文…

如何在 VitePress 中增加一个全局自定义组件

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storm…

【Python实战】轻松实现自动发送邮件

本文收录于 《一起学Python趣味编程》专栏,从零基础开始,分享一些Python编程知识,欢迎关注,谢谢! 文章目录 一、前言二、开发准备三、正式开始四、总结一、前言 本文介绍如何使用Python开源项目“PythonSendMail”,快速实现自动发送带Excel报表附件的邮件。只需要进行简…

操作系统篇--八股文学习第十天| 进程和线程之间有什么区别;并行和并发有什么区别;解释一下用户态和核心态,什么场景下,会发生内核态和用户态的切换?

进程和线程之间有什么区别 答&#xff1a; 进程是资源调度和分配的基本单位。 线程是程序执行的最小单位&#xff0c;线程是进程的子任务&#xff0c;是进程内的执行单元。 一个进程至少有一个线程&#xff0c;一个进程可以运行多个线程&#xff0c;这些线程共享同一块内存…