4.0 KiB
4.0 KiB
多轮工具调用 Token 优化实现
概述
本文档描述了为减少多轮工具调用中 token 占用而实现的优化策略。
问题描述
在多轮工具调用场景中,每一轮的工具调用结果(ToolMessage)都包含大量的检索数据,这些数据在进入下一轮时仍然被包含在 LLM 的输入中,导致:
- Token 消耗激增:前面轮次的 ToolMessage 包含大量 JSON 格式的搜索结果
- 上下文长度超限:可能超过 LLM 的最大上下文长度限制
- 效率降低:旧的工具结果对新一轮的工具调用决策帮助不大
解决方案
1. 多轮工具调用优化算法
在 ConversationTrimmer 类中实现了 _optimize_multi_round_tool_calls 方法:
策略:
- 保留系统消息(包含重要指令)
- 保留用户的原始查询
- 只保留最近一轮的 AI-Tool 消息对(维持上下文连续性)
- 移除较早轮次的 ToolMessage(它们占用最多 token)
算法流程:
- 识别消息序列中的工具调用轮次
- 检测多轮工具调用模式
- 构建优化后的消息列表:
- 保留所有 SystemMessage
- 保留第一个 HumanMessage(原始查询)
- 只保留最新一轮的工具调用及结果
2. 工具轮次识别
实现了 _identify_tool_rounds 方法来识别工具调用轮次:
- 识别 AIMessage(包含 tool_calls)
- 识别随后的 ToolMessage 序列
- 返回每个工具轮次的起始和结束位置
3. 智能修剪策略
修改了 trim_conversation_history 方法的流程:
- 优先应用多轮优化:首先尝试多轮工具调用优化
- 检查是否足够:如果优化后仍在限制范围内,直接返回
- 备用修剪:如果仍超出限制,使用 LangChain 的标准修剪策略
实现细节
代码位置
- 文件:
service/graph/message_trimmer.py - 主要方法:
_optimize_multi_round_tool_calls()_identify_tool_rounds()- 修改的
trim_conversation_history()
配置参数
parameters:
max_context_length: 96000 # 默认 96k tokens
# 历史消息限制:85% = 81,600 tokens
# 响应生成预留:15% = 14,400 tokens
测试结果
模拟测试结果
在测试脚本中创建了包含 3 轮工具调用的对话:
- 原始对话: 11 条消息,约 14,142 tokens
- 优化后: 5 条消息,约 4,737 tokens (保留 33.5%)
- 节省: 9,405 tokens (减少 66.5%)
实际运行结果
在真实的多轮工具调用场景中:
- 第一次优化: 15 → 4 条消息(移除 2 个旧工具轮次)
- 第二次优化: 17 → 4 条消息(移除 3 个旧工具轮次)
优势
- 大幅减少 Token 使用:在多轮场景中减少 60-70% 的 token 消耗
- 保持上下文连续性:保留最新轮次的结果用于最终合成
- 智能优先级:优先移除占用最多 token 的旧工具结果
- 向后兼容:不影响单轮或简单对话场景
- 渐进式优化:先尝试多轮优化,必要时再应用标准修剪
适用场景
- 多轮自主工具调用
- 大量工具结果数据的场景
- 需要保持对话完整性的长对话
- Token 成本敏感的应用
未来优化方向
- 智能摘要:对旧轮次的结果进行摘要而非完全删除
- 内容重要性评估:基于内容相关性保留重要信息
- 动态阈值:根据工具结果大小动态调整保留策略
- 分层保留:为不同类型的工具结果设置不同的保留策略
配置建议
对于不同的使用场景,建议的配置:
# 高频多轮场景
parameters:
max_context_length: 50000
# 平衡场景
parameters:
max_context_length: 96000
# 大型对话场景
parameters:
max_context_length: 128000
监控指标
建议监控以下指标来评估优化效果:
- 优化触发频率
- Token 节省量
- 消息减少数量
- 对话质量保持情况
通过这些改进,系统现在能够在多轮工具调用场景中显著减少 token 使用,同时保持对话的连续性和完整性。