关于 fable-loop
fable-loop 是用于轮询变化中的外部或异步状态的限时技能,例如 CI、部署和批处理作业。它帮助 Agent 区分等待与失败,并依据明确的结果条件、预算和重试策略停止。
主要功能
- 01定义成功、等待和失败状态
- 02设置时间与请求预算
- 03检查轮询的幂等性和副作用
- 04采用退避并遵循速率限制
- 05记录循环停止原因
适用场景
- 01等待 CI 构建结果
- 02监控部署健康状态
- 03检查异步批处理进度
- 04在期限内观察最终一致性
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ immamdouhaboammar/ get-fable --skill fable-loop安装后在 Claude Code 中输入/fable-loop确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
skill.package.jsonagents/openai.yamlevals/scenarios.jsonexamples/poll-build-job.mdreferences/loop-control-guidelines.mdpolling-state-machines-and-backoff.mdtemplates/loop-config.template.json详细介绍
Fable Loop
仅在重复检查能够揭示新状态时才重复检查,并明确终止条件、退避策略、错误分类,以及循环停止原因,确保毫无歧义。
使命
轮询不是“重复运行同一条命令,直到它变绿”。良好的循环会对变化中的外部条件建模,区分待处理与失败,遵守速率和成本预算,并在成功、终态失败、取消或预算耗尽时终止。
如果重复执行无法带来新信息,这项任务应该归入诊断,而不是循环。
适用场景
- 等待 CI/部署/构建/批处理作业状态发生变化;
- 监控有明确边界的异步操作;
- 检查最终一致的外部状态;
- 在已知流程推进期间,重复进行安全的测量;
- 执行有限的稳定性采样,其中重复本身就是测量。
不适用场景
- 一次命令/探测就足够(
fable-run/fable-verify); - 同一确定性故障反复出现,且外部状态没有变化(
fable-recover); - 用户期待的是未来通知/定时任务,而非会话内的有限循环;
- 轮询会产生重复的非幂等副作用;
- 无法定义终止条件或预算。
循环分类
| 循环类型 | 成功/终态语义 |
|---|---|
| CI/构建 | 待处理 → 成功或终态失败/取消 |
| 部署 | 进行中 → 健康/已回滚/失败 |
| 批处理作业 | 已排队/运行中 → 已完成/失败 |
| 最终一致性 | 旧状态 → 在截止时间内达到预期状态 |
| 受速率限制的 API | 待处理/可重试 → 成功或终态鉴权/架构错误 |
| 稳定性采样 | N 次有界观测 → 分布/方差判定 |
协议
阶段 1 —— 定义状态机
开始迭代前,列出:
- 成功状态;
- 待处理/可重试状态;
- 终态失败状态;
- 格式错误/未知状态;
- 取消条件。
将所有非成功状态都视为“再试一次”的循环并不安全。
阶段 2 —— 设定预算
至少定义:
- 最大耗时/截止时间;
- 适用时的最大迭代次数或请求预算;
- 初始间隔/退避策略;
- 最大间隔;
- API/成本/速率限制。
存在多个限制时,采用更严格的限制。
阶段 3 —— 检查幂等性和副作用
轮询操作应为只读/幂等。如果端点/命令会触发工作,应将触发操作与状态观测分开,并确保重试不会重复执行该操作。
阶段 4 —— 执行一次迭代并分类结果
记录:
- 迭代次数/时间;
- 观测到的状态/值;
- 传输/命令结果;
- 分类:成功/待处理/可重试错误/终态失败/未知;
- 下一次延迟/原因。
阶段 5 —— 智能应用退避策略
如果预期更新频率已知且成本较低,则使用固定间隔;如果需要应对速率限制/瞬时服务错误,则使用指数退避/带抖动的退避。
适用时遵循明确的 Retry-After/服务提供方指导。不要仅仅因为工具允许,就以亚秒级的激进频率调用运行缓慢的外部作业。
阶段 6 —— 遇到终态信息时提前停止
遇到以下情况立即退出:
- 成功;
- 明确的失败/取消状态;
- 不可重试的鉴权/架构/权限错误;
- 用户取消;
- 预算/截止时间耗尽。
结果已知后,不要继续消耗剩余迭代次数。
阶段 7 —— 检测进度停滞
如果状态包含进度/版本/时间戳,请比较各次迭代的结果。若状态长时间未变化,且已接近或超出预期 SLA,这可能成为诊断信号,而不是自动延长预算的理由。
阶段 8 —— 提供如实的结果记录
最终记录应包含停止原因、耗时、迭代次数、最后状态、瞬时错误,以及条件是否确实满足。
超时不等于成功。除非约定/截止时间另有规定,否则“仍在运行”不等于失败。
决策规则
- 可重复的确定性失败,且外部状态没有变化 → 停止循环并恢复。
- 可重试的传输错误可在预算范围内继续;身份验证、权限或架构错误通常应终止,直到配置发生变化。
- 在适用的情况下,将提供方的
Retry-After或作业建议的轮询间隔视为下限。 - 绝不能将非幂等触发操作重复用作状态轮询。
- 如果每次迭代都会消耗大量费用或配额,除时间外还要设定费用/请求预算。
- 如果预计完成时间超出当前会话/任务模型的范围,在可用时创建计划任务/条件监视机制,而不是假装会话内循环可以无限运行。
- 循环可以以
INCOMPLETE/TIMEOUT结束;不要为了获得绿色结果而悄悄延长限制。 - 如果进度没有变化,且截止时间尚远,则按策略继续,不要频繁向用户更新;对于长时间交互式运行,仅报告有意义的状态变化。
不变量
- 循环开始前,明确退出条件和预算。
- 每次迭代都是安全/幂等的,或明确控制其副作用语义。
- 终止性失败立即停止。
- 待处理状态与失败状态应区分开。
- 遵守退避策略和速率限制。
- 收据记录实际停止原因;不得将超时转换为通过。
故障分类
无限/隐式循环
没有可强制执行的预算。应拒绝并定义限制。
重试所有错误
将身份验证/架构/权限错误及终止性作业失败视为暂时性错误。应进行分类并适时停止。
重复副作用
轮询调用会重新触发工作。应使用单独的状态端点/幂等键,或停止。
轮询风暴
轮询间隔相对于服务/作业节奏过于频繁。应采用退避策略/遵循提供方的指引。
错误诊断超时
作业仍在预期 SLA 内处于待处理状态,但循环将其标记为故障。应将超时/未完成与产品故障分开报告。
进度卡住
状态在应当变化时始终没有变化。应交由恢复/运维诊断处理,而不是无限延长。
会话不匹配
请求的监控时长超出可用的执行窗口。在支持时,使用计划任务/条件监视功能。
反模式
- 使用原始的
while true/无界休眠循环; - 重试所有类别的错误;
- 通过反复重新提交作业来轮询;
- 每次未成功后都延长超时时间,直到成功为止;
- 对 10 分钟的部署每 1 秒轮询一次;
- 仅仅因为状态处于待处理就判定失败;
- 仅仅因为循环正常结束就判定成功;
- 在最终收据中隐瞒暂时性错误;
- 用循环逃避对可重复的确定性失败进行诊断。
循环收据
Condition/state machine:
Success / terminal failure states:
Time + iteration/request budgets:
Interval/backoff policy:
Idempotency/side-effect check:
Iterations: time → observed state → classification
Transient errors:
Stop reason:
Condition satisfied? yes/no
Final state:
Next action if incomplete/failed:
完成标准
循环满足以下条件时即告完成:
- 状态机、成功/失败语义和预算已明确;
- 轮询遵守幂等性/速率/费用限制;
- 终止性信息使循环提前停止;
- 如实呈现超时/卡住状态;
- 最终收据准确说明循环结束的原因以及接下来应采取的措施。
渐进式资源
- 深入指南:
references/polling-state-machines-and-backoff.md - 现有指南:
references/loop-control-guidelines.md - 示例:
examples/poll-build-job.md