/clear 。 这可以防止之前无关的上下文被再次发送给模型,从而减少 Token 使用量。/context。它会显示当前已加载的内容(CLAUDE.md、MCP 工具定义),这样你就能移除不必要的内容。/compact。提示词缓存一小时后会过期,只要缓存仍有效,压缩对话就会便宜得多。直到不久之前,你用于编写代码的工具通常都是固定收费(或免费)的。无论那天下午你修复了一个测试还是五十个测试,编辑器的成本都一样,因此单项任务本身并没有真正对应的价格。
但使用 Claude Code 这类智能代理式编程工具时,情况就不同了。同一个已完成的任务,根据你的使用方式不同,也可能产生不同的成本。
在一次会话中,Claude 读取测试及其覆盖的文件,完成编辑,几轮交互后就结束了。换一次情况,它可能先在代码仓库中到处 grep,途中读取十几个文件,最后仍然修改同样的两个文件;而且这期间的每一轮交互,都会把从今天早上开始已经读入对话的所有其他内容一并带上。

曲线仅用于示意,并不代表真实的基准测试数据。
修复内容相同,但你为此消耗的 Token 数量不同;在整个过程中,模型还不得不同时考虑十个并不需要的文件。
Token 使用高效,并不意味着总体上使用更少的 Token,而是要确保实际使用的 Token 都用于你真正要求完成的事情。
因此,先来看看一个 Token 的价格由什么决定,再看看一个会话发送多少 Token 由什么决定,并在此过程中了解这些因素会如何影响你运行会话的方式。
你按 Token 计费,但实际上付费的是推理(inference):GPU(或 TPU,或模型实际运行所在的其他硬件)处理你的 Token 并运行模型所需的时间。
三个因素决定一个 Token 需要占用多少处理时间:你运行的是哪个模型、它是输入 Token(传入)还是输出 Token(传出),以及它是否命中缓存。
更大的模型会对输入和输出 Token 执行更多工作。哪种模型适合哪类工作本身就是一个独立话题,我们在 在 Claude Code 中选择 Claude 模型和思考力度 一文中对此进行了介绍。
对于本文,你只需要知道,下面将要介绍的其他因素都会乘以模型的价格:当问题确实困难或存在歧义时使用更大的模型,而处理常规工作时使用更小的模型。

曲线仅用于示意,并不代表真实的基准测试数据。
请求会分两个阶段经过 GPU,而这两个阶段的成本不同。
首先,在预填充(prefill)阶段,模型会读取你的请求和上下文:系统提示词、你的 CLAUDE.md、你的消息,以及自此之后添加到对话中的所有内容(Claude 读取的文件和它运行的命令输出)。这些就是输入 Token。
然后,在解码(decode)阶段,它会写入输出 Token:它的思考过程、发起的工具调用,以及你看到的文本。这个过程一次生成一个 Token;一个 200 Token 的响应,就是连续运行模型 200 次。按单个 Token 计算,解码会让 GPU 忙碌得久得多,这也是输出 Token 价格约为输入 Token 5 倍的原因。

一个会话中的大量输出 Token 都是思考 Token,而模型每轮进行多少思考,取决于思考力度设置。和模型一样,你通过 /effort 选择的级别也会保留,并成为下一个会话的默认设置。
提示: 在全新会话中运行一次
/model和/effort,看看当前实际使用的设置。两者都会记住你上次的选择,因此应当有意识地做出决定。
提示: 如果你已经知道某个会话只会处理机械性工作,
MAX_THINKING_TOKENS=0claude 会在该会话中关闭思考(Fable 5 除外);其级别低于/effortlow。
如果一个请求从开头起恰好使用了与服务器刚刚处理的请求相同的 Token,那么这段共享开头所对应的状态也会相同。因此,服务器可以保留上次的状态,只对后续新增部分进行预填充。这就是提示词缓存(prompt caching)。
从缓存读取的成本是输入价格的 0.1 倍,因为服务器加载的是已有状态,而不是重新计算。将 Token 写入缓存的成本会略高于普通输入,最高可达 2 倍,因为服务器还必须在之后继续保留这些状态。但写入操作对每个 Token 只发生一次,而 0.1 倍价格的读取会在此后的每一轮中发生。
Claude Code 会在每个请求中管理提示词缓存,无需手动启用。不过,缓存可能被破坏,因此了解如何避免成本激增非常重要。
假设我们输入“修复 utils.test.ts 中失败的测试”。Claude Code 会为此发送以下内容:
CLAUDE.md 和你的消息组装出第一个请求,然后将其发送出去(输入 Token)。此时缓存中还没有任何内容,因此所有内容都会被预填充并写入缓存。utils.test.ts 的 Read 调用(输出 Token)。Claude Code 读取文件,将其附加到对话中,然后再次发送整个内容(输入 Token)。这次,请求 1 中的所有内容都会从缓存中读取,价格仅为原来的十分之一;唯一需要按全价预填充的是新增内容:Read 调用和文件。npm test (输出 Token)。Claude Code 附加测试输出并再次发送所有内容,此时只有测试输出是新增部分(输入 Token)。一个小修复就产生了五个请求,而且每个请求都包含截至当时的完整对话。典型的一轮交互往往是不对称的:输入是数万个 Token,输出只有几百个。但只有该轮新增的内容,才会按全价进行预填充。
这就是每轮的完整账单:历史内容按缓存读取计费,新内容按全额输入价格计费,响应则按输出价格计费。
订阅方案同样适用。你不会直接看到这些价格,但正是这些请求在消耗你的额度。
缓存必须从请求的最开始向后匹配,而请求始终按相同顺序发送:工具定义、系统提示词,然后是对话(其中 CLAUDE.md 位于对话开头)。
如果这个前缀中的任何内容发生变化,其后的所有内容都会再次进行预填充。将工具结果附加到对话末尾是最理想的情况,因为它后面没有其他内容。以下情况会丢弃缓存:请求中更靠前的内容发生变化,或缓存所依据的键发生变化:
/model:每个模型都有自己的缓存,因此下一轮会将整个对话重新按全价预填充。(这也包括 opusplan,因为每次进入或退出计划模式时,它都会切换模型。)/effort: 思考力度也是缓存键的一部分,因此情况相同。这就是为什么 /model 和 /effort 在对话中途切换设置时,都会要求你确认。/compact:对话会被替换成更短的版本,因此其中的内容将不再匹配(位于其前面的系统提示词仍然保留)。只要旧对话仍在缓存中,写入摘要本身的成本就很低,所以在长时间休息前执行会比休息后执行便宜得多。ENABLE_PROMPT_CACHING_1H=1 可将其延长为一小时)。如果超过这个时间再回来,下一轮就会重新预填充整个对话。恢复旧会话通常也会如此:那时缓存往往已经消失,而且系统提示词会在启动时重新构建。这些并不意味着你永远不应该切换模型或思考力度,而是说,切换存在成本较低的时机——会话开始时,或刚运行 /clear 之后;也存在成本较高的时机——一段较长对话的中途。
提示: 如果最近几轮对话偏离了方向,而你不想保留它们,请使用
/rewind回到这些内容之前,而不是运行/compact。回退只会截去末尾的这些轮次,因此之前的内容仍在缓存中,不产生额外成本。压缩会重写整个对话,因此总会产生一定成本。
这里最需要知道的是:没有任何内容只会被发送一次。所有最终进入对话的内容——无论是 Claude 读取的文件,还是它运行的命令输出——在此后的每一轮中,都会被再次发送,直到会话结束。
这些内容已被缓存,因此每次重新发送的成本都很低;但低成本并不等于零成本,而且它们还会持续占据上下文空间,模型每一轮都必须在这些内容的影响下进行思考。
这就是会话成本模型的核心:有多少 Token 最终进入上下文、它们会在其中停留多少轮,以及你同时运行了多少个上下文。
有一部分上下文在你输入任何内容之前就已经存在:工具定义、系统提示词、CLAUDE.md,以及启动时加载的其他内容。
提示:在全新会话中运行
/context,查看你还没有输入任何内容时上下文中有什么。将CLAUDE.md限定为具体指令,并将特定工作流的指令移入 skills;只有使用这些技能时,它们才会被加载。如果本次会话不需要某个 MCP 服务器,请使用/mcp将其关闭。
会话期间新增的其他内容,几乎都来自工具结果:Claude 读取的文件,以及它运行的命令输出。
Claude 读取多少内容,主要取决于它需要自行查明多少信息。如果你只说“测试失败了”,它首先必须找出是哪些测试:执行一两次 grep,打开几个文件以判断哪个相关,而所有这些结果在不再有用很久之后,仍会留在上下文中。
“修复 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,也可以使用文档中的一个小型钩子,在命令运行前重写嘈杂的命令,使其只返回重要的行。
提示:将你全天反复运行的两三个命令写入
CLAUDE.md,包括静默标志,像你自己输入时那样描述(“使用npx vitest run <file> --reporter=dot运行单个测试文件”)。这是一个很小的补充,但它能在此后的每个会话中省去一轮交互和几百行输出。
同样的工作,分散在几个短会话中,成本会低于集中在一个长会话中,而且差距可能比你想象得更大,因为第 40 轮也会重新读取之前的 39 轮内容。你需要让会话中的上下文保持简短且相关,因此不要把一个任务的上下文带入下一个任务:开始新任务时运行 /clear ,同一任务的前半部分完成后运行 /compact。

提示:如果之后还想找回该会话,请先运行
/rename,再运行/clear。运行/compact时,告诉它需要保留什么;如果每次都相同,也可以在CLAUDE.md中添加“压缩指令(Compact instructions)”部分。如果你使用的是 1M 模型,并希望恢复以前的自动压缩安全网,可以运行/autocompact 200k(需要 Claude Code v2.1.221 或更高版本)。
也要留意你没有输入内容时发生的轮次。一旦设置,/loop 会在所属会话中作为完整的一轮运行,每次都会携带整个对话;如果距离上一轮已经超过一小时,还会额外遇到一次缓存未命中。请在另一个终端中启动一个全新会话,然后从那里运行循环。
将某些内容排除在当前上下文之外的另一种方式,是让它在不同的上下文中执行,这正是子代理的用途。子代理拥有独立的上下文窗口、独立的系统提示词、工具和你的 CLAUDE.md,但不会拥有你的对话。它会自行运行多轮交互,完成后只有答案会返回主会话,其他所有内容都会被丢弃。
缺点是,由于没有你的对话,子代理有时必须重新读取主会话已经拥有的内容,而且在此过程中还要为自己的交互轮次付费。对于小任务而言,这只是额外开销。
当任务会产生大量你不需要保留的输出时,子代理就很有价值,例如遍历日志。Claude 通常会主动为这类工作使用子代理;如果它没有这样做,你也可以直接要求(“在子代理中检查这份日志”)。但请记住,主会话只能收到子代理选择汇报的内容。

提示:如果你反复交接同一种输出嘈杂的任务,可以为它单独定义一个使用
model: haiku(或 sonnet)的子代理。否则,它会使用主会话当前采用的模型运行。
在上述所有内容中,有四件事值得重点关注,按其大致成本从高到低排列:
