
Claude Code 额度回落:Agent 正在制造新的「祖传代码屎山」?
Quick Answer
Claude Code's usage costs are rising due to the inefficiencies of agent loops, where each step accumulates context weight, leading to increased token consumption.
Quick Take
The model's ability to manage context and working sets is critical for maintaining efficiency in coding tasks.
Key Points
- Agent loops in Claude Code increase token consumption significantly with each task step.
- Working set management is crucial to prevent excessive context weight during coding tasks.
- Token costs are influenced by both the number of steps and the complexity of the context.
- Semantic page faults occur when necessary historical information is prematurely discarded.
- Sub-agents can isolate and compress context to improve efficiency in long tasks.
📖 Reader Mode
~6 min read
作者丨郑佳美
编辑丨岑 峰
Claude Code 原定于 8 月 19 日结束的 +50% 周额度加成,又被 Anthropic 延长到了 8 月 31 日。也就在原定截止日前后,Hacker News 上出现了一轮关于 Claude Code 使用成本的讨论:不少人发现,一个并不复杂的任务,Agent 跑上几轮,额度就会掉得很快。

问题在于,Claude Code 消耗的并不只是最后生成的那几行代码。读文件、搜调用链、跑测试、处理日志,每一步都会继续进入后面的上下文。任务越长,Agent 背着的历史越重,系统也越依赖清理和压缩。
代码可以完整留在仓库里,早期的设计理由却可能在压缩中逐渐变薄。于是 Token 消耗和代码屎山开始在同一个地方汇合。


01
修个小 Bug,为何需要几十次推理?
普通 Chat coding 的计算边界很清楚。输入一段代码,模型读完以后给出解释或者修改方案,这一轮基本结束。雷峰网(公众号:雷峰网)
而 Claude Code 的基本单元换成了 agent loop。模型先观察当前状态,决定下一步要读哪个文件或者执行什么命令;工具返回结果以后,模型再进行下一轮判断。
读源码、搜索引用、运行测试、查看 Git diff、修改文件,看上去像一个连续动作,在模型侧其实是一串独立的推理请求。Claude Code 官方文档也把这种“模型判断—调用工具—根据结果继续判断”的循环作为 Agent 工作方式的核心。
比如一个登录状态偶发失效的问题。Agent 先找到入口,发现状态来自 service,于是继续读取 service;看到缓存后搜索谁在写它;接着跑测试,测试出现另一个异常,于是去看 fixture;修完以后再次验证,旧测试又暴露出兼容问题。
可能直到这时,它才真正开始写那几行代码。因此,diff 大小和计算量之间几乎不存在稳定比例。5 行补丁背后可能只有 3 次推理,也可能已经经过 30 次工具交互。

如果把一次 Agent 任务拆开,可以先得到两个变量:一个是 step count,Agent 为了完成任务走了多少步;另一个是 working set,走到当前这一步时,模型还需要掌握多少项目状态。
只增加 step count 已经会提高消耗。如果 working set 还在同步变大,情况就完全不同了。第 3 步也许只需要处理几千 Token,第 30 步却可能已经背着项目规则、相关源码、测试结果、修改历史和工具返回继续推理。雷峰网
这也是 Coding Agent 成本结构发生变化的起点:计算量开始取决于“走多少步 × 每一步背多重”,而不再取决于写了多少行代码。

02
Token 到底烧在哪里?
把 Agent 的一次模型请求拆开,可以粗略看成三块。相对稳定的部分包括 system prompt、CLAUDE.md、工具定义和项目规则;不断变化的部分包括代码文件、搜索结果、测试日志、Git diff 和此前的任务轨迹;最后还有这一轮模型生成的 reasoning、文字与代码。
这里容易产生一个误区:只要前面的内容已经读过,就不应该重复产生太多成本。问题在于,LLM 两次请求之间不存在一个传统程序那样可以随时访问的内部内存。上一轮知道的信息,如果下一轮判断仍然依赖它,相关状态还得继续出现在可用 context 中。

Prompt cache 能缓解这个问题。Claude Code 官方文档明确说明,如果没有 prompt caching,每轮请求需要重新处理整段历史;缓存命中后,已经处理过的稳定前缀可以复用,从而降低重复计算和成本。
但 cache 解决的是“同样的历史能不能便宜一点重新使用”,没有解决“这段历史还要不要继续存在”。100K Token 的旧状态命中缓存后便宜了,它依然占据 context,也依然是当前推理建立在上面的状态。
于是可以把一个长任务粗略写成:第 t 步的输入规模,大约等于稳定前缀 S,加上当前有效工作集 W_t,再加这一轮刚产生的新信息 Δ_t。
真正麻烦的是 W_t。如果每走一步,Agent 又多读一点源码、多得到一点日志、多留下一个决策,而旧信息没有及时退出,那么 W_t 会随着任务推进不断增加。
在一个极端简化、完全没有缓存和清理的模型里,如果每轮新增的有效状态大致相同,总处理量会出现接近 1 + 2 + 3 + … + n 的累积结构。也就是说,step count 只增加了一倍,整个任务处理过的历史状态可能增加得更快。

实际系统有 cache、context editing 和 compaction,不会机械遵循这个增长曲线,但问题的形状没有改变:Agent 运行时间越长,每一个新动作越可能建立在一块更重的历史之上。
所以长任务里那个很短的用户 prompt 很快就会失去存在感。真正开始主导成本的,是模型为了保持任务连续性而不断携带的工作集。

03
删得太狠会出现语义缺页
working set 为什么膨胀得这么快,工具输出是一个很大的来源。源码至少有结构,日志经常没有。
一次 grep 可以返回几百处引用,一次构建可能吐出大片 warning,一次测试失败可能带着完整 stack trace,Docker、编译器、包管理器也会制造大量对任务没有长期价值的文本。

假设第 10 步测试产生了 8K Token 日志。它第一次进入 context 时,只是 8K Token。可 Agent 还要继续检查源码、修改、重新测试,只要这段日志仍然处于有效历史中,它就会提高后续很多轮请求的基础重量。
这很像存储系统里的 write amplification:一次逻辑写入,造成了后续更多底层处理。Agent 里的情况是,一次 tool output 被写进执行历史,随后跟着后面的推理一起移动。
于是同样是 8K Token,放在任务结束前一轮和放在任务刚开始时,带来的整体影响完全不同。Claude Code 现在也在主动减少这种污染。官方建议用 sub-agent 隔离高输出任务,并明确提到搜索结果、日志和大量文件内容会消耗主会话 context;工具定义本身也会占用空间,因此工具集过大同样会增加状态负担。
可这里又出现一个反方向的问题:不能因为日志很贵,就把它们全部裁掉。一段 3000 行日志里,可能只有 20 行与根因有关。系统事先并不知道是哪 20 行。如果清理过早,Agent 到后面突然需要其中一个细节,只能重新跑测试或者重新打开文件。

这可以叫做 semantic page fault,语义缺页。传统虚拟内存里,程序访问一个已经不在内存中的页面,系统会从磁盘重新加载;Coding Agent 丢掉某段早期证据以后,也会发生类似现象,只不过表现成重新搜索仓库、重复读取文件、再次运行命令,甚至重新推导一个早就分析过的问题。
于是长任务陷入一个两难:留下过多历史,后续每一步越来越重;清理得过于激进,Agent 又会不断重新获取以前见过的信息。
这也解释了为什么 context 管理不能简化成“少塞一点 Token”。真正需要解决的是 working set selection:此刻有哪些信息必须留在工作区,哪些只是已经完成使命的中间产物。
到了这里,compaction、memory 和 sub-agent 才真正有了存在的理由。


04
什么信息可以被忘掉?
Claude Code 接近 context 边界时会自动压缩会话,同时还会清理部分较旧的工具结果。官方也提醒,长 session 里的无关对话、文件内容和命令结果可能占满窗口并干扰模型表现。
从系统角度看,compaction 很像一次语义垃圾回收。麻烦在于,普通垃圾回收判断的是“这个对象还有没有引用”,而 Agent 必须判断“这段信息以后还有没有意义”。
后者难得多。例如早期有这样一段设计结论:某个模块不能自己缓存用户状态,因为系统要求状态只有一个 owner,所有修改必须经过 service。
几十步之后,如果这段信息被压成:“之前通过 service 调整解决了状态问题。”事实没有错,但信息已经发生了变化。原始内容包含的是 constraint,后面的摘要保存的只是 event。
下一次 Agent 碰到性能问题,看到 service 调用很慢,很可能又在模块里增加缓存。它并没有违反自己当前掌握的信息;当初禁止缓存的因果关系已经不在有效状态中了。
Claude Code 的 context 文档甚至明确指出,部分 path-scoped rules 和嵌套的 CLAUDE.md 会随着会话一起被 compaction 摘要掉,需要再次读取匹配文件才会重新加载。
Memory 试图解决长期知识保存的问题。项目根目录的 CLAUDE.md 和 auto memory 可以把构建命令、项目规范、调试经验等内容从短期对话中抽出来,并在会话开始时重新加载。但 Anthropic 对它的定位也写得很清楚:这些 memory 仍然是 context,不属于强制配置。

这个区别非常关键。“这里不能直接访问数据库”如果只写在 memory 里,它仍然是一句模型需要理解并遵循的自然语言。如果同一条规则被写成 dependency lint、类型约束或者 CI 检查,它才变成一个无法轻易绕开的软件 invariant。
Sub-agent 解决的是另一块:隔离工作集。让一个独立 Agent 去扫描仓库或者分析长日志,再把压缩后的结果交还主 Agent,可以避免原始噪声进入主线程。Claude Code 官方给 sub-agent 的用途之一就是 context isolation。
它的代价也很有意思:主 Agent 得到了更干净的状态,却失去了部分原始证据;多个 Agent 同时运行,还会建立各自的 context。因此 compaction、memory、sub-agent 放在一起看,其实已经很像一套 Agent 时代的内存层级:
当前 context 是昂贵工作内存,compaction 负责压缩,memory 保存跨 session 状态,sub-agent 用独立地址空间隔离噪声。问题也从“context 够不够大”变成了另一个层级:
哪些状态需要高保真保存,哪些状态只需要留下摘要。这个问题会直接影响后面的代码质量。

05
无法提前预知要跑多久的程序
理解前面这套执行结构后,再看 Claude Code 的周额度,会发现平台很难继续按“消息条数”计量 Agent。因为一条消息已经失去稳定意义。
把变量改个名字是一条消息,重构整个认证模块也是一条消息。前者可能几步结束,后者可能运行几十轮,读取几十个文件,再启动多个 Agent。同样的一个 request,背后的资源需求可以完全不是一个量级。

Claude Code 用滚动限制和周额度包装这件事;Codex 现在已经明确按照 input token、cached input token 和 output token 折算 credits;Cursor 的套餐则给 Agent 提供不同 usage pool,第三方模型的消耗会受到模型 API 价格影响。
三个产品的界面语言不同,底层需要解决的问题却很接近:怎样给一个执行路径事先无法确定的智能程序分配推理资源。一个 Coding Agent 到底会跑多久,在任务开始时很难确定。

模型可能很快找到根因,也可能连续提出几个错误假设;可能一次测试就通过,也可能进入长时间 debug loop;可能只需要一个 Agent,也可能拆出多个 sub-agent。
传统 API 很喜欢按 request 计费,是因为一次 request 的资源波动还能控制在一定范围。Agent 把这种稳定性打散了。所以 Token 在这里开始有一点 CPU time 的味道。
这个类比不能画等号。不同模型处理同样数量 Token 的算力成本不同,input、cached input 和 output 也有不同成本。但站在开发者这一侧,它们承担的功能越来越相似:都是在描述一个任务为了继续运行,到底占用了多少计算资源。
Anthropic 在今年提高 Claude Code 使用上限时,也直接把额度提升和新增 compute capacity 联系在一起。这会带来一个很有意思的指标变化。以前看 Coding Agent,容易比较“同一道题谁一次写得好”。往后可能更有意义的是:完成同样的工程状态变化,谁消耗的有效计算更少。

如果一个 Agent 花掉大量 Token,只是在重复打开文件、重新跑测试、重新恢复已经丢掉的上下文,那些 Token 并没有换来对应程度的工程推进。
而这类低效状态恢复,恰好会和技术债在下一层碰到一起。

06
AI 祖传代码怎么形成
这里可以把一个 Coding Agent 维护的软件抽象成两套同时演化的状态。一套是代码状态 R_t。文件、类型、接口、测试、Git commit 全部属于这一层。Agent 第 20 步加进去的一行 retry,只要没有被删,第 100 步打开文件时仍然完整存在。代码对过去修改的保存精度非常高。
另一套是设计状态 M_t。为什么这里需要 retry,为什么那个缓存只能放在 service,为什么这个状态不能有两个 owner,为什么一个看起来多余的判断暂时不能删,这些信息属于设计因果。
M_t 没有像 Git 一样天然的无损存储。它分散在对话、推理、工具返回、memory、规则文件和 compaction summary 里。任务不断推进以后,部分内容被清理,部分内容被摘要,部分内容需要重新检索。

于是会产生一个很关键的不对称:实现结果能够高保真累积,生成这些结果的因果关系却会不断降采样。这比单纯说“Agent 会忘东西”严重得多。
假设一次并发问题中,Agent 分析后加入了一个 queue。当时它掌握的完整结论是:只有写路径 A 存在竞争,因此 queue 只能包住 A;写路径 B 需要低延迟,不能进入这个队列。

代码把 queue 完整保存下来了。经过长时间执行以后,设计状态可能只剩下“这里用 queue 解决 race condition”。
后来 B 也出现一个偶发错误。Agent 再次读到代码时,很自然地把 B 也接进现有 queue。
随后延迟上升,于是再加 bypass。bypass 又引出偶发状态不一致,于是外围补 retry。到了这里,没有任何一次修改必然是荒谬的。每个补丁在当时看到的局部状态下甚至可能相当合理。代码却已经从“一个明确的并发模型”,变成了 queue、bypass 和 retry 互相补偿。
AI 代码屎山很可能就是这样长出来的。它不一定表现成模型突然写出一团垃圾,更可能表现成局部正确不断累积,整体模型逐渐消失。

传统软件里这类问题通常经过人员交接慢慢形成。原作者离开,新开发者看到旧代码,却不知道它为什么存在,于是在外面再包一层兼容逻辑。
Coding Agent 把“人员交接”变成了“上下文交接”。第 20 步和第 100 步看起来还是同一个 Claude Code session,但它们实际拿到的设计状态已经不完全相同。从信息角度看,更像两名工程师通过一份不断缩水的交接文档维护同一个仓库。
测试也只能解决其中一部分。测试擅长保护行为:接口应该返回什么,某种输入不能崩溃,过去的 bug 不能重新出现。很多架构约束却不天然表现成输入输出。
状态只能有一个 owner、领域层不能反向依赖 UI、某个 package 不允许直连数据库、写操作必须经过统一事务边界,这些约束如果只存在于文档或者 Agent 记忆里,就很容易在局部修复中被穿过去。
结果会出现一种很麻烦的工程状态:测试还是绿的,代码已经越来越难解释。更危险的是,这里面存在反馈回路。

架构开始变乱,Agent 下一次理解功能就需要读取更多文件;依赖关系越绕,working set 越大;工作集越重,系统越需要清理和压缩;设计因果保存得越薄,后面的修改又越容易依赖眼前代码和局部测试。
于是代码复杂度开始提高 Token 成本,Token 压力又反过来鼓励更短的状态保留和更局部的修补。这才是 Agent coding 里“越迭代问题越多”背后比较值得警惕的机制。
它不是一个单独的模型能力问题,而是一种代码状态和设计状态保存精度不一致的系统问题。

07
Agent 需要「状态保真率」
Coding Agent 已经越来越能长时间行动,但“能跑几个小时”本身未必是一个很好的能力指标。
如果一个 Agent 工作 3 小时以后,需要重新阅读自己 2 小时前改过的文件,重新推理某个抽象为什么存在,再重新跑一次此前已经跑过的测试,那么这 3 小时里有相当一部分计算其实花在了状态恢复上。
接下来的问题会变成:一个 Agent 在经历 50 步、100 步之后,还能保留多少对后续决策有价值的因果信息。
可以把它叫作状态保真率。
因为它衡量的不是 context 能塞多少 Token,而是经过工具调用、压缩、跨 session 和记忆检索之后,多少关键设计信息仍然以可用的形式存在。这也意味着,Agent 的长期记忆不能只靠更长的 context。
有些知识适合存在 memory 里,比如项目构建方式和开发习惯;有些决策应该进入结构化的 ADR 或代码索引;而那些一旦违反就会破坏系统的架构边界,更适合直接写进类型、测试、 lint、依赖规则和 CI。
一条规则如果已经变成软件可以执行的约束,Agent 就不需要“记住”它。下一轮 Agent 可以忘掉一段对话,却无法轻易越过编译器和测试。
如果保真率低,Agent 跑得越久,其实是在给系统埋越多的地雷。
这可能也是 Coding Agent 从“会写代码”走向“能长期维护软件”需要跨过去的一道线:把设计知识从概率性的语言记忆,逐渐迁移到可检索、可验证、可执行的软件状态里。
否则自主运行时间越长,会出现一个很荒诞的场景。Agent 写代码的速度越来越快,项目也在飞快变化,可每隔一段时间,它又要重新理解上一段时间留下来的世界。
传统祖传代码常见的一句话是:“这段别动,不知道为什么会炸。”
AI 祖传代码可能更离谱:代码确实是 Agent 写的,只是后来的 Agent 已经不知道前面的 Agent 为什么这么写了。
参考链接:https://news.ycombinator.com/item?id=49348751
进群传送门:添加微信Qvv0909777,备注:单位/学校+姓名+方向。

上车,带你看遍全球 AI 顶会精华
可独家畅览:
专家演讲PPT
大会报告全文
热门论文解读
学术新星访谈

扫描上方二维码
或点击「阅读原文」关注专区。
雷峰网原创文章,未经授权禁止转载。详情见转载须知。
— Originally published at leiphone.com
Want this in your inbox every morning?
Daily brief at your local 8am — bilingual EN/中文, free.
More from 雷峰网 AI
See more →
刚刚,GPT 5.6 发布会上,OpenAI 暴露了哪些 Agent 技术路线?
OpenAI's GPT 5.6 integrates ChatGPT and Codex, introducing a for complex task execution, with models Soul, Terra, and Luna for efficient workflow management. The release emphasizes task orchestration, contextual understanding, and robust security measures for enterprise applications.

