第13章 容错与恢复算法
“真正的韧性不在于永不失败,而在于每次失败后都能优雅地站起来。” 13.1 问题引入 想象这样一个场景:用户正在使用 Claude Code 进行一个复杂的代码重构任务。Agent 已经分析了数十个文件,制定了修改计划,正在逐步执行。此时 API 突然返回 HTTP 529(Overloaded)错误。 这个看似简单的场景引发了一系列深刻的工程决策: 立即失败? 用户等待了几分钟的上下文将全部丢失,体验极差。 无限重试? 如果服务器已过载,盲目重试只会加剧雪崩,使所有用户的体验都恶化。 等待后重试? 等多久?如果所有客户端都在同一时刻重试呢? 降级到备用模型? 什么条件下降级?如何在质量和可用性之间取舍? 更复杂的场景还包括:网络在 SSH 会话中断开,进程收到 SIGTERM 信号,OAuth Token 在请求中途过期,SSL 证书验证失败……每一种故障都需要不同的处理策略。 Claude Code 作为一个长时间运行的交互式 Agent 系统,面临的容错挑战远比普通 Web 应用复杂。它必须在"永不放弃"和"适时认输"之间找到精确的平衡点。本章将深入分析 Claude Code 源码中的容错与恢复算法,揭示一个生产级 Agent 系统如何在真实世界的混乱中保持韧性。 13.2 错误分类状态机 容错系统的第一步是正确分类错误。不同类型的错误需要截然不同的处理策略。Claude Code 构建了一个精密的错误分类体系,将错误分为可重试、不可重试、可降级等多个类别。 13.2.1 分类的核心逻辑 错误分类是一棵决策树。Claude Code 的 shouldRetry 函数体现了这棵树的结构: 错误发生 ├── 是否为模拟错误? → 不重试(测试用) ├── 是否为持久模式下的瞬态容量错误(429/529)? → 始终重试 ├── 远程模式下的 401/403? → 重试(基础设施令牌刷新) ├── 包含 "overloaded_error"? → 重试(流式 529 的变体) ├── 上下文溢出 400? → 重试(自动调整 max_tokens) ├── x-should-retry 响应头 │ ├── "true" + 企业用户 → 重试 │ └── "false" + 非5xx → 不重试 ├── 连接错误(APIConnectionError)? → 重试 ├── 408 请求超时 → 重试 ├── 409 锁超时 → 重试 ├── 429 速率限制 → 条件重试(非订阅用户或企业用户) ├── 401 认证失败 → 清除缓存后重试 ├── 403 Token 撤销 → 重试 ├── 5xx 服务端错误 → 重试 └── 其他 → 不重试 这棵决策树的设计体现了几个关键原则: ...