Skip to content
数据至洞察

工具输出与上下文预算:79,099 条消息中的 token 消耗分布

79K 条真实消息的 token 消耗分析:巨型搜索、冗余 Read、白搜各占多少上下文窗口,以及如何用提示词约束工具输出。

你让 Peri 修一个 bug,它先全仓搜了一遍,又扫了一遍 .claude 目录,提交时还带上了完整 diff。每个动作看起来都无害,但实测数据里,这些操作单次就能消耗上下文窗口的 10-15%。

我们对自己的 79,099 条真实运行消息做了只读分析(零侵入,只读 threads.db),把 token 消耗的分布摊开。结论先行,上下文窗口是预算不是缓存,消耗后不可恢复,compact 等于推倒重来。这篇讲三件事,哪些操作消耗最大、消耗最重的三类长什么样、怎么对 Peri 说才能把搜索圈住。

量级账本

数据窗口是 2026-05-15 到 06-01,18 天,528 个会话、79,099 条消息,全部来自 Peri 自己的日常开发。工具出参分布长这样(SIZE-001):

出参大小调用数占比
<1KB18,17162.8%
1-5KB7,34125.4%
5-20KB2,92610.1%
20-50KB4231.5%
50-100KB560.2%
>100KB190.1%

62.8% 的调用都在 1KB 以下,看着很健康。但问题出在长尾。19 次超过 100KB、498 次超过 20KB 的输出,才是预算的主要消耗来源。一次 100KB+ 的返回,按 1KB ≈ 250-300 token 换算大约是 25K-30K tokens,占常见上下文窗口的 10-15%(素材里的估算值)。三四次这样的输出,半个窗口就没了,后面必然触发 compact。

三类高消耗操作

超大出参 Top 5(SIZE-001):

工具最大出参入参预览
Bash203.3KBMCP servers 配置检查命令
Grep155.6KBfiles_with_matches 全仓搜索
Bash114.4KBgit add + commit(含完整 diff)
Glob109.4KB扫描 .claude 目录
Bash109.6KBgit add + commit

巨型搜索。 Grep 一次返回 155.6KB,只是一份匹配文件的路径列表。路径列表本身就能占满一屏窗口。指标文档(metrics-spec 场景七)的结论是,Grep 缺失 head_limit 是巨型结果的主要成因。

目录扫描。 Glob 扫 .claude 目录返回 109.4KB。危险目录里通常堆着海量小文件(skill 定义、缓存、历史记录),递归 glob 会把它们全部吐出来。场景七维护了一份危险路径清单,7 类:.claude/node_modules/plugins/cache/worktrees/target/dist/build/。危险 glob 模式是 **/***/*.<ext>*

全量 diff。 git add + commit 带完整 diff,一次 114.4KB,另一次 109.6KB。最极端的是 203.3KB 的 MCP 配置检查命令,返回了整个配置文件目录的内容。

沉默的浪费

巨型输出是显性的,还有两种更隐蔽的浪费。

白搜。 搜索之后没有 Read 跟进。第二期报告窗口(168 小时,150 会话,6,870 次工具调用)里,搜索到 Read 的联动率整体只有 23.0%(202/879),Grep 单看 19.7%(135/687),Glob 34.9%(65/186)。77% 的搜索没有被 Read 跟进,要么是结果本身够用(正常),要么是 Agent 忘了结果(浪费)。Grep 的重复搜索率 16.9%(116/687),最极端的 pattern ^## 在 168 小时内被反复搜了 6 次。

最极端的循环出现在单个会话。Grep 被调用 73 次,占全部 115 条消息的 76%。上下文丢失 → 忘记搜索结果 → 重复搜索 → 上下文进一步膨胀。

重读。 冗余 Read 率 46.1%(822/1,783)。Top 文件单会话被重读 35 次(AgentModelsPage.tsx)、30 次(DataView.tsx)、25 次(peri-tui/src/acp_server/mod.rs)。同一个文件读几十遍,每遍都是全量进上下文。

健康画像

对照基线能看出健康使用长什么样。Write 工具的入参 P50 只有 5.3KB,P95 21.7KB,最大 57.5KB。出参 P50 只有 63B,只返回文件路径和大小。另一个正面信号,盲写率 0.1%,99.9% 的写入前都先 Read 过。

一句话总结,写入是产出,读出是成本,工具回执越短越好。读本身没错,错的是重复读和读完不用的白搜。

怎么对 Peri 说才能省

五条提示词写法,每条对应一个实测的高消耗场景:

  1. 搜索限定目录。不说”全仓搜”,说”在 src/ 下搜”。
  2. 限制返回量。明说”最多列 30 个结果”。
  3. 避开危险目录。明说”跳过 node_modules.claude”。
  4. 大文件按范围读。说”只看第 100-150 行”,而不是”看这个文件”。
  5. git 操作要摘要。说”用 --stat 列变更”,而不是”提交并展示”。

对比一下两种说法的开销(数字为演示估算,非真实会话记录):

用户: 搜一下代码里的 TODO
Peri: 全仓 Grep,返回 800+ 条匹配路径,约 120KB 进上下文
→ 一次搜索占掉十分之一窗口
用户: 在 src/ 下搜 TODO,最多列 30 个,跳过测试目录
Peri: Grep 限定 path 和 head_limit,返回 30 条路径,约 2KB
→ 输出量缩小两个数量级

判断标准很简单,看会话里有没有反复出现的巨型输出和重复搜索,有就说明该圈边界了。另一个值得注意的统计是,第二期窗口里 150 个会话没有一个人手动执行过 /compact。可能是 auto compact 覆盖充分,也可能大家根本看不到被消耗的预算,这恰恰是预算型浪费最难防的地方。

下一步