第 10 章

故障模式与恢复

Claude Code 会失败。不是偶尔,而是经常。理解它如何失败比理解它如何成功更有价值,因为成功是直接的,而失败是微妙的。这个工具不会以告诉你出了什么问题的错误消息而崩溃。它会静默降级、悄悄丢弃任务、自信地生成错误代码,并逐渐失去连贯性,这些方式在你检查输出之前看起来像正常操作。

上下文耗尽:缓慢死亡

最常见的故障模式也是最隐蔽的。上下文耗尽不会自我宣告。没有错误消息,没有警告弹窗。Claude 就是……变差了。

一旦你知道该看什么,症状是可以识别的。Claude 开始重复它已经做过的建议。它忘记你五分钟前给的指令。它解决一个它已经解决过的问题。它丢弃原始提示词中的约束——不是全部,只是足够让输出微妙地出错的那些。它生成与会话早期遵循的模式相矛盾的代码。

这是因为 context window 已满或接近满了。Auto-compaction(第三章)介入并总结较旧的内容以腾出空间,但总结是有损的。产生的上下文是你开始时的降级版本,而 Claude 从降级版本工作,却不知道它是降级的。

缓解。 防御不是被动的而是结构性的。使用第三章的上下文工程技术:将关键指令放入 CLAUDE.md(它以完全保真度重新加载并经受压缩),使用"Compact Instructions"部分存放必须持久存在的规则,通过 subagent(第四章)路由冗长操作以保持主上下文精简,并主动使用 /compact 而不是等待自动压缩。

注意行为信号。当 Claude 开始问它已有答案的问题,当它提出你已经拒绝的方法,当它修改你告诉它不要碰的文件——这些是上下文耗尽的症状。正确的回应不是重复你的指令。正确的回应是用一个好的 CLAUDE.md 文件启动一个新会话,因为在满的 context window 中重复指令只会加速耗尽。

Bash 环境非持久性

这个问题每个人都会被咬一次,然后因为它被遗忘又被咬一次。

Claude 执行的每个 bash 命令在一个新的 shell 环境中运行。工作目录在命令之间持久存在。其他一切都不会。环境变量、shell 别名、函数定义、激活的虚拟环境——每条命令后都消失了。

故障模式是静默的。Claude 在一个命令中设置环境变量并在下一个命令中引用它。第二个命令不会以"变量未找到"而报错。它以变量未设置的状态运行,这可能意味着空字符串,这可能意味着它悄悄地做了错误的事情。Claude 设置 NODE_ENV=production 来测试某些东西,在下一条命令中运行测试,测试在默认的开发模式下运行。没有错误。错误的结果。

恢复。 对于静默的错误结果没有恢复——你需要捕捉它。预防是意识。当 Claude 链接依赖共享状态的 bash 命令时,状态需要在每个命令中重新建立。在同一行设置变量并运行命令:NODE_ENV=production npm test。或者在每条命令开始时 source 一个设置脚本。或者使用 Claude 在 settings.json 中的环境变量配置,它会自动将变量注入每个 bash 命令。

特别注意以下情况:虚拟环境激活(source venv/bin/activate 不会持久),只被 source 一次的目录特定环境文件,跨命令使用的 shell 函数定义,以及任何"先运行这个再运行那个"假设共享状态的工作流。

MCP 断开连接:消失的工具

MCP server 在会话开始时连接,可以随时断开。当它们断开时,它们提供的工具就从 Claude 的可用工具集中消失了。没有通知,没有错误。Claude 就是突然不能做一分钟前还能做的事情。

故障模式表现为 Claude 突然无法完成之前处理得很好的任务。如果 Claude 在使用 MCP 提供的工具查询数据库而 server 断开了,Claude 不会说"我失去了数据库工具"。它会尝试找替代方法,失败,并产生越来越混乱的输出,因为它试图绕过一个它不知道已经缺失的能力。

恢复。 /mcp 命令显示已连接的 MCP server 的状态。如果 server 断开了,你可以从那里重启它。主动地,当 Claude 的行为意外改变时检查 MCP 状态,特别是如果它之前流利地使用外部工具。MCP 可靠性详情在第五章中介绍,但恢复方法不因原因而异:重新连接 server 或重启会话。

Subagent 上下文返回溢出

Subagent 通过在它们自己的 context window 中隔离工作来解决上下文耗尽。但它们的结果必须返回到主会话,而这些结果消耗主上下文空间。

故障模式:你启动十个 subagent 探索十个模块。每个返回一个详细报告。十份详细报告涌入主 context window。编排器现在比从未使用 subagent 时的推理空间还少。

这就是 subagent 上下文悖论。Subagent 保护主上下文免受中间工作的影响(文件读取、命令输出、探索噪音),但不能保护免受最终结果的影响。如果最终结果冗长,保护最多只是部分的。

缓解。 指示 subagent 返回简洁的摘要,而非全面的报告。"只返回需要更改的特定文件和每个更改的一句话描述"比"报告你的发现"更好。更好的是,指示 subagent 将详细发现写入文件并只返回文件路径。主会话然后可以选择性地读取该文件,只将需要的部分带入上下文。

更广泛的教训是,subagent 编排需要考虑信息流。多少数据跨越 subagent-编排器边界,以及哪个方向?出站数据(任务分配)通常很小。入站数据(结果)是风险所在。为小入站数据而设计。

Checkpoint 系统:它追踪什么和遗漏什么

Claude Code 在你工作时自动追踪每次文件编辑,创建让你可以回退到先前状态的 checkpoint。每次用户提示词创建一个新的 checkpoint。Checkpoint 跨会话持久存在,所以即使在恢复的对话中你也可以访问它们。这是一个真正的安全网——从错误转向恢复的最佳功能之一。

回退界面通过按两次 Esc(Esc + Esc)或输入 /rewind 访问。这会打开一个可滚动列表,显示会话中的每个提示词。选择你要操作的时间点,然后从四个选项中选择:

  • 恢复代码和对话——将文件和对话历史都还原到那个时间点。这是完全回退:Claude 丢失该 checkpoint 之后的所有记忆,代码返回到那个时刻的状态。
  • 仅恢复对话——将对话回退到那条消息,同时保留当前代码。当 Claude 走了错误的推理路径但代码更改没问题时有用。
  • 仅恢复代码——还原文件更改,同时保留完整对话历史。当代码出了问题但讨论包含你想保留的有价值上下文时有用。
  • 从此处总结——这与恢复选项不同。它不还原任何东西。相反,它将从所选时间点开始的对话浓缩为一个紧凑的摘要,释放 context window 空间同时保留关键信息。这是一个上下文管理工具,不是恢复工具。

三个恢复选项撤销状态。总结选项压缩状态。当你在决定采取哪条恢复路径时,这个区别很重要。

但 checkpoint 有一个会坑到你的缺口。

Checkpoint 追踪直接文件编辑——当 Claude 使用 Write、Edit 或 NotebookEdit 工具时。它们不追踪通过 bash 命令进行的文件更改。如果 Claude 通过 bash 工具运行 rm important_file.pymv src/old.py src/new.pysed -i 's/foo/bar/g' *.py,这些更改对 checkpoint 系统是不可见的。回退到这些命令之前的 checkpoint 不会撤销它们。

Checkpoint 也不追踪并发会话、外部进程或在 Claude Code 工具调用之外发生的任何更改所做的修改。如果另一个 Claude Code 实例修改了文件,那些修改不在你会话的 checkpoint 历史中。

恢复。 Git 是可靠的 checkpoint。如果你遵循了第一章的频繁提交模式,你有覆盖一切的 git 提交——文件编辑、bash 修改、重命名、删除。git checkout 是通用的回退,不仅适用于 Claude 工具追踪的编辑,而且适用于任何东西。把 checkpoint 看作"本地撤销",把 git 看作"永久历史"。它们互补但不可互换。

操作规则:在任何可能涉及破坏性 bash 命令(文件删除、重命名、批量替换)的会话之前,提交当前状态。如果你先提交了而 Claude 通过 bash 破坏了东西,git checkout . 会把一切恢复。如果你依赖了 checkpoint 而 Claude 通过 bash 破坏了东西,你只能从不完整的信息中恢复。

Agent 遗忘

每个新会话从一个空白的 context window 开始。Claude 对你的代码库建立的精密理解、你协商的决策、你建立的约束——全部消失了。这就是 agent 遗忘,而且这是默认状态。

故障模式不是 Claude 忘记了。而是 Claude 不知道它忘记了。它全新地接近代码库,做出与前一个会话开始时相同的假设,并可能重复前一个会话纠正过的相同错误。

恢复。 有三种持久化机制,你应该全部使用。

第一,CLAUDE.md 文件(第三章)。这些在每次会话开始时以完全保真度重新加载。把关键的项目知识、架构决策和来之不易的经验放在这里。在一个高效的会话结束后,让 Claude 建议它学到的内容的 CLAUDE.md 更新。

第二,任务系统。存储在 .claude/tasks/ 中作为 JSON 文件的任务跨会话持久存在。如果你在运行一个多步骤项目,任务列表提供会话间的连续性——Claude 可以读取任务状态并从上一个会话停下的地方继续。

第三,git 历史。代码本身是一种记忆形式。Claude 可以读取最近的提交,理解更改了什么,并从 diff 推断意图。这不如显式指令可靠,但比没有好。

最受 agent 遗忘困扰的开发者是那些依赖长会话来维持上下文,而不是将知识外化到持久结构中的人。一个两小时的会话如果不更新 CLAUDE.md,就是两小时的上下文开发蒸发了。

上下文污染

上下文污染是指窗口充满了对当前任务无用的内容。旧的探索结果。已解决问题的冗长错误输出。关于被拒绝方法的讨论。所有这些都占用了本可以存放与当前任务相关信息的空间。

故障模式:Claude 按 token 计数有大量 context window 剩余,但有用的信噪比已经退化。Claude 的响应变得不够聚焦,因为相关上下文被无关内容稀释了。在严重情况下,Claude 会丢掉 bug 而不是追踪它们——窗口污染如此严重,新信息在噪音中丢失。

缓解。 使用 /compact 主动压缩可以清除积累的噪音。Subagent 委派从源头上防止污染——当你通过 subagent 路由探索工作时,探索噪音留在 subagent 的上下文中,只有结果进入主窗口。

规范驱动开发(第八章)提供结构性缓解。当 Claude 从磁盘上的规范文档而不是从积累的对话上下文工作时,规范作为持久的、未污染的真相来源,经受上下文退化。对话可能充满噪音,但规范文件保持干净。

五个命名反模式

经验丰富的实践者编目了五个反复出现的故障模式,每个都有具体的修复方法。这些不是抽象类别。它们是浪费最多时间的真实世界错误。

大杂烩会话。 你从一个任务开始,然后问 Claude 一些无关的事情,然后回到第一个任务。上下文充满了绕道带来的无关信息。Claude 在你原始任务上的表现退化,因为 context window 中的信噪比已经崩塌。修复很简单:在不相关的任务之间使用 /clear。每个不同任务使用新的上下文比一个累积一切的单一会话表现更好。

反复纠正。 Claude 把某件事搞错了。你解释问题。Claude 打了补丁。补丁引入了新问题。你解释那个。Claude 再打补丁。三次纠正后,上下文充满了失败的方法,Claude 比开始时更困惑。修复:在两次失败的纠正后,停下来。使用 /clear 并写一个更好的初始提示词,将你从失败中学到的东西纳入。关于哪里出错了的知识应该进入新的提示词,而不是进入一个退化上下文中的纠正螺旋。

过度规范的 CLAUDE.md。 如果你的 CLAUDE.md 文件太长,Claude 会忽略其中一半,因为重要规则在噪音中丢失了。本应提供护栏的文档变成了 Claude 草草浏览的一堵文字墙。修复是无情修剪。如果 Claude 不需要指令就能正确做某事,删除那条指令。将 Claude 经常违反的风格规则转换为自动执行的 hook,而不是希望遵守的指令。CLAUDE.md 应该只包含 Claude 无法通过阅读代码弄明白的内容以及被观察到会出错的内容。

先信任后验证的缺口。 Claude 产生一个看起来合理的实现。它编译通过。它运行成功。你发布了。然后它在生产环境中因为实现从未考虑过的边缘情况而失败。输出看起来正确,所以你假设它正确。修复:始终提供验证。测试、脚本、截图、手动抽查。如果你无法验证一段输出,就不要发布它。验证基础设施不是开销。它是将 Claude 自信但不确定的输出转换为经过验证的输出的机制。

无限探索。 你让 Claude "调查"某事而不限定调查范围。Claude 读取数百个文件,用探索数据填满 context window。等它完成调查时,没有上下文留给实际工作。修复:窄范围限定调查,或使用 subagent 让探索在隔离的上下文中进行,只有摘要进入主窗口。"调查 src/auth/ 中的认证如何工作"是有限定范围的。"调查代码库"则不是。

Stop Hook 无限循环

Hook(第二章)可以在生命周期事件上触发,包括当 Claude 停止执行时。当 Claude 决定它已完成任务时,stop hook 运行。如果 stop hook 判断 Claude 不应该停止——比如说,因为测试仍在失败——它可以指示 Claude 继续。

故障模式:一个总是告诉 Claude 继续的 stop hook。Claude 完成,hook 触发,hook 说"继续",Claude 做更多工作,再次完成,hook 再次触发,再次说"继续"。这是一个无限循环。Claude 永远不会停止,因为停止条件永远不满足。

系统包含一个 stop_hook_active 字段来防止失控循环,但底层设计风险是真实的。如果你的 stop hook 的"继续"条件基于 Claude 实际上无法满足的标准——因为与 Claude 的更改无关的原因而失败的测试、不可能通过的 linting 规则、宕机的外部服务——循环将在收敛之前耗尽你的 token 预算。

预防。 在 stop hook 中包含迭代限制。"如果三次尝试后测试仍然失败,停止并报告剩余的失败。"用故意失败的条件测试 stop hook 以验证它们最终会终止。首次使用 stop hook 时监控 token 使用量。

Agent Team 的限制

Agent team(第四章)是实验性的,它们的限制由这一地位所决定。

无会话恢复。 如果团队成员的会话崩溃或被中断,它无法恢复。工作丢失。对于长时间运行的团队任务,这意味着在 90% 完成时崩溃需要从头开始。

任务状态延迟。 共享任务列表的更新不是即时的。一个 agent 可能拿起另一个 agent 已经开始处理的任务,导致重复工作。

每个会话一个团队。 编排器会话只能有一个活跃的团队。如果你需要多个独立团队,你需要多个编排器会话。

无嵌套团队。 团队成员不能创建自己的子团队。层级是扁平的:一个编排器,多个团队成员。这限制了你可表达的分解复杂性。

恢复。 务实的回应是保持团队任务足够小以至于丢失一个可以承受,接受一些重复工作作为松散协调的代价,并在精确协调重要时手动检查任务状态。

高风险上下文中的幻觉

Claude Code 生成代码。能运行的代码。能通过测试的代码。看起来正确的代码。但实际上是错误的代码。

幻觉——生成自信的、看似合理的、不正确的输出——是大型语言模型的固有属性。在低风险上下文中(文档、测试脚手架、样板代码),幻觉被快速且廉价地捕获。在高风险上下文中(财务计算、安全逻辑、有正确性要求的数据转换),幻觉可能是昂贵的。

一位实践者运行了一个自主交易实验,记录了由 agent 高度自信地创建的集中头寸驱动的 22.4% 峰谷回撤。Agent 的推理在内部是一致的。策略看似合理。但它也是错误的,而且这种错误不是测试容易捕获的那种,因为逻辑是有效的——判断是糟糕的。

缓解。 没有消除幻觉的缓解措施。缓解是结构性的:不要将 Claude Code 用作高风险逻辑的唯一决策者。用它生成候选方案,然后用领域专业知识验证。用它实现设计,然后根据需求审查实现。用它进行分析,然后对照已知基准验证分析。

被灼伤的开发者是那些基于自信而非正确性来信任自信输出的人。Claude Code 在正确时最大程度地自信,在错误时也最大程度地自信。自信水平对正确性传递零信息。只有验证告诉你输出是否正确。

33 天实验:一个自主 Agent 的完整轨迹

最全面的自主 agent 故障文档来自一位实践者,他给了 Claude Code 一个十万美元的模拟投资组合和自主交易三十三天的指令。这个实验不是一个精选的成功故事或单一的灾难性失败。它是完整的轨迹——过度自信、治理学习、市场崩溃、恢复,以及一个同时令人印象深刻和令人恐惧的最终结果。每一类自主 agent 故障都在那三十三天中浮现了。

激进的开端

Agent 的首笔交易是教科书式的过度自信。它在第一天将七万五千美元部署到波动头寸中——整个投资组合的四分之三,立即投入,没有热身期,没有仓位大小纪律。它选择了波动性大的名字和投机性股票。然后它尝试了只能被描述为假装高频交易的操作:六分钟内十六笔交易,没有信息优势的快速剥头皮交易。结果是可以预见的。交易成本吞噬了利润。价差杀死了每笔微交易。第一天以下跌 1.1% 结束。教训很清楚:没有优势的高频剥头皮就是被价差杀死。但没有人可以在 agent 身上执行这个教训。它必须从亏损中学习。

治理拯救资本——然后失败

实践者建立了一个多 agent 治理系统:一个首席执行 agent、一个策略 agent 和额外的监督 agent,旨在互相制约。在第二个活跃交易日,这个治理确实奏效了。一只大型科技股在财报后跳涨近 4%。实践者想追涨。治理 agent 阻止了它。它们建议改为卖出期权——一种更保守的方法。当天只下跌了 $292。但治理阻止了实践者本人想做的追逐交易上估计一万美元的损失。这就是系统按设计工作:agent 用结构化风险管理推翻人类冲动。

但治理系统的成功是脆弱的。结果发现其中一个 agent 极度风险厌恶,而首席执行 agent 过于轻易地听从它。工程师 agent——旨在改善交易基础设施——从未实际使用过。策略 agent 很少参与。设计为四 agent 审议系统的东西在实践中退化为一个带有过度保守护栏的 agent。实践者最终完全放弃了多 agent 架构。教训:自主操作越简单越好。系统在被给予最少指令——只是自主交易到收盘——时工作得最好,而不是在被一个只增加开销不增加价值的复杂组织层级所拖累时。

相关性崩溃

第三天,市场给出了一个任何治理架构都无法预防的相关性风险教训。一种主要加密货币在一个周末从八万七千美元暴跌到八万美元。Agent 没有直接交易加密货币,但它持有与加密货币市场高度相关的股票的看跌期权空头头寸。这些头寸被碾压了。相关性不在 agent 的模型中。它不在训练数据中以任何可操作的方式存在。它是资产类别之间的结构关系,agent 只有在它以亏损的形式显现时才发现。

Agent 的回应实际上是合理的:它平掉所有头寸,在周末转为 100% 现金。但损害已经造成。投资组合降至 $96,581——三天内 3.4% 的亏损。相关性风险——看似独立的头寸在压力期间一起移动的倾向——是任何交易者(无论人类还是人工)都最难管理的风险之一。Agent 以所有人学习它的方式学习了它:通过亏钱。

转折与巅峰

接下来发生的是实验中最令人鼓舞的部分。Agent 适应了。它削减亏损头寸,将资金重新部署到正在起作用的动量策略中,并开始建立一个由更长期限期权组成的投资组合,这些期权可以经受短期波动。耐心得到了回报。在跌至低至八万九千美元后,投资组合恢复到超过十万美元,然后继续飙升。

巅峰出现在一个主要假期前一天——整个实验中最好的单次会话,收益 $7,333。投资组合很干净:七个头寸,全部盈利,到期日在 50 到 114 天之间。这是系统在最佳状态运行——纪律性的仓位大小、在盈利者上获利、维持有足够到期时间的多元化投资组合。投资组合扩张到 $120,431,在约三周内增长超过 20%。

崩溃

然后一切都瓦解了。一家主要半导体公司的单名财报令人失望,投资组合在一个会话中暴跌 $15,147——一天下跌 13%。亏损持续了接下来的一整周。投资组合从 $120,431 跌至 $93,450,峰谷回撤 22.4%。

因果分析很有启发性,因为它揭示了 agent 处理得不好的那种风险。三个因素汇聚:对科技股的集中暴露(agent 在反弹期间大量买入了科技看涨期权)、单名财报风险(一家公司的令人失望的结果摧毁了多个头寸)、以及央行会议周波动性加剧了亏损。这些风险都不是看不见的。一个人类投资组合经理会识别出集中度。但 agent 对其头寸的信心是根据近期表现校准的,而不是根据结构性风险。

恢复与最终得分

恢复展示了关于 agent 适应行为的真正有趣之处。当央行会议引发更广泛的市场抛售时,agent 持有看跌期权——在市场下跌时获利的看跌押注。单笔隔夜交易产生了 $14,578 的收益。Agent 已经学会双向操作:当市场上涨时,它持有看涨期权;当市场下跌时,它持有看跌期权。恢复策略是有纪律的:快速止损、在盈利者上获利、当趋势改变时翻空、在重建时维持严格的仓位大小。

三十三天后的最终结果:投资组合为 $107,648,增长 7.6%。同期更广泛的市场回报 4.52%。Agent 跑赢了市场。但到达那个结果的路径包括 $120,431 的峰值和 $93,450 的谷底。最大单笔盈利 $14,578。最大单笔亏损 $15,147。最大回撤 22.4%。

实验教会了什么

7.6% 的回报不是教训。教训是旅程的形状。Agent 的结果是一条嘈杂的、波动的、令人心惊肉跳的路径,通向一个回顾看起来不错但在经历过程中会吓坏任何人类投资者的数字。实践者自己指出,回报是令人鼓舞的,但在如此短的时间框架和如此有利的市场条件下,它不值得信赖。

那三十三天中浮现的故障模式直接映射到本章讨论的自主 agent 风险。初始部署时的过度自信。不在模型中的相关性风险。逐渐积累的集中度风险。多 agent 监督要么阻止得太激进要么不够激进的多 agent 治理悖论。区分幸运结果和好结果的困难。以及根本限制:语言模型不是"智能"那个词通常意义上的智能。它不像人类那样做决策。它容易产生幻觉、不遵循规则、以及生成导致错误结论的内部一致推理。你不能百分之百地信任它处理高风险决策。实践者自己的警告很直白:不要用这个冒险真实资本。

多 Agent 人格冲突

当你给 agent 分配基于人格的角色("你是谨慎的审查者"、"你是激进的实现者")时,这些人格以破坏工作的突发方式相互作用。治理动态在第四章中介绍。故障模式本身很简单:基于人格的角色产生人格驱动的行为,而那种人格是从训练数据中学来的,不是从你团队的实际需求中学来的。

预防。 按任务而非人格定义 agent 角色。"审查 src/api/ 中的文件是否存在 SQL 注入漏洞"而不是"你是安全意识的团队成员"。基于任务的定义产生聚焦任务的输出。

Vibe Coding 与 Vibe Trading:虚假进步陷阱

有一种模式是 Claude Code 快速生成代码,代码运行了,测试通过了,开发者在没有理解代码做什么的情况下就发布了。然后代码在生产环境中以一种开发者无法诊断的方式崩溃,因为他们从未理解实现。

这就是 vibe coding。它感觉像是非凡的生产力。它是技术债务以机器速度积累。

故障模式延伸到代码之外。在任何 agent 产生看似合理输出的领域,都存在同样陷阱的版本。一位实践者创造了"vibe trading"一词来描述自主金融操作中的平行现象:agent 做出产生回报的交易,所以你假设策略是合理的。回报恰好是正的,因为市场朝着有利于你的方向移动,而不是因为策略有优势。使用 agent 可以比人类快得多地加速行动,可能带来正面或负面后果。就像编写代码一样,即使你非常有经验,也可能被虚假的进步感所迷惑。

Vibe trading 变体比 vibe coding 更危险,有一个具体原因:反馈循环更慢,赌注是财务上的。糟糕的代码立即在测试中失败。糟糕的交易策略可以在数周内产生正回报,然后底层缺陷才变成灾难性的——正如本章前面 33 天交易实验所详细展示的那样。发布 vibe 编码软件的开发者可以诊断并修复 bug。运行 vibe 交易策略的实践者在已经下跌 22% 时才发现缺陷。

预防。 审查 Claude 生成的内容,而不仅仅是它是否工作。当 Claude 产生你不理解的代码时,在发布前让它解释实现。使用 plan mode 在实现之前审查方法。保持对你自己代码库的足够理解,以便在故障发生时可以诊断。在非编码领域,应用相同原则:理解策略,而不仅仅是结果。幸运的结果和好的结果在运气耗尽之前看起来一模一样。

对立的风险是过度审查。如果你以手写代码相同的强度审查 Claude 写的每一行,你失去了大部分生产力好处。校准是:审查到足以理解方法并捕获你关心的故障模式。对于测试文件,看一眼就够了。对于核心业务逻辑更改,逐行审查是适当的。审查深度应该与赌注匹配。

三分之一现实及其含义

大约三分之一的任务在首次尝试时成功。这个由实践者坦诚报告的统计数据与自主 AI agent 的乐观框架之间存在张力。

当你不再将首次尝试成功视为重要的指标时,张力就消失了。相关的指标是到正确输出的总时间,包括迭代。一个在首次尝试失败但在第二次尝试中用三十秒额外指导就成功的任务不是失败——它是一个两分钟的任务而不是一分钟的任务。

三分之一数字也因上下文而大幅变化。有清晰验证标准(测试、类型、linter)的任务首次尝试成功率更高,因为 Claude 在智能体循环中获得自动反馈并自我纠正。没有验证标准的任务首次尝试率更低,因为 Claude 无法判断其输出是否正确。

启示。 投资验证基础设施。你写的每个测试、你添加的每个类型注解、你配置的每个 linter 规则都是对 Claude Code 首次尝试成功率的投资。自动验证的反压力(第八章)是你能对 Claude Code 工作流做出的最高杠杆改进。

老虎机式恢复

当一个任务出问题时,本能是纠正方向。解释问题。让 Claude 修复它的错误。提供更多上下文。这有时有效,有时使情况更糟,因为纠正本身消耗上下文,可能加剧原来的误解。

替代方案是老虎机方法:提交当前状态,让 Claude 运行一个固定时间段(二十到三十分钟),然后做二元决定。接受或重启。

如果结果足够好,保留它。如果不够好,git revert 回到提交,启动一个新会话,用更好的提示词再试。不尝试挽救。不纠正螺旋。只是从一个已知良好状态干净地重启。

这听起来很浪费。其实不是。纠正螺旋——解释问题、Claude 打补丁、补丁引入新问题、解释新问题、Claude 再打补丁——可以比两次全新尝试消耗更多时间和 token。老虎机方法为浪费设置了上限:一次限时尝试。如果它不收敛,就从头开始,而不是在糟糕的基础上继续投入好的上下文。

一家大型 AI 公司的数据科学和机器学习团队将此正式纳入他们的标准工作流。面对合并冲突或半复杂重构——对于编辑器宏来说太复杂但对于重大开发工作又不够大的任务——他们提交状态,让 Claude 自主工作三十分钟,然后做二元决定:接受解决方案或重新开始。他们通过反复经验获得的关键洞察:重新开始的成功率通常高于试图在过程中修复 Claude 的错误。纠正尝试本身降低了上下文质量,使后续尝试更不可能成功。一个用更好的提示词(融入了哪里出错的信息)的新会话,胜过一个积累了混乱的退化会话。

三十分钟的时间限制不是任意的。它足够长让 Claude 在有界任务上做出有意义的进展,但又足够短使得失败尝试的代价是可以承受的。如果你花两小时看 Claude 挣扎,你已经花了比两次新的三十分钟尝试更多的时间。

前提。 频繁提交。如果你在让 Claude 运行之前没有提交,你就没有一个干净的状态可以回退。老虎机只有在有 checkpoint 纪律的情况下才有效。

过度复杂的解决方案

Claude 的默认是复杂性。不是恶意的复杂性。是统计的复杂性。模型在世界代码库上训练过,这些代码库充满了抽象层、设计模式、辅助类和间接性——因为那些代码库大到需要它们。Claude 将大型代码库的模式应用于小型代码库的问题。

故障模式:你要求一个简单函数,得到一个类层次结构。你要求一个脚本,得到一个框架。你要求一个配置文件,得到一个配置管理系统。

恢复。 在你的提示词中明确指出简单性。"编写满足需求的最简单实现。""除非特定需求需要,否则不要引入抽象。""此任务优先使用函数而非类。"将简单性指令放在你的 CLAUDE.md 文件中,这样它们适用于每个会话。

更好的是,提供一个参考。将 Claude 指向你想要的风格匹配的现有代码。"遵循 src/utils/helpers.py 中的模式"给了 Claude 一个复杂度校准的具体目标,而不是一个模糊的"保持简单"指令。

近期修复:知道自己不知道什么的 Agent

本章中的大多数故障模式共享一个根本原因:agent 不知道何时超出了自己的能力范围。它尝试无法完成的任务,生成自信但错误的输出,并沿着失败的路径继续而不认识到它需要帮助。Agent 将每个任务视为同等在其能力范围之内。

这正在改变。最有价值的近期能力改进不是更好的代码生成或更快的执行。而是 agent 学习何时寻求帮助——识别需要人类判断的情况并标记不确定领域,而不是盲目尝试每个任务。一个说"我对这个安全配置不太有信心,而且搞错的后果很严重——请审查"的 agent,比一个静默生成看似合理但不正确安全配置的 agent 更有用。

这对故障模式管理的影响是重大的。升级不确定性的 agent 不会消除本章描述的故障模式,但它改变了恢复模型。你不再是事后发现故障——错误代码已发布、错误交易已执行、上下文已耗尽——而是得到早期警告,将人类注意力重定向到真正需要它的决策上。人类监督从审查一切(在 agent 速度下不可能)转变为审查重要的事情(可持续的)。

在该能力成熟之前,防御策略保持不变:验证基础设施、频繁提交、限时尝试,以及回滚而非纠正的纪律。

Checkpoint 与回滚作为恢复策略

本章中的每种故障模式都有相同的最终恢复:回退到已知良好状态然后重试。

这就是为什么第一章的频繁提交模式不是可选建议。它是每种恢复策略的基础。没有频繁提交,你从记忆中恢复。有了频繁提交,你从 checkpoint 中恢复。

Checkpoint 与回滚工作流:

  • 在开始任何任务之前提交。
  • 让 Claude 工作。监控故障模式症状。
  • 如果症状出现,评估:是纠正更快还是重启更快?
  • 如果重启,git checkout . 回退到提交。启动一个新会话。写一个更好的提示词来解决导致失败的原因。
  • 如果纠正,提供有针对性的指导。但设定一个心理限制——如果纠正两次后不收敛,回滚并重启。

所需的纪律是情感上的,不是技术上的。回滚感觉像是在浪费工作。但工作已经被失败浪费了。回滚只是承认了这个事实并将努力重定向到可能成功的路径上。你回滚的代码消失了。对它为什么失败的理解没有消失。那种理解进入你的下一个提示词,下一次尝试更聪明地开始。

要点总结
  • 上下文耗尽是最常见的故障模式——注意重复建议、遗忘指令和连贯性退化作为 context window 满的症状。
  • Bash 环境变量在命令之间不持久;在每条命令中重新建立状态或使用设置级别的环境配置。
  • Checkpoint 系统提供四种回退选项(恢复代码和对话、仅恢复对话、仅恢复代码、从此处总结),但 checkpoint 只追踪直接文件编辑——不追踪 bash 命令的文件操作;git 提交是唯一可靠的通用回退机制。
  • 五个命名反模式——大杂烩会话、反复纠正、过度规范的 CLAUDE.md、先信任后验证的缺口、无限探索——每个都有具体、即时的修复方法。
  • 33 天自主交易实验在一个连续轨迹中展示了每一类 agent 故障:过度自信、相关性风险、集中度风险、治理悖论和自信输出的根本不可靠性。
  • "Vibe trading"将 vibe coding 陷阱延伸到非编码领域——对 agent 生成结果的虚假信心在反馈循环缓慢且赌注是财务的情况下更加危险。
  • 投资验证基础设施(测试、类型、linting)以提高首次尝试成功率——自动反馈是最高杠杆的改进。
  • 对卡住的任务使用老虎机方法:提交、限时三十分钟、接受或重启——重新开始通常比在过程中修复错误更有效。
  • Claude 默认倾向于过度复杂的解决方案;提示词和 CLAUDE.md 中的显式简单性约束产生明显更好的输出。
  • 每种恢复策略都依赖于频繁提交——没有 checkpoint 纪律,你唯一的选择是纠正,而纠正是最不可靠的路径。