[控场AI]
· 11 分钟阅读· 5,638 字

实测:Claude Code 优化杠杆大多不到2%,写了规则3天就失效

实测:Claude Code 优化杠杆大多不到2%,写了规则3天就失效

一个月追踪显示:修好测量工具后,Claude Code 剩余优化杠杆天花板均低于 2%。

一位开发者对 Claude Code 的 token 消耗做了一个月的系统追踪,结论出人意料:在完成初步诊断之后,几乎所有优化手段的天花板都低于 2% 的加权成本。过程中最先修好的其实是测量工具本身——转录文件中 usage 块被重复计数 1.9 倍,修正后总量减半但结论结构不变;字符转 token 换算也按真实数据重新校准。真正有效的改进都是自动机制而非文字指令:成本阶梯式读取、阻止重复读取的钩子、基于 BM25 的路由。而写在指令里的规则只有头三天有效,之后行为回归基线。拆分会话在短会话场景下甚至是负收益。作者最终把方法本身当作产品:先用转录文件测量每个杠杆的天花板,再决定是否动手。

一位开发者对 Claude Code 的 token 消耗做了一整个月的追踪实验,结论出人意料:在完成初步诊断之后,几乎所有优化手段的天花板都低于 2% 的加权成本。有些改了等于没改,有几个甚至让开销变高了。

这位开发者此前发现 94% 的工作时间花在重读上下文上,于是列出了所有可能的优化杠杆逐一验证。结果不是预期中的大幅节省,而是发现了一堆无效操作——以及自己测量工具本身的重大误差。

measure-levers

先修的其实是尺子

实验进行到月中时,开发者发现 8 天的用量统计里总 token 数和 API 调用次数对不上。原因很隐蔽:Claude Code 在转录文件中会为每个响应块(文本、工具调用)各写一行,但 usage 块在每一行里都被重复写入。逐行累加的脚本把每次调用平均算了 1.9 次。

修复方法很简单——按 requestId 分组只计一次。修正后,8 天的数据从 10.03 亿 token 降到 5.4 亿,工具结果的拖累几乎减半。

这个误差影响了之前文章的绝对数字:313 个会话变成 294 个,23.56 亿 token 变成 12.12 亿。但重读占比从 94% 升至 96%,曲线的指数从 1.20 变为 1.19。数字减半了,论证的结构没变。

第二个校准问题出在字符转 token 的换算。通行规则是约 3.5 个字符对应 1 个 token,但用作者自己的数据校准后发现,西班牙语散文实际是 2.1 个字符每 token。这意味着记忆笔记的实际成本不是之前算的 7%,而是 10%。

两次修正都没有改变任何结论,但改变了每个杠杆可能带来的收益——而这恰恰是决定该优化什么的唯一依据。

测状态,不测历史

第二个错误更微妙:当你改变了 agent 的配置(指令、钩子、读取脚本),过去 45 天的平均值混合了两种不同的运行状态,描述的是哪种都不准确。

作者在记忆笔记上遇到了这个问题。从全量历史来看,诊断很明确:从笔记读取的内容中,近一半是不需要的累积历史,显然应该把每个文件拆成两份。但就在三天前,作者已经改了读取方式——agent 先请求一个带各节成本的章节地图,然后只取需要的那一节。只看改动之后的数据:2 次整文件读取对 198 次按地图或按节读取,阶梯式读取的浪费相比整文件读取只有 1%。拆分文件将是零回报的工作。

此后每个测量脚本都支持 --desde 和 --hasta 参数按时间切片,并且按调用而非按会话切分。还有一个单独的 regimen.py 脚本,当统计窗口跨过配置变更时会发出警告。

有效的是机制,不是文字

这个月最大的改进有一个共同点:没有一个依赖于 agent 记住什么。它们都是自动运行的代码。

成本阶梯。 问题是一个 564 行、约 1.7 万 token、含 29 个章节的记忆笔记。面对其中某一节的具体问题,唯一现实的方式是整篇打开。于是给读取器加了两个选项:一个列出各章节及其行号范围和成本(约 1200 token),另一个只取单个章节(约 1300 token)。核心原则是先看到成本,再决定是否支付,每一级的开销大致是下一级的十分之一。

阻止重复读取。 审计一个月的记忆读取记录,47% 是在同一会话中读取同一个文件——文本已经在上下文里了。解决方案是一个钩子,拒绝同一文件的第二次完整读取。这是唯一不会丢失信息的拦截,因为它拦截的内容已经加载了。

路由。 一个钩子在每条消息上建议可能相关的记忆笔记。原来用人工编写的触发词匹配消息,现在改为对笔记正文和会话前三条消息运行 BM25。为了验证效果,作者从转录文件中构建了测试台:对每条消息,实际打开了哪些笔记来回答它。在路由是唯一入口的场景中,前四条建议的命中率从 41% 升至 76%,每条消息的 token 消耗减半。只统计尚未在上下文中的笔记时,命中率从 43% 升至 68%。

这个测试台还修正了一个作者之前当作定论的数字。之前认为基于词语的路由不可能超过 70% 的准确率,因为近三分之一的消息没有可搜索的内容(比如"检查一下是不是都对了")。但那是在单独看每条消息的情况下测量的。把前两条消息一起考虑后,很多这类消息实际上有内容可以搜索。

还有一个决定是不做。有 14 条笔记在 393 个会话中从未被打开过,删除它们似乎理所当然。但逐条检查后发现,"从未打开"不等于"冗余":其中两条在始终加载的索引中,它们恰恰是不被打开就能工作的;还有几条包含其他任何地方都没有写过的规则。它们没被打开只是因为话题没出现。删除它们意味着为了节省那些不被打开就不花任何成本的 token 而丢失知识。

BM25 是一种经典的信息检索排序函数,属于“词袋”模型家族,与向量检索的语义相似度路线不同。它给每个候选文档打分时综合三点:查询词在该文档中出现的频率(词频 TF)、该词在整个语料中的稀有程度(逆文档频率 IDF),以及对长文档的惩罚(文档长度归一化)。BM25 不需要嵌入模型、不需要向量数据库、不产生额外的固定上下文开销,因此特别适合“每条消息上快速筛选候选笔记”这种高频、低延迟的场景。文中作者把人工编写的触发词替换为对笔记正文和会话前三条消息运行 BM25,既提升了路由命中率,又避免了向量库在每次会话开始时注入固定文本的隐性成本。

渐进披露(progressive disclosure) 是上下文工程中的一种分层加载策略:不把全部信息一次性塞进上下文,而是先给出一个轻量的目录或索引,让模型按需逐层展开。claude-mem 采用的就是典型的三层结构——索引、章节地图、具体内容。这种设计的成本模型是“每一层的开销大致是下一层的十分之一”,因此只要任务平均只需要展开一两次,就能比整篇加载节省一个数量级。作者的系统与之思路一致,但额外在每一层都显式标注了 token 成本,让模型(和开发者)先看到价格再决定是否支付,这是对渐进披露的一个重要增强。

写在指令里的规则会失效

每次 API 调用都会重新读取整个上下文,所以多一次调用的成本比几乎任何文件都高。作者测量了 agent 每条消息发起多少次调用,并写了一条明确的规则:将不依赖前序结果的操作链接成单个命令,独立工具一起启动。

十天后,每条消息的调用次数没有下降——翻了一倍。

那个数字有些误导。每条会话的消息数从 1.7 降到 1.1:作者在单条消息里发送了更长的任务。每条消息的调用次数既衡量任务大小也衡量纪律性,所以它是警报,不是判决。

真正可比的是规则要求的行为。包含两个及以上链式步骤的 Shell 命令在写规则前是 84-87%,之后是 86%——本来就已经链接了。而包含多个工具的调用在写规则后三天内升至 47%,然后回落到 18%,再降到 10%。好了三天就失效了。 几周前另一条规则也出现了同样的情况。

作者还尝试了反向机制:把指令从始终加载的文件中移到只在特定路径下加载的文件(.claude/rules/ 配合 paths:)。它能工作,但只有用文件工具读取或编辑时才会触发。如果 agent 通过 shell 读取,规则就不会加载。一个月的数据显示,在涉及该文件夹的会话中,78% 的情况下规则不会被加载。

结论是:写在纸上的指令只有头几天有效,之后照旧。如果某件事很重要,就把它做成机制(阻断型钩子、一步完成三步的命令),而不是多写一行指令。

钩子(hook) 是 Claude Code 提供的一种在特定生命周期事件上自动触发的外部脚本机制,例如在工具调用前(PreToolUse)或后、在会话开始时、在用户提交消息时。与写在指令文件里的自然语言规则不同,钩子是确定性代码:它要么放行,要么阻断,不依赖模型是否“记得”这条规则。文中“阻止同一文件第二次完整读取”的拦截、路由建议、批量读取警告,都是钩子实现。这也是作者核心论点的技术基础——指令是建议,模型可以忽略;钩子是机制,执行率恒为 100%。把重要约束从指令迁移到钩子,等于把概率性执行变成确定性执行。

小杠杆一览

这是这个月测出的其余杠杆。天花板一列假设 100% 执行率——这并不存在。成本一列是尝试的代价。

杠杆天花板成本或结果
批量独立读取为一次调用1.5-1.8%每次单独读取后给警告的成本是 0.25%,只有在 15% 执行率时才打平
缩小工具参数(长脚本、整文件写入)2.7%这是所有参数的总和。"编辑而非重写"规则只涉及约 0.1%
仅按路径加载指令0.2%agent 通过 shell 读取时不加载
精简全局指令文件每 10% 省 0.18%已放弃
拆分大型记忆笔记~1%阶梯式读取已经解决了
不在错误位置搜索0.25%这是下限。应从质量角度而非 token 角度来论证
用文件夹地图定位文件而非搜索1.07%包含必要的搜索
缩写指令0字符减少 4.8%,token 增加 0.6%
去掉重音和 ñ0token 增加 1%
将缓存从 1 小时降到 5 分钟不适用订阅制下 1 小时已是默认值

缩写这条值得多说一句,因为这是被问得最多的问题。作者的指令用西班牙语写成,而分词器按词汇片段切分,不按字母。Que、memoria、después 本来就各是一个 token;q、mem、dsp 仍然各是一个,而奇怪的符号("c/"、"x")反而增加了片段。带正确重音的形式恰好是词汇表中最常见的,所以去掉重音反而更贵。减少 token 靠删内容,不靠压缩。

拆分会话不划算

上一篇文章中的头号杠杆是换话题时开新会话。一个月后,测量结果说任务中途切分是负收益,有时反过来才对。

数学是这样的:切分迫使你重新将会话前缀写入缓存(指令、工具定义、agent 的启动信息),写入成本是 2,而读取成本是 0.1。你省下的是后续每次调用重读的累积冗余。只有当这个冗余乘以剩余调用次数超过前缀大小的约 19 倍时,切分才划算。在作者的会话长度下,几乎从不满足。

在转录文件上模拟:"冗余超过 2.5 万 token 时切分"给出 -2.7%;阈值 5 万时 -0.6%;7.5 万以上则不再切分任何会话。一个知道未来且不付出重定向成本的"神谕"方案也只达到 2.9%,且仅涉及 4 个会话。

真正划算的是反向操作:当会话仍然较轻时(超出基础约 2 万 token 以内、同一文件夹、间隔不足一小时),在同一个会话里继续下一个任务。第一天测得 +2.2%,排除实际并行运行的会话后为 +1.7% 到 +1.9%。第二天只有 +0.5%。

这并不矛盾,而是状态变了。第一篇文章测量的是一次数百轮的超长会话时期,切分能省三分之一。习惯起作用了:在当前测量到的状态中,54 个会话里有 43 个只有单条消息,中位数 13 次调用。会话这么短,边际收益在另一边。

缓存写入与读取的成本不对称是理解会话切分经济学的关键。在 Anthropic 的 prompt caching 机制中,首次将一段文本写入缓存的价格约为标准输入 token 的 1.25 倍(文中记为 2),而命中缓存的读取价格仅为标准价格的 0.1 倍(文中记为 0.1)。这意味着缓存前缀一旦写入,后续每次调用几乎免费复用;反之,新建会话必须把系统指令、工具定义、agent 启动信息等前缀重新写入一次,按 2 倍计费。切分省下的是旧会话中累积的冗余重读,代价却是为整个前缀支付一次写入费。只有当“冗余 token × 剩余调用次数 > 前缀大小 × 19”时,省下的读取费才能覆盖写入费——这解释了为什么在短会话中切分几乎总是亏本。

与先行者对比

月中作者审视了被引用最多的记忆处理项目:Anthropic 的上下文工程指南和记忆工具、Manus 的稳定前缀方案、claude-mem 的三层渐进披露、Letta 的空闲整合,以及 Mem0 和 Zep。

令人意外的是,作者逐项测量搭建起来的系统已经与它们持平。建议路由、章节地图和单节读取,本质上就是 claude-mem 的渐进披露,只是在每一级都展示了成本。

作者决定不安装任何一个,也不引入向量数据库:它们都会在每次会话开始时增加固定文本,这恰恰是付费最多的地方,而基于词语的路由已经达到 75% 的命中率。

测量方法本身就是产品

这个月留下的最重要的东西是顺序:在应用一个杠杆之前,先用自己的转录文件测量它的天花板,假设 100% 执行率。如果天花板很小,连解释它的文字都不值得写。如果天花板很大,优先用机制而非指令。应用之后,只从变更时刻开始测量。

脚本开源在 GitHub 的 context-economy 仓库中,现在有六个。它们读取 Claude Code 留在磁盘上的 .jsonl 文件,不向任何地方发送数据。

作者最后说:这些数据属于一个人和他的工作方式。但核心信息不依赖于此——完成初步诊断后,剩下的收益既小又分散,唯一不花一个月去优化 0.2% 杠杆的办法,就是在动手之前知道每个杠杆能带来多少。

#Claude Code#token优化#AI编程成本#上下文管理#缓存策略#Agent记忆#BM25路由
分享:

相关推荐