跳到主要内容

Agent Runtime State Machine

到这一步,专题里已经有了不少运行机制:

  • route
  • handoff
  • approval
  • interrupt / resume
  • retry
  • failure triage

如果把这些机制拆开看,都能理解。真正进入生产系统之后,新的问题会出现:

一次 run 在整个生命周期里,到底会经过哪些状态。

这篇文档专门讲这一层。

1. 为什么需要状态机视角

没有状态机视角时,系统很容易变成一堆分散机制:

  • 能 pause
  • 能 resume
  • 有 approval
  • 有 background run
  • 有 retry

但说不清:

  • 当前 run 正处在哪个状态
  • 哪些转换是合法的
  • 哪些状态能恢复
  • 哪些状态必须终止

状态机的作用,就是把这些散点收成一张运行图。

2. 一个最小 runtime 状态图

这张图不是唯一正确答案,但已经能覆盖大多数 Agent runtime 的核心状态。

3. 每个状态在做什么

3.1 created

run 刚被创建,但还没真正进入执行。

这时候通常只有这些事情:

  • 记录输入
  • 分配 run id
  • 初始化 thread / session
  • 写第一条 trace

3.2 triaging

系统在做入口判断。

这里通常会发生:

  • route
  • risk tagging
  • 参数检查
  • 是否追问
  • 是否直接进入 specialist

3.3 running

真正执行的主状态。

这里可能包括:

  • reasoning
  • tool call
  • handoff
  • retrieval
  • state update

3.4 interrupted

系统主动停下来了。

典型原因有:

  • approval
  • human review
  • 等待外部输入
  • 高风险工具调用前暂停

3.5 waiting_for_approval_or_input

中断之后,系统在等外部决定。

这时最重要的是:

  • 状态已经保存
  • interrupt payload 可追踪
  • run 不会被误当成失败

3.6 resumed

外部输入已经回来,系统准备接着往下跑。

这一层不是重新开始,而是回到原来的执行点。

3.7 retrying

运行失败了,但还没宣告终止。

进入这个状态通常意味着:

  • 错误被归类为可重试
  • retry policy 已命中
  • 下次执行需要带上上一次的运行上下文

3.8 completed

run 正常结束。

3.9 failed

run 已经失败,且不再继续。

3.10 cancelled

run 被用户或系统主动取消。

4. 哪些状态最容易被混在一起

interrupted 和 failed

这两个最容易混。

interrupted 表示:

  • 系统主动停下
  • 仍然可恢复

failed 表示:

  • 系统没法继续
  • 当前 run 已终止

如果把二者混成一种状态,监控和补救动作都会乱。

resumed 和 running

有些系统不会单独记录 resumed,而是直接回到 running

这没问题,但前提是 trace 里仍然能看出:

  • 之前发生过 interrupt
  • 恢复时带回了什么输入

retrying 和 running

同理,retrying 最终也会回到 running,但最好保留:

  • 第几次重试
  • 为什么重试
  • 是否更换了模型、工具或参数

5. 状态机里最关键的转换规则

一套 runtime 状态机真正值钱的地方,不是状态名,而是转换约束。

例如:

  • completed 不能再进入 running
  • cancelled 之后不该再 resume
  • failed 之后是否允许 replay,要单独定义
  • interrupted 只能走向 resumedcancelledfailed

如果这些规则不清楚,run 很容易出现“状态看着正常,实际已经乱了”的情况。

6. 这一层和 approval / interrupt / resume 的关系

前面那篇 Tool Approval、Interrupt 与 Resume 讲的是局部机制。

这篇把它们放回 runtime 里看:

  • approval 是中断原因之一
  • interrupt 是状态切换点
  • resume 是恢复路径

也就是说:

  • 局部机制解释“某一步怎么停”
  • 状态机解释“整个 run 怎样流转”

7. 这一层和 background / durable execution 的关系

如果系统支持长任务或 durable execution,状态机会更重要。

因为 run 不再只存在于一次 HTTP 请求里,而会跨越:

  • 异步执行
  • 外部审批
  • 重试
  • 进程重启
  • 长时间等待

这时状态机就是整个 runtime 的共同语言。

8. 最小状态字段建议

如果要把 runtime 状态记录下来,至少建议有这些字段:

{
runId: string,
threadId?: string,
sessionId?: string,
status:
| "created"
| "triaging"
| "running"
| "interrupted"
| "waiting"
| "resumed"
| "retrying"
| "completed"
| "failed"
| "cancelled",
retryCount: number,
interruptReason?: string,
failureType?: string,
lastTransitionAt: string
}

如果还要更实用,可以再加:

  • 当前节点
  • 当前 specialist
  • 当前工具调用 id
  • approval id
  • deadline / timeout

9. 最容易出问题的地方

9.1 只有 completed / failed 两种状态

这种设计在 demo 阶段够用,上线后会不够。

因为:

  • interrupt 看不见
  • retry 看不见
  • cancel 和 fail 混在一起
  • triage 和真正 running 混在一起

9.2 中断状态不落盘

如果 interrupted 只是前端本地态,那断线之后系统很难恢复。

9.3 retry 不带状态上下文

如果 retry 每次都像第一次运行,系统会:

  • 重复副作用
  • 丢掉中间进度
  • 很难做失败归因

10. 和现有专题里的关系

最适合一起看的文档有:

11. 小结

runtime state machine 的价值,在于把分散机制收成一条主线:

  • run 从哪里开始
  • 在哪里暂停
  • 怎样恢复
  • 何时重试
  • 何时终止

这张图一旦清楚,后面的 durable execution、队列和重试策略都会更容易落地。