EP.2中,我用hooks减少了Claude读取的内容。测试结果只输出失败的,构建日志只提取错误。

我决定测量到底减少了多少。

先测量

Claude Code把所有对话记录为JSONL文件。按项目堆积在~/.claude/projects/下,每条记录都包含Token用量。我写了一个脚本(analyze-tokens.js)来读取这些数据,与日期session文件交叉比对,分别统计轮次、cache_read/write/output并换算成费用。

制作过程中抓到一个bug。session记录hook引用的是e.usage,但JSONL的结构是e.message.usage。session文件里根本没记录Token。分析器改为直接读取JSONL来绕过这个问题。

以下是3月27日一天的费用。

总费用的58%是读取

项目费用占比
cache_read$19.2258%
cache_write~$9.6229%
output~$4.3313%
合计$33.17

cache_read占58%。Claude产生的费用中超过一半是"读取"。EP.1中我写过"Claude消耗的Token大部分不是推理而是读取",看到数字就确定了。

它在读什么

我追踪了Claude每轮读取的内容。

项目加载时机规模
项目CLAUDE.md每轮155-214行
根CLAUDE.md每轮10行
MEMORY.md每轮23行以内
对话历史每轮累积

有个意外发现。SKILL.md(469行)和agent文档(1,233行)不是每轮都加载的。只在调用skill时、执行agent时才加载。已经是lazy loading了。

每轮固定加载的只有CLAUDE.md和MEMORY.md。

把CLAUDE.md拆分到rules/

CLAUDE.md有155-214行并不意味着每轮都需要全部内容。产出物路径表只在写产出物时需要,游戏域规则只在处理游戏相关工作时需要。

Claude Code有一个.claude/rules/目录。在这里创建文件并添加paths:前置信息,就只在访问该路径时加载。

---
paths: tasks/**
---

产出物路径表、公共头部块、角色规则...

只有操作tasks/文件夹时这些规则才会加载。普通对话中不会加载。

我先在一个项目中试点。把产出物相关章节45行分离到artifact-rules.md,从CLAUDE.md中删除该部分。成功了。然后批量应用到其余项目。

项目CLAUDE.md(前→后)削减率分离文件
A(电商)155行→96行38%artifact-rules.md
B(教育平台)207行→140行32%artifact-rules.mdedu-rules.md
C(游戏平台)214行→114行47%artifact-rules.mdgame-domain.md

C减少了47%。因为是游戏平台,域规则(46行)每轮都在加载,现在只在操作游戏相关文件时才加载。

但是呢

数字不差。32-47%轻量化。看起来不错。

但说实话,这是"CLAUDE.md 155-214行中的32-47%"。每轮只节省几百个Token。cache_read $19.22的大部分不是CLAUDE.md的200行造成的,而是对话历史累积造成的。一个session跑20轮,到第20轮时前19轮的全部内容都作为cache_read加载。

有一个项目占了当天费用的一半以上。比其他项目贵3倍以上。原因很简单:一个session跑了17轮。后半段的cache_read急剧增加。

CLAUDE.md再怎么瘦身,不改变对话历史累积的结构,cache_read的大部分就还在那里。EP.1减少了agent数量,EP.2用hooks减少了输出,EP.3减少了固定文档。都是有意义的工作,但真正的大漏洞还在。

断还是续,这是个问题

超过20轮后开始新session对cache_read来说更高效。但开始新session就会重新产生cache_write。CLAUDE.md、MEMORY.md、系统提示都要从头写。

为减少cache_read而断开session,cache_write就增加。为减少cache_write而继续session,cache_read就增加。怎么都有成本。

答案还不知道。20轮左右是盈亏平衡点的感觉,但因工作类型而异。对话多的设计工作适合早断,连续编码适合继续。

这就是EP.3真正的发现。能减的都减了。剩下的是"怎么用"的领域。

本系列其他文章


参考