1. 一个被忽视的真相:Agent 的 token 消耗远超直觉
1.1 从一次账单异常说起
前段时间帮一个朋友排查他的智能体项目,他跟我抱怨说,明明只是做了一个"自动整理会议纪要"的小工具,每天跑几十次,结果月底一看 API 账单,差点没坐稳——消耗量比他预估的高出两个数量级。他一开始以为是计费系统出问题,反复核对了好几遍,最后发现计费没错,是他的估算模型从根上就错了。
这个场景我见过太多次了。很多人第一次接触 Agent 类应用时,脑子里算 token 的方式还停留在"单轮对话"的思维:输入一段话,输出一段话,加起来几百 token,乘以调用次数,完事。但 Agent 不是聊天机器人,它是一个会自己"思考、行动、观察、再思考"的循环体。每一轮循环都在烧 token,而且烧的方式和你想象的完全不一样。
这篇文章我想把这件事彻底讲透:Agent 到底在哪里烧 token、为什么能烧到你想的 100 倍、怎么估算、怎么优化。不管你是刚上手做智能体的开发者,还是已经在跑生产环境的老手,这里面的账都值得重新算一遍。
1.2 为什么"100 倍"不是夸张修辞
先给一个粗略的直觉。假设你做一个简单的问答机器人,用户问一句、模型答一句,单次交互的 token 消耗大概是这样的:系统提示词 200 token,用户问题 50 token,模型回答 150 token,合计 400 token 左右。你调用 1000 次,就是 40 万 token。这个量级很直观,也容易估算。
但换成 Agent,同样一个任务,流程会变成:系统提示词(往往更长,因为要写清楚工具定义、行为规范)可能 800 token;用户请求 50 token;模型第一轮思考输出 200 token;决定调用某个工具,工具返回结果 500 token;模型看到结果再思考 300 token;再调用工具,返回 800 token;再思考……最后才输出答案 200 token。一轮下来,光这一个任务就可能消耗 3000 到 5000 token。
更关键的是,每一轮循环都要把之前所有的历史上下文重新塞进去。也就是说,第二轮调用时,第一轮的提示词、思考、工具结果全都要再算一遍输入 token。这就是指数级增长的来源。循环 5 轮,实际消耗可能是单轮估算的十几倍甚至几十倍。如果工具返回的内容很长、循环次数很多,100 倍真的不是吓唬人。
2. Agent 烧 token 的五个"黑洞"
2.1 黑洞一:上下文重复累积
这是最大的一块,也是最容易被忽略的。Agent 的每一轮决策,都需要把完整的对话历史作为输入传给模型。第一轮输入是 A,第二轮输入是 A+B,第三轮输入是 A+B+C……第 N 轮输入是 A+B+...+N。
假设每一轮新增内容平均 500 token,循环 6 轮,那么总输入 token 是:
| 轮次 | 本轮新增 | 累计输入 token |
|---|---|---|
| 1 | 500 | 500 |
| 2 | 500 | 1000 |
| 3 | 500 | 1500 |
| 4 | 500 | 2000 |
| 5 | 500 | 2500 |
| 6 | 500 | 3000 |
总输入 = 500+1000+1500+2000+2500+3000 = 10500 token。而如果按"单轮 500 token × 6 轮 = 3000"来估算,你就低估了 3.5 倍。循环次数越多,这个差距越夸张。循环 20 轮,累计输入是单轮估算的 10.5 倍。
注意:很多平台的计费是按"输入 token + 输出 token"分别算的,输入往往还更便宜,但架不住量大。上下文累积主要吃的是输入 token。
2.2 黑洞二:工具返回的"隐形胖子"
Agent 调用工具,工具返回的结果会原封不动进入上下文。问题在于,很多工具返回的数据又长又啰嗦。比如你让 Agent 查一个网页,返回的是整页 HTML 清洗后的文本,动辄几千 token;你让它读一个文件,返回整个文件内容;你让它查数据库,返回一堆用不上的字段。
我见过一个案例,Agent 调用搜索工具,每次返回 3000 token 的搜索结果,循环 8 轮,光工具返回就贡献了 24000 token 的输入(因为每轮都要重新带上之前所有结果)。而实际上,模型真正需要的信息可能只有其中 200 token。这就是典型的"工具返回肥胖症"。
2.3 黑洞三:系统提示词的"固定税"
系统提示词在每一轮调用里都要重新计费。如果你的系统提示词写了 1500 token(工具定义、few-shot 示例、行为规范全塞进去),循环 10 轮,光系统提示词就贡献 15000 token 的输入。这块钱你几乎无法避免,但可以通过精简和缓存机制来降低。
2.4 黑洞四:思考链的"自言自语"
现在很多 Agent 会输出思考过程(reasoning),这些思考内容也会进入上下文,并且在后续每一轮里重复计费。思考越详细,烧得越狠。有些框架默认让模型输出很长的推理链,看着很"智能",账单上很"肉疼"。
2.5 黑洞五:失败重试与死循环
最要命的是这个。Agent 如果陷入循环——比如工具一直返回错误、模型一直重试、或者两个工具互相调用——它会一直烧下去,直到触发最大轮次限制。如果没有设置合理的终止条件,一个 bug 就能让你一夜之间烧掉一个月的预算。我朋友那次账单异常,很大一部分就是某个任务卡在重试循环里跑了上百轮。
3. 动手算一笔账:从理论到实测
3.1 建立一个可复用的估算模型
与其拍脑袋,不如建一个简单的估算公式。对一次 Agent 任务,总 token 消耗可以拆成:
总输入 token ≈ Σ(每轮系统提示 + 累计历史 + 本轮工具返回) 总输出 token ≈ Σ(每轮思考 + 每轮工具调用参数 + 最终答案)其中"累计历史"是等差数列求和。如果平均每轮新增内容为 C,循环 N 轮,累计历史总量约为 C × N × (N+1) / 2。
举个具体例子。假设:
- 系统提示词 S = 1000 token
- 每轮新增(思考+工具返回+工具参数)平均 C = 800 token
- 循环轮数 N = 8
- 最终答案 300 token
那么:
- 系统提示词累计 = 1000 × 8 = 8000
- 累计历史 = 800 × 8 × 9 / 2 = 28800
- 输出(思考+参数)≈ 800 × 8 = 6400(粗略)
- 最终答案 = 300
总计约 43500 token。而如果按"单轮 1000+800+300=2100,乘以 8 轮 = 16800"来估,实际是它的 2.6 倍。如果循环到 15 轮,倍数会拉到 5 倍以上。
3.2 实测:一个真实任务的 token 拆解
我拿一个"自动调研并生成简报"的 Agent 做了实测。任务流程是:接收主题 → 搜索 → 读取前 3 个结果 → 总结 → 再搜索补充 → 生成简报。整个流程跑了 11 轮。
实测数据(用某平台的 token 计数器):
| 项目 | token 量 | 占比 |
|---|---|---|
| 系统提示词累计 | 11000 | 12% |
| 历史上下文累计 | 42000 | 46% |
| 工具返回累计 | 28000 | 31% |
| 输出(思考+参数) | 8000 | 9% |
| 最终答案 | 600 | 0.7% |
| 合计 | 89600 | 100% |
可以看到,历史上下文和工具返回加起来占了 77%。真正"有用"的最终答案只有 600 token,占比不到 1%。这就是 Agent 烧 token 的真相:绝大部分消耗在"过程"上,而不是"结果"上。
3.3 不同循环轮数下的消耗曲线
为了让你有更直观的感受,我模拟了不同循环轮数下的总消耗(假设 S=1000,C=800):
| 循环轮数 | 单轮估算总量 | 实际累计总量 | 倍数 |
|---|---|---|---|
| 3 | 5400 | 10200 | 1.9x |
| 5 | 9000 | 21000 | 2.3x |
| 8 | 14400 | 43500 | 3.0x |
| 12 | 21600 | 87000 | 4.0x |
| 20 | 36000 | 210000 | 5.8x |
注意,这还只是"正常"情况。如果工具返回特别长、或者有重试,倍数轻松突破 10 倍甚至更高。所谓"100 倍",通常出现在工具返回巨大 + 循环次数多 + 有重试的叠加场景。
4. 优化实战:把 token 消耗打下来
4.1 策略一:上下文压缩与摘要
既然历史上下文是大头,就要想办法压缩它。常见做法是:每几轮之后,把之前的对话历史做一次摘要,用摘要替换原始历史。比如前 5 轮的详细内容压缩成 300 token 的摘要,后续调用只带摘要,不带原文。
具体操作上,可以设置一个阈值:当累计历史超过 X token 时,触发摘要。摘要本身也要花 token,但一次性成本远低于后续每轮重复携带原文的成本。
提示:摘要要保留关键信息——已完成的步骤、当前状态、待办事项。丢掉的是冗余的中间过程。
4.2 策略二:工具返回瘦身
工具返回的内容,在进入上下文之前先做过滤。比如搜索工具只返回标题+摘要+URL,不返回全文;文件读取只返回相关段落,不返回整个文件;数据库查询只返回必要字段。
我一般会在工具层加一个"结果裁剪"函数,把返回内容限制在 500 token 以内。如果确实需要长内容,就分段读取,按需加载,而不是一次性全塞进去。
4.3 策略三:系统提示词精简与缓存
系统提示词能砍就砍。工具定义用最简格式,few-shot 示例控制在 2-3 个,行为规范用短句。如果平台支持提示词缓存(prompt caching),一定要开启,这样重复的系统提示词部分可以按更低的成本计费。
4.4 策略四:设置硬性终止条件
这是保命的。必须设置最大循环轮数(比如 15 轮)、最大 token 预算(比如单任务 50000 token)、以及重复检测(如果连续两轮工具调用和返回高度相似,强制终止)。没有这些,一个 bug 就能让你破产。
4.5 策略五:模型分级使用
不是每一轮都需要用最强的模型。简单的工具调用决策可以用小模型,复杂的推理再用大模型。很多框架支持在 Agent 循环里动态切换模型,这个能省不少钱。
5. 常见问题与排查技巧实录
5.1 为什么我的账单比估算高这么多
先查三件事:第一,循环轮数是不是比预期多(看日志里的实际轮次);第二,工具返回是不是特别长(打印每轮工具返回的 token 数);第三,有没有重试或死循环(看是否有重复的调用模式)。这三个查完,基本能定位 90% 的异常。
5.2 常见问题速查表
| 现象 | 可能原因 | 排查方法 | 解决方向 |
|---|---|---|---|
| 账单远超估算 | 上下文累积 | 统计每轮输入 token | 开启摘要压缩 |
| 单任务消耗巨大 | 工具返回过长 | 打印工具返回长度 | 结果裁剪 |
| 任务卡住烧钱 | 死循环/重试 | 看轮次和重复模式 | 设终止条件 |
| 系统提示词占比高 | 提示词太臃肿 | 单独统计提示词 | 精简+缓存 |
| 输出 token 异常 | 思考链太长 | 看 reasoning 长度 | 限制思考长度 |
5.3 几个我踩过的坑
第一个坑:以为"输入 token 便宜就无所谓"。实际上输入量大起来,便宜也扛不住,尤其是上下文累积这种指数级增长。
第二个坑:工具返回直接透传。早期我图省事,工具返回什么就塞什么,结果一个网页抓取工具每次返回上万 token,直接把成本拉爆。后来加了裁剪,成本降了 60%。
第三个坑:没设最大轮数。有一次测试一个多步任务,Agent 陷入"搜索-不满意-再搜索"的循环,跑了 40 多轮才被我手动停掉。那次教训之后,我所有 Agent 都强制设了轮数上限。
5.4 一个实用的监控小技巧
在 Agent 的每一轮循环里,打印当前累计 token 数。这样你能实时看到消耗曲线,一旦发现某轮突然暴涨,立刻能定位到是哪个工具或哪段内容的问题。这个习惯帮我省了很多钱。
6. 把 token 账算明白,Agent 才能跑得久
做 Agent 这件事,功能跑通只是第一步,成本可控才是能长期跑下去的前提。我见过太多项目,demo 阶段很惊艳,一上量就被 token 成本压垮。核心原因就是没把账算明白——不知道钱花在哪,就无从优化。
回到标题那句话,"你的 Agent 烧 token,比你想的狠 100 倍",这不是危言耸听,而是很多人的真实经历。但只要理解了消耗的结构——上下文累积、工具返回、系统提示词、思考链、重试——你就能有针对性地把它打下来。我自己的项目在做了上下文压缩和工具裁剪之后,同样的任务成本降到了原来的三分之一左右,效果几乎没有损失。
最后分享一个我一直在用的小习惯:每次上线新 Agent 之前,先拿一个典型任务跑一遍,把每一轮的 token 消耗打印出来,画个曲线。这条曲线会告诉你这个 Agent 到底"健康"不"健康"。如果某一轮突然翘起来,那多半就是有黑洞。把这个习惯坚持下来,你对 token 的直觉会越来越准,估算和实际的差距也会越来越小。