Claude Code 额度频繁告急:Agent 正在制造新的「祖传代码屎山」?
8 月 19 日本是 Claude Code +50% 周额度加成的截止日,Anthropic 却把它延到了 8 月 31 日。就在原定截止日前后,海外技术社区出现集中讨论:一个并不复杂的任务,Agent 跑上几轮,额度就肉眼可见地蒸发。
8 月 19 日本是 Claude Code +50% 周额度加成的截止日,Anthropic 却把它延到了 8 月 31 日。就在原定截止日前后,海外技术社区出现集中讨论:一个并不复杂的任务,Agent 跑上几轮,额度就肉眼可见地蒸发。
按原计划,Claude Code +50% 的每周额度加成应在 8 月 19 日终止。Anthropic 在外界讨论声中又一次延后:新截止日定在 8 月 31 日。延长本身不是新闻——真正的讨论,发生在原定截止日的前后。
海外技术社区里,不少开发者晒出同一个感受:一个看起来并不复杂的任务,Agent 多跑几轮,额度就掉一大截。
问题在于,Claude Code 消耗的不只是最后生成的那几行代码。
时间线按公开信息整理;额度政策以 Anthropic 官方最新公告为准。
普通 Chat coding 的计算边界很清楚:输入一段代码,模型读完,给出解释或修改方案,这一轮基本结束。Claude Code 的基本单元换成了 agent loop——模型观察当前状态,决定下一步读哪个文件、执行什么命令;工具返回结果后,再进入下一轮判断。
一轮输入输出即结束,边界清晰,计算量与代码量大致成正比。
「判断 → 调工具 → 看结果 → 再判断」循环,直到任务完成为止。
官方文档把这种循环描述为 Agent 工作方式的核心。它带来的直接变化是:读源码、搜引用、跑测试、看 Git diff、改文件,在模型侧是一串独立的推理请求。
把一次 Agent 任务拆开,可以得到两个变量:step count(走了多少步)与 working set(走到当前步时,模型还需要掌握多少项目状态)。
只增加 step count 已经会提高消耗;如果 working set 同步变大,总成本的结构就变成了:
该式是为理解成本结构做的简化;真实系统存在 prompt cache、上下文编辑与压缩,但「任务越长、每一步越重」的方向不变。
第 3 步也许只需要几千 Token,第 30 步却可能背着项目规则、相关源码、测试结果和修改历史一起推理。这正是 Coding Agent 成本结构变化的起点:计算量取决于「走多少步 × 每一步背多重」,而不是写了多少行代码。
源码至少有结构,日志经常没有。
一次 grep 可以返回几百处引用,一次构建可能吐出整屏 warning,一次测试失败往往带着完整 stack trace。它们第一次进入上下文时,只是几段文本;但之后每一轮推理都要背着它们移动——很像存储领域的 write amplification:一次逻辑写入,造成后续大量底层处理。
同样的 8K Token,放在任务结束前一轮与放在任务刚开始时,带来的整体成本完全不同——位置决定权重。
于是长任务陷入一个两难:
后续每一步越来越重,直到触发压缩、清理或上下文降级。
Agent 不断重新获取旧信息:重读文件、重跑测试、重新推导早已分析过的问题。
后者可以被称作语义缺页(semantic page fault)。传统虚拟内存里,程序访问不在内存中的页面,系统会从磁盘重新加载;Agent 丢掉某段早期证据后,也会发生类似现象——只是代价变成了重新搜索仓库、重复读取文件、再次运行命令。
真正需要解决的不是「少塞一点 Token」,而是 working set selection:此刻哪些信息必须留在工作区,哪些只是已经完成使命的中间产物。
接近 context 边界时,Claude Code 会自动压缩会话(compaction),同时清理部分较旧的工具结果。它很像一次语义垃圾回收。但普通 GC 判断「这个对象还有没有引用」,Agent 必须判断「这段信息以后还有没有意义」——后者难得多。
官方文档甚至提醒:部分 path-scoped rules 和嵌套的 CLAUDE.md 会随会话一起被摘要掉,需要再次读取匹配文件才会重新加载。
Anthropic 给出的是一套组合拳,组合起来已经很像 Agent 时代的内存层级:
sub-agent 的代价同样明显:主 Agent 得到更干净的状态,却失去部分原始证据;多个 Agent 并行,还会建立各自的上下文。
还有一个关键区别容易被忽略。Anthropic 对 memory 的定位写得很清楚:它们仍然是 context,不属于强制配置。
「这里不能直接访问数据库」如果只写在 memory 里,它是一句需要模型理解并遵循的自然语言;如果被写成 lint 规则、类型约束或 CI 检查,它才变成无法轻易绕开的软件不变量。同一条规则,两种载体,可靠性完全不同。
把 Agent 维护的软件抽象成两套同时演化的状态。一套是代码状态 R_t:文件、类型、接口、测试、Git commit 全部留痕,对过去修改的保存精度极高。另一套是设计状态 M_t:为什么这里需要 retry、为什么缓存只能放 service、为什么状态不能有两个 owner——它们分散在对话、推理、工具返回、memory 与压缩摘要里。
文件、类型、接口、测试、Git commit 全部留痕。实现结果高保真累积——第 20 步加的一行 retry,第 100 步打开文件时依然完整存在。
「为什么这样写」分散在对话、摘要与记忆里。因果持续降采样,部分被清理,部分被改写,部分需要重新检索。
这个不对称,比「Agent 会忘东西」严重得多。看一个具体漂移:
「只有写路径 A 存在竞争,queue 只能包住 A;路径 B 需要低延迟,不能进队列。」
记忆变成:「这里用 queue 解决 race condition」。约束被降级成了事件。
B 也出现偶发错误。Agent 自然地把 B 接进现有 queue,随即延迟上升。
加 bypass 绕开延迟 → 引出偶发状态不一致 → 再补 retry。queue、bypass、retry 互相补偿,「并发模型」消失了。
步骤编号与 Token 数值为示意,用于展示设计信息随压缩衰减的路径;真实压缩行为以官方实现为准。
每个补丁在当时看到的局部状态下都相当合理。代码却已经从「一个明确的并发模型」,变成了 queue、bypass 和 retry 互相补偿的复合体。
AI 代码屎山,很可能就是这样长出来的。
传统软件里,这类问题通过人员交接慢慢形成:原作者离开,新开发者不知道为什么,于是再包一层兼容逻辑。Coding Agent 把「人员交接」变成了「上下文交接」——第 20 步和第 100 步看起来是同一个 session,实际拿到的是两份信息量不同的设计状态,像两名工程师靠一份不断缩水的交接文档维护同一个仓库。
更麻烦的是反馈回路:
测试也救不了这个场景:测试擅长保护行为——接口应该返回什么、过去的 bug 不能重新出现——但很多架构约束并不天然表现为输入输出。状态只能有一个 owner、领域层不能反向依赖 UI、写操作必须经过统一事务边界,这些如果只存在于文档里,就很容易在局部修复中被穿过去。
结果是:测试还是绿的,代码已经越来越难解释。代码复杂度推高 Token 成本,Token 压力又反过来鼓励更短的状态保留与更局部的修补——这才是「越迭代问题越多」背后值得警惕的机制。
Agent 的长期记忆,不能只靠更长的 context。一个能连续跑三小时的 Agent,未必比只跑 30 分钟的更可靠——如果它有大量算力花在重读旧文件、重跑旧测试、重新推导早已分析过的问题上,那它只是在为状态恢复买单。
衡量标准应该是「状态保真率」:经历 50 步、100 步和若干次压缩之后,多少关键设计信息仍然可用。保真率低的时候,Agent 跑得越久,越是在给系统埋地雷。从「会写代码」走向「能长期维护软件」,中间的分水岭是:把设计知识从概率性的语言记忆,迁移到可检索、可验证、可执行的软件状态里。
开发者之间开始流传一句很荒诞的总结:「这段代码确实是 Agent 写的,只是后来的 Agent 已经不知道前面的 Agent 为什么这么写了。」
想要避开这条路径,可以先用三句话自查:
「状态只能有一个 owner」应该长成 lint、类型或依赖检查,而不是 CLAUDE.md 里的一段话。
日志、搜索结果、大文件交给 sub-agent 处理,压缩后再回传主会话,避免噪声进入主线程。
关键设计决策写入 ADR 或代码索引,而不是只存在于会随会话一起缩水的对话历史里。