当一个 Agent 系统开始具备质量闸门之后,新的问题就会接着出现:

  • 如果 Reviewer 判定要整体重写,系统怎么回炉?
  • 回炉过程中失败了,是不是和普通失败一样处理就行?
  • 为什么有时候“看起来已经会重试”,但流程还是会跑错?

这章讲的就是当前项目里一个非常真实、也非常工程化的话题:

自动回炉和失败重试,不能只做成“再试一次”,而要做成“按流程语义恢复”。


为什么“失败重试”不是一个简单的 if-else

很多人第一次做重试,会自然写成这种思路:

  1. 某一步失败
  2. 如果错误可重试,就 sleep 一下
  3. 再重新跑这一步

单看这套逻辑没什么问题,但在多 Agent 系统里,它很容易不够。

因为真实系统里,失败不是孤立的。
它发生在某一条“有上下文的流程”里。

比如:

  • 普通 Writer revision 失败
  • 自动回炉阶段的 Writer draft 失败

这两个失败虽然都可能是“网络超时”,但它们在流程中的语义完全不同。

如果系统只看“失败步骤名”,而不看“当前处于什么流程语义里”,就很容易恢复错。


当前项目里,普通失败重试是什么样

先看比较基础的一层。

当前项目已经具备了比较完整的失败重试机制:

  • 记录 last_error_type
  • 记录失败的 current_agent / current_step
  • 判断错误是否可重试
  • 控制最大自动重试次数
  • 从失败步骤继续,而不是整任务重跑

这已经比很多原型项目成熟很多了。

这套能力主要解决的是:

任务失败后,不要让用户重新从头开始。

在普通线性流程里,这通常已经够用。


自动回炉为什么会让问题复杂化

事情在引入自动回炉后开始变复杂。

当前项目现在有这样一条逻辑:

  1. Writer draft
  2. Reviewer review
  3. 如果质量闸门结果是 rewrite
  4. 系统自动回炉一次 Writer draft
  5. 回炉成功后再次 Reviewer review
  6. 再进入 Writer revision

这已经不是简单的线性主链路了。
它在主链路中间插入了一段“子流程”。

而子流程一旦失败,系统就必须回答:

我到底是在恢复主链路,还是在恢复自动回炉子流程?


当前项目真实踩过的坑

这不是理论问题,而是当前项目实际跑验证时踩出来的坑。

当时的现象大概是这样:

  1. Reviewer 已经判定 rewrite
  2. 系统确实触发了 reviewer_auto_rewrite
  3. 自动回炉阶段的 Writer draft 因为模型超时失败
  4. 通用重试机制把它从 draft 恢复了
  5. draft 后一旦成功,系统却直接掉回了 writer_done 审批点

结果就是:

自动回炉后的第二次 Reviewer 被绕过去了。

也就是说,系统虽然“会重试”,但恢复语义是错的。


这个坑为什么会出现

根因其实很典型:

系统当时只知道:

  • 最近失败的是 Writer / draft

但它不知道:

  • 这个 draft 不是普通初稿阶段
  • 它其实处于“自动回炉中”

于是恢复逻辑就按普通 draft 来处理了。

这说明一个很重要的设计原则:

恢复逻辑不能只根据失败步骤判断,还必须知道当前流程所处的语义状态。


当前项目后来怎么修的

当前项目最后走的是一个很务实、也很有效的方案:

  • 给自动回炉阶段增加独立状态标记

具体来说,后来新增了:

  • auto_rewrite_pending

这个字段的意义就是:

当前任务不只是“在跑 draft”,而是“正在自动回炉的 draft 阶段”。

这一步看起来只是多了一个布尔状态,但实际上把恢复语义补齐了。


auto_rewrite_pending 带来了什么变化

有了这个状态以后,系统就能区分两种完全不同的 draft

普通 draft

表示当前是在主链路里第一次生成初稿。

成功后通常会:

  • 暂停到 writer_done

自动回炉 draft

表示当前是在质量闸门 rewrite 之后,系统主动回炉。

成功后不应该暂停给用户,而应该:

  • 清掉自动回炉状态
  • 继续再跑一次 Reviewer

这就是“同样是 draft,流程语义却不同”的典型例子。


自动回炉阶段的参数为什么也要单独调

当前项目在修复语义之后,还继续往前做了一步:

给自动回炉阶段单独设置了更稳的调用参数。

比如当前已经落到代码里的策略包括:

  • 自动回炉 Writer draft 使用更长的超时
  • 第二次 Reviewer 使用更长的超时
  • Writer revision 也使用更稳的超时和温度参数

这背后的思路很简单:

自动回炉不是普通生成,它本来就更像一次“补救动作”。
既然系统都已经决定要自救了,就应该给它一组更适合自救的调用策略。


更清晰的重试日志为什么重要

当前项目后面还顺手做了一个很实用的优化:

  • 自动回炉阶段的失败日志和普通失败日志分开表述

比如会在日志里明确体现:

  • 这是普通流程失败
  • 还是自动回炉阶段失败

这听起来像文案细节,但其实非常重要。
因为调试的时候,你最怕看到:

  • “Writer / draft failed”

却不知道这到底是:

  • 初稿生成失败
  • 还是自动回炉阶段失败

当流程越来越复杂时,日志必须承担“解释当前语义”的职责。


当前项目已经验证到什么程度

这部分不是纸上设计,而是当前项目已经真实验证过的。

项目后面专门构造了“明显跑题的草稿”去跑这条链路,并确认了完整闭环:

  1. Reviewer / review / completed
  2. System / reviewer_auto_rewrite / completed
  3. Writer / draft / completed
  4. 第二次 Reviewer / review / completed
  5. Writer / revision / completed
  6. revision_done

并且这条链路现在还被自动化测试锁住了。

这意味着:

自动回炉不再只是“代码里看起来有这个逻辑”,而是已经被真实跑通并验证过了。


这一章真正想说明什么

当前项目在这条线上最值得借鉴的一点,其实不是“会自动回炉”,而是:

一旦流程变复杂,失败恢复必须按语义做,而不是按步骤名做。

否则系统很容易出现一种错觉:

  • 表面上它会重试
  • 实际上它恢复到了一条不该去的路径

这是很多 Agent 项目在往复杂流程走时非常容易踩的坑。


这一章的结论

在多 Agent 系统里,自动回炉和失败重试不能只做成通用“再来一次”,而要考虑:

  • 当前失败发生在哪个流程语义里
  • 恢复后应该接回主链路,还是接回子流程
  • 是否需要独立状态标记
  • 是否需要单独的模型参数和日志文案

当前项目最终给出的答案是:

  • auto_rewrite_pending 显式标记自动回炉状态
  • 恢复时按自动回炉语义继续,而不是按普通 draft 继续
  • 回炉成功后强制再走一次 Reviewer

这是一套非常实战的设计。


下一章看什么

当你已经有:

  • 自动回炉
  • 失败重试
  • 冲突确认
  • 质量闸门

下一个问题就会变成:

这些关键语义,怎么防止以后改代码时被悄悄改坏?

下一章我们就讲当前项目最近开始补的另一块关键能力:

自动化测试。