AI测试-05-Agent Workflow执行多步骤测试任务时怎么做状态管理和失败恢复
一提到 Agent Workflow,最容易先想到的是多步骤规划、自动拆解任务、串联工具调用和减少人工编排。
这些能力当然重要,但只要它开始执行真实测试任务,问题就会立刻从“会不会规划”变成“出了问题怎么收”。
原因很简单。多步骤测试任务通常同时具备下面几种特征:
- 步骤之间存在顺序依赖
- 执行动作会改变环境或业务状态
- 一次失败可能污染后续上下文
- 工具调用、模型决策和环境异常会交织出现
- 补跑和恢复如果没有边界,很容易把现场改得更乱
这意味着 Agent Workflow 真正难的部分,并不是把任务拆成 5 步还是 10 步,而是要先回答下面这些更工程化的问题:
- 当前任务到底执行到了哪一步
- 哪一步已经真正生效,哪一步只是模型规划过
- 当前失败属于参数错误、工具错误、环境错误,还是状态漂移
- 这次失败能不能重试,应该从哪一层恢复
- 恢复动作会不会覆盖现场、重复写数据或者误伤后续步骤
如果这些问题没有先收稳,Agent Workflow 很快就会变成一种看起来很自动、实际上很难治理的执行方式:
- 任务失败后只能整条重跑
- 重跑后问题更难复现
- 人工接管时说不清哪一步已经真正执行过
- 报告里只有“失败”,没有失败前的状态变化
- 环境问题、模型问题、工具问题被混在一起
所以这篇文章只聚焦一个更实际的问题:
Agent Workflow 在执行多步骤测试任务时,状态应该怎么分层记录,失败应该怎么分类,恢复应该怎么设计,才能让整条执行链路真正具备可观察、可补跑、可回放和可收敛的能力。
一、先把边界说清:多步骤测试任务里的状态,不是“成功”或“失败”两个字
多步骤任务最常见的错误,是把状态理解成:
- 成功
- 失败
- 运行中
这类状态在看板上够用,在恢复上完全不够。
因为多步骤测试任务里的“状态”至少有两个维度:
- 生命周期状态:任务和步骤此刻处于什么阶段
- 语义状态:这个阶段产生了什么真实影响
例如“下单后校验支付状态”的任务里,某一步可能显示为执行失败,但这一步背后的真实语义可能已经分裂成几种情况:
- 接口没发出去,业务状态没有变化
- 接口发出去了,结果没拿到,但订单已经创建
- UI 点击成功了,但页面跳转没被记录
- 数据已写入,后置校验失败
- 工具调用超时,但服务端异步任务仍在继续
如果平台只记录“步骤失败”,恢复动作就会非常危险,因为系统根本不知道:
- 失败前是否已经造成写入
- 当前会话还能不能继续
- 后续步骤是不是已经失去前提
- 环境是否已经进入脏状态
所以在 Agent Workflow 里,状态管理的第一原则不是“状态枚举多一点”,而是:
把不同层级、不同语义的状态拆开,避免用一个简单结果覆盖整个执行现场。
二、状态分层:至少拆成 5 层,才能支撑恢复
更适合多步骤测试任务的状态模型,通常至少要拆成下面 5 层。
1. 任务层状态
任务层状态回答的是:这一次任务实例整体进行到了哪里。
这一层建议至少包含:
PENDING:待执行PLANNING:规划中RUNNING:执行中WAITING_RETRY:等待系统补跑WAITING_MANUAL:等待人工接管FAILED:已失败COMPLETED:已完成CANCELLED:已取消
任务层状态的价值不是展示进度,而是给外部系统一个清晰信号:
- 调度层知道任务是否还能继续占资源
- 报告层知道是否应该封板
- 人工接管层知道现在是补跑还是直接终止
2. 步骤层状态
步骤层状态回答的是:每一个步骤是否真正被规划、执行、确认和收口。
这一层不能只用“成功/失败”,更稳的做法是拆成:
PLANNED:已规划,尚未执行READY:依赖满足,准备执行EXECUTING:正在执行APPLIED:动作已生效,但结果尚未完全确认VERIFIED:动作结果已确认FAILED_RETRYABLE:失败但可补跑FAILED_TERMINAL:失败且应终止链路SKIPPED:前置条件不满足,被跳过ROLLED_BACK:已执行回滚
这里最关键的是 APPLIED 和 VERIFIED 不能混。
例如:
- 页面按钮点下去了,不代表结果页已经正确出现
- 调接口返回
200,不代表异步任务已经真正完成 - 发起删除动作成功,不代表数据已经在读链路里消失
这层拆开以后,恢复时才能知道是:
- 补确认
- 补观察
- 重试动作
- 还是直接终止
3. 会话与上下文层状态
这一层回答的是:任务当前依赖的执行上下文是否仍然可信。
常见内容包括:
- 当前登录态是否仍然有效
- 当前页面或路由是否仍然正确
- 当前测试账号是否已被占用
- 当前浏览器、设备、会话 ID 是否发生变化
- 当前中间变量是否仍然可用于后续步骤
这层状态非常容易被忽略,但它决定了“能不能继续在原地恢复”。
很多恢复失败,不是恢复动作设计错了,而是上下文已经变了:
- 页面被强制跳转
- Token 已过期
- 会话被别的流程踢掉
- 临时数据被后台清理
- 设备或 Pod 已经重建
如果这层状态没有单独记录,平台就会在错误上下文里继续执行,造成更大污染。
4. 环境与资源层状态
这一层回答的是:任务外部依赖当前是否可用,以及资源是否还被正确占用。
常见对象包括:
- 测试环境实例
- 账号池和租约
- 浏览器实例或移动设备
- 数据库连接、消息队列、存储桶
- 依赖服务和第三方接口
这层状态如果不单独管理,就很容易把环境问题误判成模型或步骤问题。
例如一次“步骤 4 无法确认订单状态”的失败,真正根因可能是:
- 读库延迟
- 测试账号被其它任务复用
- 环境发布中途滚动
- 队列积压导致异步结果未回写
这时直接从步骤层重试,通常只会重复报错。
5. 证据层状态
这一层回答的是:当前现场有没有足够证据支撑回放、归因和恢复决策。
建议至少记录:
- 任务级时间线
- 步骤输入与输出
- 模型规划结果
- 工具调用参数
- 截图、录屏、DOM 或控件树快照
- 关键日志片段
- 环境版本、会话 ID、租约 ID
证据层不是为了写报告更好看,而是为了避免恢复动作建立在猜测上。
没有证据层,恢复就会变成:
- 看起来像没执行过,那就重跑
- 看起来像网络问题,那就重试
- 看起来像页面问题,那就重开浏览器
这种恢复方式在短链路里还能勉强工作,放到复杂任务里几乎一定会把现场越修越乱。
三、失败分类:先判断失败类型,再决定恢复方式
Agent Workflow 最怕的一种实现,是所有失败都走同一条路:
- 失败
- 重试
- 还失败
- 整条任务终止
这类实现通常不是“恢复策略简单”,而是“根本没有失败分类”。
更适合多步骤测试任务的失败分类,至少应该拆成下面 5 类。
1. 参数与规划类失败
这一类通常发生在动作真正执行之前,例如:
- 模型规划了不允许的动作
- 参数缺字段
- 参数类型错误
- 资源 ID、环境 ID 不合法
- 本步骤引用了上一步不存在的输出
这类失败的特点是:
- 尚未真正改变业务状态
- 适合在工具执行前就被拦住
- 恢复重点是重新规划或补参数,不是重启环境
更合适的做法是:
- 标记为
FAILED_RETRYABLE - 重新生成该步骤规划
- 对参数做二次约束
- 保留原始规划供后续审计
2. 工具执行类失败
这一类通常发生在工具层,例如:
- 浏览器操作超时
- 接口调用失败
- 数据查询报错
- 设备连接断开
- 文件取证动作失败
这类失败能不能重试,关键看两件事:
- 该动作是否幂等
- 动作是否可能已经部分生效
如果没有这两层判断,系统就很容易把“可能已生效的写动作”当成普通失败去重试。
3. 环境与依赖类失败
这一类通常不是单个步骤自身能解决的,例如:
- 测试环境发布中
- 下游依赖超时
- 队列积压
- 数据库只读切换
- 第三方服务限流
这类失败最常见的误判,是把它当成步骤执行问题继续重试。
更合适的处理是:
- 暂停任务推进
- 冻结当前上下文
- 重新探活环境与依赖
- 判断是否整体延期、切环境或人工接管
4. 状态漂移类失败
这是 Agent Workflow 最有代表性的一类失败。
它的典型特征是:
- 当前步骤看起来失败了
- 但真正原因不是步骤本身
- 而是前置上下文已经漂移
例如:
- 当前页面不是预期页面
- 登录态失效
- 本该引用的订单号来自过期会话
- 同一个任务里的中间变量被覆盖
这类失败如果不单独分类,系统很容易一直在错误上下文上重试,最后把所有步骤都跑脏。
5. 结果不确定类失败
这类失败比普通报错更危险,因为它既不是明确成功,也不是明确失败。
典型场景包括:
- 工具超时,但服务端可能已经处理
- 页面没回显,但后台状态可能已经变化
- 结果采集失败,但动作本身可能完成
- 断言链断在中间,最终状态未知
这类失败不能直接重试,也不能直接判失败。
更稳的做法通常是:
- 先进入
WAITING_MANUAL或WAITING_RETRY - 启动补确认动作
- 查日志、查库、查接口、查事件链
- 确认“是否已生效”之后再决定是否回滚或补跑
四、恢复策略:不是所有失败都要“从头再来”
恢复设计真正要解决的,不是“怎么继续跑”,而是:
在不破坏现场、不重复写入、不丢失证据的前提下,把任务尽量收回到一个可继续、可终止或可人工接管的状态。
更合适的恢复策略,通常可以分成 4 层。
1. 步骤内重试
适用场景:
- 幂等读操作
- 纯取证动作
- 页面元素瞬时不可见
- 网络瞬断但业务未写入
要求:
- 有明确最大次数
- 每次重试前重新确认上下文
- 重试结果单独记录,不覆盖首错证据
不适合直接走步骤内重试的场景包括:
- 创建、删除、支付、提交这类可能写状态的动作
- 会触发异步链路的动作
- 已经判断为上下文漂移的动作
2. 步骤级补跑
适用场景:
- 当前步骤失败,但前置步骤状态可信
- 当前动作可安全重放
- 上下文可通过少量动作恢复
这类补跑的关键不是“重试这个步骤”,而是先做一个小恢复:
- 刷新会话
- 重新打开正确页面
- 重新获取最新资源 ID
- 重新确认依赖服务可用
如果这些上下文恢复动作没有先做,步骤级补跑通常只是重复失败。
3. 子流程级恢复
适用场景:
- 中间步骤失败导致后续上下文整体失效
- 当前任务可自然拆成多个阶段
- 已完成阶段的结果可以冻结
例如一个长链路任务可以拆成:
- 登录与准备阶段
- 核心业务执行阶段
- 验证与取证阶段
一旦“核心业务执行阶段”里出现状态漂移,更稳的恢复方式通常不是只重跑单个动作,而是从该阶段入口重新进入,并且复用前一阶段确认过的产物。
4. 人工接管与安全终止
适用场景:
- 高风险写操作后状态不确定
- 同一类失败连续触发
- 环境异常范围过大
- 证据不足以支撑自动恢复决策
这类场景里,自动恢复继续推进的收益通常已经低于风险。
更合适的做法是:
- 冻结任务
- 挂起资源租约
- 保留全部中间状态和证据
- 给出建议的人工排查入口
- 明确“哪些动作已经生效,哪些仍未确认”
这一步看起来像保守处理,但它真正避免的是平台把一次局部失败升级成一次全链路污染事故。
五、最小执行骨架:先把恢复点设计进流程里,而不是失败后再补
如果希望 Agent Workflow 真正可恢复,更稳的做法不是“失败后写一堆兜底逻辑”,而是在执行骨架里预留恢复点。
一套更适合第一阶段落地的最小执行骨架,可以这样设计:
1. 任务初始化
在任务开始前先固定下面这些信息:
- 任务模板 ID
- 环境 ID
- 租约资源 ID
- 可用工具白名单
- 关键断言点
- 恢复策略级别
- 是否允许自动补跑
初始化阶段的目标不是启动执行,而是先把可恢复边界写清楚。
2. 规划与步骤冻结
规划结果不要直接一边生成一边执行。
更稳的做法是:
- 先生成步骤草案
- 对每一步标注类型:读、写、取证、确认、恢复
- 对每一步标注幂等属性
- 对高风险写步骤附带恢复约束
这样后面一旦失败,平台才能根据步骤属性决定是重试、补确认、子流程恢复,还是人工接管。
3. 执行前快照
每个关键步骤执行前,至少记录:
- 当前步骤输入
- 当前页面或会话状态
- 环境健康探活结果
- 上一步关键输出
- 当前证据引用点
执行前快照的价值,是让恢复决策建立在“这个步骤开始前到底是什么样”之上。
4. 执行动作与即时确认
动作执行后,不要只看工具层返回。
更稳的做法是:
- 动作执行
- 即时确认动作是否已落地
- 判断状态是否不确定
- 需要时进入补确认
- 再决定是否推进下一步
这一步能显著减少“把未确认动作当成成功继续推进”的问题。
5. 恢复决策节点
一旦出现失败,不要立即重试。
先做 4 个判断:
- 失败类型是什么
- 当前步骤是否可能已生效
- 上下文是否仍可信
- 证据是否足够支撑自动恢复
只有这 4 个问题答案清楚,恢复动作才有意义。
6. 收口与报告
任务结束时,报告里至少要明确:
- 最终停在第几步
- 哪些步骤仅规划未执行
- 哪些步骤已执行但结果不确定
- 哪些恢复动作被触发过
- 哪些资源已回收,哪些仍需人工清理
如果报告只写“第 6 步失败”,后续接手的人仍然要从头还原现场,平台的恢复能力就没有真正落地。
六、一个更实用的状态与恢复记录表
多步骤任务里,建议至少保留一张这种粒度的记录表:
| 步骤 | 动作类型 | 当前状态 | 是否已生效 | 上下文可信 | 失败类型 | 恢复方式 | 证据 |
|---|---|---|---|---|---|---|---|
| 1 | 登录 | VERIFIED | 是 | 是 | 无 | 无 | 截图、会话 ID |
| 2 | 创建订单 | APPLIED | 待确认 | 是 | 结果不确定 | 补确认 | 接口日志、订单号 |
| 3 | 校验回写 | FAILED_RETRYABLE | 否 | 否 | 状态漂移 | 子流程恢复 | 截图、DOM、控制台日志 |
这张表的价值不是展示,而是支撑:
- 自动恢复判断
- 人工接管
- 报告收口
- 同类故障归类
七、常见坑:状态和恢复最容易写坏的 6 个地方
1. 只记录任务状态,不记录步骤语义状态
结果是任务一失败,系统完全不知道前面哪些写动作已经生效。
2. 把“工具返回成功”当成“业务结果已确认”
接口 200、按钮点击成功、脚本没有报错,都不等于业务状态已经稳定。
3. 把所有失败都交给统一重试器
统一重试器适合瞬时读失败,不适合覆盖写动作、不确定结果和上下文漂移。
4. 恢复时覆盖首错证据
一旦补跑前没有冻结首错现场,后续所有排查都会被污染。
5. 人工接管时没有明确“已执行边界”
最常见的后果是人工又执行了一遍写动作,造成重复创建、重复扣减或重复通知。
6. 环境异常和 Agent 失败没有分流
环境发布、依赖故障、资源租约异常如果都挂在步骤失败下面,报告里看起来像 Agent 不稳定,实际问题根本不在 Agent。
八、真实案例:一个下单回归任务为什么越恢复越乱
1. 场景
一次 AI 驱动的回归任务需要完成下面这条链路:
- 登录后台
- 创建测试订单
- 调用支付模拟接口
- 进入订单详情页校验状态
- 拉取日志并生成证据包
这条链路被编排成一个 Agent Workflow,允许在单步失败时自动补跑 1 次。
2. 执行
任务前 3 步执行正常:
- 登录成功
- 订单创建成功
- 支付模拟接口返回成功
第 4 步进入订单详情页时,页面长时间未出现“已支付”状态,系统判定为步骤失败,并触发自动补跑。
3. 现象
补跑后问题不但没有消失,反而出现了更多异常:
- 第二次进入详情页时跳到了登录页
- 自动恢复重新执行了“创建订单”
- 报告里出现了两个不同订单号
- 最后任务被判为“详情页断言失败”
表面上看,这是一次普通 UI 断言失败。
但真正的问题已经不是“第 4 步没断上”,而是恢复过程把原始状态打乱了。
4. 排查
排查按状态层逐层展开:
先看步骤层。
原始执行记录显示第 2 步“创建订单”状态是 APPLIED,但没有被提升到 VERIFIED,因为订单号采集逻辑晚于页面跳转,导致系统没有把订单号冻结到上下文里。
再看会话层。
第 4 步失败前,后台登录态已经接近过期,补跑动作重新打开详情页时被系统重定向到了登录页,但平台没有把“上下文漂移”识别出来。
再看恢复策略。
统一重试器把第 4 步视为“可补跑步骤”,但恢复脚本内部为了拿到订单详情页入口,错误地回调了“创建订单”子流程。
最后看证据层。
首错截图和第一次支付接口回包都在,但第二次恢复把任务主上下文里的订单号覆盖了,导致报告里两个订单号混在一起。
到这里可以确认根因不是“订单状态没更新”,而是三件事叠加:
- 步骤状态没有把
APPLIED和VERIFIED分开收口 - 会话漂移没有独立识别
- 恢复脚本没有显式声明可重放边界
5. 修复
修复动作分成 4 步:
第一步,重构步骤状态。
创建订单后必须先冻结订单号和接口回包,再把步骤从 APPLIED 提升到 VERIFIED。
第二步,补上下文探针。
每次进入需要登录态的页面前,先检查会话状态和当前路由,一旦发现被重定向到登录页,直接判定为“状态漂移”而不是普通步骤失败。
第三步,拆恢复策略。
详情页校验失败只允许做“上下文恢复 + 补确认”,不允许回跳到写订单子流程。
第四步,冻结首错证据。
一旦触发恢复,首错步骤的截图、接口回包、订单号和日志引用必须写入只读证据区,后续恢复不能覆盖。
修复之后,同类任务再遇到类似问题时,报告能直接给出更准确的收口:
- 订单已创建并支付模拟成功
- 当前失败属于会话漂移
- 原始订单号已冻结
- 建议从“重新登录后进入详情页确认”恢复,而不是重建订单
这时候恢复动作才真正从“碰运气补跑”,变成“基于状态和证据的受控恢复”。
九、结语:Agent Workflow 能不能用,最终看恢复时是不是还知道自己在干什么
多步骤测试任务里,Agent Workflow 的价值不只是自动化执行更多步骤,而是把原本依赖人工串起来的计划、执行、确认、取证和恢复收成一条可治理的链路。
这条链路一旦进入真实平台,最先决定它能不能长期可用的,通常不是模型能拆多少步,而是下面这几件事有没有收稳:
- 状态是不是分层记录
- 失败是不是先分类再恢复
- 恢复是不是有明确边界
- 首错现场是不是能被冻结
- 任务结束时是不是说得清哪些动作已经真实生效
如果这些问题没有被认真设计,Agent Workflow 很容易停留在“能跑一遍”的阶段。
只有把状态管理和失败恢复真正做成平台能力,它才有机会从演示链路走到长期可用的工程系统。