首页 / 资讯中心 / 文章详情

多模态Agent的UI测试路径规划:从感知到决策的工程实践

多模态Agent的UI测试路径规划:从感知到决策的工程实践 ★ FEATURED ARTICLE
多模态 Agent 做 UI 测试最近是测试圈里最热的话题之一。一句话概括它解决的问题过去测试路径要靠人一条条写进脚本现在则可以让一个能看、能懂、能动手的 Agent 在真实界面上自己观察、自己规划下一步点哪里、输入什么、验证什么。这不是录制回放的升级版而是把测试路径设计这件事从人脑搬进了推理模型里。这篇文章我会聚焦路径规划这条链路Agent 怎么读界面、怎么决定下一个动作、怎么记住已经走过的状态、怎么避免走着走着迷路。内容主要来自我自己在某跨平台系统的智能体测试改造项目里的实践经验也包含对行业里公开方案的观察。适合正在做测试自动化的开发、想尝试智能体测试的 QA以及被脚本维护成本折磨的团队参考。1. 从手写脚本到看图决策路径规划的本质变化1.1 传统路径规划的瓶颈在哪里传统自动化测试里路径其实是被枚举出来的。每个用例都是一串写死的操作序列driver.find_element(By.ID, username).send_keys(tester) driver.find_element(By.ID, login-btn).click() time.sleep(2) assert driver.find_element(By.XPATH, //div[classwelcome]).is_displayed()这段代码背后有个隐含假设界面元素永远在预期位置导航流程永远按预期顺序发生。但这个假设在真实产品里基本不成立。按钮换了个位置、弹窗插进来、某个接口慢导致 loading 多转了两秒路径立刻就断了。更麻烦的是维护成本。一个中型后台系统可能有几百条用例涉及几十条业务路径。产品每周迭代测试脚本跟着改改到后面团队已经分不清是业务变了还是脚本写错了。我见过不少团队最后干脆放弃自动化退回手工点测因为脚本维护的边际成本已经超过了收益。传统方案不是没有改良比如 Page Object 模型、基于 DOM 属性的动态定位、视觉回归比对这些都能缓解元素变动的问题但都治标不治本。它们的共同局限是路径本身仍然是人设计的机器只是机械执行。路径规划这件事从来没有真正交还给系统。1.2 多模态 Agent 把路径规划变成了序列决策问题多模态 Agent 的范式转变在于它把测试路径描述成一个序列决策过程给定当前界面状态 s_t选择动作 a_t执行后观察到新状态 s_{t1}再选择动作 a_{t1}循环直到测试目标达成。这里的关键差异是闭环。传统的脚本一次性生成后就不再感知环境Agent 则每一步都重新观察、重新决策。界面变了没关系它可以根据新的截图和 DOM 信息重新规划路线。这就好比你开车去一个地方传统方式是背死路线Agent 方式是看路牌随时调整走错路口还能绕回来。在这个框架下写测试用例变成了给 Agent 描述目标。比如验证用户能从购物车完成结算Agent 需要自己规划出一系列动作找到购物车入口、确认商品存在、点击结算、填写收货地址、选择支付方式、提交订单、断言成功页面。后续每一步它都在看图 读结构 推理。需要说明的是这种能力依赖的是多模态大模型的推理基础。模型自身具备对 UI 截图的理解力——能认出按钮、输入框、弹窗、Toast 提示也能理解元素的语义。Agent 要做的是把这种理解力转化为稳定的测试执行能力。规划质量因此成了整个智能体测试系统成败的核心模型再强如果路径规划一塌糊涂测试结果也不可用。1.3 为什么重点讨论规划而不是生成很多人把 Agent 测试简单理解为让大模型写一段 Selenium 脚本——输入截图输出代码跑一遍完事。这个认知需要纠正。一次性生成完整脚本有两个致命问题。第一生成长代码时存在注意力漂移前面定位的元素失效了后面还在使用最后生成的脚本可能一个都跑不过。第二它没有利用执行反馈走了两步发现界面和预期不一致时脚本已经不知道该怎么调整了只能报错退出。规划则不同。规划是走一步、看一步、想一步。每一步的决策都基于上一步的真实执行结果而不是基于模型对界面的想象。这是 Agent 测试和 LLM 代码生成最本质的区别。规划算法可以很简单哪怕是一个贪心策略每次选最有把握的动作在线反馈带来的稳定性也远超一次性生成。2. 感知层拆解多模态 Agent 到底在用哪些信号读界面2.1 视觉通道截图里的空间信息密度多模态 Agent 的第一只眼睛是截图。截图带来的是空间和布局信息按钮在页面哪个位置旁边配了什么文字Logo 在左上角弹窗盖住了哪些区域下拉菜单展开后的选项在哪。这些信息文本通道往往给不了。举个例子网页里很多交互元素不是标准控件。一个自定义的卡片组件整块区域都可以点击但 DOM 里可能只有一个 div 配了一堆样式类。靠 DOM 属性去定位你拿不到任何语义暗示但截图上清清楚楚写着立即购买Agent 一看就知道这是个购买入口。还有一类场景必须靠视觉地图类产品、画布类编辑器、图表组件。这些界面的元素位置是动态渲染的DOM 结构是一个巨大的 canvas没有任何可交互节点的语义信息。这时候截图几乎是唯一能用的信号。视觉通道的代价是信息冗余和歧义。一张截图里可能有几十个可交互区域模型要从中选出最相关的那个依赖的是对用户意图的理解。如果截图分辨率低、界面元素过密模型就容易漏看。实践中我们会做两件事一是统一截图缩放规范保证视觉信息的稳定输入二是把截图分段对关键区域做局部放大给模型提供特写。2.2 文本通道DOM 与无障碍树的结构化信息如果截图是眼睛DOM 和无障碍树就是Agent的骨架。它们提供的是结构信息和元素语义哪些节点可以点击、哪些可以输入、元素的层级关系、标签文本、ARIA 角色。这里我强烈建议优先使用**无障碍树Accessibility Tree**而不是原始 DOM。原因有三语义更干净。无障碍树已经过滤掉了大量纯样式节点只保留对用户有意义的元素。角色信息直接可用。Button、TextField、Checkbox、Link这些角色直接对应动作空间里的操作类型。和视觉有对齐基础。无障碍树中的元素通常都有屏幕坐标可以画成边界框和截图做对应。DOM 的优势则是信息完整。很多前端框架渲染出来的节点有丰富的 data 属性和测试 ID这些对稳定定位非常有帮助。我常用的策略是无障碍树作为语义主干DOM 作为补充信号测试框架的专用定位属性比如>目标验证购物车结算流程 计划 1. 进入购物车页 2. 确认商品列表 3. 点击去结算 4. 填写收货地址 5. 选择支付方式 6. 提交订单 7. 校验成功状态第二层叫动作执行每一步落到具体动作时再结合当前界面状态决定。两层之间有一个对齐机制意图计划里的每一步是目标状态执行层每完成一步就标记一次如果跳过或改变了顺序Agent 会重新校正剩余计划。这种设计的价值是容错。如果第一步点击后弹出了登录框Agent 不会死板地执行第二步而是插入登录动作完成后再回到原计划。意图计划相当于给 Agent 提供了一个主线任务而执行层允许支线任务插入只要主线的目标状态最终达成。3.2 行动决策给候选动作打分的贪心策略每一轮规划的核心是在当前界面状态下从所有可交互元素中选择一个动作。我用的方法是对候选动作集合做多维打分分数由四部分组成意图相关度权重最高候选动作如果直指当前意图计划中的未完成步骤大幅加分。信息增益执行该动作后预期能获得多少新的界面信息。展开菜单比重复点击同一个切换按钮的信息增益高。风险系数会导致页面跳转、数据提交、弹窗关闭这类不可逆操作的动作风险分高非必要时靠后。状态置信度模型对这个元素确实是目标的把握程度低置信度的动作压后执行。打分的结果不一定要全局最优。真实 UI 测试场景里最优路径很难提前预知贪心策略配合合理的探索机制效果已经足够好。关键是要避免短视——每一步都选相关度最高的动作可能在几步之后走进死胡同。所以我们给信息增益设了一个最低阈值当相关度最高的动作连续两步都没带来新状态时强制切到探索模式。3.3 探索与验证的平衡不要让 Agent 到处乱点纯探索的 Agent 会在界面上到处乱点就像第一次进超市的小孩什么都想碰。这对测试目标来说毫无意义。纯目标驱动的 Agent 又太死板界面稍微变化就卡住。我最后采用的策略是目标驱动为主受控探索为辅。核心逻辑可以描述为Agent 先按意图计划推进一旦某个步骤执行失败或超时进入一个局部探索循环。这个循环的作用域被限制在当前页面内最多尝试若干个候选动作然后判断是否出现了意图目标相关的界面特征。如果出现了回到主线如果没出现认定目标不可达记录失败原因并结束。探索不是随机的而是按相似性组织的先尝试和目标语义最近的元素再逐步放宽。比如目标是设置里的退出登录第一次遍历优先点个人中心账号设置这类按钮不会去点帮助中心。4. 状态跟踪与路径记忆避免 Agent 原地打转4.1 状态表征怎么判断这个界面我去过路径规划里最尴尬的失败是 Agent 在一个页面里反复点同一个区域看起来在干活实际在转圈。要解决这个问题必须给状态一个可比较的表示。我给界面状态定义了三层指纹结构指纹无障碍树的关键节点哈希。提取所有可交互节点的角色 文本 坐标序列做一个排序后哈希。坐标归一化处理缩放避免分辨率影响。视觉指纹截图的感知哈希pHash。局部 UI 变化不会改变整体哈希只有页面切换或大面积变化才触发差异。文本指纹页面主要文本的抽取集合。用于检测内容加载完毕比如列表从空到有数据。三个指纹组合使用。判定是否进入新状态时视觉和结构指纹联合判断。如果视觉没变但结构变了说明可能是动态渲染如果视觉变了但结构没变可能是焦点状态或动画变化。4.2 去重与循环检测路径记忆的实战设计有了状态指纹就可以做访问历史的去重了。我维护了一个全局访问图节点是状态指纹边是动作。每次 Agent 执行完一个动作计算出新状态指纹后做三件事def check_state_cycle(new_state, action): if new_state in state_history: # 场景1完全重复说明这个动作没有带来新状态 mark_action_ineffective(action) return repeat if transition_exists(state_history, current_state, action, new_state): # 场景2状态转移已经在历史里出现说明形成环 mark_cycle_detected(current_state, action) return cycle append_state_history(current_state, action, new_state) return newrepeat和cycle的处理逻辑不同。repeat说明动作无效直接把它加入禁止动作集合近期不再尝试。cycle说明 Agent 在几个状态之间绕圈更危险除了禁止当前动作外还要触发回溯机制——回退到进入循环前最近的意图分支点重新规划。回退实现不能依赖浏览器的 back 按钮因为单页应用里 back 经常不可用。我用的方案是在动作执行前记录状态快照必要时通过执行反向动作关闭弹窗、取消操作回到分支点。如果反向动作也失败就做一个软重置回到首页重新从意图计划开头执行。软重置很粗暴但比在死循环里浪费算力强。5. 执行层的稳定性设计动作空间、重试与自愈5.1 动作空间先定义清楚 Agent 能做什么路径规划再聪明最终要靠执行层落地。我建议动作空间保持小而封闭而不是开放给模型自由发挥。动作越开放幻觉越容易混进来。我们的动作空间只有七种动作参数说明click目标元素 ID点击可交互元素input目标元素 ID、文本向输入框填入文本select目标元素 ID、选项值下拉选择scroll方向、距离滚动页面或容器open_urlURL导航到指定地址assert断言类型、期望值检查当前状态wait条件、超时等待界面变化动作空间封闭的意义在于模型只需要做选哪个动作 选哪个元素两个决策不需要发明新的交互方式。同时每个动作都有明确的参数校验比如click的目标元素必须是当前候选集里的元素 ID如果模型输出了不存在的 ID执行层会拒绝并重新请求。不过完全封闭也有问题比如复杂手势拖拽、上下滑动翻页在网页里很常见。我们的处理办法是提供一个补充动作接口把特殊交互封装成可配置的动作插件Agent 在规划时可以调用但参数格式仍然是结构化的。5.2 重试、超时与自愈规划失败后的兜底链路执行层一定会遇到失败规划器不可能预测所有运行时问题。我们设计了一个三级兜底机制第一级是动作级重试。执行click后如果界面在 N 秒内没有任何变化先重试一次确认元素没有因为动画延迟而丢失。第二级是状态级自愈。动作报错时元素被遮挡、输入框不可见Agent 收到具体的错误信息重新感知当前界面尝试修复性动作。比如弹窗挡住了目标按钮Agent 会去点击弹窗的关闭按钮。第三级是规划级重新规划。连续两次自愈失败就放弃当前步骤回退到意图计划层面重新生成从当前位置到达目标状态的计划。这一步会消耗较多推理资源我们给它加了频控防止 Agent 在同一个地方反复自我折腾。这里有一个关于断言的重要心得断言不是最后一步而是每一步都在做。Agent 每执行一步动作都应该用wait或assert型动作确认预期界面出现再进入下一步。否则路径规划相当于闭眼开车等到终点才发现方向错了。6. 实测翻车现场多模态规划的典型失败模式与对策6.1 视觉幻觉模型看见了不存在的按钮多模态模型最强的能力也是它最大的风险——它太擅长脑补了。有次实测中Agent 在一个空白区域点击了一枚按钮但执行层回报说该坐标根本没有可交互元素模型还不信坚持认为截图里显示了一个灰色按钮。对策有几个层面。第一动作元素必须从结构化信号里取不允许模型自由编造坐标。第二视觉信息只作为辅助信号不作为动作目标的直接来源。第三对识别置信度设置门槛低置信度时宁可多问一次 DOM也不要冒险执行。6.2 模态冲突截图和结构说的是两套话最典型的冲突场景是视觉可见树里没有。某个图形化选项是用 canvas 绘制的无障碍树里空空如也。或者相反树里有一堆元素截图里看不到因为它们在折叠菜单里。这种冲突没法完全靠规则解决。我的判断标准是如果目标元素的语义在视觉上足够明确有文本标签、有清晰的按钮形状就以视觉为主如果视觉上模糊就以结构为主。但无论如何执行前要做一次真实性校验——元素是否真的在屏幕上、是否可见、是否可交互。这个校验会拦截掉大部分幻觉动作。6.3 长路径漂移步骤越多错误累积越快路径规划在十步以内的短任务上表现很好一旦超过二十步失败率会迅速上升。原因是每步的小误差会累积——前一步点击的位置偏了几像素后一步感知到的界面就整体偏移越走偏得越远最后完全离题。应对长路径漂移我总结了三个有效手段中途锚点。在意图计划里显式设置验证点每完成 4~5 步就做一个状态断言发现偏移立即回溯避免误差滚雪球。步骤压缩。尽量把相邻的简单动作合并成一步复合动作比如填写表单作为一个目标状态而不是十个独立的 input 步骤减少模型决策次数。分支回滚。保留每个分支点的状态快照一旦检测到偏移不做整体重启而是回滚到最近的有效分支点保住之前的执行成果。这三个手段单独用效果都一般组合起来才能让 Agent 稳定跑完二十步以上的复杂流程。我在某跨平台系统的结算流程测试里试过不加锚点跑二十一步的长任务成功率大概只有四成加上锚点和分支回滚之后成功率能稳定到七成以上。这个差距说明长路径场景的问题主要不在模型能力而在工程防护机制。6.4 实操中最重要的三条经验如果让我把一个项目里踩过的所有坑浓缩成三条经验大概是第一条先保证结构的干净再谈模型的能力。很多 Agent 测试项目失败不是因为大模型不够聪明而是因为产品的可访问性树一塌糊涂、元素没有语义标签、测试 ID 缺失。先把这些工程基础补齐Agent 的能力才能发挥出来。第二条规划算法的目标不是最优路径而是可解释、可回退的路径。测试场景里稳定的执行比聪明的执行更重要。一条有点绕但每一步都有据可查的路径远远好过一条理论最短但偶尔灵异发挥的路径。第三条一定要把执行数据和规划日志保存下来。每次测试运行保存截图、状态指纹、动作打分、模型原始输出。Agent 测试调试非常依赖这些痕迹没有日志失败分析基本靠猜。我们后来做了简单的运行回放页面能逐帧看到 Agent 每一步在想什么调试效率提升了不止一个量级。多模态 Agent 做 UI 测试路径规划现在还不是一个开箱即用的成熟方案它更像一套需要团队根据自己的产品特征去打磨的框架。感知信号怎么融合、动作空间怎么设计、状态记忆怎么组织、兜底链路怎么搭建这些工程细节才是决定成败的部分。模型的能力在快速迭代但这些规划机制和工程经验在很长一段时间里都会是智能体测试落地的基础。如果你正在这个方向探索我上面写的这些坑和规则应该能帮你绕开一些弯路。
阅读完成 · 觉得有帮助?
咨询建站