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不能再进入runningcancelled之后不该再resumefailed之后是否允许 replay,要单独定义interrupted只能走向resumed、cancelled或failed
如果这些规则不清楚,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. 和现有专题里的关系
最适合一起看的文档有:
- Tool Approval、Interrupt 与 Resume
- Approval 与 Human Review Workflow
- Agent Failure Triage
- Agent-Latency-Cost-and-Reliability.md
11. 小结
runtime state machine 的价值,在于把分散机制收成一条主线:
- run 从哪里开始
- 在哪里暂停
- 怎样恢复
- 何时重试
- 何时终止
这张图一旦清楚,后面的 durable execution、队列和重试策略都会更容易落地。