当前位置: 首页 > news >正文

LangChain —— Message —— How to trim messages

文章目录

  • 一、概述
  • 二、获取最后的 max_tokens 令牌
  • 三、获取第一个 max_tokens 令牌
  • 四、编写自定义令牌计数器
  • 五、连成链
  • 六、使用 ChatMessageHistory


一、概述

 所有模型都有 有限的 上下文窗口,这意味着它们可以作为输入的 token 数量是有限的。如果你有很长的消息,或者一个 chain 或 agent 累积了很长的 历史消息,你需要管理你传递给模型的消息的长度。
 trim_messages util 提供了一些基本策略,用于将消息列表修剪为特定的 token 长度。


二、获取最后的 max_tokens 令牌

 为了获取消息列表中的最后一个 max_tokens,我们可以设置 strategy=“last”。请注意,对于我们的 token_counter,我们可以将其传入到一个函数 (下面将详细介绍) 或一个语言模型 (因为语言模型有一个消息令牌计数方法) 中。当调整消息以适应特定模型的上下文窗口时,将其传入到模型是有意义的:

# pip install -U langchain-openai
from langchain_core.messages import (AIMessage,HumanMessage,SystemMessage,trim_messages,
)
from langchain_openai import ChatOpenAImessages = [SystemMessage("you're a good assistant, you always respond with a joke."),HumanMessage("i wonder why it's called langchain"),AIMessage('Well, I guess they thought "WordRope" and "SentenceString" just didn\'t have the same ring to it!'),HumanMessage("and who is harrison chasing anyways"),AIMessage("Hmmm let me think.\n\nWhy, he's probably chasing after the last cup of coffee in the office!"),HumanMessage("what do you call a speechless parrot"),
]trim_messages(messages,max_tokens=45,strategy="last",token_counter=ChatOpenAI(model="gpt-4o"),
)

 如果我们想始终保留初始系统消息,我们可以指定 include_system=True:
 如果我们想允许拆分消息的内容,我们可以指定 allow_partial=True:
 如果我们需要确保我们的第一条消息 (不包括 SystemMessage) 始终是特定类型的,我们可以指定 start_on:

trim_messages(messages,max_tokens=60,strategy="last",token_counter=ChatOpenAI(model="gpt-4o"),include_system=True,start_on="human",
)

三、获取第一个 max_tokens 令牌

 我们可以通过指定 strategy=“first” 来执行获取第一个 max_tokens 的翻转操作:

trim_messages(messages,max_tokens=45,strategy="first",token_counter=ChatOpenAI(model="gpt-4o"),
)

四、编写自定义令牌计数器

 我们可以编写一个自定义令牌计数器函数,该函数接收消息列表并返回一个整数。

from typing import List
# pip install tiktoken
import tiktoken
from langchain_core.messages import BaseMessage, ToolMessagedef str_token_counter(text: str) -> int:enc = tiktoken.get_encoding("o200k_base")return len(enc.encode(text))def tiktoken_counter(messages: List[BaseMessage]) -> int:"""Approximately reproduce https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynbFor simplicity only supports str Message.contents."""num_tokens = 3  # every reply is primed with <|start|>assistant<|message|>tokens_per_message = 3tokens_per_name = 1for msg in messages:if isinstance(msg, HumanMessage):role = "user"elif isinstance(msg, AIMessage):role = "assistant"elif isinstance(msg, ToolMessage):role = "tool"elif isinstance(msg, SystemMessage):role = "system"else:raise ValueError(f"Unsupported messages type {msg.__class__}")num_tokens += (tokens_per_message+ str_token_counter(role)+ str_token_counter(msg.content))if msg.name:num_tokens += tokens_per_name + str_token_counter(msg.name)return num_tokenstrim_messages(messages,max_tokens=45,strategy="last",token_counter=tiktoken_counter,
)
  • 定义 str_token_counter 函数
    • 该函数接受一个字符串 text 并返回该字符串的令牌数量。
    • 使用 tiktoken.get_encoding(“o200k_base”) 获取编码器,然后使用 enc.encode(text) 将文本编码为令牌,并返回令牌的长度。
  • 定义 tiktoken_counter 函数:
    • 该函数接受一个 BaseMessage 类型的消息列表 messages 并返回总的令牌数量。
    • 由于每个回复都以 <|start|>assistance<|message|> 开头,所以每个消息列表初始都默认有 3 个 token,每个消息有一个基本的令牌数 tokens_per_message,每个 name 属性预设的固定令牌数 tokens_per_name,假设其值为 1。
    • 函数通过迭代消息列表,并根据消息的角色 (如 user、assistant、tool、system) 计算令牌数量。
    • 根据消息的 tokens_per_message、role、content,计算总的令牌数。
    • 如果遇到不支持的消息类型,会引发 ValueError。
    • 对于每个消息,如果消息对象 msg 有 name 属性 (即 msg.name 不为 None 或空),那么就要计算该 name 属性所包含的令牌数量,并将其加入到总令牌数 num_tokens 中。
  • 调用 trim_messages 函数 (假设定义在其他地方):
    • messages:要处理的消息列表。
    • max_tokens=45:最大允许的令牌数。
    • strategy=“last”:修剪策略 (假设修剪最后的消息)。
    • token_counter=tiktoken_counter:用于计算令牌数的函数。

五、连成链

 trim_message可以以命令式(如上所述)或声明式的方式使用,从而便于与链中的其他组件组合。

llm = ChatOpenAI(model="gpt-4o")# Notice we don't pass in messages. This creates
# a RunnableLambda that takes messages as input
trimmer = trim_messages(max_tokens=45,strategy="last",token_counter=llm,include_system=True,
)chain = trimmer | llm
chain.invoke(messages)

 查看 LangSmith 跟踪,我们可以看到,在消息传递到模型之前,它们首先被修剪。
 如果只看 trimer,我们可以看到它是一个Runnable对象,可以像所有Runnables一样被调用:

trimmer.invoke(messages)

六、使用 ChatMessageHistory

 在处理聊天历史记录时,修剪消息特别有用,因为聊天历史记录可能会变得任意长:

from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistorychat_history = InMemoryChatMessageHistory(messages=messages[:-1])def dummy_get_session_history(session_id):if session_id != "1":return InMemoryChatMessageHistory()return chat_historyllm = ChatOpenAI(model="gpt-4o")trimmer = trim_messages(max_tokens=45,strategy="last",token_counter=llm,include_system=True,
)chain = trimmer | llm
chain_with_history = RunnableWithMessageHistory(chain, dummy_get_session_history)
chain_with_history.invoke([HumanMessage("what do you call a speechless parrot")],config={"configurable": {"session_id": "1"}},
)
  • 第四行,创建一个 InMemoryChatMessageHistory 对象 chat_history,并初始化它的消息历史为 messages 列表 (除了最后一个消息)。
  • 第六行,定义一个函数 dummy_get_session_history,根据 session_id 返回相应的聊天历史记录:
    • 如果 session_id 不等于 “1”,则返回一个新的空的 InMemoryChatMessageHistory 对象。
    • 如果 session_id 等于 “1”,则返回之前定义的 chat_history。
  • 倒数第五行,创建一个 RunnableWithMessageHistory 对象 chain_with_history,将 chain 和 dummy_get_session_history 结合在一起,使其能够处理带有历史记录的消息。
  • 倒数第四行,调用 chain_with_history 对象的 invoke 方法,传入一个包含 HumanMessage(“what do you call a speechless parrot”) 的列表,和配置 {“configurable”: {“session_id”: “1”}}:
    • 该方法将根据 session_id 为 “1” 调用 dummy_get_session_history 返回相应的历史记录。
    • 将消息传递给链 chain,先修剪再由 llm 处理。

 查看 LangSmith 跟踪,我们可以看到我们检索了所有消息,但在将消息传递给模型之前,它们被修剪成只有系统消息和最后一条人类消息。

相关文章:

LangChain —— Message —— How to trim messages

文章目录 一、概述二、获取最后的 max_tokens 令牌三、获取第一个 max_tokens 令牌四、编写自定义令牌计数器五、连成链六、使用 ChatMessageHistory 一、概述 所有模型都有 有限的 上下文窗口&#xff0c;这意味着它们可以作为输入的 token 数量是有限的。如果你有很长的消息&…...

专升本-1.0.3(英语)-升本209天-星期二

自己要耐得住寂寞&#xff0c;守得住自己的初心&#xff0c;守得住自己的未来&#xff0c;然后不断地真实地面对自己&#xff0c;使自己不断地获得一个真实地成长&#xff0c;说真话办真事&#xff0c;自己总会有一条路了&#xff0c;说真话&#xff0c;办真事的那条路才是最为…...

集合媒体管理、分类、搜索于一体的开源利器:Stash

Stash&#xff1a;强大的媒体管理工具&#xff0c;让您的影音生活井井有条- 精选真开源&#xff0c;释放新价值。 概览 Stash是一个专为个人媒体管理而设计的开源工具&#xff0c;基于 Go 编写&#xff0c;支持自部署。它以用户友好的界面和强大的功能&#xff0c;满足了现代用…...

数仓工具—Hive语法之事务表更新Transactional Table Update

Hive事务表更新 众所周知,Apache Hive 是建立在 Hadoop HDFS 之上的数据仓库框架。由于它包含表,您可能希望根据数据的变化更新表记录。直到最近,Apache Hive 还不支持事务。从 Hive 0.14 及以上版本开始支持事务性表。您需要启用 ACID 属性才能在 Hive 查询中使用更新、删…...

系统架构师(每日一练2)

每日一练 1.为实现对象重用&#xff0c;COM支持两种形式的对象组装&#xff0c;在()重用形式下&#xff0c;一个外部对象拥有指向一个内部对象的唯一引用&#xff0c;外部对象只是把请求转发给内部对象;在()重用形式下&#xff0c;直接把内部对象的接口引用传给外部对象的客户…...

Django REST Framework(十)视图集-ViewSet

视图集&#xff08;ViewSet&#xff09;是 Django REST framework 中的一个高级特性&#xff0c;它允许你使用更少的代码来实现标准的 CRUD&#xff08;创建、读取、更新、删除&#xff09;操作。ViewSet 类本质上是基于 GenericAPIView 的&#xff0c;但它们提供了更多的默认行…...

sping总览

一、spring体系 1. spring是什么&#xff1f; 轻量级的开源的J2EE框架。它是一个容器框架&#xff0c;主要实现了ioc&#xff0c;同时又通过aop实现了面向切面编程&#xff0c;它又是一个中间层框架&#xff08;万能胶&#xff09;可以起一个连接作用&#xff0c;比如说把myba…...

【Godot4.2】MLTag类:HTML、XML通用标签类

概述 HTML和XML采用类似的标签形式。 之前在Godot中以函数库形式实现了网页标签和内容生成。能用&#xff0c;但是缺点也很明显。函数之间没有从属关系&#xff0c;但是多有依赖&#xff0c;而且没有划分出各种对象和类型。 如果以完全的面向对象形式来设计标签类或者元素类…...

美式键盘 QWERTY 布局的起源

注&#xff1a;机翻&#xff0c;未校对。 The QWERTY Keyboard Is Tech’s Biggest Unsolved Mystery QWERTY 键盘是科技界最大的未解之谜 It’s on your computer keyboard and your smartphone screen: QWERTY, the first six letters of the top row of the standard keybo…...

【JavaEE】HTTP(2)

&#x1f921;&#x1f921;&#x1f921;个人主页&#x1f921;&#x1f921;&#x1f921; &#x1f921;&#x1f921;&#x1f921;JavaEE专栏&#x1f921;&#x1f921;&#x1f921; &#x1f921;&#x1f921;&#x1f921;下一篇文章&#xff1a;【JavaEE】HTTP协议(…...

LinuxShell编程2——shell搭建Discuzz论坛网站

目录 一、环境准备 ①准备一台虚拟机 ②初始化虚拟机 1、关闭防火墙 2、关闭selinux 3、配置yum源 4、修改主机名 二、搭建LAMP环境 ①安装httpd(阿帕奇apache&#xff09;服务器 查看是否安装过httpd 启动httpd 设置开机启动 查看状态 安装网络工具 测试 ②安装…...

.NET MAUI开源架构_1.学习资源分享

最近需要开发Android的App&#xff0c;想预研下使用.NET开源架构.NET MAUI来开发App程序。因此网上搜索了下相关资料&#xff0c;现在把我查询的结果记录下&#xff0c;方便后面学习。 1.官方文档 1.1MAUI官方学习网站 .NET Multi-Platform App UI 文档 - .NET MAUI | Micro…...

Unsloth 微调 Llama 3

本文参考&#xff1a; https://colab.research.google.com/drive/135ced7oHytdxu3N2DNe1Z0kqjyYIkDXp 改编自&#xff1a;https://blog.csdn.net/qq_38628046/article/details/138906504 文章目录 一、项目说明安装相关依赖下载模型和数据 二、训练1、加载 model、tokenizer2、…...

热修复的原理

热修复的原理 水一篇哈&#xff0c;完事儿后删掉热修复的原理 水一篇哈&#xff0c;完事儿后删掉 热修复的原理 Java虚拟机 —— JVM 是加载类的class文件的&#xff0c;而Android虚拟机——Dalvik/ART VM 是加载类的dex文件&#xff0c;而他们加载类的时候都需要ClassLoader,…...

【对顶堆 优先队列】2102. 序列顺序查询

本文涉及知识点 对顶堆 优先队列 LeetCode 2102. 序列顺序查询 一个观光景点由它的名字 name 和景点评分 score 组成&#xff0c;其中 name 是所有观光景点中 唯一 的字符串&#xff0c;score 是一个整数。景点按照最好到最坏排序。景点评分 越高 &#xff0c;这个景点越好。…...

Go 语言中的互斥锁 Mutex

Mutex 是一种互斥锁,名称来自 mutual exclusion,是一种用于控制多线程对共享资源的竞争访问的同步机制。在有的编程语言中,也将其称为锁(lock)。当一个线程获取互斥锁时,它将阻止其他线程对该资源的访问,直到该线程释放锁。这可以防止多个线程对共享资源进行冲突访问,从而…...

CSS 中的 ::before 和 ::after 伪元素

目录 一、CSS 伪元素 二、::before ::after 介绍 1、::before 2、::after 3、content 常用属性值 三、::before ::after 应用场景 1、设置统一字符 2、通过背景添加图片 3、添加装饰线 4、右侧展开箭头 5、对话框小三角 6、插入icon图标 一、CSS 伪元素 CSS伪元…...

JuiceFS缓存特性

缓存 对于一个由对象存储和数据库组合驱动的文件系统&#xff0c;缓存是本地客户端与远端服务之间高效交互的重要纽带。读写的数据可以提前或者异步载入缓存&#xff0c;再由客户端在后台与远端服务交互执行异步上传或预取数据。相比直接与远端服务交互&#xff0c;采用缓存技…...

R语言实现SVM算法——分类与回归

### 11.6 基于支持向量机进行类别预测 ### # 构建数据子集 X <- iris[iris$Species! virginica,2:3] # 自变量&#xff1a;Sepal.Width, Petal.Length y <- iris[iris$Species ! virginica,Species] # 因变量 plot(X,col y,pch as.numeric(y)15,cex 1.5) # 绘制散点图…...

React@16.x(57)Redux@4.x(6)- 实现 bindActionCreators

目录 1&#xff0c;分析1&#xff0c;直接传入函数2&#xff0c;传入对象 2&#xff0c;实现 1&#xff0c;分析 一般情况下&#xff0c;action 并不是一个写死的对象&#xff0c;而是通过函数来获取。 而 bindActionCreators 的作用&#xff1a;为了更方便的使用创建 action…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

WebRTC从入门到实践 - 零基础教程

WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09;是一个支持网页浏览器进行实时语音…...

提升移动端网页调试效率:WebDebugX 与常见工具组合实践

在日常移动端开发中&#xff0c;网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时&#xff0c;开发者迫切需要一套高效、可靠且跨平台的调试方案。过去&#xff0c;我们或多或少使用过 Chrome DevTools、Remote Debug…...

人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型

在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重&#xff0c;适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解&#xff0c;并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...

在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例

目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码&#xff1a;冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...