原文:Maximizing the value of your Claude Code sessions
TL;DR
- 每完成一项任务就运行一次
/clear。 这样可以避免把之前无关的上下文再次发送给模型,从而减少 Token 消耗。 - 开始前先确定模型和 effort 级别。 在会话中途更改其中任何一个,都可能让提示词缓存失效,进而增加 Token 成本。
- 使用 @ 提及文件,而不是只写文件名。 文件会直接附加到你的消息中,省去一次 Read 调用;如果 Claude 原本还需要自行寻找文件,也省掉了搜索过程。
- 给输出嘈杂的命令加上 quiet 参数,或者把它们交给子代理运行。 命令输出和文件一样会进入对话,并在之后的整个会话中一直保留。
- 在全新会话里运行一次
/context。 它会显示当前已经加载的内容,例如CLAUDE.md和 MCP 工具定义,方便你删掉不必要的部分。 - 准备离开键盘休息前,先运行
/compact。 提示词缓存会在一小时后过期;趁旧对话仍在缓存中时生成摘要,要便宜得多。
最大化会话价值
直到不久前,我们用来写代码的工具通常采用固定费用,甚至完全免费。无论你一个下午修复一项测试还是五十项测试,编辑器的成本都一样,所以单个任务并没有明确的价格。
Claude Code 这类智能体编程工具改变了这件事。同一个已经完成的任务,也会因为使用方式不同而产生不同的成本。
在一次会话中,Claude 读取测试和被测试的文件,完成修改,几个回合就结束了。在另一次会话中,它先在整个仓库里搜索,读取十几个文件,最后才找到同样的两个文件;而从早上开始进入对话的其他所有内容,也会在每一个回合里被重新带上。

图中的曲线仅用于说明,不代表真实基准测试数据。
最终修复完全相同,但你消耗了不同数量的 Token,而且模型一直不得不同时考虑十个根本用不到的文件。
高效使用 Token 并不意味着总体上必须少用 Token,而是要确保花掉的 Token 真正在为你提出的任务服务。
下面先看看什么决定一个 Token 的价格,再看看什么决定一次会话会发送多少 Token,并由此理解我们应该怎样组织一次会话。
什么决定 Token 的价格
费用按 Token 计算,但你真正购买的是推理:GPU(或者 TPU,以及模型实际运行所用的任何硬件)处理这些 Token 所花费的时间。
有三件事决定一个 Token 会占用多少推理时间:你使用哪个模型,它是输入 Token 还是输出 Token,以及它是否命中缓存。
模型
更大的模型会在输入和输出 Token 上执行更多计算。哪种工作值得使用哪种模型,本身就是一个独立话题;Claude 官方已经在 《在 Claude Code 中选择 Claude 模型与 effort 级别》中讨论过。
阅读本文只需要知道一点:接下来讨论的所有成本,最终都会乘上模型自身的价格。真正困难或模糊的问题使用更大的模型,常规工作则使用更小的模型。

图中的曲线仅用于说明,不代表真实基准测试数据。
输入与输出 Token
一次请求会分成两个阶段通过 GPU,而这两个阶段的成本并不相同。
首先,在预填充(prefill)阶段,模型会读取请求和上下文:系统提示词、你的 CLAUDE.md、你发送的消息,以及此前加入对话的所有内容,包括 Claude 读取的文件和执行命令产生的输出。这些都是输入 Token。
然后,在解码(decode)阶段,模型会写出输出 Token,包括思考、工具调用和你最终看到的文本。这个过程一次只生成一个 Token;一段 200 Token 的回复,意味着模型连续运行 200 次。按单个 Token 计算,解码占用 GPU 的时间远长于预填充,因此输出 Token 的价格大约是输入 Token 的 5 倍。

一次会话中的许多输出 Token 都是思考 Token,而模型每回合思考多少,取决于 effort 级别。和模型选择一样,通过 /effort 设置的级别也会保留,并成为下一个会话的默认值。
提示: 在新会话中分别运行一次
/model和/effort,确认自己实际使用的配置。两者都会记住上一次的选择,所以最好主动做出决定。
提示: 如果你已经知道这次会话只是处理机械性的工作,可以使用
MAX_THINKING_TOKENS=0 claude关闭本次会话的思考功能(Fable 5 除外)。这相当于比/effortlow 再低一级。
提示词缓存
如果一次请求开头的 Token 与服务器刚刚处理过的请求完全相同,那么这段共同前缀产生的状态也完全相同。服务器可以保留这部分状态,下次只对后续新增的内容执行预填充。这就是提示词缓存。
从缓存读取只需要输入价格的 0.1 倍,因为服务器是在加载状态,而不是重新计算状态。把 Token 写入缓存会比普通输入稍贵,最高可以达到 2 倍,因为服务器之后还要保存这段状态。但是每个 Token 只写入一次,此后的每一回合都能以 0.1 倍价格读取。
Claude Code 会在每次请求时自动管理提示词缓存,不需要手动开启。不过你有可能破坏缓存,所以了解怎样避免成本突然升高非常重要。
假设我们输入“修复 utils.test.ts 中失败的测试”。Claude Code 会这样处理:
- Claude Code 用系统提示词(包括工具定义)、你的
CLAUDE.md和消息组成第一个请求,然后发送出去。这些都是输入 Token。此时缓存还是空的,因此全部内容都会执行预填充并写入缓存。 - 模型没看过测试,无法直接修复,于是先思考片刻,再输出一个读取
utils.test.ts的 Read 调用。Claude Code 读取文件,把它追加到对话中,并再次发送完整内容。这一次,请求 1 的全部内容都会以十分之一的价格从缓存中读取,只有新增的 Read 调用和文件需要按完整价格预填充。 - 模型接着需要被测试的源文件,于是再输出一次 Read 调用。新的请求会再次发送全部内容:请求 1 和请求 2 从缓存读取,第二个文件按完整价格处理。
- 模型输出一次 Edit 调用。Claude Code 应用修改,把结果追加到对话并重新发送。仍然是相同的规则:Edit 和执行结果是新增内容,前面的全部历史都是缓存读取。
- 模型运行
npm test。Claude Code 把测试输出追加到对话并再次发送,此时只有测试输出属于新增的输入 Token。 - 测试通过,模型输出一段简短总结。因为没有新的工具调用,也就不需要再发起第六个请求,会话到此结束。
一个很小的修复就产生了五次请求,而且每一次都包含截至当时的完整对话。典型回合通常很不对称:数万 Token 进入模型,只有几百 Token 输出。但因为缓存存在,每回合只有新增内容需要按完整价格预填充。
这就是每回合费用的全部组成:历史内容按缓存读取价格计算,新增内容按完整输入价格计算,回复则按输出价格计算。
订阅用户也遵循相同规律。你不会直接看到这些价格,但这些请求会消耗你的使用额度。
缓存必须从请求的第一个 Token 开始连续匹配。请求内容总是按照相同顺序发送:先是工具定义,然后是系统提示词,最后是对话内容,而 CLAUDE.md 位于对话的前部。
只要这个前缀中的任何内容发生变化,后面的所有内容都需要重新预填充。把工具结果追加到对话末尾是最理想的情况,因为它后面没有其他内容。真正会丢掉缓存的,是那些改变请求靠前部分、或者改变缓存匹配条件的操作:
/model: 每个模型都有独立缓存,因此切换模型后的下一回合需要按完整价格重新预填充整个对话。这也包括 opusplan,因为进入或退出计划模式时都会切换模型。/effort: effort 级别也是缓存键的一部分,所以结果与切换模型相同。这也是在长对话中切换/model或/effort时,两者都会要求你确认的原因。- Fast mode: 它同样属于缓存键的一部分,而且重新预填充会按照 Fast mode 的价格计算。所以如果准备开启,最好从会话一开始就开启。仅从缓存角度看,关闭 Fast mode 不会产生额外成本。
/compact: 对话会被一段更短的内容替换,因此原对话中的内容不再匹配,只有前面的系统提示词还能保留。只要旧对话仍在缓存中,生成摘要本身并不贵,所以在长时间离开之前压缩,要比回来以后再压缩便宜得多。- 时间: 每个新回合都会重置计时,但订阅用户的缓存会在一小时后过期,API Key 用户则是五分钟。设置
ENABLE_PROMPT_CACHING_1H=1可以让 API Key 的缓存也保持一小时。如果在过期后继续,会重新预填充整个对话。恢复旧会话通常也是如此:缓存一般已经失效,而且启动时系统提示词还会重新构建。
这些并不是说永远不要切换模型或 effort,而是说切换存在便宜和昂贵的时机。会话开始时、或者刚刚运行 /clear 之后很便宜;长对话进行到一半时则很昂贵。
提示: 如果最近几个回合走向了你不想保留的方向,用
/rewind回到这些回合之前,而不是运行/compact。回退只是从末尾剪掉几个回合,前面的内容仍然命中缓存,因此不产生额外成本。压缩会重写整个对话,所以一定会产生费用。
什么决定一次会话发送多少 Token
这里最重要的一点是:没有什么内容只会发送一次。任何进入对话的内容——Claude 读取的文件或者执行命令得到的输出——都会在之后每一回合中再次发送,直到会话结束。
因为命中缓存,这些重复发送很便宜,但便宜并不等于免费;同时,它们还会占据上下文空间,让模型在每一回合都不得不绕过这些内容进行思考。
这基本就是一次会话的完整成本模型:有多少 Token 进入上下文,它们在多少个回合里一直保留,以及你同时运行了多少个上下文。
哪些内容会进入上下文
一部分上下文在你输入任何内容之前就已经存在,包括工具定义、系统提示词、CLAUDE.md,以及启动时加载的其他内容。
提示: 在全新会话里运行
/context,看看你还没输入任何内容时已经加载了什么。让CLAUDE.md只保留明确、具体的指令,把工作流专用说明移到 Skills 中,让它们只在真正使用时加载。如果本次会话不需要某个 MCP Server,可以通过/mcp把它关闭。
会话启动后新增的内容几乎都是工具结果:Claude 读取的文件,以及它执行命令产生的输出。
Claude 会读取多少内容,主要取决于它需要独自弄清多少事情。如果你只说“测试失败了”,它首先必须找出是哪些测试:执行一两次搜索,打开几个文件判断哪个相关,而所有这些结果即使早已失去作用,也会继续留在上下文中。
“修复 utils.test.ts 中失败的测试”省去了搜索,但仍然需要一次 Read 调用;“修复 @utils.test.ts 中失败的测试”连这次 Read 调用也省掉了。

提示: 引用文件时,通过 @ 提及它,而不是只输入路径。Claude Code 会在发送请求前把文件附加到消息中,因此文件从第一个请求起就在上下文里,不需要额外的 Read 调用。无论通过哪种方式,文件本身占用的上下文空间相同;每次对话只需要提及一次,因为它之后会一直保留。后续回合再次 @ 提及,通常会附加第二份副本。
另一个会填满上下文的来源,是 Claude 执行命令时产生的输出。每当它运行测试、构建或者 git log,打印出来的内容都会像读取的文件一样追加到对话中,并在后续同样多的回合里继续保留。
特别大的输出反而问题不大:超过 30,000 个字符后,Claude Code 会把输出写入文件,只在对话中放入简短预览和文件路径。你可以通过 BASH_MAX_OUTPUT_LENGTH 调整这个阈值。
真正的问题是所有没有达到这个阈值的输出。一个测试运行器如果逐行打印 400 项通过的测试,整体可能仍然低于限制,于是这 400 行就会进入之后每一个回合。
Claude 经常会主动使用参数或 tail 控制输出。如果你不想把这件事完全交给 Claude,官方文档还提供了一个小型 Hook,可以在嘈杂命令运行前改写它,只把真正重要的行返回到对话中。
提示: 把每天都会使用的两三个命令写进
CLAUDE.md,包括 quiet 参数,并按照你自己实际执行的方式描述,例如“使用npx vitest run <file> --reporter=dot运行单个测试文件”。这只是很小的补充,却能为之后每次会话省掉一个回合和数百行输出。
内容会在上下文里停留多少回合
一段很长的会话,会比拆成几个短会话完成相同工作昂贵得多。原因并不难理解:第 40 回合还要重新读取前面的 39 个回合。你应该让当前会话中的上下文始终简短且相关,不要把上一个任务的上下文带进下一个任务:开始新任务时运行 /clear;同一任务的前半部分已经完成时,则运行 /compact。

提示: 如果之后还想找回这个会话,在
/clear前先运行/rename。执行/compact时,可以告诉它必须保留什么;如果每次都需要保留同类信息,也可以在CLAUDE.md中加入“Compact instructions”部分。如果你使用 1M 上下文模型,希望自动压缩的安全线回到过去的位置,可以运行/autocompact 200k(需要 Claude Code v2.1.221 或更高版本)。
还要留意那些并非由你主动输入触发的回合。一次 /loop 的每次执行,都是在创建它的会话中运行一个完整回合,每次都会携带整段对话;如果距离上一回合已经超过一小时,它还会额外遭遇缓存失效。最好在另一个终端启动全新会话,并在那里运行循环。
子代理
要避免某些内容进入主上下文,还可以让它们在另一个上下文中处理。这正是子代理的用途。
子代理拥有自己的上下文窗口、系统提示词、工具和你的 CLAUDE.md,但不会继承主会话的对话内容。它会独立执行自己的多个回合,最后只有答案返回主会话;任务结束后,其余内容都会被丢弃。
不继承对话也有代价:子代理有时需要重新读取主会话已经看过的文件,并为自己的每个回合付出成本。对于很小的任务,这只会增加额外开销。
当一项工作会产生大量不需要长期保留的输出时,例如检查一份很长的日志,子代理就很划算。Claude 通常会主动在这类任务中使用子代理;如果它没有这么做,你也可以直接提出要求,例如“用子代理检查这份日志”。不过要记住,主会话最终只能得到子代理选择汇报的内容。

提示: 如果你反复把同一种嘈杂任务交出去,可以为它创建一个专用子代理定义,并指定
model: haiku或model: sonnet。否则,它会使用主会话当前所用的模型。
应该先关注什么
在上面讨论的所有因素中,最值得留意的有四项。下面按成本影响从高到低排列:
