这两天,看了不少知乎上关于用好 Codex 和 Claude Code 的回答,收获不少指令笔记,也产出几篇文章。紧赶慢赶,Anthropic 也在 8 月 14 日发了一篇官方最佳实践:《Maximizing the value of your Claude Code sessions》。
我整理了下文章的思路,原文核心分为 3 个层次,分别是 token 的价格组成、session 内的 token 活动、和如何最大化单一 session 的价值。
本文章不打算全篇复述,而是划一些我认为的重点:包括一些被忽视的细节以及客观规律。我自己拿到这篇文章,用这些重点去 review 了我近期的操作日志,也有一些发现和大家分享。
一、成本模型变化
编辑器时代是固定费用,修 1 个测试和修 50 个测试,工具成本一样。到了 Agent 时代,同一个任务的价格随用法浮动。
我自己的理解是,如果一条工作流已经被你验证过了(比如有现成的 SOP 或者 skills),那把它编码成固定流程或代码让 Agent 调用。被验证过的事情不需要反复探索,也能省下不少时间和 token。
二、token 价格的决定方式
原文说,计费单位是 token,但实际买的是 GPU 跑模型的推理时间。三个因素决定单价:模型选型、输入输出的差异、以及缓存命中率。
模型大小就不展开了:前沿模型给复杂任务,小模型给简单杂活。
输入和输出的区别
原文用了 Prefill 和 Decode 这两个术语。为什么不叫 Encode?因为大语言模型推理是纯 Decoder 架构。输入阶段叫 Prefill,是因为它在一次性填充 KV Cache,而不是在做编码转换。(训练时会用到 Encoder)
输出价格约为输入的 5 倍。Decode 阶段每个 token 都要独立跑一次前向传播,200 token 的输出就是 200 次运算。但 Prefill 并非零成本,200 个输入 token 虽然一批并行处理,注意力计算量依然和 token 数成正比。5 倍的价格差来自 GPU 利用率的差异:Prefill 是计算密集型,GPU 并行度高,单位 token 成本低;Decode 是内存带宽受限,每步只产出一个 token,GPU 大部分时间在等数据搬运。
思考 token 是输出的大头。你看到的文本可能只有几行,但模型的内部推理可能消耗了几千 token。/effort 控制的就是这个量。原文还提到一个环境变量:MAX_THINKING_TOKENS=0,在启动时加上这个变量可以为整个 session 关闭思考(Fable 5 除外),等于比 /effort low 更激进一档。
如果你关注 token 的占比细节,可以看我开发的 TrakToken,查看不同任务的输入输出占比。
提示缓存(Prompt Cache)
这块是全文的实操重点。大家其实都知道"有缓存"这件事,但容易忽视的是缓存失效的触发条件。
每次请求发到服务端时,服务端会检查请求开头的 token 序列是不是跟上一次完全一样。如果一样,就直接加载之前算好的 KV Cache,不用重新计算。读缓存只花 0.1 倍输入价。
需要注意的是首次写入缓存的成本最高可达 2 倍输入价。服务端不光要做正常的 Prefill 计算,还要把结果持久化到缓存存储里。这个 2 倍只发生一次,之后每轮都是 0.1 倍的读取。缓存写入是"贵一次,省后面所有轮"的逻辑。什么时候会触发写入?每次缓存不命中的时候,也就是新 session 的第一轮、切模型之后、缓存过期之后,都会重新写一次。
一个典型的 5 轮交互
原文用了"fix the failing test in utils.test.ts"做例子。核心模式是:每一轮请求都带着完整对话历史,但前面已发过的内容走缓存(0.1 倍价),只有本轮新增的内容按全价 Prefill。
具体流程:发指令(首次全价 + 写入缓存)-> Read 测试文件 -> Read 被测文件 -> Edit 修改 -> 跑测试 -> 返回总结。一共 5 次请求,从第 2 轮开始,前序内容全部走缓存。真正按全价计费的只有每轮新增的部分。
什么操作会让缓存失效?
缓存必须从请求的第一个 token 开始精确匹配。任何打断前缀的操作都会导致整段对话重新 Prefill:
- 切模型(/model):每个模型有独立缓存。进出 plan mode 也算切模型,因为 plan mode 使用的模型配置不同,即使你没有手动选择另一个模型,每次切换都会触发缓存重建。
- 切 effort(/effort):effort level 是缓存 key 的一部分。
- 开 Fast mode:同上。要用就 session 开头就开,中途开等于给整段对话交一次全价。
- /compact:对话被替换成摘要,前缀全部对不上了。
- 时间过期:订阅用户 1 小时,API key 用户 5 分钟。超时后下一轮就是全量 Prefill。
所以原文的建议是:切模型、切 effort 这些操作,选在 session 刚开始或者刚 /clear 之后做(此时上下文为空,重建成本接近零)。长对话中途做性价比极低。
关于 /rewind
原文提到"想丢掉最近几轮,用 /rewind 而不是 /compact"。/rewind 是 Claude Code 的会话级撤销。每次你发送一个 prompt,Claude Code 都会自动保存一个 checkpoint。/rewind(或者按两次 Esc)打开菜单,你可以选择回退到任意一个历史节点。
它有三个选项:回退代码和对话、只回退对话(保留当前代码)、只回退代码(保留对话)。
关键在于,/rewind 只是把对话末尾砍掉。前面的内容没动,缓存还在。而 /compact 是把整段对话重写成摘要,前缀全部失效。所以如果你只是想丢掉最近走偏的几轮,/rewind 是零成本的选择。
三、单次 session 的 token 组成
原文的表述是"没有任何东西只发一次"。进入对话的文件和命令输出,之后每一轮都会重发。有缓存所以便宜,但便宜不等于免费,它们一直占着上下文窗口的空间,模型每一轮都得绕着这些东西思考。
上下文里装了什么
打字之前就已经存在的部分:工具定义、系统提示词、CLAUDE.md、MCP server 的定义。原文建议用 /context 看一下这部分有多大,把 CLAUDE.md 里工作流性质的内容挪进 Skills(按需加载),用不到的 MCP server 用 /mcp 关掉。
我看了下自己的,这部分在 1M 上下文的模型里占比很小。Cursor 用户还能直接在界面里看到 context 使用情况。我的建议是,除非你已经观察到明确的性能问题或者 context 频繁爆满,不用刻意去砍这些。倒是值得排查一下有没有装了但已经过时、长期不用的 MCP 和 skills,用 /doctor 指令检查。
文件读取,精确指令总是更好
这是原文给的一个很有意思的对比:
- 你说"测试挂了",Claude 先 grep、再翻几个文件,结果全部留在上下文里
- 你说"修复 utils.test.ts 里失败的测试",省掉搜索,只花一次 Read
- 你说"修复 @utils.test.ts",连 Read 都省了,文件随首个请求一起发出
你可能会想:我又不知道具体是哪个文件挂了,怎么给精确指令?这确实是鸡和蛋的问题。如果你已经从终端输出或者 CI 里看到了失败的文件名,直接 @ 过去最高效。如果你真的不知道,让 Claude 去搜是合理的,这时候的 token 花费是"有价值的探索"。
还有一个细节:同一个文件在一次会话里只 @ 一次。重复 @ 会再塞一份副本进上下文。后面 HN 的讨论里有人争论 @ 是不是反模式,结论是小文件用 @,大文件让 Claude 自己按需读片段更划算。
命令输出的陷阱
超大输出反而安全,超过 30000 字符 Claude Code 会写入文件,只留预览和路径在对话里。真正的坑是刚好没超限的。比如测试跑完打印 400 行 pass 信息,一行行全在上下文里赖到 session 结束。
对策是加静默参数。原文建议在 CLAUDE.md 里写上你每天常用的命令和对应的安静参数(比如 npx vitest run <file> --reporter=dot)。也可以把这些写进 Skills 而不是 CLAUDE.md,效果一样,区别在于 Skills 按需加载不会默认占上下文。Claude Code 还有 hook 机制,可以在命令执行前自动重写这些命令。
上下文停留多少轮
一个长 session 比拆成几个短 session 贵得多。第 40 轮还在重读前 39 轮的内容。换任务该新开就新开。
关于 /clear 和 /compact 的选择:原文建议换任务用 /clear,同一任务做完前半段用 /compact。我更倾向于直接新开 session,因为有时候需要回头检索之前的对话内容。我自己操作下来,/clear 的对话消失了就真的消失了。虽然文档说可以通过 resume 指令恢复。
HN 上有人推荐了 /handoff 来替代 /compact。/handoff 是一个社区 Skill,它把当前 session 的关键决策、失败路径和待办事项导出成一个结构化的 HANDOFF.md 文件。你开新 session 的时候把这个文件喂进去,新 session 就能继续之前的工作。相比 /compact 的好处是:你能看到、编辑导出的内容,而且新 session 的上下文是干净的。
关于 /loop
原文提了一句"留意 /loop 会带着整段对话反复发"。/loop 是 Claude Code 的会话内轮询指令。用法是 /loop 5m check the deploy,每 5 分钟自动执行一次你给的 prompt。
典型场景是部署监控、CI 状态轮询这类"隔几分钟看一眼"的活儿。问题在于,/loop 的每一次触发都是一个完整的 turn,带着你当前 session 的全部上下文一起发。如果距离上次交互超过 1 小时,缓存已经过期,那每次 loop 都是一次全量 Prefill。
所以原文说"放到另一个终端的新 session 里跑"。新 session 上下文为空,loop 每轮带的负担轻得多。
Subagent
Subagent 拥有独立上下文窗口,但拿不到你的对话。跑完把结论带回主 session,其他全部丢弃。
什么时候用性价比高?典型场景是任务会产生大量输出但你只需要一个结论。比如翻日志找报错、跑一遍 lint 看问题汇总、在大仓库里做全局搜索。这些活儿的中间过程全是噪音,在主 session 里做会赖在上下文里影响后续每一轮。丢给 subagent 就是"做完告诉我结果就行"。
不划算的场景是小任务。subagent 有启动成本(重新读 CLAUDE.md、加载工具定义),任务本身只需要一两轮就能解决的话,这个开销反而更大。
在 prompt 里直接说"在 subagent 里翻这份日志"就能触发。如果有反复出现的噪音活儿,可以给它定义一个专用 subagent 并指定小模型(model: haiku 或 sonnet)。
需要注意的是,新版本的 Claude Code subagent 并不像 Cursor 默认触发,需要用户明确声明。
四、速查行动清单
原文给了六条,按我的实际体验做了重新排序(实际效果见第五节)。
给高频命令加静默参数,或丢进 subagent。 命令输出会和文件一样,待在会话里直到结束。在 CLAUDE.md 或 Skills 里写上常用命令的安静参数(比如 npx vitest run --reporter=dot),纯探索类的大范围搜索交给 subagent,做完只把结论带回来。
离开键盘前先 /compact。 缓存 1 小时过期,趁热总结便宜。API key 用户窗口只有 5 分钟,ENABLE_PROMPT_CACHING_1H=1 可以延长到 1 小时(两倍价格)。
换任务就 /clear。 避免无关旧上下文被反复回传。直接新开 session 也行,好处是还能回头看历史。
新 session 跑一次 /context。 看清 CLAUDE.md、MCP 工具定义占了多少,砍掉不必要的。用不到的 MCP 用 /mcp 关掉,工作流内容挪进 Skills 按需加载。
开始前定好 model 和 effort。 中途改会打爆缓存,给整段对话交一次全价 Prefill。
用 @ 提及文件,而不是打文件名。 省掉一次 Read 调用,甚至省掉一次搜索。大文件不建议 @,整个塞进上下文太贵。同一个文件在一次会话里只 @ 一次,重复 @ 会再塞一份副本。
五、我的 context 审计
上面说的都是原理。我拿 cc-context-audit 跑了一遍自己最近两个月的 Claude Code 日志。161 个 session,36 个项目,934 条指令,11,048 轮,1.51B token,$1,638。 每条指令中位 $1.35、P90 $4.28,平均跑 11.8 轮。
若按最佳实践,除上下文质量提高外,理论上最高可省20%的消耗;若采用更性价比的模型进行任务分流,这个数据还可以更高。
数据分布
先看 token 类型:
| token 类型 | token | 占 token | 实测单价 | 占成本 |
|---|---|---|---|---|
| 缓存读取 | 1.45B | 96.4% | $0.57/M | 50.5% |
| 缓存写入 | 43.9M | 2.9% | $11.84/M | 31.5% |
| 输出 | 9.9M | 0.7% | $29.31/M | 17.7% |
| 未缓存输入 | 734k | 0.05% | $6.81/M | 0.3% |
实测单价是按 requestId 去重后、跨模型加权的均值。
再看内容来源:
| 来源 | 金额 | 占比 |
|---|---|---|
| 缓存写入 | $519 | 31.5% |
| 工具返回(后续重读) | $322 | 19.7% |
| 模型输出(生产) | $289 | 17.7% |
| 模型输出(后续重读) | $248 | 15.1% |
| 固定段(每轮重发) | $232 | 14.2% |
| 你的输入(后续重读) | $28 | 1.7% |
撑大上下文的主力是工具往回吐的东西。假设工具返回减半(比如全面加静默参数 + subagent),对应的重读成本从 $322 降到 $161 左右,接近总成本的 10%。
作用机制
整个会话周期里真正新产生的内容只有 23.9M token,最后进出模型的是 1.51B,放大 63 倍。
写入这道:每份内容至少写进缓存一次,干净会话的中位数是 1.20 次。理想情况下写入缓存应该就一次。超出 1.0 的部分来自三个原因:缓存过期、中途切模型/effort,以及缓存断点的步长。碎片化交互的单位写入成本天然更高。
缓存的价值没有疑问。把所有 token 按不缓存重算一遍是 $8,698,开缓存 $1,638,省了 5.4 倍。1 小时缓存的回本点是第 3 次请求。所以默认开启没毛病。
改进实践预估
七条措施,按估算量级排序:
| 措施 | 省 | 占总成本 | 拆解 | 上下文质量 |
|---|---|---|---|---|
| 给高频命令加静默参数 | $92 | 5.6% | 写入 $27 + 重读 $64 | 变好 |
| 离开前先 compact 或 clear | $85 | 5.2% | 写入 $85 | 变好 |
| 探索类工作交给 subagent | $68 | 4.2% | 写入 $10 + 重读 $58 | 变好 |
| 换任务就 clear | $33 | 2.0% | 写入 $22 + 重读 $11 | 变好 |
| 砍掉每轮重发的固定段 | $21 | 1.3% | 写入 $5 + 重读 $16 | 变好 |
| 切换动作放在会话边界 | $15 | 0.9% | 写入 $15 | 无影响 |
| 用 @ 提及代替重复读取 | $10 | 0.6% | 写入 $2 + 重读 $8 | 变好 |
七条加起来约 $324,占总成本 20%。省消耗的同时效果也变好,上下文变短,模型分给每个 token 的注意力也更多。
只减少缓存失效的三条措施(compact、切换放边界、换任务 clear)有数学天花板:$199,总成本的 12.2%。按理论下限 1.0 算是 14.9%。
一些其他数据发现
我的项目对于工具输出基本没做控制,导致大量中间信息被缓存和大量读取。这里要点名Claude Code 自身的浏览器插件,大量中间日志由它产生。Subagent用的次数也不多。缓存过期发生了20来次,最大一次间隔7天激活了之前的一个session。这种需要避免,当时做完要留档,后面新开更好。
以上数据来自本机 161 份 session 日志(按 requestId 去重后),按各模型公开 API 牌价折算。订阅制用户不按此计费,金额用于比较结构。
六、社区讨论反馈
实用技巧
- 自定义 statusline:Claude Code 支持在终端底部显示 token 用量、缓存命中率、quota 进度条等信息。社区做了 bfabio/ccstatusline 和 ndave92/claude-code-status-line 两个开箱即用的工具,在
~/.claude/settings.json的statusLine字段里配置即可。 - 缓存过期提醒:用 hook 记录每次交互时间戳,statusline 脚本根据时间差推算缓存剩余时效。不是精确值,但作为本地计时器够用。
- 压低单轮思考成本:追问模型解释时直接说"快速回答,不要深度思考",手动把单次 turn 的思考量压到最低,且不触发缓存重建。比切 effort 更灵活。
争议话题
- effort 为什么绑定缓存? 猜测是 effort 参数写在系统提示词前缀里,改了前缀就不匹配。痛点在于高 effort 出了结果之后追问解释,低 effort 就够了,但切了要交一次全价。变通办法是在 prompt 里写"快速回答"来代替切 effort。
- “这是产品设计问题”:HN 上最激烈的争论。批评方认为手动管理上下文和缓存是产品缺陷。反驳方拿调 Postgres 索引和优化 AWS 账单做类比,说复杂系统都有调优这一层。不过这个类比本身就有火药味:不少人觉得优化 AWS 账单同样是糟糕的用户体验。
- 缓存过期窗口太短:布置任务后去忙别的,20 分钟后回来缓存已失效。延伸想一下:国内厂商计算是瓶颈但存储相对宽松,有动力给更长的缓存时效;Anthropic 的 Pro 订阅是固定月费按用量限额,没有强动力给更多缓存宽限。
写在最后
我将原文整理成了一份思维导图版本(PDF),方便快速浏览全貌。这篇文章里的很多操作(比如"发指令前先想清楚精确度")其实和技术无关,是工作习惯。token 成本意识也一样。你不需要精确到每一轮花了多少,但"这个 session 已经很长了,该重开了"这种直觉值得培养。
上面第五节的数据来自我写的诊断 Skill:kuhung/cc-context-audit,可以分析你自己的 Claude Code session 数据,跑一遍就能看到你的 token 和成本分布,并给出调整建议。
另外两个相关的工具:
参考资料
- Maximizing the value of your Claude Code sessions - Anthropic 官方博客原文
- Hacker News 讨论帖 - 157 条评论,含大量实操反馈
- Claude Code 官方文档:Checkpointing - /rewind 和 checkpoint 机制
- Claude Code 官方文档:Sessions - session 管理、/clear、/resume
- Claude Code 官方文档:Scheduled Tasks - /loop 和定时任务
- Claude Code 官方文档:Statusline - 自定义状态栏
- bfabio/ccstatusline - 社区 statusline 工具,支持 token 用量和缓存命中率显示
- status203/handoff-skill - /handoff session 交接 Skill
- Issue #39658: /clear 导致 session 不可见 - 已确认 Bug