LangChain 16 通过Memory记住历史对话的内容

LangChain系列文章

  1. LangChain 实现给动物取名字,
  2. LangChain 2模块化prompt template并用streamlit生成网站 实现给动物取名字
  3. LangChain 3使用Agent访问Wikipedia和llm-math计算狗的平均年龄
  4. LangChain 4用向量数据库Faiss存储,读取YouTube的视频文本搜索Indexes for information retrieve
  5. LangChain 5易速鲜花内部问答系统
  6. LangChain 6根据图片生成推广文案HuggingFace中的image-caption模型
  7. LangChain 7 文本模型TextLangChain和聊天模型ChatLangChain
  8. LangChain 8 模型Model I/O:输入提示、调用模型、解析输出
  9. LangChain 9 模型Model I/O 聊天提示词ChatPromptTemplate, 少量样本提示词FewShotPrompt
  10. LangChain 10思维链Chain of Thought一步一步的思考 think step by step
  11. LangChain 11实现思维树Implementing the Tree of Thoughts in LangChain’s Chain
  12. LangChain 12调用模型HuggingFace中的Llama2和Google Flan t5
  13. LangChain 13输出解析Output Parsers 自动修复解析器
  14. LangChain 14 SequencialChain链接不同的组件
  15. LangChain 15根据问题自动路由Router Chain确定用户的意图
    在这里插入图片描述

1. Memory 记忆

在这里插入图片描述
大多数LLM应用程序都有对话界面。对话的一个重要组成部分是能够引用先前在对话中介绍的信息。最基本的是,对话系统应该能够直接访问某些过去的信息窗口。更复杂的系统将需要具有一个世界模型,它不断更新,这使它能够维护有关实体及其关系的信息。

我们称这种存储关于过去交互的信息的能力为“记忆”。LangChain为系统添加记忆提供了许多实用工具。这些实用工具可以单独使用,也可以无缝地整合到链中。

记忆系统需要支持两个基本操作:读取和写入。请记住,每个链定义了一些核心执行逻辑,期望某些输入。其中一些输入直接来自用户,但一些输入可以来自记忆。链将在给定运行中两次与其记忆系统交互。

  1. 在接收到初始用户输入但在执行核心逻辑之前,链将从其记忆系统中读取并增强用户输入。
  2. 在执行核心逻辑但在返回答案之前,链将把当前运行的输入和输出写入记忆中,以便在将来的运行中可以引用它们。

2. 将内存构建到系统中

在任何内存系统中的两个核心设计决策是:

  • 状态如何存储
  • 状态如何查询

2.1 存储:聊天消息列表

任何记忆的基础都是所有聊天互动的历史。即使这些并非全部直接使用,也需要以某种形式存储。LangChain记忆模块的关键部分之一是一系列用于存储这些聊天消息的集成,从内存列表到持久性数据库。

  • 聊天消息存储:如何处理聊天消息以及提供的各种集成。

2.2 查询:在聊天消息之上的数据结构和算法

保留聊天消息列表相当简单。不太简单的是建立在聊天消息之上的数据结构和算法,以便提供最有用的消息视图。

一个非常简单的记忆系统可能只返回每次运行最近的消息。一个稍微复杂一点的记忆系统可能会返回过去K条消息的简明总结。一个更复杂的系统可能会从存储的消息中提取实体,并且只返回当前运行中涉及的实体信息。

每个应用程序对于如何查询记忆都可能有不同的要求。记忆模块应该让简单的记忆系统易于入门,并且如果需要,也能够编写自定义系统。

  • 记忆类型:LangChain支持的各种数据结构和算法所构成的记忆类型

3. 代码实现

让我们来看看LangChainMemory实际上是什么样子。在这里,我们将介绍与任意记忆类互动的基础知识。

让我们来看看如何在链中使用ConversationBufferMemoryConversationBufferMemory是记忆的一种极其简单的形式,它只是在缓冲区中保留聊天消息的列表,并将其传递到提示模板中。

from langchain.memory import ConversationBufferMemorymemory = ConversationBufferMemory()
memory.chat_memory.add_user_message("hi!")
memory.chat_memory.add_ai_message("what's up?")

在使用链式内存时,有一些关键概念需要理解。请注意,这里我们涵盖了对大多数类型的内存都有用的一般概念。每种个别的内存类型可能都有自己必须理解的参数和概念。

3.1 从内存中返回哪些变量

在进入链之前,会从内存中读取各种变量。这些变量有特定的名称,需要与链期望的变量相匹配。您可以通过调用memory.load_memory_variables({})来查看这些变量是什么。请注意,我们传入的空字典只是真实变量的占位符。如果您使用的内存类型依赖于输入变量,您可能需要传入一些变量。

print(memory.load_memory_variables({}))

输出结果

    {'history': "Human: hi!\nAI: what's up?"}

在这种情况下,您可以看到load_memory_variables返回一个名为history的key。这意味着您的链条(很可能是您的提示)应该期望一个名为history的输入。通常您可以通过内存类的参数来控制这个变量。例如,如果您希望将内存变量返回到键chat_history中,您可以这样做:

from langchain.memory import ConversationBufferMemorymemory = ConversationBufferMemory(memory_key="chat_history")
memory.chat_memory.add_user_message("hi!")
memory.chat_memory.add_ai_message("what's up?")print(memory.load_memory_variables({}))

输出结果

    {'chat_history': "Human: hi!\nAI: what's up?"}

这些键的控制参数名称可能因内存类型而异,但重要的是要明白:(1)这是可控的,(2)如何控制它。

3.2 Memory是string字符串还是chat list消息列表

最常见的记忆类型之一涉及返回聊天消息列表。这些可以作为单个字符串返回,全部连接在一起(当它们将被传递到LLMs时很有用),或者作为ChatMessages列表返回(当它们被传递到ChatModels时很有用)。

默认情况下,它们作为单个字符串返回。为了返回消息列表,您可以设置return_messages=True

from langchain.memory import ConversationBufferMemorymemory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
memory.chat_memory.add_user_message("hi!")
memory.chat_memory.add_ai_message("what's up?")print(memory.load_memory_variables({}))

输出结果

 {'chat_history': [HumanMessage(content='hi!', additional_kwargs={}, example=False),AIMessage(content='what's up?', additional_kwargs={}, example=False)]}

3.3 什么Keys保存在内存中

通常情况下,链条会接收或返回多个输入/输出键。在这种情况下,我们如何知道要保存哪些键到聊天消息历史记录中?这通常可以通过内存类型的input_keyoutput_key参数来控制。这些参数默认为None-如果只有一个输入/输出键,则可以直接使用它。但是,如果有多个输入/输出键,则必须指定要使用哪一个的名称。

最后,让我们来看看如何在一个链中使用这个。我们将使用LLMChain,并展示如何同时使用LLM和ChatModel。

# 导入 Langchain 库的 ChatOpenAI 类,用于与 OpenAI 聊天模型进行交互。
from langchain.chat_models import ChatOpenAI# 导入 Langchain 库的不同提示模板类,用于构建会话提示。
from langchain.prompts import (ChatPromptTemplate,MessagesPlaceholder,SystemMessagePromptTemplate,HumanMessagePromptTemplate,
)# 导入 Langchain 的 LLMChain 类,用于创建语言模型链。
from langchain.chains import LLMChain# 导入 Langchain 的 ConversationBufferMemory 类,用于存储和管理会话记忆。
from langchain.memory import ConversationBufferMemory# 导入 dotenv 库,用于从 .env 文件加载环境变量,管理敏感数据,如 API 密钥。
from dotenv import load_dotenv  # 调用 load_dotenv 函数来加载 .env 文件中的环境变量。
load_dotenv()  # 创建 ChatOpenAI 的实例。
llm = ChatOpenAI()# 创建聊天提示模板,包含一个系统消息、一个聊天历史占位符和一个人类消息模板。
prompt = ChatPromptTemplate(messages=[SystemMessagePromptTemplate.from_template("You are a nice chatbot having a conversation with a human."),MessagesPlaceholder(variable_name="chat_history"),HumanMessagePromptTemplate.from_template("{question}")]
)# 创建一个会话记忆,用于存储和返回会话中的消息。
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)# 创建一个 LLMChain 实例,包括语言模型、提示、详细模式和会话记忆。
conversation = LLMChain(llm=llm,prompt=prompt,verbose=True,memory=memory
)# 使用会话链处理第一个问题,并打印回应。
response = conversation({"question": "hi"})
print(response)# 使用相同的会话链处理第二个问题,并打印回应。
response = conversation({"question": "how are you?"})
print(response)

输出

zgpeace at zgpeaces-MBP in ~/Workspace/LLM/langchain-llm-app (develop●) (.venv) 
$ python Memory/memory_theory.py> Entering new LLMChain chain...
Prompt after formatting:
System: You are a nice chatbot having a conversation with a human.
Human: hi> Finished chain.
{'question': 'hi', 'chat_history': [HumanMessage(content='hi'), AIMessage(content='Hello! How can I assist you today?')], 'text': 'Hello! How can I assist you today?'}> Entering new LLMChain chain...
Prompt after formatting:
System: You are a nice chatbot having a conversation with a human.
Human: hi
AI: Hello! How can I assist you today?
Human: how are you?> Finished chain.
{'question': 'how are you?', 'chat_history': [HumanMessage(content='hi'), AIMessage(content='Hello! How can I assist you today?'), HumanMessage(content='how are you?'), AIMessage(content="Thank you for asking! As an AI, I don't have feelings, but I'm here to help you. How can I assist you today?")], 'text': "Thank you for asking! As an AI, I don't have feelings, but I'm here to help you. How can I assist you today?"}

在这里插入图片描述

代码
https://github.com/zgpeace/pets-name-langchain/tree/develop

参考

https://python.langchain.com/docs/modules/memory/

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

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

相关文章

Windows系列:windows2003-建立域

windows2003-建立域 Active Directory建立DNS建立域查看日志xp 加入域 Active Directory 活动目录是一个包括文件、打印机、应用程序、服务器、域、用户账户等对象的数据库。 常见概念:对象、属性、容器 域组件(Domain Component,DC&#x…

snat与dnat

一.SNAT的原理介绍 1.应用环境 局域网主机共享单个公网IP地址接入Internet (私有IP不能在Internet中正常路由) 2.SNAT原理 源地址转换,根据指定条件修改数据包的源IP地址,通常被叫做源映谢 数据包从内网发送到公网时&#xf…

Loki安装部署

Loki安装部署 1、Loki介绍 Loki 是受 Prometheus 启发由 Grafana Labs 团队开源的水平可扩展,高度可用的多租户日志聚合系统。开发语 言: Google Go。它的设计具有很高的成本效益,并且易于操作。使用标签来作为索引,而不是对全文进行检索&…

<avue-crud/>,二级表头,children下字典项的dicUrl失效问题

目录 1.提出问题&#xff1a; 1.1 代码&#xff1a; 1.2 效果图&#xff1a;会发现处在children下的dicUrl失效了 2. 解决思路 3. 解决代码&#xff08;你要的都在这&#xff0c;看这里&#xff09; 1.提出问题&#xff1a; 在使用<avue-crud/>组件实现二级表头时&…

C++中异常的栈展开概念

C中的异常栈展开是指&#xff0c;当某个函数中有异常产生&#xff08;这里不考虑是主动抛出的还是被动产生的&#xff09;&#xff0c;在异常被捕获之前的函数调用链上&#xff0c;函数不会正常执行返回&#xff0c;即异常产生之后的程序逻辑不会被执行。 &#xff08;注意&…

Kafka的存储机制和可靠性

文章目录 前言一、Kafka 存储选择二、Kafka 存储方案剖析三、Kafka 存储架构设计四、Kafka 日志系统架构设计4.1、Kafka日志目录布局4.2、Kafka磁盘数据存储 五、Kafka 可靠性5.1、Producer的可靠性保证5.1.1、kafka 配置为 CP(Consistency & Partition tolerance)系统5.1.…

建堆的时间复杂度和堆排序

文章目录 建堆的时间复杂度向下调整建堆向上调整建堆 堆排序实现 建堆的时间复杂度 下面都以建大堆演示 向下调整建堆 void Adjustdown(HPDataType* a, int size,int parent) {int child parent * 2 1;while (child < size){if (child1<size&&a[child 1] &…

Pandas进阶:transform 数据转换的常用技巧

引言 本次给大家介绍一个功能超强的数据处理函数transform&#xff0c;相信很多朋友也用过&#xff0c;这里再次进行详细分享下。 transform有4个比较常用的功能&#xff0c;总结如下&#xff1a; 转换数值 合并分组结果 过滤数据 结合分组处理缺失值 一. 转换数值 pd.…

贪心算法的介绍

贪心算法&#xff08;又称贪婪算法&#xff09;是指&#xff0c;在对问题求解时&#xff0c;总是做出在当前看来是最好的选择。也就是说&#xff0c;不从整体最优上加以考虑&#xff0c;他所做出的是在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解&#…

Windows 基于 VMware 虚拟机安装银河麒麟高级服务器操作系统

前言 抱着学习的态度研究一下麒麟系统的安装 银河麒麟&#xff08;KylinOS&#xff09;原是在“863计划”和国家核高基科技重大专项支持下&#xff0c;国防科技大学研发的操作系统&#xff0c;后由国防科技大学将品牌授权给天津麒麟&#xff0c;后者在2019年与中标软件合并为…

如何选择共模噪声滤波器

在当前电子产品中&#xff0c;绝大多数的高速信号都使用地差分对结构。 差分结构有一个好处就是可以降低外界对信号的干扰&#xff0c;但是由于设计的原因&#xff0c;在传输结构上还会受到共模噪声的影响。 共模噪声滤波器就可以用于抑制不必要的共模噪声&#xff0c;而不会对…

RNN:文本生成

文章目录 一、完整代码二、过程实现2.1 导包2.2 数据准备2.3 字符分词2.4 构建数据集2.5 定义模型2.6 模型训练2.7 模型推理 三、整体总结 采用RNN和unicode分词进行文本生成 一、完整代码 作者在文章开头地址中使用C实现了这一过程&#xff0c;为了便于理解&#xff0c;这里我…

Java将JavaFX程序最小化托盘

Windows最小化拖盘其实就是将程序放到托盘里面,需要的时候再点击托盘里面的应用图标,此时就可以正常使用应用了,托盘如下: 下面是一个简单的Java程序,可以把窗口最小化到系统托盘: import java.awt.*; import java.awt.event.*; import javax.swing.*;public class Tray…

Paraformer 语音识别原理

Paraformer(Parallel Transformer)非自回归端到端语音系统需要解决两个问题&#xff1a; 准确预测输出序列长度&#xff0c;送入预测语音信号判断包含多少文字。 如何从encoder 的输出中提取隐层表征&#xff0c;作为decoder的输入。 采用一个预测器&#xff08;Predictor&…

GPT带我学Openpyxl操作Excel

注&#xff1a;以下文字大部分文字和代码由GPT生成 一、openpyxl详细介绍 Openpyxl是一个用于读取和编写Excel 2010 xlsx/xlsm/xltx/xltm文件的Python库。它允许您使用Python操作Excel文件&#xff0c;包括创建新的工作簿、读取和修改现有工作簿中的数据、设置单元格格式以及编…

vue中.sync修饰符与$emit(update:xxx)双向数据绑定

文章目录 一、单向数据流二、props父子传值2.1、父组件2.2、子组件2.3、优缺点2.3.1、优点2.3.2、缺点 三、.sync修饰符双向绑定3.1、父组件3.2、子组件3.3、优缺点3.3.1、优点3.3.2、缺点 3.4、[文档](https://v2.cn.vuejs.org/v2/guide/components-custom-events.html#sync-%…

WPF应用开发之附件管理

在我们之前的开发框架中&#xff0c;往往都是为了方便&#xff0c;对附件的管理都会进行一些简单的封装&#xff0c;目的是为了方便快速的使用&#xff0c;并达到统一界面的效果&#xff0c;本篇随笔介绍我们基于SqlSugar开发框架的WPF应用端&#xff0c;对于附件展示和控件的一…

文献速递:机器学习在超声波非破坏性评估中的合成和增强训练数据综述(第一部分)— (机器学习方法在超声波检测中的概述)

文献速递&#xff1a;机器学习在超声波非破坏性评估中的合成和增强训练数据综述&#xff08;第一部分&#xff09;— &#xff08;机器学习方法在超声波检测中的概述&#xff09; Title 题目 A review of synthetic and augmented training data for machine learning in ul…

浅谈STL中的分配器

分配器是STL中的六大部件之一&#xff0c;是各大容器能正常运作的关键&#xff0c;但是对于用户而言确是透明的&#xff0c;它似乎更像是一个幕后英雄&#xff0c;永远也不会走到舞台上来&#xff0c;观众几乎看不到它的身影&#xff0c;但是它又如此的重要。作为用户&#xff…

rest_framework_django 学习笔记二(视图路由)

rest_framework_django 学习笔记二&#xff08;视图路由&#xff09; rest_framwork_django学习笔记一(序列化器) 一、rest framework 中Request 与 Response 1、Request REST framework 传入视图的request对象不再是Django默认的HttpRequest对象&#xff0c;二是REST Fame…