前阵子我把一个在 FPS 游戏环境里调出来的 AI Agent 决策模型,迁移到了 Web 自动化测试场景里跑了一轮。这个模型代号叫 Jev,最开始它只会玩 DOOM——在一张张满是拐角、弹药稀缺、敌人从不跟你讲武德的地图里找路、索敌、控血、躲伤害。本质上,它就是一个“在极端动态环境里持续做决定的大脑”。迁移到自动化测试之后,它负责的事情变成了:盯住页面状态、判定异常、决定下一步测什么、发现元素不稳定时是否回滚、以及什么时候该向测试报告里喊一声“这里有问题”。
这篇文章我想完整讲一遍 Jev 的决策模型是怎么从 DOOM 世界搬到自动化测试世界的,中间做了哪些任务映射、踩了哪些坑、实测结果如何。如果你也在做测试智能化、UI 自动化的复杂场景,或者你想知道“游戏 AI 的经验到底能不能用到工程里”,这篇应该对你有用。我不会讲太多晦涩的算法公式,重点是整个决策链路的思路和落地细节。
1. 为什么拿 DOOM 当 AI Agent 的第一块试验田
很多人听到 DOOM 第一反应是“一个打枪游戏”,但在 AI 决策模型这个领域,DOOM 这类 FPS 环境是一个标准到不能再标准的试验场。它和围棋、Atari 小游戏不一样的地方在于:DOOM 不是一个“信息全开”的棋局,玩家只靠一帧一帧的画面和有限的弹药血量数据,去推断屏幕外有没有敌人、该往前冲还是蹲守。这种环境对决策模型的要求,几乎就是自动化测试面对真实 Web 应用时的要求。
1.1 部分可观测性与“只看得到眼前一亩三分地”
DOOM 里的智能体永远看不到完整地图,它只能靠当前屏幕画面、雷达提示、血量弹药数字来估计局面。这和测试工程师面对一个动态页面时差不多——你不可能让自动化脚本把整个页面所有状态都拿在手里,你只能通过 DOM 结构、接口返回值、网络状态这些“局部观测”去猜测系统整体是否健康。
Jev 在 DOOM 环境里学到的第一件事就是:对未知区域保持怀疑,不要因为眼前安全就认为全图安全。这一点在自动化测试里被原封不动地搬了过来。一个页面局部加载正常,不代表整条业务流程没有隐患。Jev 的决策逻辑里专门有一个“未知状态”标记,凡是当前页面未覆盖到的分支,在决策权重上自动降级,优先去探索那些没被验证过的路径。
1.2 实时对抗与资源约束:弹药、血量就是你的测试预算
DOOM 里最折磨人的不是操作,而是资源管理。血量低了要退回来找血包,弹药不够要换武器,敌人扎堆的时候必须先撤再打。这一套“资源约束下的实时对抗”,和自动化测试跑批任务时的处境几乎一模一样:可用的执行时间有限,测试环境稳定性有限,接口被调用次数有限。你不能什么都跑,只能决定当前最值得跑的场景。
Jev 的决策模型在游戏阶段就被逼出了一种“动态预算分配”的能力。它会给每一个待执行动作算一笔账:这个动作的预期收益是多少,要消耗多少资源(时间、网络、环境配额),失败的代价是什么。算完之后再决定做不做、什么时候做、做到什么程度。迁移到自动化测试之后,这笔账从“弹药”“血量”换成了“用例成本”“执行时间窗口”“环境稳定性评分”,但内心的决策逻辑没有变。
1.3 游戏里的“记分牌”是天然的奖励信号
强化学习最怕的是没有明确的奖励信号。DOOM 在这方面特别友好:击杀数、受伤值、弹药消耗、物品拾取、关卡探索率,每一条都是可观测、即时、数值化的反馈。可以说 DOOM 自带了一张完整记分牌,给智能体训练提供了清晰的奖惩来源。
自动化测试世界里,其实也有记分牌:用例通过率、异常发现数、覆盖率、脚本执行耗时、误报率。问题在于很多团队的测试数据没有结构化,一堆散落的日志和截图躺着,没人把它们提炼成可用于决策的反馈信号。Jev 迁移过程中我干的第一件脏活,就是把某模拟项目 X 的测试结果全部清洗成结构化指标,做成了一套类似游戏记分牌的反馈矩阵。没有这个,后面所有的“决策”都是空中楼阁。
2. Jev 的决策模型骨架:感知-推理-执行三层怎么搭
在 DOOM 里跑得通的决策模型,核心不是某个神经网络,而是一套很有工程味的三层结构:感知层、推理层、执行层。很多做自动化测试的人一说 AI 就想着“端到端模型输入截图输出操作”,但 Jev 的设计思路恰恰相反——它把决策拆成可解释、可干预、可回滚的三段,这样每段都能单独测试、单独调参,出了问题也更容易定位。
2.1 感知层:从“像素画面”到“页面状态摘要”
游戏里 Jev 的感知层做的事情,是把一帧帧画面压缩成有语义的“战场摘要”:我在地图哪个区域、朝哪个方向、有哪些敌人可见、当前血量弹药百分比、最近一次被攻击是什么时候。它不会记住每个像素,只保留对决策有用的状态向量。
迁移到自动化测试后,感知层的任务同样是把杂乱的页面信息压缩成状态摘要。我给它设计了几个特征维度:
- 页面元素完整性:关键按钮、输入框、表格数据是否存在且可见
- 响应指标:接口响应时长、资源加载失败数量、控制台报错数量
- 状态异常标记:是否有弹窗遮挡、是否有数据加载不出来的区域
- 业务阶段定位:当前处于流程的第几步,比如登录页、列表页、下单确认页
这里有一个特别值得说的点:感知层不能只依赖 DOM 层级结构。Jev 在游戏里学会了一个习惯——结合多种信息源交叉验证。比如游戏里判断“前方拐角有没有敌人”,它不会只信雷达,还要看画面里有没有阴影移动。在测试场景里也一样,判断“某个按钮是否可点击”,不能只看 HTML 里有没有这个元素,还要看它是否被遮罩、是否处于 disabled 状态、点击后接口是否真的有响应。我把这套交叉验证写成了一个独立的感知模块,Jev 的所有决策都基于这个模块产出的状态摘要,而不是直接拿原始 DOM 去拍板。
2.2 推理层:事件驱动的策略选择
推理层是 Jev 的大脑核心。最开始我也考虑过端到端的深度强化学习策略,调了一个多月,又慢又难解释。后来换成了“事件驱动的分层策略选择”,效果立刻好了起来。
所谓事件驱动,就是先把业务里可能发生的“事件”枚举出来,每个事件对应一组候选策略。在 DOOM 里事件大概是:听到枪声、血量低于 30%、发现敌人、弹药耗尽、遇到死路。每个事件后面挂着不同的战术选项。在自动化测试里事件变成了:页面加载超时、断言失败、新用户注册校验不通过、接口返回 500、弹窗出现、元素找不到。每个事件一样挂着一组候选策略。
Jev 的推理过程分两步。第一步是识别当前最主要的事件,第二步是在该事件的候选策略集合里选一个分数最高的策略。分数计算会考虑当前状态摘要、历史执行结果、资源预算剩余量三个因素。相比单一模型直接输出动作,这种分层方式的好处是:每一个决策都能追溯到具体的事件和策略,出问题的时候你可以直接问“它为什么在这时候读到了‘页面加载超时’事件?它凭什么选了‘等待并重试’而不是‘立即截图标记异常’?”
2.3 执行层:置信度门槛与回滚机制
执行层是 Jev 和真实世界握手的地方,也是从游戏环境带过来的最大教训。在 DOOM 里,一个错误的操作可能直接掉血甚至死亡,所以 Jev 学会了一个习惯:动作执行前先看置信度,低于阈值的动作要么不做,要么先做一个小规模试探。
自动化测试里,这个习惯变成了“试探-确认-执行”三步走:
- 试探:先做一个只读操作,比如获取元素状态、检查接口返回值,不产生数据变更
- 确认:把试探结果和预期状态做比对,达到阈值才进入正式动作
- 执行:执行真正的操作,比如点击下单按钮、提交表单
- 验证:执行后立刻读取新状态,判断是否产生了预期影响,否则触发回滚
回滚机制在游戏里对应的概念是“立刻撤退到安全位置回血”。在测试场景里,回滚可能是刷新页面、清除当前输入、恢复数据库快照、或者跳过这条用例继续下一条。我专门给 Jev 配了一套回滚优先级表,比如遇到数据被污染这种风险,先触发数据库快照恢复,再清页面缓存,最后才考虑整个环境重建。这三层结构建好之后,Jev 才真正具备了从 DOOM 走向测试的基本骨架。
3. 从 FPS 战斗任务到测试任务:一张任务映射表
很多人问,游戏里的敌人和测试里的 Bug 根本不是一回事,怎么迁移?我的经验是:不要看表面的元素,要看任务的抽象结构。DOOM 里的“击杀敌人”抽象出来是“发现异常目标、消耗资源处理它、确认目标消失”。而测试里的“处理一个 Bug”抽象出来是“发现异常行为、定位原因、验证修复”。结构非常相似。
3.1 目标发现:从敌人检测到异常识别
FPS 里敌人出现有许多前兆:声音、阴影、视线边缘的色块。Jev 从 DOOM 学到的不是“看到红色就开枪”,而是“把各种微弱信号综合起来推断敌情”。迁移到自动化测试后,这套思路用到异常识别上非常自然。
比如一个订单页面,正常情况下接口返回在 200ms 以内,页面表格在 2 秒内渲染完成。某一次执行时接口用了 800ms,页面 4 秒才渲染完。传统的自动化脚本可能等默认超时的 10 秒,然后判定页面正常。Jev 不一样,它会像嗅到危险气味一样,把这个“偏离基线”的信号记下来,然后主动调低后续动作的置信度,开始做更细致的检查:是不是网络波动?是不是数据库慢查询?是不是某个接口报错被吞了?
我在某模拟项目 X 上做过一个对比测试:传统脚本和 Jev 同时跑一组包含 20 条用例的业务流程,其中埋了 5 个“非阻断型异常”(比如页面报错但不影响主流程)。传统脚本 20 条全绿通过,Jev 在一条用例中途就把可疑信号上报了,最后人工确认这 5 个异常全被它提前抓到了。这就是“识别异常前兆”和“等到彻底报错再处理”的区别。
3.2 地图导航:从 DOOM 地图到页面状态流
游戏里的地图理解,放到测试场景就是业务流程拓扑。DOOM 里 Jev 脑子里有一张“已探索区域地图”,标注哪些地方去过、哪些地方被封锁、哪些地方值得再去。自动化测试里,我给它建了一张“业务状态图”,节点是页面状态(登录页、列表页、详情页、订单确认页),边是操作(输入账号、点击查询、选择商品、提交订单)。
这张图的价值在于,Jev 可以在图上做规划。比如它想覆盖“订单提交”分支,但当前在“列表页”上,它不会像普通脚本那样只按写死的路径走,而是会决策:是先回到登录页重新走一遍完整流程,还是通过浏览器后退按钮快速返回列表页再进入详情页?决策依据是当前的测试预算和状态稳定性。预算充足就选完整路径,预算紧张就选捷径。实测下来,这种规划能力让同样预算下的用例路径覆盖率提升了 40% 左右。
3.3 资源管理:弹药血量映射到预算和重试次数
FPS 里的弹药血量是硬通货,没了就得去捡、去等。自动化测试里的硬通货是“时间预算”和“重试额度”。Jev 在 DOOM 里学会了省弹药,在测试里学会了省重试。
传统自动化脚本经常干一件事:元素找不到就疯狂重试,默认重试 3 次、5 次,甚至 10 次。这在页面真的没渲染出来的时候纯粹是浪费时间和接口资源。Jev 的做法是给每次重试设置一个递减的收益评估:第一次找不到元素,重试一次;如果第二次还找不到,就把置信度砍半,同时切换检查策略,比如先查网络、查控制台报错;如果第三次还找不到,就不再盲目重试,而是直接上报异常并跳到别的用例。
这套“资源约束下选择放弃”的能力,是 Jev 从游戏里带出来的最珍贵习惯。因为 DOOM 里有时候最正确的操作就是“不进那条走廊”,回到安全区补给,换一条路走。自动化测试里最正确的操作有时候也是“不跟这条用例死磕”,记录现场、上报异常、换一条用例继续跑,把有限的测试资源留给更可能发现问题的路径。我在模拟项目 X 上的实测数据里,Jev 的重试次数比传统脚本少了 60%,而异常发现数反而多了 30%。
4. 在模拟项目 X 上的落地实测:结构、配置与结果
理论说再多,不如直接看一次真实落地。我挑了一个某公司内部的模拟电商订单管理系统来跑 Jev,这个系统有 6 个核心页面、3 条主要业务流程,页面间耦合度高,而且数据库状态会随着测试执行不断变化,是个很典型的“动态状态困扰自动化”的场景。整个接入过程我拆成了三个阶段来推进。
4.1 接入结构:感知模块怎么和现有测试框架融合
我没有把 Jev 写成一套全新的测试工具,而是做了一个“决策中控”包裹在已有测试框架外面。这样既有框架已经实现的用例逻辑可以继续用,Jev 只在中间做调度和决策。结构大致是:
- 底层还是浏览器自动化脚本,负责具体操作和元素定位
- 中层是状态采集器,负责产出状态摘要
- 上层是 Jev 推理引擎,订阅状态摘要,输出动作决策和控制指令
- 最外面是报告模块,记录每个决策点的事件、置信度、策略选择理由
这套结构的最大好处是可以渐进式迁移。你不需要一次性让 Jev 接管所有用例,可以先让它只负责一条业务流程的“重试判定”和“异常上报”,跑稳了再把覆盖范围扩大。我当时就是这么干的:先用登录-搜索-查看详情这条最稳定的链路试了三天,确认没有误判之后,才放行到整个下单流程。
4.2 关键配置:奖励函数和动作空间如何从游戏语义替换成测试语义
Jev 从 DOOM 出来之后,内部还保留着游戏时代的策略参数和奖励权重。直接拿过来用肯定不行,我把迁移过程做成了这张映射表,也可以说是模型里最核心的一部分:
| DOOM 语义 | 自动化测试语义 | 初始权重 | 说明 |
|---|---|---|---|
| 击杀敌人 | 发现一个真实异常并确认 | 0.35 | 异常发现是核心目标 |
| 掉血 | 用例失败或断言不通过 | -0.25 | 克制负面事件 |
| 拾取弹药 | 成功执行一个业务操作 | 0.10 | 维持流程推进 |
| 探索新区域 | 覆盖一条未走过的业务分支 | 0.20 | 提升覆盖率 |
| 被敌人命中 | 出现误报、假阳性 | -0.30 | 重点打压误报 |
| 获取治疗包 | 回滚到安全状态 | 0.05 | 允许恢复,但不鼓励频繁回滚 |
这套权重不是一次定死的。第一轮跑完之后我发现 Jev 太偏向“发现异常”了,凡是有一点点风吹草动就上报,误报率居高不下。我把“误报”的负权重从 -0.15 一路压到 -0.30,同时把“确认异常”的流程加强——上报前必须经过两轮独立验证,误报率才从 26% 降到了 7% 左右。
4.3 实测数据对比
跑了一周,我把 Jev 的决策模式和传统线性脚本做了对比。为了保证公平,两组用例集相同,执行时间窗口都是 4 个小时,同一个环境,同一批埋点异常。结果如下:
| 指标 | 传统线性脚本 | Jev 决策模式 |
|---|---|---|
| 用例执行数 | 420 | 355 |
| 真实异常发现数 | 18 | 24 |
| 误报数 | 9 | 5 |
| 首轮失败后自动恢复并最终通过 | 26 | 41 |
| 平均单条用例耗时(秒) | 22.4 | 18.7 |
| 环境进入不可用状态的次数 | 3 | 1 |
数字背后的意思很明确:Jev 虽然执行的用例数少了 15%,但真实异常发现数反而多了 33%。而且它大量利用“失败后决策恢复”机制,把很多传统脚本直接放弃的用例救回来了。环境进入不可用状态的次数从 3 次降到了 1 次,这是因为 Jev 会在数据库状态异常之前自动降级为只读操作,而不是闷着头继续跑写操作把环境彻底搞脏。
4.4 一次真实的故障发现过程
我想讲一个具体案例,这个过程最能说明 Jev 的决策模型到底是怎么工作的。某一次下班前的执行窗口里,模拟项目 X 的商品列表页突然出现图片懒加载失效的问题。普通脚本跑到这里会尝试点击商品图片,点击毫无反应,预期中的跳转没有发生,于是脚本失败,记录一条“点击图片未跳转”的错误。
Jev 在这个节点上的决策链路完全不一样:
- 感知层先发现“页面渲染完成但图片区域大量空白”,这个状态摘要与平时明显偏离
- 推理层把“图片加载异常”识别为高优先级事件,但没有立刻判定失败
- 执行层触发试探动作:读取接口返回状态,发现图片 CDN 路径返回 403;再试一次,依然 403
- 推理层综合“非阻断型异常”的特征,决定执行“软失败”上报——标记为疑似问题但不中断整轮执行
- 后续同一轮里,Jev 遇到所有图片元素时都自动切换为“降低验证深度,只检查 DOM 存在性”
最后人工排查发现是某次发布把图片服务的鉴权配置弄坏了,接口报 403 但页面为了不显眼,JS 层做了容错处理,用户看到的是空白占位图,业务其实还能用。这种问题以前最容易漏掉,因为用例本身是能跑通的,只有 Jev 这种“看到画面偏离就起疑心”的决策模型会把它挖出来。
5. 迁移路上踩过的坑与调优心得
从 DOOM 到自动化测试的迁移,表面上是换了个环境,实际操作中有四个坑特别容易踩。我把它们记下来,给后面想做类似迁移的人当路标。每一坑都是真金白银换来的教训。
5.1 奖励函数迁移的惯性:别让“击杀奖励”变成“疯狂上报”
奖励函数在游戏里用的是“击杀 +1、掉血 -1”这套结构,换到测试领域很容易犯一个惯性错误:把“上报异常”当成高分奖励。结果模型会变成惊弓之鸟,什么都报,因为报得越多得分越高。
我第一轮跑出来的误报率高达 26%,罪魁祸首就是这个。后来我加了一个关键约束:异常上报的奖励不是在上报瞬间发放,而是要等人工复核之后才结算。模型必须承担“报错不实”的负反馈,才能学会克制。这个机制加入之后,误报率立刻下降并稳定在了 7% 出头。记住,奖励函数千万不要只看短期信号,不然你的测试模型会变成“喊狼来了的小孩”。
5.2 帧率节奏和轮询节奏的错配
DOOM 里的决策是以帧为单位做的,60 帧每秒相当于每 16ms 就要出一个决策。自动化测试完全不是这个节奏。第一次接入时我用模型带着游戏时代的“高频决策习惯”去跑测试,每秒钟都要对页面状态做一次全面采集,结果 …
页面状态采集是重量级操作,瞬时把浏览器资源占满,反而把正常的页面渲染拖慢了,部分用例出现了超时假失败。调整方式是把决策频率做慢,让 Jev 只在两个动作之间的“决策点”才启动感知流水线,不再持续高频轮询。这个改动让资源占用降了将近一半。如果你也在做类似场景,记得先算清楚环境的轮询开销,别让决策机制本身成为新的干扰源。
5.3 动作过于激进:重试和回滚都不是免费的
DOOM 里激进打法经常换来高击杀高掉血,测试场景里激进策略换来的是“高覆盖率和环境搞挂”。有一次 Jev 为了快速探索分支,在数据库快照恢复还没完成的时候就发起了依赖该快照状态的写操作,结果把数据状态搞得错乱,后续十几条用例全部受到污染。
后来我在执行层加了一个“环境状态锁”:只有状态标志位达到“稳定”时,才允许执行写操作;否则只允许做只读探测。这个锁机制直接影响策略选择得分,不是硬编码禁止,而是从决策源头降低了激进动作的优先级。加了之后,环境进入不可用状态的次数从 3 次降到了 1 次,同时真正的异常发现并没有减少。
5.4 如何判断模型是学会了,还是“背题”了
这是我最想提醒的一个问题。Jev 在某模拟项目 X 上表现很好,我当时一度以为模型真的理解了“测试决策”。直到我把它放到另一个没见过的内部模拟系统上,效果立刻掉了一半。这就像 DOOM 里的一套打法只适合特定地图,换一张地图就失效。
后来我做了两个改变。第一,在训练和验证时强制切分不同的业务流程,不让模型见过所有路径。第二,给感知层加了“特征扰动”,比如随机调整页面的元素加载顺序、随机注入网络延迟,让模型必须靠真实的状态特征做判断,而不是靠某个写死的页面指纹。经过这两轮改造之后,Jev 在新的模拟系统上异常发现率回升到了原系统的 85% 以上。做迁移验证的时候,永远要留一部分没见过的场景出来当试金石,别让模型的“高分”骗了你。
我在这次迁移里最大的体会,其实是“决策模型的迁移重点不在模型本身,而在于你愿不愿意把真实业务环境拆成和游戏世界同构的状态空间、动作空间和奖励系统”。DOOM 里的一套决策习惯——怀疑未知、控制预算、试探确认、果断回滚——放到自动化测试里同样成立,关键在于你用什么样的框架去接住它。
最后再分享一个小技巧。如果你也想在自己的测试框架里试 Jev 这套思路,不用一开始就做一个大而全的模型。先选一条最不重要的用例,用事件驱动的方式给它加上决策逻辑:遇到失败先不重试,而是采集状态、判断根因、决定回滚还是继续。跑两个礼拜看看误报率和异常发现数怎么变。这个小小的实验,足够让你判断这套思路适不适合你的业务现状。