同时开三个终端,让三个 AI 在同一个仓库里干活,是很多人现在的日常。但很少有人知道:你以为的“模型上下文窗口”和实际每轮烧掉的 token,是两回事。
我手上有一个自建 LLM 网关,所有 agent 的请求都过它,日志里存着 token 用量和分段账单。于是把这事量了一遍:9080 条请求,其中 8444 条带完整 token 字段。
先说结论,三个都是我原本猜错的:
- 上下文不是“模型窗口决定的”,是 harness(客户端)的注入策略决定的。 同一模型下两个 harness 的起点能差 3.8 倍。
- 最大的开销不是 MCP 工具,是项目记忆。 我一直以为挂太多 MCP 拖慢了启动,实测它只占三成。
- “上下文小”不等于“快”。 省了一半上下文的那个 harness,单请求反而慢 24%。
口径先说清楚,否则全是错的
三个坑,踩过才知道:
上下文 = input + cache_read + cache_write
只看 input 会把缓存命中误判成小请求。
我第一版就是只取 input,得出“某家特别省”的结论,后来发现它
9 成 prompt 是 cache read。
峰值不能用来评判 harness。 会话末尾上下文冲到 280k,看着像堆积失控,但那是因为它跑的模型窗口就有那么大、压缩阈值也在那。按模型归集后,同一个模型下两个 harness 的峰值中位是 143.6k vs 137.2k——几乎一样,差异跟着模型走,不跟着 harness 走。
这一条我一开始写反了,后来被数据打回来。所以下面只讲“起点”,不讲“峰值”。
跨模型比“prompt/输出 token 比”是无效的。 全历史算出来 A > B > C,同模型算出来 C > B > A,排序直接翻转——这个比值被各家输出风格污染,只能同模型比。
起点差多少:3.8 倍
同一天、同一 provider、同一模型、同一 effort 档,三个
harness 各跑一批请求:
| 指标 | A(重注入) | B(轻注入) | C(原生通道) |
|---|---|---|---|
| 请求数 | 70 | 20 | 39 |
| 每请求上下文中位 | 108.1k | 56.1k | 67.2k |
| 首请求基线 | 73.3k | 49.2k | 19.0k |
| cache_read 占比 | 93.8% | 91.3% | — |
| TTFT 中位 | 3,746ms | 3,682ms | — |
| 单请求耗时中位 | 6.09s | 7.58s | — |
起点 73.3k / 49.2k / 19.0k —— 最重的那个是“最轻”的 3.8 倍。
但注意第二行和第三行:每请求上下文中位和首请求基线不是一回事。 会话跑起来之后,A 和 B 的差距从 3.8 倍缩到 1.9 倍,因为对话本身会长,把初始差距摊薄了。
所以“某家初始上下文是另一家的 10 倍”这种说法,只在极端配置下成立。我这套配了三层提示词 + MCP + skills,实测只有 1.5~3.8 倍。
拆开看:钱花在哪一节
这是整篇最有用的一张表。网关每条请求都带 prompt.parts
分段 token 账单,取同一个项目、会话首条请求:
| 分段 | A | B | C |
|---|---|---|---|
| MCP 工具 schema | 23,000(79 个全量展开) | 871(1 个代理入口) | 0 |
| 原生工具 | 14,941 | 11,011 | 3,667(14 个) |
| system prompt | 9,659 | 32,134 | 7,029 |
| skill 清单 | 1,750 | 含在 system 里 | 4,200 |
| 项目记忆 | 30,638 | 0 | 4,122 |
| 对话 | 6 | 4,734 | 4 |
| 合计 | 79,994 | 48,750 | 19,022 |
四个归因,按金额从大到小:
① 项目记忆是最大单笔(30.6k)。 这个 A
会读三层:项目 CLAUDE.md 19.3k + 项目
MEMORY.md 6.9k + 全局 CLAUDE.md 4.0k。C
只读项目 AGENTS.md 4.1k,B 一份都不读。差
26.5k,占整笔差距的一半。
有意思的是:B 省下的这 26.5k,转头在 system prompt 上多花了 22.5k——它有 38 条 skill,每条都把完整 description 和绝对路径塞进 system。省钱的地方和花钱的地方不是同一处,光看总量会误判谁更“聪明”。
② MCP 的差距不在 server 数量,在注入形态(23k vs
871)。 两家接的是同一个 MCP hub、同一批 server。A 把 79
个工具全量展开成 schema;B 只挂 find_tools +
call_tool 两个代理入口,真正要用的工具调用时再取。
同样的 server,同样的能力,23 倍差距,纯粹是注入方式。
③ 全局提示词不是差异来源。 我原本以为各家提示词长度差很多,实测是 4.0k / 7.0k / 12k 量级——这里面 C 和 B 的“大”分别来自读文件策略和 skill 注入,不是提示词本身写得啰嗦。
④ 对话本身只占几个 k。 6 / 4.7k / 4。也就是说:开头那一下就决定了后面每一轮的底价。
两个把结论带偏的数据陷阱
这两个值得单独说,因为它们会让你得出完全相反的结论。
陷阱一:同一会话内多模型路由。
有个会话 867 条请求,里面 sonnet
和另一个模型交替出现,上下文在 60k 和 100–140k
两条流之间跳。我按“会话末尾减会话开头”求差分,得出“每轮新增
25.1k”——假的,那只是切换了模型。
改用累计最大值(running max)重算,每轮真正新增的中位是:A 1.2k / B 1.3k / C 1.5k。基本一样。 也就是说,抛开启动开销,三家每轮的增量没有本质差别。
陷阱二:压缩不是“省”,是策略。
很多人以为早压缩能省钱。实际上早压缩会压低平均值,但代价是重读文件、多跑回合,总 token 未必降。所以“每请求平均上下文”这个指标本身不能当成本指标用。
真想省,该动哪里
按我实测的账,优先级是这样的(假设典型请求 93k):
| 优先级 | 动手对象 | 金额 | 为什么排这里 |
|---|---|---|---|
| ① | 项目记忆全量注入 | 19.5k | 单项最大,且大部分是“这个项目的背景”,不是每轮都要 |
| ② | Bash / 命令输出 | 27.9k | 一次 ls -R 或长日志就能顶掉整个 MCP |
| ③ | MCP 改代理入口形态 | 23.4k | 有效,但只占 13–25% |
| ④ | 删 MCP server | — | 基本用不上,代价是“下次要用还得装” |
第 ③ 项有个反直觉的地方:这 23.4k 建议放后面做。
因为它是每轮字节完全相同的前缀——prefix cache 命中率最高的那一段,单价大约是普通输入的 1/10。真正贵的是每次都不一样的东西:命令输出、文件内容、对话。
判定阈值我给自己定的是:MCP 占每请求 > 50%,或者 prefix cache 命中率掉到 70% 以下,才值得为它动手。 否则先去看项目记忆和命令输出。
一个必须承认的局限
上面所有数字,都不能证明哪个 harness “更强”。
积分口径不同、任务粒度不同、样本也不厚(B 只有 2 个会话 20 条请求)。要下定论只能同任务对照跑:同仓库、同 commit、同模型,各跑 bugfix / 多文件改动 / 重构 / 补测试 / 大上下文排查几类,记通过率、接管次数、token、耗时。
而且更难量化的东西——接管次数——才是真正决定体感的:同一个任务,你当天重开了几个会话?一个会话跑了几轮?有没有中途直接扔掉重来?
这些不用人工打分,从日志里就能数出来。我觉得它比 token 数更能说明“这个工具好不好用”。
三句话带走:
- 上下文是注入策略,不是模型能力。 换个客户端,起点能差 3.8 倍。
- 先算分段账单再优化。 你以为的瓶颈(工具 schema)往往只占三成,真正的大头是项目记忆和命令输出。
- 检查数据口径再下结论。 多模型路由和压缩策略,能让同一份日志得出相反答案——我就这么翻过一次车。