Skip to content
数据至洞察

工具 token 消耗研究

93,997 次真实工具调用的 token 消耗分析——Read/Grep/Bash 占出参 86.3%、26.2% 的浪费(重读与白搜)、写入类成本藏在入参、以及 ~100KB 截断的实证。

编写于 2026-08-09

本文来自 2026-06-05 ~ 08-09 的 peri 运行数据内部调查(threads.db 主库 + metrics 事件日志旁证,快照 2026-08-09)。93,997 次真实工具调用,数字由 agent-defect-analyzer/src/tool_token_consumption.ts 动态计算;字节按二进制前缀(1 MiB = 1,048,576 B)。


1. 样本与口径

主线程(全部可见)3,207 个,消息 207,011 条
子代理线程4,887 个,消息 95,645 条(均属 06 月;07-16 起不再写入主库,整体排除)
净化排除18,731 条(上下文排除标记 16,045 / 系统注入 398 / 压缩摘要 2,288)

口径:调用次数 = 配对成功的 tool_result 条数(93,997 次中 4 条未配对,99.996% 配对);入参 = tool_use 的 input JSON UTF-8 字节,出参 = tool 消息 content UTF-8 字节。存储截断记录(truncated=1)保留在统计中,其字节是真实值下界(见局限)。token 换算按实测标定比率(见 §2),凡 token 数均标注所用比率。

浪费定义:

浪费项定义
白搜Grep/Glob 调用后 K 次工具调用内无 Read/Edit/Write/MultiEdit/WebFetch 消费(K=3 主口径,敏感性 K=1 / K=5)
重读(定义 B)同会话内,同文件相邻 Read 之间无 Edit/Write/MultiEdit 对该文件写入
重复搜索同会话内,同工具(Grep/Glob/WebSearch)相同 pattern/query 的第二次及以后调用
巨型输出单次出参 >100KB

四项浪费分别计数,另计算四者并集字节(避免重叠项重复计数)。

token 标定(metrics 旁证,事件窗口 06-19~08-08 与主窗口不一致):

方法配对线程全局比率(token/字节)中位数
A: agent_turn_end860.3410.349
C: compact_trigger540.2840.299
B: cache_anomaly0(sid 语义不同)不可用,弃用

方法 A 与 C 独立收敛于 0.280.35 token/字节,与经验区间 250350 token/KB 一致。主口径取 0.341;敏感性分析覆盖 0.284 与 250/300/350 token/KB。共同偏差:事件时刻上下文 ≤ 线程全程字节(比率偏低),而工具内容(代码/日志)token 密度低于中文对话(比率偏高)——方向相反、量级未知,不取净值,只给区间。


2. 总量概览

指标
工具调用次数(有出参)93,997
出参字节268.3 MiB
入参字节52.4 MiB
工具上下文消耗合计320.7 MiB
错误出参(is_error=true)1,787 次(1.9%)
估算 token(主口径 0.341/B)约 1.14 亿;敏感性 8,400 万 ~ 1.18 亿

核心结论:工具调用(入参+出参)约占全量上下文预算的 320.7 MiB。 若以会话上下文峰值占比衡量(标定方法 C:compact 触发时 tokens_used 中位数 143,181,对应约 500KB 字节),工具内容是上下文的主体。


3. 出参集中在三个工具

工具出参占比 top8

口径:主窗口 93,997 次调用出参合计 268.3 MiB

  • Read + Grep + Bash 占出参 86.3%(top5 占 96.4%);调用次数与字节分布严重错位——Read 调用占 29.3% 但字节占 40.7%,Bash 调用占 26.2% 但字节仅 13.1%。
  • 两类典型形态:“平均出参小但调用极多”(Edit 13,662 次 P50 61B、TodoWrite 4,667 次 P50 33B)与”调用少但单次巨大”(Glob P95 97.6KB、WebFetch P95 39.7KB、Grep 单次最大 6.68MB)。
  • 写入类工具的成本在入参:Edit+Write 出参仅约 1 MiB,但入参合计 29.3 MiB,占全部入参的 55.9%——整文件内容随 input 进入上下文。

4. 分桶:调用多的小桶,字节少

出参分桶 vs 字节占比

口径:按单次出参分桶;<1KB 的调用占 59.3% 却只贡献 4.3% 字节

  • 59.3% 的调用出参 <1KB,但仅占 4.3% 字节;5-20KB 桶是字节主体(39.0%)
  • 长尾:70 次 >100KB 调用(0.07%)贡献 7.3% 出参字节,集中在 Glob 与 Grep(单次最大 Grep 6.68MB);全量出参 P50=499B、P95=12.2KB、最大 6.68MB。

5. token 排名:三巨头占四分之三

工具 token 消耗排名 top10

口径:入参+出参 × 0.341(方法 A 全局比率),灰色为入参、陶土色为出参

  • Read/Grep/Bash 合计约 8,660 万 token,占总工具消耗 75.6%;前 7 名占 95%+。
  • 图可见两类形状:Read/Grep/Bash 以出参为主,Edit/Write/Agent/TodoWrite 以入参为主——后者正是 §3 说的”隐藏消耗”。

6. 浪费:26.2% 的出参

浪费构成(四类 + 并集)

口径:并集已去重(一次调用同时命中多项只计一次)

浪费项次数涉及会话字节说明
重读(定义 B)9,35697428.8 MiB占 Read 调用 34.0%,全窗口最稳定的可压缩池
白搜(K=3)2,94570528.6 MiB占 Grep+Glob 出参 28.3%;K=1 时 7,476 次(58.0%),K=5 时 1,499 次(11.6%)
巨型输出(>100KB)705719.5 MiB占全部出参 7.3%
重复搜索9604258.5 MiB占搜索类调用 7.4%
四者并集70.3 MiB占全部出参 26.2%,≈ 2,510 万 token(敏感性 2,090 万 ~ 2,510 万)
  • 重读与白搜各约 28.8 MiB,合计已超过并集的一半;“浪费”语义边界(如重读可能是刻意刷新)见局限。

7. 周演变:07-13 见顶后回落

周演变 P95

口径:按线程创建时间归周(周边界近似);虚线为调用数

  • 工具出参消耗在 07-13 当周见顶(52.1 MiB),之后回落,08-03 周降至 16.1 MiB(峰值的三成)。
  • 上行主要来自会话数扩张(59→289)与调用数增长;而单次出参 P95 从 6 月的 ~15.5KB 持续收敛至 8 月的 ~7KB,单次输出变克制。

8. 会话级与 metrics 旁证

会话级(工具消耗按入参+出参,主口径):

  • Top1 案例:25 次调用 = 15 Read(65KB)+ 8 Grep(7.17MB)+ 2 Glob(1KB),单会话 7.21 MiB 消耗几乎全部来自这 8 次 Grep——单次 Grep 近 900KB。
  • 分布高度右偏:工具消耗 P50≈100KB、P95=615KB、最大 7.56 MiB;调用数 P50=28、P95=177。头部 10 个会话约占全部工具消耗的 7%。

metrics 旁证(事件窗口 06-19~08-08,与主窗口不一致):

  • agent_turn_end 5,481 次(带 sid 3,112),其中 2,596 次(47.4%)input=0(空 turn,无 LLM 调用)——用该事件做”上下文峰值”标定必须先过滤。
  • compact_trigger 239 次(54 个线程),74% 集中于 06-22 当周;触发时占用 P50=71.6%、tokens_used P50=143,181。06-22 当周曾出现密集的 200K 上下文预算压力(70% 触发线)。事件侧 07-15 后基本停止采样,与主窗口周演变无法直接对照。

9. 讨论

9.1 与上一窗口(05-15~06-01,547 会话)的对照

两窗口时间上不重叠,以下对照为”同一口径在不同时期的表现”,不能解读为连续变化:

指标上一窗口全量窗口是否成立
Read 出参占比63.4%(8,960 次)40.7%(27,549 次)仍居首,占比明显下降
Bash 出参占比17.5%13.1%下降
Grep 出参占比10.3%32.5%大幅上升,取代 Bash 成为第二大出参工具
冗余 Read(定义 B)32.1%34.0%(9,356 次)成立,比例几乎不变——最稳定的可压缩池
>100KB 出参4 次70 次大幅增加;构成从 Bash 变为 Glob/Grep
Bash ~100KB 截断聚集16 次(聚集于 [97KB,100.5KB))9 次,全部恰好 100,221B截断仍存在,Bash 侧减少
Write 出参 P5063B62B成立(写入类出参依旧极小)

9.2 机制推演(推演成分,已附证据)

  • P1:工具出参存在 ~100KB 截断。 证据:9 次 Bash 出参字节完全相同(100,221B),Read 最大 100,220B、WebFetch 最大 100,456B 同处 [97KB,100.5KB) 窄带。反证:Grep/Glob 的 >100KB 输出(最大 6.68MB)不被截断,说明截断作用于执行输出层而非存储层。结论限定:截断机制存在,具体上限值(约 100KB)为推演。
  • P2:Read 主导地位下降、Grep 上升,可能与工具生态演进有关。反证:无法排除 6 月早期与 7 月后会话工具 schema 不同的数据质量差异。置信度低,仅作观察记录。
  • P3:浪费集中于搜索与重读,与上下文预算压力正相关。 反证:compact 事件 74% 集中在 06-22 当周,而该周调用数(5,197)并非峰值——预算压力与工具输出量并非简单线性关系,更可能与长会话相关。置信度中。

9.3 反证汇总

  • 未配对仅 4/93,997,排除”大量调用因格式问题漏计”。
  • 标定方法 A(0.341)与 C(0.284)独立收敛且落在经验区间内,排除比率严重失真。
  • 100KB 的 Grep/Glob 输出完整保留,证明截断在工具执行层而非存储层。

  • 空 turn 占比 47.4%,任何用 agent_turn_end 做”上下文峰值”的标定都需先过滤(本报告已过滤)。

10. 结论

  1. 工具调用是上下文预算的主要消耗方。 93,997 次调用,入参+出参 320.7 MiB,约 1.14 亿 token(主口径 0.341;敏感性 8,400 万 ~ 1.18 亿)。出参集中在 Read(40.7%)、Grep(32.5%)、Bash(13.1%)(top3 占 86.3%)。
  2. 浪费约 26% 的出参,主体是重读与白搜。 冗余 Read 9,356 次(占 Read 调用 34.0%,与上窗口 32.1% 高度一致)、白搜 2,945 次(占搜索调用 22.8%);四类并集 70.3 MiB ≈ 2,510 万 token。
  3. 写入类工具的成本在入参。 Edit/Write 出参 P50 仅 61/62B,但入参合计 29.3 MiB(占全部入参 55.9%)。
  4. 截断仍在,但形态变化。 Bash 出参在 100,221B 处聚集 9 次(上窗口 16 次);Grep/Glob 存在 70 次 >100KB 真实大输出(最大 6.68MB)。
  5. 消耗随使用强度波动,单次输出趋于克制。 出参 07-13 周见顶 52.1 MiB 后回落;P95 单次出参从 6 月 ~15.5KB 收敛到 8 月 ~7KB。

11. 局限

  1. 消息无时间戳,时间归桶失真。 全部时间维度按线程 created_at 归周,跨周会话整体计入创建周,周边界为近似。
  2. truncated=1 消息的字节是下界。 存储截断记录(主要为大文件读/搜索输出)保留在统计中,对 Read/Grep 的大输出统计影响方向为低估。
  3. 字节≠token,标定偏差方向相反。 事件时刻上下文 ≤ 全程字节(比率偏低);工具内容 token 密度低于中文对话(比率偏高)。报告给区间,不取单一精确值。
  4. 浪费判定是启发式的。 重读无法区分”刻意刷新”与冗余;白搜 K 窗口内”无消费”不排除搜索结果被用作中间推理依据;重复搜索不排除上下文压缩导致的重发。故浪费数字为上限估计
  5. 事件窗口与主窗口不一致。 metrics 侧 compact/token_spike 集中于 06-22 周后归零,与主库周演变(07-13 见顶)分属不同观测面,不可直接互相归因。
  6. subagent 消耗不可见。 07-16 起 subagent 消息不写入主库,06 月 95,645 条已整体排除;Agent 工具的 13.0 MiB 出参(子代理摘要)是仅存的部分代理。另:数据库活跃写入,数字为快照,重跑波动 <0.1%。