降低大语言模型代理框架令牌成本的实操步骤
这是一个基于我们在Cursor学到的经验,用来改进你的智能体框架的prompt。请享用。
# 提升智能体框架的Token效率
你正在开发一个大语言模型智能体框架,涉及系统提示词、工具定义、请求组装、上下文缓存、压缩、检索,以及任务如何在多个智能体之间分配。你的目标是降低运行成本,同时不降低任务完成质量。
- 目标:降低每个已完成任务的按价格加权的Token成本。
- 约束:任务质量不能出现可测量的下降。指标按任务统计,而非按请求统计。因为每一轮对话都会重新发送前缀(工具、指令、设置和到目前为止的对话),所以如果你的修改缩小了单个请求的大小但增加了轮数,总成本反而可能更高。
- 要按计费类型对Token加权:输出、未缓存输入、缓存输入这三者的定价差异很大。
请按照以下步骤操作:绘制框架地图并测量基线,对优化机会排序,完成可直接安全修改的部分,将其余部分放在功能开关后或写成提案,最后汇报。
下方数据来自某团队的生产级编码智能体及其多智能体实验。这些数据用来判断量级,而非作为目标。经过一轮修改(提示词裁剪、工具卸载、缓存布局、稀疏行号、子智能体调优)后,该团队整体Token成本降低了约7%,且没有出现质量损失。更大的百分比仅适用于每次修改影响的请求部分。
## 原则
1. 修改框架发送的内容,不要要求模型降低Token使用量。不要让模型去节省Token。如果框架要求模型“注意节约Token,不要浪费”,会发现模型变得不愿承担有挑战性的任务,有时还会直接退出,说自己不应该浪费Token。
2. 能力强的模型需要定义,不需要命令。那些“禁止”、“必须”、“重要”的列表,以及针对旧模型行为的防护措施,通常都可以替换成每个工具作用的直白描述。有一个团队通过这种方式删掉了约三分之二的系统提示词,更短的提示词在所有模型系列上都能正常工作。只需要说明模型无法预先知道的内容(产品、环境、用户流程),以及你在对话记录中发现的特殊问题。
3. 静态上下文只保留大部分轮次都需要的内容。其他内容都应该在需要的时候再获取。更少的前置上下文也意味着更少混乱或矛盾的信息。
4. 优先考虑删除。为较弱模型添加的防护栏、成为瓶颈的协调步骤、模型现在已经能自主完成的行为提示,这些都会消耗Token。
5. 以真实使用情况为准。评估是快速的参考,但它会偏向难问题,无法反映真实请求的混合情况。
## 1. 绘制框架地图并测量基线
查找:
- 请求的组装位置,系统提示词和工具schema。如果是框架或SDK组装请求,找到它用于消息顺序、缓存控制和工具加载的钩子。
- 工具结果的格式化方式,以及历史记录的保存、裁剪或总结方式。
- 如果存在子智能体或并行智能体,它们的生成方式。
- 使用了哪些模型和服务商API。从服务商文档获取提示词缓存行为(自动或显式断点、TTL、最小可缓存长度),以及输出、未缓存输入、缓存输入的定价。
- 现有的日志记录、Token统计和评估。如果框架没有按计费类型和缓存命中记录每个请求的Token使用量,请先添加这部分。后续所有工作都依赖它。
然后渲染几个真实请求(来自日志,或运行代表性任务),用模型的分词器或API的使用字段统计每个部分的Token数量。
生成:
- 按来源×计费类型划分的成本占比。来源包括:系统提示词、工具定义、技能/规则/集成描述、用户消息、文件读取、搜索结果、命令和其他工具输出、历史、总结、子智能体。
- 每个请求的静态Token数量、缓存命中率、每个任务的轮次数。
- 按工具统计:至少调用一次的运行占比,以及错误率。
要阅读渲染后的请求,不要只看模板。重复、易失值泄露、块顺序错误只有在这里才会显现。按花费占比×可删除比例÷质量风险对优化机会排序。
## 2. 系统提示词和注入的上下文
给每条指令分类:
- 保留:模型无法推断出的产品或环境知识、针对该模型对话记录中发现的特殊问题的修复、模式依赖的规则。
- 重写:把命令和强调改成直白描述。把提醒改成约束:“不要留待办,不要部分实现”比“记得完成实现”效果更好。把模糊的数量改成范围:“生成20–100个任务”比“生成很多任务”能得到更积极的结果。
- 删除:能力强的模型默认会做的事情、针对该模型从未出现过的行为防护、重复工具描述的文本、可能和用户请求矛盾的内容。训练时把系统指令优先级放在用户消息之上的模型会优先服从系统提示词。
- 移动:把所有和用户或请求相关的内容(日期、环境、仓库状态、技能或子智能体列表、用户规则)移动到缓存边界之后的用户角色设置消息中。
用同样的方式审核其他注入的上下文。随着模型能力提升,收集这些数据的团队删掉了目录树、预检索片段、附件压缩副本、每次编辑后注入的lint错误、强制展开短文件读取、每轮工具调用次数上限。他们只保留了少量高价值信息:操作系统、仓库状态、打开或最近查看的文件。开放式工作不要用清单。模型会优化列出的项,降低其他所有内容的优先级。
## 3. 工具定义
工具schema会随每个请求一起发送。核心集之外的大部分工具,在不到20%的对话中才会用到,把它们移出静态上下文可以砍掉60%的工具描述Token。对集成工具(比如MCP服务器)做同样处理——只在上下文中保留名称,完整schema放在每个服务器对应文件夹里,智能体可以用grep或jq搜索,这样使用这类工具的会话总Token减少了46.9%。
- 保留在静态上下文:高频工具(对编码智能体来说就是读取、搜索、编辑、shell)、模型即使不存在也会尝试调用的工具、模式依赖的工具。
- 其余卸载:只保留名称或一行指引,完整schema按需获取。把相关工具分组一起加载,把状态(比如“需要重新认证”)放在智能体能看到的位置。
- 精简保留下来的内容:只描述行为和参数,删掉使用说明。
- 通过测试少量配置、跟踪Token、成本、延迟、工具调用错误、任务成功情况来确定拆分方式。
## 4. 缓存布局
排列每个请求的顺序,让可复用前缀尽可能长:`工具定义 → 系统指令 → [断点] → 设置消息(技能、子智能体、规则、环境) → [断点] → 对话`
- 跨轮次保持前缀字节完全一致。使用确定的工具顺序和序列化,把时间戳和ID放在边界之后,除了压缩之外不要重写之前的消息。
- 如果服务商支持,使用显式断点。否则依赖自动前缀缓存,把稳定部分放在前面。遵守TTL和最小长度规则。
- 对话中途切换模型会丢弃缓存(缓存按模型和服务商区分),还会给新模型传递它没生成过的历史。如果需要使用不同模型,把它作为带全新上下文的子智能体运行。
- 使用显式断点并把每个请求的设置移到断点之后,减少了20%的冷缓存未命中。
## 5. 运行过程中添加的工具结果和其他上下文
- 大输出(命令、集成、日志):把它们写入文件,只返回路径、大小和短结尾。智能体可以根据需要追加、grep或读取范围。截断会丢失数据,而内联会让后续每个请求都变大。长时间运行的终端会话也做同样处理。
- 大体积格式:查找每行或每个项重复的开销。读取文件时,每10行编号一次,而不是每行都编号,这样缓存读取Token减少了1.6%,且不影响引用准确率。每个编号占3–5个Token,而智能体每个会话会读取数万行。另外还要检查重复的绝对路径、冗长JSON键、ANSI码、进度条和重复表头。
- 好的检索能减少探索轮次。在grep之外添加语义搜索,代码库问答准确率平均提升12.5%,还减少了用户需要的迭代次数。
- 工具错误会浪费Token,还会在上下文中留下混乱的冗余内容。对预期错误分类(无效参数、意外环境、服务商错误、超时、用户中止),把未知错误当作框架bug,按工具和模型跟踪错误率。按照这个思路专注优化后,某团队的意外工具错误减少了10倍。
## 6. 长运行:压缩、子智能体和模型混合
- 压缩:保持总结提示词简短、总结紧凑,保留计划状态和剩余任务,把完整历史保存到文件,智能体可以搜索总结遗漏的细节。用一行提示训练出的自总结模型生成约1k Token的总结,压缩错误比数千Token提示生成5k+ Token总结少一半。未训练的模型可能需要更多引导,所以测试你能做到多短。更贵的总结模型带来的提升可以忽略不计。
- 临时记录和运行笔记:重写而非追加。对于在同一个环境中的重复工作,一个由智能体维护的带行数限制的小笔记文件,在启动时加载,是缩短后续运行的有效方法。
- 子智能体:全新上下文能保持父智能体简洁,但隔离会增加协调成本(重复或过时工作)。如果模型已经能自主委派,删掉强迫它委派的提示词。让子智能体返回简短的交接:完成了什么、发现、问题、偏差。只有用户或框架要求时,子智能体才应该使用不同模型。
- 模型混合:在大型多智能体运行中,工作模型至少占用69%的Token,大多数运行中超过90%。用前沿模型做规划器,便宜模型做工作器,效果和全用前沿模型相当,成本约为八分之一。规划器的选择仍会影响工作器花费。某个规划器自身成本更低,但它的工作器会多消耗数倍Token,整体运行成本更高。要测量整棵树的成本。
- 路由和推理工作量:把简单轮次发送给更便宜的模型或降低推理工作量,只有明确需要更强模型时才升级。用这种方式构建的路由器,用户满意度和单个前沿模型相当或更高,成本降低41–68%。
- 推理连续性:如果API返回推理项(包括加密的),后续轮次要把它们传回,缺失时要发出提醒。丢弃推理项会让某个推理模型在编码基准上得分下降30%,还会消耗Token重建计划。
## 7. 让框架适配每个模型
要适配每个模型的训练内容,不要强行用统一格式适配所有模型。如果你已经为相似模型调优过框架,从那个版本开始。
- 编辑格式:使用模型训练时用的格式(比如补丁风格或搜索替换)。不熟悉的格式会消耗额外的推理Token,导致更多错误。
- Shell或工具:优先用shell的模型会退回到`cat`或内联脚本。给工具命名和shell对应(比如`rg`),必要时添加:“如果某个操作有对应工具,请优先使用工具而非shell命令(例如用read_file代替`cat`)。”
- 字面性:有些模型系列会严格字面执行指令,另一些能容忍不精确。有些模型会对强调文字过度反应。对严格字面的模型去掉大写和强调。
- 触发:有些模型直到被告知什么时候用才会调用工具。有效的触发写法是:“完成实质性编辑后,使用<lint工具>检查最近编辑的文件是否有linter错误。如果引入了错误,能轻松解决就修复。”
- 进度更新:如果模型通过推理总结汇报进度,把进度控制在1–2句话,说明新发现或战术改变,删掉轮次中途发消息的指令。
- 值得针对性添加一行的特殊问题:上下文填满后的规避或拒绝(“上下文焦虑”)、提前宣布完成、停下来请求许可、调用不存在的工具。每条添加的指令都要对应对话记录中修复的行为。模型更新后重新审核,因为上一个版本需要的指导对下一个版本来说就是累赘。
## 8. 验证
- 离线:修改前后运行一组固定的真实任务,最好是从真实使用中提取,用用户实际的写法(简短且模糊)。对比任务成功率、Token数、每个任务成本、轮次数、工具错误。不要发布会降低成功率的修改。
- 在线,如果有用户:对每个修改或小批量修改做A/B测试。首要指标是每个已完成任务的成本。防护指标是任务成功信号、工具调用错误、延迟、每个任务轮次数、缓存命中率。对编码智能体来说,好的成功信号是智能体编写的代码长期留存率。一般来说,检查用户下一条消息是继续推进还是报告问题。
- 只有成本下降且没有任何防护指标超出噪声范围的退步,才发布。记录零结果。
## 哪些可以直接修改,哪些需要提案
- 直接修改,每个放在可回退提交里:Token和缓存遥测、确定序列化和工具顺序、把易失内容移出缓存前缀、显式缓存断点、大输出写入文件而非截断、回传被丢弃的推理项、 recurring工具错误修复。
- 放在功能开关后修改,方便测试:系统提示词编辑、工具卸载、输出格式修改、压缩修改、子智能体提示词。
- 仅做提案:运行模型变更、路由、推理工作量默认值、任务在智能体之间分配方式变更。
## 陷阱
- 要求模型更少使用Token或少做事情。
- 截断工具输出。
- 丢弃推理项来节省输入Token。
- 缓存前缀中有易失内容,或请求之间工具顺序变化。
- 卸载模型第一轮就需要,或缺失时模型会尝试调用的工具。
- 强调过多的提示词(必须、禁止、重要、全大写),对严格字面模型尤其如此。
- 强制使用比模型训练时更简洁的输出格式。输出Token更少可能意味着思考更少,结果更差。
- 优化原始Token数而非成本,按请求而非按任务统计,用评估而非真实使用。
- 对话中途切换模型省钱。
- 添加成为瓶颈的协调层。
## 汇报内容
1. 框架地图和基线:按来源×计费类型划分成本,标出最大成本来源。
2. 排序后的修改列表:层级、修改内容、预估节省和预估方式、质量风险、验证方式、回滚方式。
3. 你做出的修改,包括系统提示词diff,每行标注保留、重写、删除或移动的原因。
4. 带功能开关修改的测试计划。
5. 缺口:你找不到或无法测量的内容。
本文由 AI 翻译自英文原帖,技术名词保留英文。
查看 X 原帖