Anthropic 把 Claude Code 的 Token 账算明白了:一个长会话,可能多烧 1.9 倍
原文标题:Maximizing the value of your Claude Code sessions
原文链接:claude.com/blog/maximi...

最近用 Claude Code 写代码的人,大概率都碰到过这种情况:明明只是改一个小测试,Token 却像漏水一样往下掉。同样一处修复,有的会话五个请求就收工,有的会话先在仓库里来回搜索,又读了一堆无关文件,最后发出十八个请求。事情都做成了,消耗却完全不是一回事。
Anthropic 这篇文章把 Claude Code 的成本账讲得很透。真正影响消耗的,不只是"用了多少 Token",还包括模型大小、输入与输出的价格差异、提示词缓存有没有命中、上下文里塞了多少东西,以及这些内容在后续多少轮里被反复带上。
说白了,省 Token 并不等于一味少用 Token,而是尽量让每一个 Token 都花在当前真正要解决的问题上。
核心结论:先记住这 6 个习惯
- 不同任务之间及时执行
/clear。 这样可以避免上一个任务留下的无关上下文,在后续每一轮里继续被重复发送。 - 开始前就选好模型和推理强度。 在长会话中途切换
/model或/effort,可能直接打断提示词缓存,导致整段上下文按全价重新预填充。 - 提到文件时直接用
@引用。 文件会随第一条消息直接附上,既省掉一次 Read 调用,也免得 Claude 再去仓库里搜索。 - 给输出很吵的命令加静默参数,必要时交给子智能体。 命令输出会像文件内容一样进入会话,并在后续轮次里一直跟着走。
- 新会话先运行一次
/context。 它能显示启动时已经加载的内容,例如CLAUDE.md和 MCP 工具定义,方便删掉不需要的部分。 - 准备离开电脑前先执行
/compact。 订阅环境下,提示词缓存大约一小时后过期;趁缓存还在时压缩会话,成本会低得多。
同一个任务,为什么有人花 5 次请求,有人要花 18 次
在传统开发工具里,编辑器通常按月订阅,甚至完全免费。一个下午修一个测试还是修五十个测试,工具本身不会给每项任务单独计价。
但 Claude Code 这类智能体编程工具不一样。每一次模型推理、文件读取、仓库搜索、命令执行和结果回传,都会进入 Token 账单。同一个任务最终都能完成,但使用方式不同,成本可能差出一大截。
一种做法是直接告诉 Claude:具体哪个测试失败、对应哪个文件。Claude 读完测试和目标文件,改代码、跑验证,几轮就结束。另一种做法只说"测试挂了",Claude 只能先在仓库里 grep,接着打开一批文件,绕一圈才找到真正相关的那两个。更麻烦的是,前面搜到的内容不会自动消失,它们会在这个会话后面的每一轮里继续被带上。

图中左侧会话直接读取两个目标文件,共发出 5 次请求;右侧会话先搜索仓库、再陆续打开文件,共发出 18 次请求。两边完成的是同一项修复,但后者让模型额外背着大量无关上下文工作。
所以,所谓 Token 效率,并不是把总用量压到越低越好,而是减少无意义的搜索、读取和重复携带,让模型的计算真正落到任务本身。
接下来需要拆开看两件事:一个 Token 为什么有时贵、有时便宜;一次会话为什么会不断发送越来越多的 Token。
一个 Token 到底值多少钱
虽然账单按 Token 计算,但真正付费的其实是推理:GPU、TPU 或其他计算设备,需要花多少时间让模型处理这些 Token。
影响单个 Token 成本的主要有三件事:使用的是哪个模型、它是输入 Token 还是输出 Token,以及它有没有命中缓存。
模型越大,基础价格越高
更大的模型,在处理输入和生成输出时都要做更多计算。具体任务该选哪种模型、哪档推理强度,本身可以单独写一篇文章。这里最值得记住的一点是:后面讨论的所有成本,最终都要乘上模型本身的价格。
任务确实困难、含糊,或者需要更强推理时,大模型更值;只是机械修改、格式调整、跑固定流程这类常规工作,小模型往往更划算。

图里的曲线只用于解释思路,不代表真实 Benchmark 数据。简单任务上,两种模型最终效果可能逐渐收敛;困难任务上,大模型往往能达到更高上限,小模型则可能更早碰到能力天花板。
输入 Token 和输出 Token,不是一个价
一次请求在 GPU 上大致分成两个阶段,而且价格差得不小。
第一个阶段叫 预填充(Prefill) 。模型会读取本轮请求及全部上下文,包括系统提示词、CLAUDE.md、开发者刚发出的消息,以及从会话开始到现在累积下来的所有内容------Claude 读过的文件、执行过的命令、命令返回的输出,统统算在里面。这部分就是输入 Token。
第二个阶段叫 解码生成(Decode)。模型开始逐 Token 生成思考过程、工具调用和最终可见文本。生成是一个 Token 接一个 Token 往外吐的:一段 200 Token 的回复,相当于模型连续运行 200 次。解码阶段对 GPU 的占用明显更重,所以输出 Token 的单价通常大约是输入 Token 的 5 倍。

图中上半部分是预填充:工具定义、系统提示词、
CLAUDE.md、当前消息、Claude 读过的文件和命令输出,会按顺序整体送入模型。下半部分是解码:模型每生成一个 Token,就会再运行一次;因此 200 Token 的回复,本质上是 200 次连续生成。
一次会话里,很多输出 Token 实际上都来自模型的内部思考。每轮到底思考多少,主要由推理强度控制。和模型设置一样,通过 /effort 选择的档位也会被记住,下一次会话仍会沿用。
实用提示: 新会话里最好先分别运行一次
/model和/effort,确认当前到底启用了什么。两项设置都会记住上一次的选择,不主动查看,很容易在不知情的情况下继续使用高价配置。
实用提示: 如果某次会话确定只是机械活,可以用MAX_THINKING_TOKENS=0 claude为这一次会话关闭思考 Token。除 Fable 5 外,这相当于比/effort low更低一档。
提示词缓存,才是长会话里最关键的账
假设新请求的开头,和服务器刚刚处理过的某次请求完全一致,那么这段共同前缀经过模型计算后得到的状态也会一致。服务器可以把上一次的结果暂时留着,下次只对新增内容做预填充。这就是 提示词缓存(Prompt Caching)。
从缓存读取时,价格大约只有普通输入的 0.1×,因为服务器只需要加载已有状态,不必重新计算。把 Token 首次写入缓存会比普通输入稍贵,最高可到 2×,因为服务器还要保存对应状态。不过,每个 Token 只需要写一次,之后的每一轮都可以按 0.1× 读取,整体仍然非常划算。
Claude Code 会自动管理提示词缓存,不需要手动开启。真正需要注意的是:缓存虽然不用开,但很容易被中途打断。 一旦打断,整段长上下文可能重新按全价预填充,成本会突然跳起来。
一个小修复,实际是怎么产生 5 次请求的
假设开发者输入:修复 utils.test.ts 中失败的测试。从操作上看会经过下面 6 步,但真正向服务器发出的请求只有 5 次,因为最后一步没有新的工具调用。
-
Claude Code 把工具定义、系统提示词、
CLAUDE.md和开发者消息拼成第一次请求,作为输入 Token 发给模型。此时缓存还是空的,所以全部内容都会按正常价格预填充,并写入缓存。 -
模型还没看过测试文件,不可能直接修,于是先思考一下,返回一个读取
utils.test.ts的 Read 调用,这部分属于输出 Token。Claude Code 读完文件,把内容追加到会话末尾,再把整个会话发出去。此时第一次请求的内容都能从缓存按十分之一价格读取,只有新增的 Read 调用和文件内容需要按正常价格预填充。 -
模型接着需要查看被测试的源文件,于是再次发起 Read。第二个文件继续追加到会话末尾,前面的内容走缓存,新文件按正常输入价格计算。
-
模型返回 Edit 调用。Claude Code 应用修改,把编辑结果追加进会话,再次发送全部内容。新增的 Edit 及执行结果按正常价格计算,前面历史继续读缓存。
-
模型运行
npm test。测试输出被追加到会话末尾,下一次请求里只有这部分是新增输入,其余内容仍然来自缓存。 -
测试通过后,模型输出一段简短总结。因为没有新的工具调用,也就不需要再追加结果和发出第六次请求,会话到这里结束。
看起来只是修了一个小问题,背后却已经发出了 5 次完整请求,而且每次请求都带着当时为止的整段会话历史。典型的一轮往往很不对称:输入可能有几万 Token,输出只有几百 Token。不过只要缓存还在,历史部分就能按低价读取,真正按全价预填充的只是本轮新增加的内容。
因此,每轮的成本可以简单理解成三部分:历史上下文的缓存读取费、新增输入的正常预填充费,以及本轮回复的输出费。
订阅用户同样受这套机制影响。界面里虽然看不到每一项具体价格,但这些请求依然会消耗套餐额度。
哪些操作会让缓存失效
缓存必须从请求开头开始连续匹配。Claude Code 发请求时,顺序通常固定为:工具定义、系统提示词、会话内容,其中 CLAUDE.md 位于会话前部。
只要这个前缀中的某部分发生变化,后面的所有内容就可能被重新预填充。工具结果追加在会话末尾是最理想的情况,因为它后面没有旧内容,不会破坏前缀。真正容易把缓存打断的,主要是下面几类操作:
- 中途执行
/model。 每个模型都有各自的缓存。切换后,下一轮会把整段会话重新按全价预填充。opusplan也包括在内,因为每次进入或退出 Plan Mode 都会切换模型。 - 中途执行
/effort。 推理强度也是缓存键的一部分,改变档位同样会导致缓存不再匹配。这也是/model和/effort在长会话中途切换时会弹出确认的原因。 - 中途打开 Fast mode。 快速模式同样参与缓存匹配,而且重新预填充会按 Fast mode 的价格计算。确实要用,最好一开始就打开。再次关闭 Fast mode 本身不会打断缓存。
- 执行
/compact。 该命令会用更短的摘要替换原会话,因此原有会话内容不再匹配,只有前面的系统提示词还能保留。好消息是,只要旧会话仍在缓存里,生成压缩摘要本身并不贵,所以长时间离开前压缩,要比缓存过期后再压缩便宜得多。 - 等待太久。 每次请求都会重置缓存计时。订阅环境下缓存大约一小时过期;API Key 默认约五分钟,设置
ENABLE_PROMPT_CACHING_1H=1后可延长到一小时。超过这个时间再回来,下一轮往往要重新预填充整段会话。恢复很久以前的旧会话也基本如此,因为缓存通常已经失效,而且 Claude Code 启动时还会重新构建系统提示词。
这并不意味着模型和推理强度永远不能切换。只是切换也分便宜时机和昂贵时机:新会话刚开始,或者刚执行完 /clear,是便宜时机;一段很长的会话进行到一半,是最贵的时机。
实用提示: 如果只是最近几轮聊偏了,不必急着
/compact。可以用/rewind回退到跑偏之前。回退只是从会话末尾剪掉几轮,前面的缓存仍然有效,几乎没有额外代价;而/compact会重写整段会话,必然产生新的成本。
一次会话到底会反复发送多少 Token
这里最容易被忽略的一点是:进入会话的内容,几乎没有什么只发送一次。 Claude 读过的文件、执行命令产生的输出,都会在后面的每一轮里再次随请求发出,直到会话结束。
这些历史内容通常会命中缓存,所以每次重发并不算贵,但"便宜"不等于"免费"。更重要的是,它们还会占用上下文空间,让模型在每一轮推理时都得绕着这些内容工作。
一段会话的成本,归根结底取决于三件事:上下文里最终堆进了多少 Token,这些 Token 在多少轮中一直存在,以及同时运行了多少个独立上下文。
会话开始前,上下文就已经不为空
开发者还没输入任何内容时,上下文里通常已经有工具定义、系统提示词、CLAUDE.md,以及启动阶段加载的其他内容。
实用提示: 新会话里先运行
/context,可以看到输入第一句话之前到底已经加载了什么。CLAUDE.md最好只保留明确、长期有效的项目指令;某个工作流专用的说明,可以放进 Skill,需要时再加载。当前会话用不到的 MCP Server,也可以通过/mcp暂时关闭。
会话开始之后,新加入的内容几乎都来自工具结果:Claude 打开的文件,以及命令执行后打印出来的内容。
Claude 最终会读多少东西,很大程度取决于任务描述给得有多明确。只说一句"测试失败了",Claude 首先得找出到底是哪项测试:可能先 grep 几次,再打开若干文件判断相关性。即使这些搜索结果很快就没用了,它们仍会继续留在上下文里。
把要求写成"修复 utils.test.ts 中失败的测试",可以跳过搜索,但仍需要一次 Read 调用。进一步写成"修复 @utils.test.ts 中失败的测试",连 Read 调用也省掉了。

图中第一种只说"测试失败了",Claude 在真正开始修复前还要搜索和打开多个文件,共多出 6 轮;第二种直接给出文件路径,只需读取一次;第三种用
@附上文件,可以直接进入修复,不需要额外工具轮次。
提到文件时,最好直接使用 @,而不是只敲路径。Claude Code 会在请求发出前把文件附到消息里,因此文件从第一次请求起就已经在上下文中,不再需要额外 Read。无论哪种方式,文件本身占用的上下文空间都一样,所以一个会话里附一次就够了;后面再次 @ 同一个文件,通常会把第二份副本也附进去,反而增加上下文。
真正容易悄悄塞满上下文的,是命令输出
每次运行测试、构建命令或 git log,终端里打印的内容都会像文件一样被追加到会话中,并在后续轮次里继续存在。
特别大的输出反而没那么可怕。超过 30,000 个字符后,Claude Code 会把完整输出写入文件,只在会话里保留一小段预览和文件路径。这个阈值可以通过 BASH_MAX_OUTPUT_LENGTH 调整。
真正麻烦的是那些没超过阈值、但又足够啰嗦的输出。比如测试框架把 400 个通过的用例逐行打印出来,总字符数可能还不到 30,000,于是这 400 行会原封不动留在上下文里,并跟着后面的每一轮继续发送。
Claude 通常会主动加静默参数,或者用 tail 只保留末尾结果。要是不想把控制权完全交给模型,官方文档也提供了一个小 Hook,可以在命令执行前自动改写噪声很大的命令,只把真正有用的几行带回来。
实用提示: 可以把每天反复执行的两三个命令直接写进
CLAUDE.md,连静默参数也一起写清楚,格式就按平时真正会输入的样子。例如:使用 npx vitest run <file> --reporter=dot 运行单个测试文件。看起来只多了一行配置,却能让之后每次会话少一轮沟通,也少几百行无用输出。
一段上下文留得越久,后面每一轮越重
同样一批工作,全部塞进一个长会话,通常比拆成几个短会话更贵,而且差距往往比直觉里更大。原因很简单:第 40 轮不仅要处理新消息,还要重新带上前面 39 轮的历史。
会话里的上下文应该尽量短、尽量相关。一个任务结束后,不要把它的上下文继续拖进下一个任务。开始新任务时执行 /clear;仍是同一任务,但前半段已经完成且不再需要细节时,再用 /compact 做压缩。

图中完成的是同样三个任务。任务之间执行
/clear时,每个任务只携带当前需要的上下文;全部塞进一个会话时,历史不断累积,最终发送的 Token 约为前者的 1.9 倍。
实用提示: 如果以后还想找回当前会话,可以在/clear前先执行/rename。执行/compact时,最好明确告诉 Claude 哪些信息必须保留;如果压缩规则一直相同,也可以在CLAUDE.md里增加一个"Compact instructions"部分。使用 1M 上下文模型时,如果仍希望保留过去的自动压缩保护,可以运行/autocompact 200k,但需要 Claude Code v2.1.221 或更高版本。
还要留意那些"人没在输入,但会话仍在自动跑"的轮次。/loop 每触发一次,都会在创建它的会话里完整执行一轮,并带上当时整段上下文。如果距离上一轮已经超过一小时,还可能叠加一次缓存未命中。更省的做法是在另一个终端里新建一段干净会话,专门运行循环任务。
子智能体的价值,是把噪声隔离在另一个上下文里
还有一种办法可以避免主会话被塞满:把任务放到另一个上下文里执行,这正是子智能体存在的意义。
子智能体拥有自己的上下文窗口、系统提示词、工具和 CLAUDE.md,但不会继承主会话中的聊天历史。它会独立运行若干轮,最后只把答案返回主会话。中间读过的文件、跑过的命令和产生的大量输出,在任务结束后都会被丢弃,不会污染主会话。
代价也很明显。由于看不到主会话,子智能体有时需要重新读取主会话已经看过的内容,而且它自己执行的每一轮同样会产生成本。任务很小时,这种隔离反而只是额外开销。
真正适合交给子智能体的,是那些会产生大量过程输出、但主会话并不需要长期保留的任务,比如翻查一大段构建日志。Claude 遇到这类工作时往往会主动调用子智能体;没有主动调用时,也可以明确要求"在子智能体中分析这份日志"。需要注意的是,主会话最终只能看到子智能体选择汇报的内容,中间细节不会自动带回来。

图中主会话只保留启动内容、当前对话和三个子智能体的最终答案。三个子智能体分别分析构建日志、运行完整测试套件和搜索 Git 历史,各自读取和执行产生的过程内容,在任务完成后直接丢弃。
实用提示: 如果某类高噪声任务经常反复外包,可以单独为它定义一个子智能体,并指定model: haiku或model: sonnet。否则,子智能体默认会沿用主会话当前使用的模型,成本可能比预期更高。
最后先盯住这 4 件事
前面的机制看着不少,但真到日常使用里,优先关注下面四项就够了。它们大致按照可能造成的成本从高到低排列。

第一,长会话。 每一轮都会重新带上之前的全部内容,所以一段会话消耗的大头,往往不是刚输入的那句话,而是前面累积的历史。任务换了,及时 /clear;同一任务进入新阶段,再考虑 /compact。
第二,上下文太臃肿。 Claude 读了但其实不需要的文件、噪声很大的命令输出、早已完成的旧任务、当前根本用不到的 MCP Server,以及进入 Agent Loop 后额外产生的内容,都会在每一轮里被继续携带。上下文越干净,模型越省,也越不容易被无关信息带偏。
第三,模型过大或推理强度过高。 模型和 /effort 会放大后面所有成本,不管是当前任务本身,还是那些长期黏在会话里的无关内容。真正困难的问题再上大模型,机械任务没必要一直顶配运行。
第四,打断提示词缓存。 会话中途更换模型、切换推理强度或 Fast mode,或者等到缓存过期后再回来,都会让整段历史重新按全价预填充。能在开局决定的设置,尽量不要拖到长会话中途再改。
写在最后
Claude Code 的 Token 成本并不神秘,甚至可以压缩成一句话:上下文里放了多少东西,这些东西跟了多少轮,以及每一轮用了多贵的模型。
真正有效的优化,也不是时时盯着 Token 数字焦虑,而是养成几个简单习惯:任务之间清空会话,文件直接 @,命令尽量安静,长日志交给子智能体,模型和 /effort 开始前选好,离开前趁缓存还在及时压缩。
这些动作单看都很小,但放进每天几十轮、上百轮的真实开发流程里,差距就会被迅速放大。少让模型背着无关内容跑,省下来的不只是 Token,还有响应速度、上下文空间,以及模型真正理解当前任务的注意力。