文章摘要
文章解释了Claude Code会话中输入和输出令牌的成本差异:输入令牌在预填充阶段处理,输出令牌在解码阶段生成,后者成本约为前者的5倍。输出令牌包含思考令牌,可通过/effort控制思考量。建议使用/model和/effort检查当前设置。
文章总结
好的,这是根据您的要求,对原文主要内容进行的中文重述,保留了关键细节,并删减了与主题无关的冗余内容。
如何最大化 Claude Code 会话的价值
输入与输出 Token
一个请求在 GPU 上经历两个阶段,成本不同:
- 预填充阶段:模型读取你的请求和上下文,包括系统提示、
CLAUDE.md、你的消息以及会话中累积的所有内容(如 Claude 读取的文件和命令输出)。这些是你的输入 Token。 - 解码阶段:模型生成输出 Token,包括它的思考过程、工具调用和最终文本。这个过程是逐 Token 进行的,例如,一个 200 Token 的响应需要模型运行 200 次。由于解码阶段占用 GPU 时间更长,其成本大约是输入的 5 倍。
会话中大量的输出 Token 是“思考 Token”,而思考的深度由“努力级别”(effort level)控制。你可以通过 /effort 命令调整。
提示:在新会话中运行
/model和/effort查看当前设置。这两个设置会记住你上次的选择,确保你的选择是有意的。 提示:如果你知道接下来的任务很简单,可以通过MAX_THINKING_TOKENS=0关闭思考功能(Fable 5 模型除外),这比/effort的低级别更省成本。
提示缓存
如果新请求的开头部分与服务器刚处理过的请求完全相同,那么这部分共享内容的计算结果也相同。服务器可以保留上次的计算状态,只需为新内容进行预填充。这就是提示缓存。
- 读取缓存:成本仅为正常输入价格的 0.1 倍,因为服务器直接加载状态而非重新计算。
- 写入缓存:成本略高于正常输入(最高 2 倍),因为服务器需要保存状态。但写入只需一次,后续每次交互的读取都是 0.1 倍成本。
Claude Code 会自动管理提示缓存,无需手动开启。但你需要了解如何避免破坏缓存,导致成本飙升。
示例:修复 utils.test.ts 中的测试
- 首次请求:Claude Code 发送系统提示、
CLAUDE.md和你的消息。此时缓存为空,所有内容都被预填充并写入缓存。 - 读取文件:模型需要查看文件,发出
Read调用。Claude Code 读取文件并追加到对话中,再次发送整个请求。此时,第一次请求的内容从缓存读取(0.1 倍成本),只有新的Read调用和文件内容需要全价预填充。 - 读取依赖文件:模型需要查看被测试文件依赖的另一个文件。再次发出
Read调用,追加文件内容。前两次请求的内容从缓存读取,新文件内容全价预填充。 - 编辑文件:模型发出
Edit调用。Claude Code 应用编辑并追加结果。编辑和结果是新的,其余内容从缓存读取。 - 运行测试:模型运行
npm test。Claude Code 追加测试输出。只有测试输出是新内容。 - 完成:测试通过,模型给出总结。没有新的工具调用,会话结束。
一次简单的修复就产生了 5 次请求,每次请求都包含整个对话历史。典型的交互是“头重脚轻”的:数万个 Token 输入,几百个 Token 输出。但只有每次交互中的新内容才需要全价预填充。
订阅用户也适用此规则,只是不直接看到价格,这些请求会消耗你的使用额度。
破坏缓存的情况:缓存必须从请求的最开始就完全匹配。如果请求前缀的任何部分发生变化,其后的所有内容都需要重新预填充。以下操作会破坏缓存:
/model:切换模型会清空该模型的缓存,导致整个对话重新预填充。/effort:努力级别也是缓存键的一部分,切换同样会清空缓存。- 快速模式:切换快速模式也会清空缓存,建议在会话开始时开启。
/compact:压缩对话会生成一个更短的对话,导致大部分内容不匹配缓存。- 时间:缓存会过期(订阅用户 1 小时,API 用户 5 分钟)。长时间后恢复会话,通常需要重新预填充整个对话。
提示:如果最后几步操作不理想,使用
/rewind回退,而不是/compact。回退只是删除末尾的交互,之前的缓存仍然有效,成本为零。压缩则会重写整个对话,总是有成本。
决定会话 Token 消耗的因素
核心原则是:任何进入对话的内容,都不会只发送一次。Claude 读取的文件或命令输出,都会在后续每次交互中重新发送。虽然缓存使重新发送成本很低,但并非零成本,而且这些内容会占用模型的上下文窗口。
因此,会话的成本模型取决于:有多少 Token 进入了上下文、它们停留了多少次交互,以及同时运行了多少个上下文。
什么会进入上下文
- 启动时:工具定义、系统提示、
CLAUDE.md等。 - 会话中:主要是工具调用的结果,如 Claude 读取的文件和命令的输出。
Claude 读取多少内容,取决于它需要自行探索多少。例如,你说“测试失败了”,Claude 需要先找到是哪些测试,这会产生多次 grep 和文件读取操作,这些结果都会留在上下文中。如果你直接说“修复 utils.test.ts 中的测试”,则省去了搜索步骤。
提示:引用文件时,使用
@提及文件,而不是手动输入路径。这样文件会直接附加到你的第一条消息中,无需额外的Read调用。文件本身占用的上下文空间是一样的,所以每个文件只需提及一次。
另一个占用上下文的是命令输出。每次运行测试、构建或 git log,其输出都会被追加到对话中。超过 30,000 字符的输出会被写入文件,对话中只保留简短预览和路径。但低于此限制的输出(如打印 400 个通过测试的列表)会全部留在上下文中。
提示:将你常用的命令(带静默标志)写入
CLAUDE.md,可以节省一次交互和数百行输出。
停留多少次交互
一个长会话的成本远高于将相同工作分散到几个短会话中。因为第 40 次交互需要重新读取前 39 次交互的内容。因此,保持上下文简短和相关至关重要:开始新任务时使用 /clear,完成当前任务的一部分后使用 /compact。
提示:使用
/rename为会话命名,然后/clear开始新任务。压缩时,明确告诉它要保留什么。如果你使用 100 万 Token 的模型,可以通过/autocompact 200k恢复自动压缩功能。
注意那些你不在输入时发生的交互。例如,/loop 会在你设置的会话中作为一次完整交互运行,每次都携带整个对话。如果距离上次交互超过一小时,还会导致缓存未命中。建议在新终端中启动一个新会话来运行循环。
子代理
子代理拥有自己的上下文窗口,包含独立的系统提示、工具和 CLAUDE.md,但不包含你的主会话对话。它独立运行,完成后只将结果返回给主会话。这可以防止大量输出污染主会话的上下文。
子代理的缺点是,它有时需要重新读取主会话已有的信息,这会增加成本。因此,它适用于产生大量你不需要保留的输出的任务(如分析日志)。Claude 通常会自行决定是否使用子代理,你也可以主动要求。
提示:对于频繁执行的“噪音”任务,可以为子代理指定一个更便宜的模型(如 Haiku 或 Sonnet),否则它会使用主会话的模型。
优先关注点
根据成本高低,以下四点值得关注:
- 上下文大小:保持上下文简短,及时清理。
- 交互次数:避免长会话,善用
/clear和/compact。 - 模型与努力级别:在会话开始时设定好,避免中途切换。
- 子代理使用:合理使用子代理处理噪音任务。
评论总结
根据评论内容,总结如下:
主要观点与论据:
效率与成本问题(评分:无)
- 用户反映Claude在信息检索上不如Codex高效,且因额外上下文处理导致速度慢(评论1)。
- 缓存意外重写导致高额token消耗,如400K token后突然增至800K甚至2M(评论2)。
- 项目全面审查消耗预算远超预期(评论7)。
用户责任与产品设计争议(评分:无)
- 批评文章将成本问题归咎于用户,类似“你拿错了”的推卸责任(评论4、8、15)。
- 用户认为产品应自动管理上下文、缓存等,而非要求用户手动优化(评论15)。
- 讽刺“超级智能”却需用户学习繁琐技巧(评论5)。
具体优化技巧与反馈(评分:无)
- 推荐使用
@-mention文件、/clear、/compact、/handoff等命令减少token消耗(评论5、18)。 - 指出
@-mention在桌面端存在bug,搜索结果不相关(评论10)。 - 质疑
/context运行缓慢,且缺乏实时token显示(评论13)。
- 推荐使用
功能限制与改进建议(评分:无)
- 询问为何缓存与effort级别绑定,希望低effort模式用于简单追问(评论6)。
- 建议支持脚本保持缓存活跃或自动compact(评论12)。
- 讨论
/clear与新建会话的区别(评论14)。
平衡性总结:
- 正面:部分用户认可优化技巧的有效性(如/handoff),并认为可提升效率。
- 负面:多数用户批评产品设计不完善,将成本控制责任转嫁给用户,且功能存在bug(如@-mention、缓存重写)。
- 中立:用户对缓存机制、effort切换等细节存在困惑,期待更透明的产品设计。