如何使用 `trim_messages` 函数优化消息处理

在进行基于聊天模型的开发时,我们常常面对消息上下文窗口有限的问题。这就要求我们有效地管理传递给模型的消息长度。本文将详细介绍如何使用 trim_messages 实用工具来精简消息列表,从而符合给定的 token 长度要求。

技术背景介绍

语言模型的上下文窗口具有有限容量,即限定了输入消息的 token 数量。如果我们的对话链很长或消息历史积累过多,就需要修剪消息以适应窗口大小。trim_messages 提供了一些基本策略用于修剪消息列表,使其符合上下文窗口的 token 限制。

核心原理解析

trim_messages 函数允许我们设置不同的修剪策略,如获取最后的 max_tokens 或获取最开始的 max_tokens。我们还可以通过传递一个语言模型或自定义的 token 计数器函数,精确计数消息的 token 数量以便正确修剪。

代码实现演示(重点)

以下是代码实现的几个示例,展示了 trim_messages 函数的不同用法:

获取最后的 max_tokens

# 安装必要库
# pip install -U langchain-openai

from langchain_core.messages import AIMessage, HumanMessage, SystemMessage, trim_messages
from langchain_openai import ChatOpenAI

messages = [
    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"),
]

# 修剪消息以获取最后的 45 个 tokens
trimmed_messages = trim_messages(
    messages,
    max_tokens=45,
    strategy="last",
    token_counter=ChatOpenAI(model="gpt-4o")
)
print(trimmed_messages)

保留初始系统消息

trimmed_messages = trim_messages(
    messages,
    max_tokens=45,
    strategy="last",
    token_counter=ChatOpenAI(model="gpt-4o"),
    include_system=True,
)
print(trimmed_messages)

允许部分拆分消息内容

trimmed_messages = trim_messages(
    messages,
    max_tokens=56,
    strategy="last",
    token_counter=ChatOpenAI(model="gpt-4o"),
    include_system=True,
    allow_partial=True,
)
print(trimmed_messages)

应用场景分析

在应用中,修剪消息可以帮助我们优化聊天历史,使其在长时间对话中不超过模型的上下文限制。这在使用语言模型进行问答、情感分析或推荐系统时尤为重要。

实践建议

  1. 选择合适的修剪策略:根据应用场景决定使用 “first” 或 “last” 等策略。
  2. 使用自定义 token 计算器:在需要精确计数的情况下,实现自定义 token 计算器。
  3. 结合实际应用:使用修剪工具链与聊天模型结合,确保对话流畅而不丢失关键上下文。

如果遇到问题欢迎在评论区交流。

—END—

#!/bin/bash # FIO存储性能自动化测试脚本 # 功能:在0-500GB随机位置执行128KB随机写,30秒后在500GB-1TB范围执行随机1G Trim # 测试组合:QD(64,32) × numjobs(1,4,8) # 每组测试后对500GB-1TB区域填盘 # ===== 配置参数 ===== DEVICE="/dev/nvme0n1" # 测试设备 OUTPUT_DIR="fio_test_results" # 结果输出目录 RUNTIME=60 # 主测试时长(秒) TRIM_DELAY=30 # Trim操作延迟时间(秒) SIZE_WRITE="1G" # 每次写操作大小 SIZE_TRIM="1G" # 每次Trim操作大小 MAX_OFFSET="500G" # 写操作最大偏移量 TRIM_START="500G" # Trim起始位置 TRIM_END="1T" # Trim结束位置 FILL_PATTERN="0x00" # 填盘数据模式 # ===== 数学函数 ===== # 将可读存储大小转换为字节数 to_bytes() { echo $1 | numfmt --from=iec } # 生成随机偏移量($\text{offset} \in [\text{start}, \text{end}-\text{size}]$) generate_offset() { local start=$(to_bytes $1) local end=$(to_bytes $2) local size=$(to_bytes $3) local max_offset=$((end - size)) echo $(( RANDOM * RANDOM % (max_offset - start + 1) + start )) } # ===== 性能统计函数 ===== extract_metrics() { local output=$1 local metric_type=$2 # 提取带宽(MB/s) local bw=$(grep -A5 "$metric_type" $output | grep "bw=" | grep -oP 'bw=\K[\d.]+' | head -1) # 提取延迟(μs) local lat=$(grep -A10 "$metric_type" $output | grep -A5 'lat' | grep 'avg=' | grep -oP 'avg=\K[\d.]+') local max_lat=$(grep -A10 "$metric_type" $output | grep -A5 'lat' | grep 'max=' | grep -oP 'max=\K[\d.]+') echo "$bw $lat $max_lat" } # ===== 填盘操作 ===== fill_trim_area() { echo "▶ 开始填盘操作 (${TRIM_START} - ${TRIM_END})" # 使用fio执行全零填充 fio --filename=$DEVICE \ --name=fill \ --ioengine=libaio \ --rw=write \ --bs=1M \ --offset=$TRIM_START \ --size=$(( $(to_bytes $TRIM_END) - $(to_bytes $TRIM_START) )) \ --iodepth=32 \ --numjobs=1 \ --direct=1 \ --buffer_pattern=$FILL_PATTERN \ --group_reporting > /dev/null 2>&1 echo "✔ 填盘完成" } # ===== 主测试函数 ===== run_test() { local qd=$1 local numjobs=$2 local output_file="$OUTPUT_DIR/fio_qd${qd}_j${numjobs}.log" echo "==================================================" echo "▶ 开始测试 [QD=$qd, numjobs=$numjobs]" echo "⏱ 将在${TRIM_DELAY}秒后启动Trim操作" # 生成随机Trim偏移量 local trim_offset=$(generate_offset $TRIM_START $TRIM_END $SIZE_TRIM) trim_offset=$(numfmt --to=iec $trim_offset) # 执行FIO测试 fio --filename=$DEVICE \ --name=randwrite \ --ioengine=libaio \ --rw=randwrite \ --bs=128k \ --size=$SIZE_WRITE \ --offset=0 \ --offset_increment=$MAX_OFFSET \ --iodepth=$qd \ --numjobs=$numjobs \ --runtime=$RUNTIME \ --group_reporting \ --time_based \ --direct=1 \ --name=trim_op \ --rw=trim \ --bs=$SIZE_TRIM \ --offset=$trim_offset \ --size=$SIZE_TRIM \ --startdelay=$TRIM_DELAY \ --random_distribution=random \ --randrepeat=0 > $output_file 2>&1 # 提取性能指标 local write_metrics=($(extract_metrics $output_file "randwrite")) local trim_metrics=($(extract_metrics $output_file "trim_op")) # 输出结果 echo "📊 测试结果:" printf "%-12s %-8s %-12s %-12s\n" "操作类型" "带宽(MB/s)" "平均延迟(μs)" "最大延迟(μs)" printf "%-12s %-8.2f %-12.2f %-12.2f\n" "随机写" ${write_metrics[0]} ${write_metrics[1]} ${write_metrics[2]} printf "%-12s %-8.2f %-12.2f %-12.2f\n" "Trim" ${trim_metrics[0]} ${trim_metrics[1]} ${trim_metrics[2]} # 保存详细结果 echo "QD=$qd, numjobs=$numjobs, 写带宽=${write_metrics[0]} MB/s, Trim带宽=${trim_metrics[0]} MB/s" >> $OUTPUT_DIR/summary.log } # ===== 初始化环境 ===== echo "======== FIO 存储性能测试开始 ========" mkdir -p $OUTPUT_DIR rm -f $OUTPUT_DIR/*.log 2>/dev/null echo "测试设备: $DEVICE" echo "Trim范围: $TRIM_START - $TRIM_END" echo "======================================" # 安装依赖 (numfmt) if ! command -v numfmt &> /dev/null; then echo "⚠ 安装必要工具: numfmt" sudo apt-get install -y coreutils > /dev/null 2>&1 || sudo yum install -y coreutils > /dev/null 2>&1 fi # ===== 执行测试矩阵 ===== for qd in 64 32; do for numjobs in 1 4 8; do run_test $qd $numjobs fill_trim_area done done # ===== 最终报告 ===== echo -e "\n======= 测试完成 =======" echo "详细报告保存在: $OUTPUT_DIR" echo "性能摘要:" cat $OUTPUT_DIR/summary.log echo "完成时间: $(date)" 把这个脚本中的中文注释都改成英文。
09-21
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值