Flowness 运行机制:从任务派发到故障恢复 · 阅读系列导读 →

Flowness 会安排 AI Agent 执行任务,也会在一次执行失败后尝试恢复。连接中断、临时服务异常或执行上下文不足,都可能使第一次尝试失败。重新派发有时确实能让工作继续,因此完全取消重试并不合适。
常驻调度器是一个在后台持续运行的派发进程,7 月 19 日以前由它派活:它一轮轮扫描尚未完成的任务,把能派的交给 Agent。这里说的失败,指一次执行没有成功收尾:要么执行它的 Agent 自己报告了未成功的结果,要么 Agent 按证据确认已经死了。如果调度器每次都把失败任务重新交给一个 Agent,同一个问题就可能不断招来新的 Agent、日志和费用。本文介绍的是有界重派机制:输入是任务或触发标识、累计自愈重派次数和已有停止标记,输出是继续允许重派,或从本轮派发候选中排除。
自动恢复必须知道之前已经试过几次
设一个任务反复因为缺少某项访问权限而失败。第一次重新派发或许能帮助排除偶然错误,但如果权限始终没有变化,再多派几个执行者也不会直接补出权限。调度器若只知道“任务还没完成”,就无法区别第一次恢复与第十次重复。
因此,重派记录需要跨扫描保留。我们给每个任务留一个计数:任务每失败一次、被放回待派,计数加一。常驻调度器挑选这一轮要派的任务时,读这个计数,和上限比较。上限是代码里的默认值 3,我们没有另行调整。首次启动不算重派,但它失败时计数就加一;所以计数到 3 时,这个执行任务已经跑过 3 次,常驻调度器不再派它。
计数使决策变得明确:在其他条件都满足时,计数 0、1、2 仍未达到上限;计数达到 3,常驻调度器就不再派它。上限以内也只是允许成为候选,资源、状态和其他限制仍然可能阻止实际启动。

达到上限后,需要留下能够跨轮次读取的停止状态
如果达到上限时只打印一句警告,下一轮扫描仍可能重新提出同样的警告,甚至再次启动任务。一次判断正确,并不能保证持续运行时始终沿用这个判断。
常驻调度器为耗尽的重派路径写入持久停止标记,并产生重派耗尽事件。后续扫描读到同一个标识已经停止,就不再重复告警或派发。这样,终止重复消耗本身也不会变成一条不断重复的后台工作。
以常驻调度器为例,把过程连起来看:任务正常启动后失败,系统进入有限的自动恢复;恢复计数达到预算,任务离开自动重派候选池,留下需要处理的明确记录。随后十次扫描经过,只要对应停止状态仍然存在,就不会再凭“尚未完成”这个条件自动开启相同尝试。
这是一种按任务或触发标识管理的停止机制。它不等同于带自动半开探测的通用服务熔断器,也没有因为等待了一段时间就自然恢复通行。
停止以后,先改变失败条件,再决定恢复
耗尽预算说明自动尝试已经用完,不说明任务永远不可完成。缺少权限可以由有权的人补齐;输入不完整可以补充材料;执行器缺陷可以修复;确实不适合原路线的任务也可以重新规划。
当前停止标记有显式清除入口,应由对应的处理过程决定何时解除。若只清除标记而没有改变失败条件,系统可能重新走进同一个循环。因此,处理记录最好能说明此次恢复依据:新增了什么材料、修好了什么错误,或者谁作出了哪项必要决定。
部分恢复路径能够附带更高模型档位的提示,这也是一种可尝试的条件变化。但换模型不能替代缺失权限,更不能保证修复每一类故障。把恢复方法与失败原因对应起来,才有机会让下一次尝试产生新结果。
次数上限与退避等待,解决不同的重试成本
常见重试策略还会在两次尝试之间增加等待,并用随机扰动分散同时发起的请求。等待处理的是尝试发生得过密的问题;有限次数处理的是一条恢复路径是否会无休止持续的问题。两者可以组合,单独延长间隔仍可能让一个无法自行恢复的任务一直留在后台。
对有副作用的动作,还需要考虑重复执行是否会重复扣款、重复发送或重复写入。本文这项重派上限只限制启动次数,没有自动赋予动作幂等性。实际执行层必须继续承担相应的去重与权限检查。
上限设得太低,暂时性故障可能过早转交;设得太高,又可能增加无效尝试。默认上限 3 是一项工程选择。评估它需要区分故障类型,并统计第几次恢复真正成功、耗费多少资源、转交后是否得到解决。
可以确认的是停止行为,节省多少还需要运行对照
已有构造测试覆盖上限内允许、达到上限阻止启动、停止标记幂等以及不同候选来源有界等情况,这些测试走的都是常驻调度器的批量派发。本文没有把阅读这些测试写成一次新的端到端实验,也没有取得真实节省费用的对照数字。
这道上限在我们自己的系统里真停过任务:6 月 13 日到 7 月 17 日,常驻调度器写下 35 条重派耗尽记录,涉及 28 个任务或触发。7 月 19 日起,我们暂停了自动派发,常驻调度器没有再跑;9 月起,执行任务改由一个每 20 分钟一拍的定时节拍逐个派发。这条路认已经写下的停止标记,但派发前不拿计数和上限比:计数到上限就写停止标记,这一步只写在常驻调度器里。9 月有 13 个执行任务的计数到了 3 以上,最高到 8,没有一个写下停止标记,其中 7 个在计数到 3 之后又至少派出过一次。(这个计数也把重排计划时的中止、人工清理算在里面,不全是同一个毛病重复。)评审、修复这类任务的上限写在另一处,定时节拍仍然会走到。
这项机制的直接作用很具体:在接上它的派发路径里,一次失败恢复不能无限获得新的执行机会;预算耗尽会留下持续有效的停止状态,直到后续处理改变它。它也提醒我们,上限要跟着派发路径走:派发换了一条路,计数还在涨,检查却没跟过去。对长期运行的 Flowness,能够明确结束一条无效尝试路径,才能把资源和人的注意力交还给真正可能改变结果的工作。
更正(2026年10月26日):此前正文写“当前实现读取累计的 retry_count,并与配置的上限比较”,又写“计数达到 3,就不再进入这条自动派发路径”,读起来像系统现在每次派发都会按计数停下任务。实际上,按计数写停止标记这一步只写在常驻调度器的批量派发里;常驻调度器 7 月 19 日起没有再跑,9 月起执行任务由每 20 分钟一拍的定时节拍逐个派发,这条路认已经写下的停止标记,但派发前不拿计数和上限比。9 月有 13 个执行任务的计数到了 3 以上,最高到 8,没有一个写下停止标记;最后一条重派耗尽记录在 7 月 17 日。另外,“默认自愈重派上限是 3”差一:常驻调度器在计数到 3 时就不再派,算上第一次,一个执行任务最多跑三次,不是重派三次。正文已改这几处,补了常驻调度器与定时节拍的一段,把“失败”定义成一次执行没有成功收尾,并把“会话”换成了“Agent”;机制图上“首次正常启动不计入这项预算”也改成了“首次启动不算重派,失败一次计数加一”。
公众号排版与配图
本篇另备有明亮、适合手机连续阅读的公众号排版稿,配图按照本文机制单独绘制。查看公众号版,或下载 Markdown、HTML、PNG 与 SVG 配图包。