LangChain与大型语言模型(LLMs)应用基础教程:记忆力组件

news2025/4/8 17:06:40

 

如果您还没有看过我之前写的两篇博客,请先看一下,这样有助于对本文的理解:

LangChain与大型语言模型(LLMs)应用基础教程:Prompt模板

LangChain与大型语言模型(LLMs)应用基础教程:信息抽取

LangChain与大型语言模型(LLMs)应用基础教程:角色定义 

在默认情况下Chain和LLM都是无状态的,这意味着它们独立地处理每个传入的prompt(底层 LLM 和聊天模型也是如此),因此它们不具有记住上下文的能力,但是在很多应用场景中我们需要LLM具有记住上下文的能力,这样会使我们的机器人看起来更加“聪明”,从而给用户带来更好的用户体验。今天我们来介绍几种在LangChain中常用的记忆力组件。

首先我们需要安装如下的python包:

pip -q install openai langchain huggingface_hub transformers

1. ConversationBufferMemory

这是最简单的内存记忆力组件,它的功能是直接将用户和机器人之间的聊天内容记录在内存中。下面我们看一个例子:

from langchain.chains.conversation.memory import ConversationBufferMemory
from langchain import OpenAI
from langchain.chains import ConversationChain
import os
#你申请的openai的api_key
os.environ['OPENAI_API_KEY'] = 'xxxxxx'

#定义llm
llm = OpenAI(model_name='text-davinci-003', 
             temperature=0, 
             max_tokens = 256)

#定义记忆力组件
memory = ConversationBufferMemory()

#定义chain
conversation = ConversationChain(
    llm=llm, 
    verbose=True, 
    memory=memory
)

这里我们首先定义了一个openai的语言模型llm, 一个记忆力组件ConversationBufferMemory,和一个chain, Chain是Langchain中的核心组件,llm必须和Chain结合在一起才能正常工作。接下来就开始我们和openai语言模型的聊天:

print(conversation.predict(input='你好,我是王老六'))

 这里我们看到在内存中存放了两部分信息,首先是一个前缀信息:The following is ....,然后是机器人和用户之间的聊天内容。这里的前缀信息有助于让机器人明确自己的角色定义,从而限制机器人不能随心所欲的回答用户提出的问题。

print(conversation.predict(input='你叫什么名字啊?'))

print(conversation.predict(input="那就叫你大聪明吧,怎么样?"))

 

print(conversation.predict(input="你还记得我叫什么名字吗?"))

 

这里我们注意到我们和机器人之间的多轮的对话内容全部被自动保存在了内存中。这样机器人就有了记忆力,它能记住我之前说过的话。

 2. ConversationBufferWindowMemory

ConversationBufferWindowMemory组件与之前的ConversationBufferMemory组件的差别是它增加了一个窗口参数,它的作用是可以指定保存多轮对话的数量:

#定义openai的语言模型
llm = OpenAI(model_name='text-davinci-003', 
             temperature=0, 
             max_tokens = 256)

#定义内存组件,k=2表示只保存最近的两轮对话内容
window_memory = ConversationBufferWindowMemory(k=2)

#定义chain
conversation = ConversationChain(
    llm=llm, 
    verbose=True, 
    memory=window_memory
)

这里ConversationBufferWindowMemory的参数k=2表示在内存中只保存最近的2轮对话内容,因此更早的对话内容将被抛弃掉。

print(conversation.predict(input='你好,我是王老六'))

print(conversation.predict(input='你叫什么名字啊?'))

 

print(conversation.predict(input='那就叫你大聪明吧,怎么样?'))

 

print(conversation.predict(input='你还记得我叫什么吗?'))

 

 这里我们观察到,在内存中只保留了Human-AI,Human-AI两轮对话内容再加当前用户提出的问题。更早之前的Human-AI的对话内容会被抛弃掉,所以最后机器人不记得我叫什么名字了。

3. ConversationSummaryMemory

与ConversationBufferMemory不同,ConversationSummaryMemory它不会将用户和机器人之前的所有对话都存储在内存中。它只会存储一个用户和机器人之间的聊天内容的摘要,这样做的目的可能是为了节省内存开销和token的数量,因为像openai这样的语言模型是按token数量来收费的,所以能省则省。

#定义openai的语言模型
llm = OpenAI(model_name='text-davinci-003', 
             temperature=0, 
             max_tokens = 256)
#定义内存组件
summary_memory = ConversationSummaryMemory(llm=OpenAI())
#定义Chain
conversation = ConversationChain(
    llm=llm, 
    verbose=True, 
    memory=summary_memory
)

这里我们将内存组件换成了ConversationSummaryMemory,它会在内存中产生聊天内容的摘要信息。

print(conversation.predict(input='你好,我是王老六'))

 

print(conversation.predict(input='你叫什么名字啊?'))

 这里我们看到在内存中会保留前缀信息,之前多轮对话的摘要信息,以及用户当前提出的问题这三部分内容。

print(conversation.predict(input='那就叫你大聪明吧,怎么样?'))

 

print(conversation.predict(input='你还记得我叫什么吗?'))

4. ConversationSummaryBufferMemory

ConversationSummaryBufferMemory结合了前面的ConversationBufferWindowMemory,ConversationSummaryMemory两种工作方式,即在内存中保留一部分聊天内容的摘要,和一部分的多轮聊天内容,但是要在内存中保留多少轮聊天内容,这取决于参数max_token_limit,如果将max_token_limit设置为较小的值时,那么大部分之前的聊天内容都被转换成了摘要,少部分的聊天内容被保存下来,相反当max_token_limit设置为较大的值时,小部分的之前聊天内容被转换成摘要,而大部分聊天内容被保留下来。

from langchain.chains.conversation.memory import ConversationSummaryBufferMemory
from langchain import OpenAI
from langchain.chains import ConversationChain
import os

os.environ['OPENAI_API_KEY'] = 'xxxxx'


llm = OpenAI(model_name='text-davinci-003', 
             temperature=0, 
             max_tokens = 256)

memory = ConversationSummaryBufferMemory(llm=OpenAI(), max_token_limit=256) 

conversation = ConversationChain(
    llm=llm, 
    memory=memory, 
    verbose=True
)

这里我们将max_token_limit设置为256,表示当我们多轮聊天内容的prompt长度超过256时,较早的聊天内容将会被转换成摘要,同时小于256个token的聊天内容会被保留下来。

print(conversation.predict(input='你好,我是王老六'))

print(conversation.predict(input='你叫什么名字啊?'))

 

print(conversation.predict(input='我给你取个名字叫大聪明吧,怎么样?'))

print(conversation.predict(input='你还记得我叫什么吗?'))

print(conversation.predict(input='你还记得我给你起的名字吗?'))

print(conversation.predict(input='我生病了,肚子疼,还呕吐发烧,你说我是自己吃点药对付一下呢还是去医院看一下比较好?'))

 从上述多伦聊天内容中我们可以发现,随着聊天轮次的增加,内存中的摘要信息量也在增加,而内存中的多轮聊天内容的长度被限制在256个token,当有新的聊天内容进到内存中后,较早的聊天内容将会被转换成摘要从而被踢出内存中的多伦聊天记录。

5.ConversationKGMemory

我们知道像ChatGPT这样的LLM最大的问题是会“产生幻觉(hallucinate)”,也就是当llm不知道正确答案的情况下,往往会天马行空自由发挥从而导致llm给出了完全不正确的答案,为了避免llm产生幻觉,Langchain提供了ConversationKGMemory组件即“对话知识图谱记忆”组件,该组件可以从和用户的对话中提取出知识图谱信息,即一些核心的关键信息,这些信息比之前的ConversationSummaryMemory组件所保存的信息更为精简。llm将会严格依据知识图谱的中的相关内容来回答用户的问题,从而避免产生幻觉。

from langchain import OpenAI
from langchain.prompts.prompt import PromptTemplate
from langchain.chains import ConversationChain
from langchain.chains.conversation.memory import ConversationKGMemory

llm = OpenAI(temperature=0)


template = """下面是一段人与AI的友好对话。 人工智能很健谈,并根据其上下文提供了许多具体细节。
如果 AI 不知道问题的答案,它会如实说它不知道。 AI 仅使用“相关信息”部分中包含的信息,不会产生幻觉。

相关信息:

{history}

对话内容:
Human: {input}
AI:"""
prompt = PromptTemplate(
    input_variables=["history", "input"], template=template
)

conversation_with_kg = ConversationChain(
    llm=llm, 
    verbose=True, 
    prompt=prompt,
    memory=ConversationKGMemory(llm=llm)
)

这里我们创建了一个prompt模板,模板中有三部分信息:前缀信息, 相关信息,对话内容。前缀信息之前已经介绍过,这里不再说明,相关信息指的是从之前的多轮对话中提取出来的知识图谱信息,即精简的核心关键信息,对话内容则只保留用户当前所提出的问题。

conversation_with_kg.predict(input="你好")

conversation_with_kg.predict(input="我叫大神,我有一位朋友叫小明,他是一位宠物医院的医生。")

 

conversation_with_kg.predict(input="小明是做什么的?")

 

conversation_with_kg.predict(input="小明的爸爸也是一位宠物医生")

conversation_with_kg.predict(input="不过你小明的妈妈是位老师")

conversation_with_kg.predict(input="小明的哥哥是个老板")

conversation_with_kg.predict(input="小明的妈妈是做什么的?")

6.Entity Memory

在自然语言处理(NLP)技术中一项基本的功能就是:命名实体识别(Named Entity Recognition,简称NER)又称作专名识别、命名实体,是指识别文本中具有特定意义的实体,主要包括人名、地名、机构名、专有名词等,以及时间、数量、货币、比例数值等文字。Langchain提供的实体记忆(Entity Memory)组件能自动提取AI与人类交互过程中的实体信息,并将其以字典的形式保存在内存中。实体的正确识别能帮助AI能更准确的回答人类提出的关于实体的相关问题。下面我们来看一个例子:

from langchain import OpenAI, ConversationChain
from langchain.chains.conversation.memory import ConversationEntityMemory
from langchain.chains.conversation.prompt import ENTITY_MEMORY_CONVERSATION_TEMPLATE
from pydantic import BaseModel
from typing import List, Dict, Any

这里我们会使用一个ENTITY_MEMORY_CONVERSATION_TEMPLATE的模板,该模板为内存记忆的固定格式,下面我们看一下该模板的主要内容:

## The propmpt
print(ENTITY_MEMORY_CONVERSATION_TEMPLATE.template)

 我们将其翻译成中文:

 该模板基本上也是由3部分组成:前缀信息, 上下文,历史聊天信息,其中,“上下文”中记录的是历史聊天信息中提取出来的实体信息。

conversation.predict(input="你好,我家的小狗生病了怎么办?")

 

conversation.predict(input="我突然想起来我有一个朋友叫小明,他是一位宠物医生。")

conversation.predict(input="可我听说他只会给小猫看病,不会给小狗看病,怎么办?")

conversation.predict(input="我还是去找小王吧,他是一个更专业的兽医。")

 

conversation.predict(input="请问小明会给小狗看病吗?")

 通过上述简单的几轮对话,我们看到聊天记录中的实体信息被提取出来,并且AI能够根据实体信息来准确回答我的问题。下面我们看一下实体信息中的完整内容:

from pprint import pprint
pprint(conversation.memory.entity_store.store)

 总结

今天我们学习了Langchain提供的6种记忆力组件它们分别是:

  • ConversationBufferMemory
  • ConversationBufferWindowMemory
  • ConversationSummaryMemory
  • ConversationSummaryBufferMemory
  • ConversationKGMemory
  • Entity Memory

它们有着各自不能的功能和特点,根据不同的应用场景我们可以选择不同的记忆力组件,当我们开发一个与AI交互的应用程序时选择正确的记忆力组件能够成倍的提高AI的工作效率,同时让AI在回答人类的问题时更加准确,自然,而不会产生幻觉。

参考资料

LangChain官方文档

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

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

相关文章

在线甘特图制作教程

在线甘特图制作教程 很多的甘特图工具都是需要下载到本地,并且做好了之后也不方便分享给别人。给大家分享一个在线的甘特图制作工具 不需要登录注册 知竹甘特图 https://www.yxsss.com/ 打开知竹甘特图 https://www.yxsss.com/gatt/3b7d1ecb7211b9473e7d1ecb72 …

015:Mapbox GL绘制修改多边形,实时更新面积

第015个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中添加draw组件,绘制多边形,编辑多边形,实时显示面积值。这里使用turf来计算面积值。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源代码(共92行)安装…

ASP.NET Core MVC 从入门到精通之wwwroot和客户端库

随着技术的发展,ASP.NET Core MVC也推出了好长时间,经过不断的版本更新迭代,已经越来越完善,本系列文章主要讲解ASP.NET Core MVC开发B/S系统过程中所涉及到的相关内容,适用于初学者,在校毕业生&#xff0c…

remvw布局

文章目录 rem&vw布局rem布局方式原理使用第三框架 vw布局方式原理使用 rem&vw混合布局方式vw方案案例 rem&vw布局 rem布局方式 原理 rem是相对于根元素(html元素)的字体大小来计算的,因此可以根据不同的屏幕尺寸和设备类型自动…

EF Core入门

文章目录 前言一、EF Core环境搭建二、基本的增删改查1.增加数据2.查询数据3.修改数据,删除数据 前言 EF Core是微软官方提供的ORM框架。EF Core不仅可以操作Microsoft SQL Server、MySQL、Oracle、PostgreSQL等数据库,而且可以操作Azure Cosmos DB等No…

【让你惊呼的“神器”,ChatGPT inside】

让你惊呼的“神器”,ChatGPT inside ChatGPT 的横空出世,已经搅动了整个科技圈。而它给自然语言处理领域带来的革命性变革,也为很多初创公司和开发者打开了新世界的大门。 在过去,自然语言处理技术通常只被各大科技巨头藏私&…

玩机搞机----root面具的安装 更新 隐藏root 德尔塔面具等等综合解析

目前的机型都是root面具,今天的帖子主要分析下面具的一些使用常识。一般面具如何使用一参考我前面的帖子。基本步骤都是解锁bl---修补boot---刷入boot----安装面具apk。但目前很多app会检测系统root,对于有些敏感类软件例如银行等等然后会检测当前系统ro…

C/C++每日一练(20230423)

目录 1. 多组输入求和 ※ 2. 螺旋矩阵 II 🌟🌟 3. 路径交叉 🌟🌟🌟 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 1. 多组…

用golang实现traceroute

Traceroute 概念 traceroute是一种网络诊断工具,通过traceroute可以诊断出本机到目的地IP之间的路由情况,例如路由跳数、延迟、是否可达等信息。该工具在linux环境下的命令是traceroute或者tracepath,在windows下命令是tracert。 工作原理…

动态路由四大天王:OSPF、RIP、IS-IS、BGP,收藏这篇文章足以!

在计算机网络中,OSPF、RIP、IS-IS、BGP 都是常见的路由协议。它们分别具有不同的特点和适用场景。本文将对这四种路由协议进行对比,以帮助读者更好地了解它们的优缺点和适用范围。 OSPF OSPF(Open Shortest Path First)是一种链路…

中文编程最高境界,不用编程,会用excel就会用,香不香?

一直以来,关于中文编程的争议从未消停过。现如今,中文编程发展又是如何? ★为了实现中文编程,从未停下脚步 我们知道,中国人一直以来为了实现中文编程付出了不懈的努力,前前后后研发了几十种中文编程语言。…

JavaSE补充 | 了解数据结构与常用集合的源码分析

目录 一:数据结构 1. 数据结构剖析 1.1 研究对象一:数据间逻辑关系 1.2 研究对象二:数据的存储结构(或物理结构) 1.3 研究对象三:运算结构 2. 常见存储结构之:数组 3. 常见存储结构之&am…

奇葩的new Date()

大家平时在开发的时候有没被new Date()折磨过?就是它的诸多怪异的设定让你每每用的时候,都可能不小心踩坑。造成程序意外出错,却一下子找不到问题出处,那叫一个烦透了…… 下面,我就列举它的“四宗罪”及应用思考 可恶…

微前端运行时

目录 微前端运行时基于 SPA 的微前端架构应用生命周期 微前端运行时 谈到微前端绕不开的话题就是为什么不适用 iframe 作为承载微前端子应用的容器,其实从浏览器原生的方案来说,iframe 不从体验角度上来看几乎是最可靠的微前端方案了,主应用…

关于FPV图传系统时延讨论

关于FPV图传系统时延讨论 1. 源由2. 时延测试方法3. 时延测试资料4. 关于模拟图传5. 关于FPV时延感受5.1 静态时延5.2 动态时延 6. 参考资料7. 附录 DJI 图传系统 1. 源由 视频图传系统最重要的几个指标: 分辨率视角帧率时延传输距离 目前高清图传主要规则&#…

【Cartopy基础入门】如何丝滑的加载Geojson数据

原文作者:我辈李想 版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。 Cartopy基础入门 【Cartopy基础入门】Cartopy的安装 【Cartopy基础入门】如何丝滑的加载Geojson数据 文章目录 Cartopy基础入门一、Geojson数据来源二…

C语言 非本地跳转 实现native层TryCatch

前言 最近研究native hook的技术,了解到了这个非本地跳转,本文就是介绍他,对于解决native crash非常有用。 非本地跳转介绍 C语言的本地跳转是指goto、break、continue等语句,但是这个语句最大局限就是只能实现函数内部的跳转。…

Day3 自学Pytorch 数据集 torchvision.transforms类&torchvision.datasets.ImageFolder类

1.torchvision.transforms类 可调用的函数列表https://pytorch.org/vision/stable/transforms.html 介绍几个常用的函数: ① transforms.Resize() 将图像转换成目标大小 参数列表: size (sequence or int): (h,w&a…

Scala 中的 List 列表详解

目录 一、不可变长的List列表 1.List列表的声明与遍历 2.List列表的map、flatMap函数 3.List列表的filter过滤函数 4.List列表的count计数函数 二、可变长的List列表 1.可变长List声明 2.可变长List的添加方法 三、List列表其余的方法与函数 一、不可变长的List列表 …

任务调度原理 通俗讲解详细(FreeRTOS)

寄存器说明 以cortex-M3,首先先要了解比较特别的几个寄存器: r15 PC程序计数器(Program Counter),存储下一条要执行的指令的地址。 r14 LR连接寄存器(Link Register ),保存函数返回地址&#x…