Claude Code 会话效率指南:别让无关上下文偷走你的 Token

从 Token 价格、提示词缓存到上下文卫生,建立一套可复用的 Claude Code 会话运行手册

Posted by iceyao on Wednesday, August 19, 2026

原文:Maximizing the value of your Claude Code sessions · Lydia Hallie · Anthropic · 2026 年 8 月 14 日

说明:本文是对原文的中文技术解读和工程化整理。文中的成本比例用于解释机制,不是 Anthropic 的完整计价表;配图是基于原文机制绘制的概念示意图。

一、引言:同一个修复,为什么会有不同的 Token 账单

以前用编辑器写代码,修一个测试和修五十个测试,工具本身通常都是固定费用。Agentic coding tool 改变了这件事:同一个已经完成的任务,可能因为会话的组织方式不同,消耗完全不同的 Token。

例如,用户只想修复 utils.test.ts 中的一个失败测试。一个高效会话可能只读取测试文件和它覆盖的实现文件,然后编辑、运行测试;另一个会话却可能先搜索整个仓库、打开十几个无关文件,接着在同一窗口里继续处理早上的另一个任务。最后两者得到相同的修复,但后者让模型在每一轮都携带更多无关上下文。

这篇文章最值得记住的不是“尽量少用 Token”,而是另一句话:

Token efficiency 不是让 Token 总量越少越好,而是让已经花掉的 Token 尽可能服务于当前任务。

Claude Code 会话效率:把 Token 花在当前任务上

这也意味着,Claude Code 的会话管理不只是一些快捷命令的记忆题。/clear/compact/rewind@ 文件引用、安静的测试命令和 Subagent,背后其实对应一套完整的成本模型:

  1. 一个 Token 的处理价格由什么决定?
  2. 一个会话最终会把哪些内容送进上下文?
  3. 这些内容会在多少轮请求里被反复携带?
  4. 哪些操作会让已经建立的提示词缓存失效?

下面沿着这四个问题展开。


二、先建立成本模型:模型、方向、缓存和会话长度

2.1 模型选择会放大后续所有成本

模型越大,对输入和输出 Token 所做的计算通常越多,单 Token 价格也越高。原文的建议很朴素:真正困难、含糊或需要复杂判断的问题使用更强的模型;机械、边界清晰的工作使用更小的模型。

这里有一个容易被忽略的细节:模型选择不是只影响“这一轮回答多少钱”,它还决定了后续会话的缓存边界。Claude Code 的提示词缓存按模型隔离,同一段会话从 Opus 切换到 Haiku,不能直接复用原模型的缓存。

因此,长任务开始前就应该先做出有意识的选择:

新会话 → 选择模型 → 选择 effort → 开始任务

不要把“先用大模型探索,遇到简单步骤再切小模型”当成无成本优化。切换发生在长会话中间时,重新预填充上下文的代价可能抵消模型本身的价格差异。

2.2 输入 Token 和输出 Token 不是同一种成本

一次请求可以粗略分成两个阶段:

  • Prefill(预填充):模型读取系统提示、工具定义、CLAUDE.md、用户消息,以及此前已经加入会话的文件和命令输出;这些是输入 Token。
  • Decode(解码):模型逐个生成思考内容、工具调用和最终文字;这些是输出 Token。

输出阶段需要逐 Token 运行模型,原文用“输入价格约五分之一”这个近似量级解释为什么输出 Token 通常更贵。对 Claude Code 来说,输出不只是最终显示在终端上的文字,还包括:

  • 模型的思考 Token;
  • ReadEditBash 等工具调用;
  • 工具调用参数和中间决策。

所以,/effort 会影响的不只是答案“想得深不深”,还会影响每一轮的输出量。原文建议在新会话中运行 /model/effort,确认当前到底继承了什么设置;两者可能沿用上一次会话的选择。

对于已经确定是纯机械任务的单个会话,原文还提到可以使用下面的环境变量关闭思考(Fable 5 除外):

MAX_THINKING_TOKENS=0 claude

这不是默认建议,而是一个应当只在任务性质明确时使用的边界选项。关闭思考不能弥补模糊需求、错误文件范围或脏上下文带来的损耗。

2.3 提示词缓存让重复历史变得便宜,但不是免费

如果新请求从开头开始,和服务器刚刚看到的请求拥有完全相同的 Token 前缀,服务器就可以复用已经计算好的状态,这就是提示词缓存(prompt caching)。原文给出的简化相对比例是:

  • 从缓存读取的输入 Token,成本约为正常输入的 0.1x
  • 写入缓存的 Token,可能比普通输入更贵,最高约 2x
  • 但写入通常发生一次,后续每轮都可以用较低成本读取。

Claude Code 会自动管理提示词缓存,用户不需要额外打开开关。真正需要关注的是:不要在不合适的时机破坏它。

Claude Code 会话成本模型:稳定前缀、增量输入与输出阶段

2.4 会话总成本取决于上下文留了多久

文件内容和命令输出一旦被加入会话,就不会只发送一次。之后每一轮请求都会携带它们:缓存命中时成本更低,但并不等于没有成本;更重要的是,模型还要在这些内容中寻找当前任务真正相关的部分。

因此,可以用一个简单的近似模型理解会话账单:

会话消耗 ≈ 上下文规模 × 保留轮数 × 同时运行的会话数

这个公式不是计费 API,而是一个工程决策模型。它解释了三个现象:

  • 一个无关文件在第 1 轮读入,可能会影响后面几十轮;
  • 一条冗长的测试输出会像文件一样长期留在上下文中;
  • 两个并行会话如果都各自加载同一份大上下文,成本不会自动合并。

三、提示词缓存的工作方式:稳定前缀,动态后缀

3.1 一次小修复其实会产生多次请求

把“修复 utils.test.ts 中的失败测试”拆开看,Claude Code 大致会经历下面的过程:

  1. 发送系统提示、工具定义、CLAUDE.md 和用户任务;第一次没有缓存,需要完整预填充并写入缓存。
  2. 模型返回读取 utils.test.ts 的工具调用;Claude Code 执行读取,把文件追加到会话,再次发送整个历史。前面的内容从缓存读取,读取调用和新文件按完整输入处理。
  3. 模型继续读取被测实现文件;这一次只有新的读取调用和第二个文件是新增部分。
  4. 模型返回编辑调用;Claude Code 应用编辑并把结果追加到会话。
  5. 模型运行测试;测试输出成为新的上下文尾部。
  6. 测试通过,模型给出总结。因为没有新的工具调用,不再需要发送下一轮请求。

因此,一个看起来只有“读文件—改文件—跑测试”的小任务,实际上可能有五次请求,而且每次请求都包含完整的会话历史。缓存的价值就在于:前面已经处理过的稳定前缀不需要每次按完整价格重新计算。

3.2 缓存匹配从请求最前面开始

原文强调,Claude Code 请求的顺序大致是:

工具定义 → 系统提示 → 会话内容(包含 CLAUDE.md)→ 本轮新增内容

只要这个前缀中的某个位置发生变化,后面的内容就可能全部从缓存边界之后重新预填充。于是,稳定内容应该前置,动态内容应该后置:

  • 系统提示保持稳定;
  • 工具定义顺序保持确定;
  • 项目规则保持可复现;
  • 当前时间、临时状态、文件变化和工具输出通过消息追加到尾部。

这不是“把内容排得整齐”这么简单,而是 Agent harness 的架构约束。一个无意中放在 system prompt 开头的时间戳,就可能让后面所有工具定义和历史消息都失去复用机会。

提示词缓存生命周期:从首次预填充到缓存命中,再到前缀变化造成失效

3.3 五个容易破坏缓存的操作

1. 在长会话中途切换模型

每个模型拥有独立缓存。即使新模型更便宜,也需要重新建立自己的前缀状态。

2. 在长会话中途改变 effort

/effort 也是缓存键的一部分。切换 effort 的确认提示不是多余的,它是在提醒你:这次改变可能带来重新预填充。

3. 临时打开 Fast mode

Fast mode 同样参与缓存键。如果确实要使用,应该在会话开始时就决定,而不是在长会话中途打开。

4. 用 /compact 改写整个历史

/compact 会把原始会话替换成摘要。系统提示前缀仍然存在,但原来的对话 Token 不再逐字匹配,因此压缩本身会产生成本。它适合在同一任务还要继续时主动整理,不适合被当成任意时刻的“免费清理按钮”。

5. 让缓存自然过期后再回来

原文给出的时间边界是:订阅计划通常约一小时,API key 通常约五分钟;API key 可以用 ENABLE_PROMPT_CACHING_1H=1 将后者延长到一小时。每一轮请求都会重置计时,但长时间离开后,下一轮仍可能需要重新预填充整个会话。

这解释了一个很实用的操作顺序:准备离开键盘时,趁缓存还热先 /compact;回来后如果任务已经换了方向,则直接 /clear

3.4 /rewind 有时比 /compact 更便宜

如果最近几轮已经走错方向,但更早的文件读取和分析仍然有用,可以用 /rewind 回到错误尝试之前。它只截掉会话末尾的那段内容,前面仍然保持不变,通常比重写整个历史的 /compact 更节省缓存。

两者的分工可以这样记:

操作 处理对象 典型目的
/rewind 会话尾部的错误尝试 保留之前的有效探索,删除错误分支
/compact 同一任务的完整历史 压缩旧上下文,保留任务继续推进所需的摘要
/clear 当前会话的全部对话历史 切换到无关的新任务,重新建立干净上下文

四、上下文卫生:别把无关信息留在主会话里

提示词缓存解决的是“重复计算”,上下文管理解决的是“到底有没有必要重复携带”。两者有关,但不是同一件事:一段无关内容即使每轮都命中缓存,仍然会占据模型的注意力空间。

4.1 新会话先运行一次 /context

刚启动一个新会话时,可以运行一次 /context,检查模型在你输入第一个任务之前已经加载了什么:

  • 工具定义;
  • 系统提示;
  • 根目录和当前路径上的 CLAUDE.md
  • MCP 工具定义;
  • 其他启动时注入的内容。

如果某个 MCP server 在当前任务中完全用不到,可以用 /mcp 将它关闭。CLAUDE.md 也不应该成为团队所有流程的垃圾桶:稳定、普遍适用的仓库事实留在里面;只在特定工作流需要的内容,放进 Skill,让它按需加载。

4.2 引用文件时优先使用 @

如果已经知道要处理的文件,直接使用 @ 引用比只在文字里写出路径更高效:

请修复 @src/utils.test.ts 中的失败测试,并检查它覆盖的实现文件。

@ 引用会把文件直接附加到消息中,避免模型先发起一次 Read,也避免它通过搜索去猜文件在哪里。文件本身仍然会占用上下文空间,所以同一个文件在后续消息中不要反复 @ 一遍;重复引用可能附加第二份副本。

这条建议可以推广为一个工作习惯:能明确给出范围,就不要让 Agent 为了确认范围而搜索整个仓库。

4.3 命令输出也是上下文,不只是终端噪声

Claude Code 执行测试、构建或 git log 时,命令输出会像文件一样追加到会话,并在之后的每一轮继续存在。

输出超过约 30,000 个字符时,Claude Code 会将它写入文件,只在会话中放入短预览和路径;真正容易污染会话的,反而是那些“没有大到触发外置、又足够长”的输出。例如,一个逐行打印 400 个通过测试的 runner,可能完整留在后续每一轮上下文中。

因此,应该给常用命令配置安静输出:

npx vitest run src/utils/utils.test.ts --reporter=dot

或者把命令的推荐写法放进 CLAUDE.md,让 Agent 从一开始就知道如何只返回有用信息。对于特别嘈杂的日志分析,则可以直接让 Subagent 处理。

上下文卫生:精准输入、安静命令与隔离任务共同控制上下文规模

4.4 一个会话不要承载多个无关任务

长会话的后半段会重复携带前半段的所有内容。第 40 轮并不是只读取第 39 轮,而是要在前面 39 轮共同构成的上下文中继续工作。

所以原文给出的建议非常直接:任务切换时使用 /clear 如果以后可能还要回到旧任务,先运行 /rename,再清除当前会话,避免把一个值得保留的会话变成混杂的工作日志。

这里的判断标准不是“旧内容还在不在”,而是“旧内容是否仍然与新任务相关”。相关就继续,不相关就清掉;不要因为上下文窗口很大,就把所有任务都堆在同一个会话里。


五、Subagent:把高噪声工作放到另一个上下文

Subagent 的核心价值不是“多一个模型帮忙”,而是上下文隔离

一个 Subagent 拥有自己的上下文窗口、系统提示、工具和 CLAUDE.md,但没有父会话的完整对话历史。它运行自己的多轮读取、搜索和命令,最终只把它选择报告的答案返回到主会话,中间过程在结束后被丢弃。

这会带来一个明确的取舍:

  • 小任务:Subagent 需要重新读取文件和建立上下文,隔离本身可能就是额外开销;
  • 高噪声任务:例如遍历大型日志、扫描大量文件、重复执行验证,中间输出很多,但主线只需要结论,Subagent 通常更划算。

可以用一个问题做判断:

我需要这个任务产生的完整过程,还是只需要最终结论?

如果只需要结论,就可以把它交给 Subagent。例如:

请用一个 Subagent 检查最近修改是否违反安全规范,只返回按严重程度排序的问题清单和文件路径,不要把所有搜索过程带回当前会话。

如果某类噪声任务会反复执行,可以为它定义独立的 Subagent,并指定更合适的模型,例如 Haiku 或 Sonnet;否则它可能默认继承主会话正在使用的模型。

/loop 也值得单独留意:它会在创建它的那个会话中作为完整轮次运行,并携带整个会话上下文。如果循环任务会长期运行,最好在另一个终端启动一个全新的会话,而不是把它挂在正在写代码的主线上。


六、把原理变成运行手册

6.1 开始任务:先固定会话边界

一个新的、目标明确的任务可以按下面的顺序开始:

1. /clear(如果上一个任务无关)
2. /model
3. /effort
4. /context
5. 明确任务范围,优先 @ 关键文件

/clear 的位置不是固定的:如果新任务与上一个任务紧密相关,就不要为了“看起来干净”而清空;如果只是同一个项目中的另一个功能,也不代表上下文仍然有价值。

6.2 执行任务:让新增上下文保持小而有用

执行过程中,可以遵守四条规则:

  1. 已知路径就直接给路径或 @ 文件,不要让 Agent 盲搜。
  2. 测试、构建和日志命令使用安静模式,只保留失败和关键摘要。
  3. 需要大量中间结果的侧线调查交给 Subagent。
  4. 不要为了一个简单步骤在长会话中途切换模型、effort 或 Fast mode。

这些规则共同指向同一个目标:让每一轮新增的尾部内容尽可能短、尽可能相关,并让前面的稳定前缀持续命中缓存。

6.3 任务转折:在三个动作之间做选择

当一个阶段完成后,可以这样判断:

  • 仍在同一任务,旧内容大多有用:直接继续;
  • 仍在同一任务,但调试噪声已经过时/compact,并明确告诉它要保留什么;
  • 最近几轮走错了,但更早的探索有用/rewind 到错误分支之前;
  • 完全切换到无关任务/clear,重新给一份精炼简报;
  • 下一步会产生大量扫描或日志:用 Subagent 隔离。

6.4 离开键盘:趁缓存还热时压缩

如果只是暂时离开,且回来后还会继续同一任务,先运行带提示的 /compact

/compact 保留当前 API 契约、数据库 schema 变更、已通过的测试和下一步计划;丢弃早期的 CSS 调试过程。

这样做有两个好处:压缩摘要更容易复用当前仍然有效的缓存;回来后模型不必重新在一长串历史中筛选重点。

如果任务已经结束,或者回来后准备做完全不同的事情,则不要为了保留缓存而强行延续旧会话。/rename/clear,通常比背着旧上下文开始更稳。

Claude Code 会话运行手册:根据任务关联性选择继续、压缩、回退、清除或 Subagent

6.5 一张命令速查表

命令或动作 最适合的时机 主要收益 需要注意
/model 新会话开始 确认模型选择 中途切换会破坏模型级缓存
/effort 新会话开始 控制推理强度 中途切换也会影响缓存
/context 新会话开始 看清已加载内容 用它发现不必要的 MCP 或规则
@file 已知目标文件 跳过搜索或 Read 同一文件不要重复附加
/rewind 最近几轮走错 保留旧探索,删除错误分支 先确认回退点
/compact <hint> 同一任务继续 摘要旧历史 它会改写会话,最好趁缓存仍有效时执行
/clear 切换无关任务 重新建立干净上下文 /rename,方便以后找回
Subagent 大量中间输出 隔离噪声,只返回结论 小任务可能不值得付出启动成本

七、给团队的工程化建议

原文面向的是 Claude Code 使用者,但其中的规律也适用于自建 Agent harness。

7.1 把上下文预算当作产品指标

不要只监控最终请求是否成功,还可以观察:

  • 每个会话的输入 Token 和输出 Token;
  • 未命中缓存的输入规模;
  • 首 Token 延迟;
  • 工具输出在上下文中的占比;
  • /compact 或摘要请求的成本;
  • 长会话中模型和 effort 的切换次数。

如果某个版本上线后 cache hit rate 突然下降,优先检查 prompt 前缀、工具顺序和系统提示是否发生了非预期变化,而不是先归因于模型“变笨了”。

7.2 把静态规则和动态状态分开

一个稳定的 CLAUDE.md 适合保存仓库地图、关键约束和常用命令;当前时间、分支状态、临时故障和用户刚刚修改的文件,应通过消息或工具结果追加到后面。

同样,工作流的详细步骤不必塞进每次都加载的配置文件。把它们放入 Skill,按任务需要加载,既能减少固定 Token,也能避免无关规则和当前任务争夺模型注意力。

7.3 不要把上下文隔离误解为“永远开 Subagent”

Subagent 不是免费线程池。它有自己的系统提示、工具定义和文件读取成本,而且父会话只拿到它主动总结的结果。真正有价值的场景是:

  • 中间过程很长;
  • 结果边界清晰;
  • 主会话不需要逐步参与;
  • 任务可以用简短结果交接。

否则,直接在主会话里完成小范围任务,往往更快也更便宜。


八、结语:会话管理就是 Token 的资源调度

Anthropic 这篇文章把一个常被忽略的事实讲得很清楚:Agent 的成本不是“用户发一条消息、模型回一段文字”这么简单。每一个被读入的文件、每一行命令输出、每一次工具调用,都会进入会话并影响后续所有轮次。

可以把整套方法浓缩成六句话:

  1. 开始前固定模型和 effort,不要在长会话中途随意改变缓存边界。
  2. 稳定内容放前面,动态内容放后面,让提示词缓存有机会持续命中。
  3. 已知文件用 @ 直接附加,不要让 Agent 为了确认路径多走一轮搜索或读取。
  4. 命令输出要安静,因为终端噪声会像文件一样留在上下文中。
  5. 同一任务用 /compact,错误分支用 /rewind,无关任务用 /clear
  6. 只需要结论的高噪声工作交给 Subagent,不要让主会话承担所有中间过程。

真正高效的 Claude Code 用户,不是单纯追求更大的上下文窗口,也不是机械地追求更少的 Token,而是在每次操作前都问一句:

这段信息对当前任务有用吗?它还需要在会话里留下多少轮?

当答案是否定的,就应该在它进入主上下文之前缩小范围、安静输出、隔离任务,或者清除会话。这样做的结果不是让 Agent 做得更少,而是让它把更多计算真正用在你要解决的问题上。

参考资料

  1. Maximizing the value of your Claude Code sessions
  2. Lessons from building Claude Code: Prompt caching is everything
  3. Using Claude Code: session management and 1M context

「真诚赞赏,手留余香」

爱折腾的工程师

真诚赞赏,手留余香

使用微信扫描二维码完成支付