executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
circuit-breaker-pattern为智能体工具调用实现断路器逻辑——追踪工具健康状态、在关闭/开启/半开 状态之间切换、在工具失败时缩减任务范围、通过能力映射路由至备用方案, 并强制执行故障预算以防止错误积累。将编排(决定尝试什么)与执行(调用 工具)分离,遵循指挥官模式。当构建依赖多个可靠性不一的工具的智能体、 设计容错的智能体工作流、从任务中途的工具中断中优雅恢复,或强化现有 智能体防止级联工具故障时使用。
Independent GitHub snapshot · Automated classification · Original documentation governs
工具故障时的优雅降级。一个调用五个工具且其中一个损坏的智能体不应该完全失败——它应该识别损坏的工具、停止调用它、将范围缩减到剩余可实现的内容,并如实报告跳过了什么。此技能使用来自分布式系统的断路器模式规范化该逻辑,并将其适配到智能体工具编排中。
核心洞见,来自 kirapixelads 的「厨房火灾问题」:指挥官(编排层)不能下厨。将「尝试什么」和「怎么尝试」的关注点分离,可以防止编排器陷入失败工具的重试循环中。
声明每个工具提供什么以及存在什么备用方案。此映射是范围缩减的基础——没有它,工具故障会让智能体不知下一步该怎么做。
capability_map:
- tool: Grep
provides: content search across files
alternatives:
- tool: Bash
method: "rg or grep command"
degradation: "loses Grep's built-in output formatting"
- tool: Read
method: "read suspected files directly"
degradation: "requires knowing which files to check; no broad search"
fallback: "ask the user which files to examine"
- tool: Bash
provides: command execution, build tools, git operations
alternatives: []
fallback: "report commands that need to be run manually"
- tool: Read
provides: file content inspection
alternatives:
- tool: Bash
method: "cat or head command"
degradation: "loses line numbering and truncation safety"
fallback: "ask the user to paste file contents"
- tool: Write
provides: file creation
alternatives:
- tool: Edit
method: "create via full-file edit"
degradation: "requires file to already exist for Edit"
- tool: Bash
method: "echo/cat heredoc"
degradation: "loses Write's atomic file creation"
fallback: "output file contents for the user to save manually"
- tool: WebSearch
provides: external information retrieval
alternatives: []
fallback: "state what information is needed; ask user to provide it"
对每个工具,记录:
预期结果: 覆盖智能体使用的每个工具的完整能力映射。每个条目至少有一个后备方案,即使没有工具备用方案。映射使通常隐式的内容变为显式:哪些工具是关键的(无备用方案)以及哪些是可替换的。
失败处理: 若工具列表不清晰,从技能的 frontmatter 中的 allowed-tools 开始。若备用方案不确定,将其标记为 degradation: "unknown — test before relying on this route" 而非省略。
为每个工具设置状态追踪器。每个工具以 CLOSED 状态(健康,正常运行)开始。
断路器状态表:
+------------+--------+-------------------+------------------+-----------------+
| 工具 | 状态 | 连续失败次数 | 最后失败时间 | 最后成功时间 |
+------------+--------+-------------------+------------------+-----------------+
| Grep | CLOSED | 0 | — | — |
| Bash | CLOSED | 0 | — | — |
| Read | CLOSED | 0 | — | — |
| Write | CLOSED | 0 | — | — |
| Edit | CLOSED | 0 | — | — |
| WebSearch | CLOSED | 0 | — | — |
+------------+--------+-------------------+------------------+-----------------+
故障预算:0 / 5 已消耗
状态定义:
状态转换:
预期结果: 状态表已为所有工具初始化为 CLOSED 状态和零失败计数。故障阈值和预算被明确声明。
失败处理: 若无法提前枚举工具列表(动态工具发现),在首次使用每个工具时初始化状态。该模式仍然适用——只是逐步构建表格。
当智能体需要调用工具时,遵循此决策序列。这是指挥官逻辑——它决定「是否」尝试调用,而非「如何」执行。
每次工具调用前:
1. 在断路器表中检查工具状态
2. 若 OPEN:
a. 检查是否到了半开探测的时间
- 是 → 转换到 HALF-OPEN,继续进行探测调用
- 否 → 跳过此工具,路由至备用方案(第 4 步)
3. 若 HALF-OPEN:
a. 进行一次探测调用
b. 成功 → 转换到 CLOSED,将连续失败重置为 0
c. 失败 → 转换到 OPEN,增加故障预算消耗
4. 若 CLOSED:
a. 正常进行调用
每次工具调用后:
1. 成功:
- 将连续失败重置为 0
- 记录最后成功时间戳
2. 失败:
- 增加连续失败计数
- 记录最后失败时间戳和错误消息
- 增加故障预算消耗
- 若连续失败 >= 阈值:
转换到 OPEN
日志:「[工具] 断路器开启:[失败次数] 次连续失败」
- 若故障预算耗尽:
暂停——不继续任务
向用户报告(第 6 步)
指挥官从不立即重试失败的调用。它记录失败、检查阈值,然后继续前进。重试仅通过 HALF-OPEN 探测机制在后续步骤中发生。
预期结果: 智能体在每次工具调用前后遵循的清晰决策循环。工具健康状态持续追踪。指挥官层从不在失败工具上阻塞。
失败处理: 若跨调用追踪状态不可行(例如,无状态执行),降级为更简单的模型:统计总故障次数,并在预算时暂停。三状态断路器是理想的;故障计数器是最小可行模式。
当工具的断路器是 OPEN 时,查阅能力映射(第 1 步)并路由至最佳可用备用方案。
路由优先级:
路由决策示例:
需要的工具:Grep(断路器 OPEN)
任务:查找所有包含 "API_KEY" 的文件
路由 1:带 rg 命令的 Bash
→ 降级:失去 Grep 内置的格式化
→ 决策:可接受——使用此路由
若 Bash 也 OPEN:
路由 2:直接读取可疑的配置文件
→ 降级:需要猜测哪些文件;无法广泛搜索
→ 决策:部分——仅尝试已知的配置路径
若 Read 也 OPEN:
路由 3:询问用户
→ 「我需要查找包含 'API_KEY' 的文件,但我的搜索
工具不可用。你能运行:grep -r 'API_KEY' . 吗?」
→ 决策:后备——用户提供信息
若用户不可用:
路由 4:范围缩减
→ 从任务范围中移除「查找 API 密钥引用」
→ 记录:「SKIPPED: API key search — no tools available」
预期结果: 当工具断路器开启时,智能体透明地路由至备用方案或降级范围。路由决策和任何降级都记录在任务输出中,使用户知道受到了什么影响。
失败处理: 若能力映射不完整(未列出备用方案),默认为范围缩减并报告。永不静默跳过工作——始终记录跳过了什么以及原因。
当工具断路器开启且备用方案耗尽时,将任务缩减至使用正常工具仍可完成的内容。这不是失败——这是诚实的范围管理。
范围缩减协议:
范围缩减报告:
原始范围:5 个子任务
[x] 1. 读取配置文件 (Read: CLOSED)
[x] 2. 搜索已废弃的模式 (Grep: CLOSED)
[ ] 3. 运行测试套件 (Bash: OPEN — 无备用方案)
[x] 4. 更新文档 (Edit: CLOSED)
[ ] 5. 部署到预发布环境 (Bash: OPEN — 无备用方案)
缩减后的范围:3 个子任务可实现
延迟:2 个子任务需要 Bash(断路器 OPEN)
建议:立即完成子任务 1、2、4。
子任务 3 和 5 需要 Bash——将在下一个周期中探测
或用户可以手动运行命令。
不要尝试延迟的子任务。不要重试断路器开启的工具,寄希望于它们能运行。断路器的存在正是为了防止这种情况——信任其状态。
预期结果: 任务被清晰地划分为可实现的和延迟的工作。智能体完成所有可实现的工作,并报告延迟项目及其原因和解除阻塞的条件。
失败处理: 若范围缩减移除了所有子任务(每个工具都损坏),直接跳至第 6 步——暂停并报告。没有可用工具的智能体不应假装取得进展。
当工具返回可能陈旧的数据(缓存结果、过时快照、先前获取的内容)时,明确标记而非将其当作新鲜数据处理。
陈旧性指标:
标记协议:
呈现可能陈旧的数据时:
「[STALE DATA — retrieved at {timestamp}, may not reflect current state]
File contents as of last successful Read:
...」
「[CACHED RESULT — Grep returned identical results to previous call;
filesystem may have changed since]」
「[UNVERIFIED — WebSearch result from {date}; current status unknown]」
永不静默地将陈旧数据呈现为当前数据。用户或下游智能体必须知道数据质量以做出合理决策。
预期结果: 所有可能陈旧的工具输出都带有明确标签。新鲜数据不标注(标注保留用于不确定性,而非确认)。
失败处理: 若无法确定陈旧性(无时间戳,无比较基准),注明不确定性:「[FRESHNESS UNKNOWN — no baseline for comparison]」。对新鲜度的不确定性本身就是信息。
追踪所有工具的总故障次数。当预算耗尽时,智能体暂停并报告,而非继续积累错误。
故障预算执行:
预算:每个周期 5 次故障
当前:4 / 5 已消耗
故障 1:Bash — "permission denied"(第 3 步)
故障 2:Bash — "command not found"(第 3 步)
故障 3:Bash — "timeout after 120s"(第 4 步)
故障 4:WebSearch — "connection refused"(第 5 步)
状态:强制暂停前还剩 1 次故障
→ 下一次工具调用以高度谨慎进行
→ 若失败:暂停并生成状态报告
预算耗尽时:
故障预算耗尽 — 暂停中
已完成工作:
- 子任务 1:读取配置文件(成功)
- 子任务 2:搜索已废弃的模式(成功)
未完成工作:
- 子任务 3:运行测试套件(失败 — Bash 断路器 OPEN)
- 子任务 4:更新文档(未尝试 — 已暂停)
- 子任务 5:部署到预发布环境(未尝试 — 已暂停)
工具健康状态:
Grep: CLOSED(健康)
Read: CLOSED(健康)
Edit: CLOSED(健康)
Bash: OPEN(3 次连续失败 — 权限/命令/超时)
WebSearch: OPEN(1 次失败 — 连接被拒绝)
故障:5 / 5 预算已消耗
建议:
1. 调查 Bash 故障 — 可能是环境问题
2. 检查 WebSearch 的网络连接
3. 解决后从子任务 4 恢复
暂停并报告的功能与电气系统中的断路器相同:它防止损害积累。一个持续调用损坏工具的智能体会浪费上下文窗口,用重复错误混淆用户,并可能产生不一致的部分结果。
预期结果: 当故障预算耗尽时,智能体干净地停止。报告包括已完成的工作、未完成的工作、工具健康状态和可操作的后续步骤。
失败处理: 若智能体无法生成干净的报告(例如,状态追踪丢失),输出任何可用的信息。部分报告比静默继续要好。
验证编排逻辑(第 2-7 步)与工具执行干净地分离。
指挥官(编排)做:
指挥官不做:
若指挥官在「下厨」(通过工具调用来解决其他工具的故障),则分离已被破坏。指挥官应该路由至备用工具或缩减范围——而非尝试修复损坏的工具。
预期结果: 编排决策与工具执行之间有清晰的边界。指挥官层可以在不引用特定工具 API 或错误类型的情况下被描述。
失败处理: 若编排和执行纠缠在一起,通过将决策逻辑提取到每次工具调用前运行的单独步骤中来重构。决策步骤产生四个输出之一:CALL、SKIP、PROBE 或 PAUSE。执行步骤根据该输出采取行动。
当多个工具共享基础设施(网络、文件系统、权限)时,单一根本原因可能同时触发多个断路器。检测并处理这种相关模式,而非独立处理每个断路器。
级联故障指标:
响应协议:
退避倍增: 当级联故障触发时,对半开探测使用指数退避:在第 3 步探测,然后第 6 步,然后第 12 步。将最大间隔限制在 20 步以防止断路器永久锁定。这防止了快速探测使正在恢复的系统超载。
预期结果: 相关故障被检测并作为单个系统性事件处理,而非 N 个独立的断路器触发。故障预算将系统性事件计为一次,而非 N 次。
失败处理: 若相关检测不可行(故障有不同的错误特征,尽管原因相同),回退到独立的每工具断路器。系统仍然优雅降级——只是预算消耗得更快。
在执行断路器循环(第 3 步)之前,可选地验证工具是否可用且可能成功。这减少了来自可预测故障的不必要断路器触发。
调用前检查:
| 检查 | 方法 | 失败时的操作 |
|---|---|---|
| 工具存在 | 验证工具在 allowed-tools 列表中 | 跳过——甚至不尝试 |
| MCP 服务器健康状态 | 检查服务器进程/连接状态 | 立即路由至备用方案 |
| 资源可用性 | 验证目标文件/URL/端点存在 | 路由或降级范围 |
决策表:
调用前评分:
AVAILABLE → 继续进行断路器循环(第 3 步)
DEGRADED → 谨慎继续,将故障阈值降低 1
UNAVAILABLE → 跳过工具,路由至备用方案(第 4 步),不消耗预算
调用前检查是建议性的,而非权威性的。通过调用前检查的工具在执行期间仍可能失败。断路器仍是主要可靠性机制。
预期结果: 可预测的故障(缺失的工具、无法访问的服务器)在消耗故障预算之前被捕获。断路器只处理真正的运行时故障。
失败处理: 若调用前检查不可用或增加了过多开销,完全跳过此步骤。第 3 步中的断路器循环处理所有故障——调用前选择是优化,不是要求。
fail-early-pattern — 互补模式:尽早失败在工作开始前验证输入;断路器在工作期间管理故障escalate-issues — 当故障预算耗尽或范围缩减显著时,升级至专家或人类write-incident-runbook — 将反复出现的工具故障模式记录为运行手册以加速诊断assess-context — 当多个工具降级时评估当前方法是否能适应;与范围缩减决策配合使用du-dum — 双时钟架构将观察与决策分离;补充模式,用于降低智能体循环中的观察成本