一、背景:为什么消息需要裁剪?
- 大模型输入窗口有限:无论是 OpenAI、Anthropic 还是 Google Gemini,每次输入的 token(词元)数量都有限制。
- 多轮对话容易历史膨胀:对话越长,历史越多,会导致超出模型窗口、报错或上下文丢失。
- 自动裁剪让你的测试更稳定可靠:自动保持历史在合规范围,减少“超长”引发的杂音和问题。
二、trim_messages
能做什么?
- 自动裁剪消息历史,让对话窗口始终在安全范围(按 token 数或消息条数)。
- 保证历史格式合法,比如:
- 以
HumanMessage
或SystemMessage+HumanMessage
开头(符合大模型习惯) - 以
HumanMessage
或ToolMessage
结尾(避免 ToolMessage 孤立) SystemMessage
(系统设定)通常要保留- 工具消息(ToolMessage)只在有 AI tool call 后才出现
- 以
三、最常用的两种裁剪方式
1. 按 token 数 裁剪(最常见,也最精细)
适合场景:你需要严格保证传给模型的 token 不超过窗口上限
from langchain_core.messages import (
AIMessage,
HumanMessage,
SystemMessage,
trim_messages,
)
from langchain_core.messages.utils import count_tokens_approximately
trimmed = trim_messages(
messages,
strategy="last", # 保留最近的消息
token_counter=count_tokens_approximately, # 估算每条消息的 token 数
max_tokens=45, # 最大窗口
start_on="human", # 历史以人类消息开头
end_on=("human", "tool"), # 历史以人类或工具消息结尾
include_system=True, # 如果有 SystemMessage,自动保留
allow_partial=False, # 不截断单条消息
)
效果举例:只保留最后一条 HumanMessage 和 SystemMessage,其他都自动丢弃。
2. 按 消息条数 裁剪(适合粗略场景)
适合场景:你只关心历史条数,不精确到 token,但想简单防爆表
trimmed = trim_messages(
messages,
strategy="last",
token_counter=len, # 每条消息算1 token
max_tokens=5, # 最多保留5条消息
start_on="human",
end_on=("human", "tool"),
include_system=True,
)
四、进阶用法
1. 允许部分截断 allow_partial=True
- 会在必要时截断单条消息(如内容太长),保证整体 token 不超标
2. 自定义 token 计数器
- 可以用 tiktoken 或模型自身的 token 统计方式,确保和实际模型窗口一致,避免“明明裁了还是超限”
- 参考 openai-cookbook tiktoken 计数方法
3. 和链/历史结合
- 可以把
trim_messages
作为链的前处理,无感集成到任何多轮对话应用 - 支持配合
RunnableWithMessageHistory
自动化裁剪与历史管理,适合 session/多用户测试
五、测试工程师常见问题与实用技巧
1. 如何验证裁剪后历史是否合规?
- 用
trim_messages
裁剪后,检查:- 开头是否是 HumanMessage 或 SystemMessage+HumanMessage
- 结尾是否是 HumanMessage 或 ToolMessage
- SystemMessage 是否如预期被保留
- 总 token 或消息数是否达标
2. 如何为不同模型/窗口快速切换裁剪策略?
- 配置
token_counter
为目标模型 - 配置
max_tokens
为模型 context window(比如 4096、8192)
3. 如何自动化测试多轮消息裁剪?
- 构造超长历史,传入
trim_messages
,再断言裁剪结果(内容、条数、token等) - 用不同参数(allow_partial、include_system 等)覆盖全分支
4. 如何链式集成到对话测试?
- 把裁剪和模型调用组合为 chain
- 每轮对话自动调用
trim_messages
,保持历史安全
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o")
trimmer = trim_messages(
token_counter=llm,
max_tokens=45,
strategy="last",
start_on="human",
end_on=("human", "tool"),
include_system=True,
)
chain = trimmer | llm
result = chain.invoke(messages)
六、LangSmith 可视化溯源
可通过 LangSmith Trace 示例 直观看到裁剪处理过程,便于调试和结果溯源。
七、总结
trim_messages
是多轮对话系统最强大的裁剪工具:
- 灵活支持 token/消息/部分截断/自定义计数
- 保证历史格式安全,易于集成和自动化测试
- 搭配 LangSmith 可视化和多用户隔离,极大提升测试效率
建议测试工程师:
把消息裁剪测试作为多轮对话测试的必测环节。优先覆盖不同窗口、不同历史长度、特殊边界(如只剩 SystemMessage)等场景,提升产品鲁棒性和用户体验。