
工具输出与上下文预算:79,099 条消息中的 token 消耗分布
你让 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):
| 出参大小 | 调用数 | 占比 |
|---|---|---|
<1KB | 18,171 | 62.8% |
| 1-5KB | 7,341 | 25.4% |
| 5-20KB | 2,926 | 10.1% |
| 20-50KB | 423 | 1.5% |
| 50-100KB | 56 | 0.2% |
>100KB | 19 | 0.1% |
62.8% 的调用都在 1KB 以下,看着很健康。但问题出在长尾。19 次超过 100KB、498 次超过 20KB 的输出,才是预算的主要消耗来源。一次 100KB+ 的返回,按 1KB ≈ 250-300 token 换算大约是 25K-30K tokens,占常见上下文窗口的 10-15%(素材里的估算值)。三四次这样的输出,半个窗口就没了,后面必然触发 compact。
三类高消耗操作
超大出参 Top 5(SIZE-001):
| 工具 | 最大出参 | 入参预览 |
|---|---|---|
| Bash | 203.3KB | MCP servers 配置检查命令 |
| Grep | 155.6KB | files_with_matches 全仓搜索 |
| Bash | 114.4KB | git add + commit(含完整 diff) |
| Glob | 109.4KB | 扫描 .claude 目录 |
| Bash | 109.6KB | git 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 说才能省
五条提示词写法,每条对应一个实测的高消耗场景:
- 搜索限定目录。不说”全仓搜”,说”在
src/下搜”。 - 限制返回量。明说”最多列 30 个结果”。
- 避开危险目录。明说”跳过
node_modules和.claude”。 - 大文件按范围读。说”只看第 100-150 行”,而不是”看这个文件”。
- git 操作要摘要。说”用
--stat列变更”,而不是”提交并展示”。
对比一下两种说法的开销(数字为演示估算,非真实会话记录):
用户: 搜一下代码里的 TODOPeri: 全仓 Grep,返回 800+ 条匹配路径,约 120KB 进上下文 → 一次搜索占掉十分之一窗口
用户: 在 src/ 下搜 TODO,最多列 30 个,跳过测试目录Peri: Grep 限定 path 和 head_limit,返回 30 条路径,约 2KB → 输出量缩小两个数量级判断标准很简单,看会话里有没有反复出现的巨型输出和重复搜索,有就说明该圈边界了。另一个值得注意的统计是,第二期窗口里 150 个会话没有一个人手动执行过 /compact。可能是 auto compact 覆盖充分,也可能大家根本看不到被消耗的预算,这恰恰是预算型浪费最难防的地方。
下一步
- 上下文窗口怎么管理、compact 何时触发,见 ContextEngineering 和 Agent 主循环
- 代码库探索的正确姿势,见 探索代码库
- 刚上手 Peri,先读 快速开始