Bounded Loops——有界循环
Effort: free — 循环启动前就声明好上限和检查点;直接降低净成本。消除:失控循环的开销——烧光的配额、被 429 封死的路由、以及一次崩溃就清零的进度。
无界循环是 agent 能造出的最贵的 bug。它烧预算、把服务商敲到封你号,还把自己的失败藏在空转里。每个循环在启动之前,都要有一个上限、一个检查点、一种大声死掉的方式。
什么时候用
启动任何循环之前:修复循环、重试包装、轮询器、调度器、多步自主运行——凡是能重发调用或重试步骤的东西。
步骤
- 先声明预算。 token、成本、墙钟时间、最大尝试次数——第一次迭代之前写下来。 没有声明预算的循环按定义就是无界的,不许启动。
- 给内层回合封顶。 一个内层回合(针对一个问题的一次 LLM/工具循环)只有一个小的 固定轮次上限(4 上下)。上限约束的是回合,不是任务——没做完的活向上移交, 而不是原地硬磨。
- 每次迭代都存检查点。 持久状态写到磁盘——运行清单、证据日志、当前步骤—— 绝不放在聊天记忆里。任何人(包括一个全新会话)都能从最后一个检查点接着跑。
- 预算耗尽:先存档,再上报。 把检查点连同已完成的、还剩下的、卡在哪,一起交给 外层循环或你的人类。绝不悄悄越过预算继续跑,也绝不悄悄停下——耗尽必须大声。
- 尊重每一个外部 API。 第一次调用之前,先弄清服务商的限流和配额;不清楚时按最严 处理——单次调用、间隔拉宽——直到实测出来。每次调用都过节流,响应缓存复用, 并守住每个时间窗的硬上限。
- 被顶回来就指数退避。 429 或 503 的意思是等,然后等更久。同一端点零瞬时重试。 对着一个端点密集重试,正是一条活路被弄死的方式:它烧光配额,还可能连累你的整个 出口地址被封。
- 带一个大声的、有界的熔断开关。 任何能重发调用的循环都有最大尝试次数;触顶时 循环带着证据大声停下——绝不无限或无声地空转。
- 只在安全点停下和排队。 停下 = 存档后取消。新工作排到下一个安全点(步骤之间的 状态边界)——绝不在步骤中途插入。一个循环实例、一个写者、原子化状态写入。
硬规则(踩中即失败)
- 没有声明 token / 成本 / 时间 / 尝试预算就启动的循环。
- 预算耗尽后继续跑——无论悄悄还是明着——却不上报。
- 对同一端点的瞬时重试,或任何没有退避的重试路径。
- 没有尝试上限的重试循环,或触顶时无声失败的上限。
- 进度状态只存在对话记忆里——一次崩溃就抹掉整个运行。
- 两个循环实例写同一份状态,或非原子的状态写入。
- 靠削弱自己的退出检查来逃出循环——降线、删数据、吞错误换来的绿是假绿,不是出口。
搭配使用
- optimus——任何循环启动前先加载地板。
- repair-loop——这些上限最大的用户。
- fleet-ladder——在模型之间有界回退,而不是敲死一个。
- session-handoff——检查点上报之后变成的东西。