☰
多模态Agent如何规划UI测试路径:从感知到重规划的工程实践
2026/10/22 12:07:34 网站建设 项目流程

1. 多模态 Agent 介入 UI 测试的底层逻辑

1.1 为什么传统 UI 自动化在复杂界面面前频频翻车

做过 UI 自动化的人都有一个共同感受:脚本写起来容易,维护起来要命。传统方案的核心思路是“定位元素—执行动作—断言结果”,这条链路在静态页面上跑得挺顺,一旦界面结构发生调整、元素层级变化、异步加载时序波动,脚本就开始大面积报错。更麻烦的是,很多界面并不是纯 DOM 结构,而是混合了 Canvas 绘制、WebGL 渲染、原生控件嵌入等形态,元素定位工具根本抓不到有效的选择器。

我早期做过一个后台管理系统的自动化项目,页面里嵌了一个可视化配置面板,整个面板是用 Canvas 画的。当时用常规的元素定位方式完全失效,最后只能靠硬编码坐标去点击,结果换了一台分辨率不同的机器,坐标全偏了。这个经历让我意识到,单纯依赖 DOM 结构的测试方案存在天然的盲区。

多模态 Agent 的出现,本质上是换了一条路来解决这个问题。它不再要求测试脚本必须“理解”页面的 DOM 结构,而是像人一样去看界面、理解界面、操作界面。视觉信息、文本信息、甚至界面上的空间关系,都成为 Agent 做决策的依据。这就把 UI 测试从“元素定位驱动”推向了“意图理解驱动”的新阶段。

1.2 多模态 Agent 的感知与决策链路拆解

要理解多模态 Agent 怎么规划 UI 测试路径,得先搞清楚它的工作链路。我把它拆成四个环节:

感知层负责采集界面信息。这里的信息源通常包括截图、DOM 树、可访问性树、界面文本内容等。不同信息源各有优劣:截图能覆盖所有视觉呈现,但缺少语义;DOM 树语义丰富,但面对 Canvas 或跨域 iframe 就无能为力;可访问性树介于两者之间,覆盖面比 DOM 广,但信息完整度取决于开发者的实现质量。

理解层把感知到的原始信息转化成结构化的界面描述。这一步通常会用到视觉语言模型,把截图和文本一起送进去,让模型输出“当前页面上有哪些可交互区域、它们分别是什么、处于什么状态”。这一步的质量直接决定了后续路径规划的上限。

规划层根据测试目标和当前界面状态,决定下一步该做什么。比如目标是“完成一次下单流程”,当前在商品详情页,规划层就要判断应该先点“加入购物车”还是先选规格。这一步是路径规划的核心,也是最考验 Agent 能力的地方。

执行层把规划结果转化成具体的操作动作,比如点击某个坐标、输入某段文本、滚动到某个位置。执行完之后,感知层再次采集界面信息,形成闭环。

这四个环节环环相扣,任何一个环节出问题都会导致整个测试流程失败。实际落地时,感知层和理解层往往是瓶颈所在,因为界面状态的多样性和不确定性远超预期。

1.3 路径规划在 UI 测试中的核心价值

为什么路径规划这么重要?因为 UI 测试的本质不是“点按钮”,而是“走完一条业务链路”。一条完整的测试路径可能包含十几个甚至几十个步骤,每一步都依赖前一步的结果。如果 Agent 只会机械地执行预设步骤,那它和传统脚本没有本质区别。

路径规划的价值体现在三个方面。第一是自适应:界面变了、弹窗出现了、加载慢了,Agent 能根据当前实际状态调整下一步动作,而不是死等某个元素出现。第二是探索性:面对不熟悉的界面,Agent 能通过视觉理解推断出可操作的区域,而不是依赖预先写好的选择器。第三是容错性:某一步操作没有达到预期效果时,Agent 能识别异常并尝试替代路径,而不是直接报错终止。

这三点加起来,就是多模态 Agent 相比传统方案的核心优势。它把 UI 测试从“照着剧本演”变成了“带着目标找路”。

2. 多模态感知能力的工程化落地

2.1 截图与 DOM 信息的融合策略

单独用截图或单独用 DOM 都有明显短板,所以实际工程中通常采用融合策略。我的做法是:以截图为主干,DOM 信息作为补充标注。

具体来说,先对当前界面截一张全图,然后把 DOM 树中可交互元素的边界框提取出来,映射到截图的对应位置上。这样得到的是一张“带标注的截图”,每个可交互区域都有对应的语义标签。Agent 在理解界面时,既能看到视觉布局,又能知道每个区域的功能含义。

这个融合过程有几个坑要注意。滚动偏移是最常见的:DOM 元素的坐标是相对于文档的,而截图只覆盖当前视口,两者需要对滚动位置做补偿。固定定位元素也容易出问题:导航栏、悬浮按钮这类元素在滚动时位置不变,但 DOM 坐标会变,需要单独处理。动态加载内容更麻烦:截图的那一刻和提取 DOM 的那一刻,界面可能已经变了,需要尽量保证两个操作在时间上接近,或者对界面做短暂冻结。

实操建议:融合时给每个标注区域加一个置信度分数。视觉上清晰可辨、DOM 语义明确的区域给高分;视觉模糊或 DOM 语义缺失的区域给低分。后续规划时优先使用高置信度区域,低置信度区域作为备选。

2.2 视觉语言模型在界面理解中的选型考量

视觉语言模型是理解层的核心组件,选型时主要看三个维度:界面元素识别准确率、推理延迟、部署成本。

界面元素识别准确率是最关键的指标。不同模型对按钮、输入框、下拉菜单、复选框这些常见控件的识别能力差异很大。我的经验是,通用视觉语言模型在标准控件上表现都不错,但在自定义控件、图标按钮、密集列表这些场景下差距就拉开了。选型时一定要用自己项目的真实界面做测试,不能只看公开评测数据。

推理延迟直接影响测试执行效率。一条测试路径可能有几十步,每一步都要调用模型做界面理解,如果单次推理要好几秒,整个测试跑下来时间就不可接受了。实际项目中,我通常会把模型分成两级:轻量模型做快速初筛,判断当前界面是否处于预期状态;重量模型做精细理解,在需要做复杂决策时才调用。

部署成本包括硬件资源和运维复杂度。大模型效果好但资源消耗高,小模型资源省但能力有限。折中方案是使用中等规模的模型,配合针对界面理解场景的微调,在效果和成本之间找平衡。

2.3 界面状态表征的标准化方法

Agent 要规划路径,首先得知道“现在在哪”。界面状态表征就是把当前界面转化成一个结构化描述的过程,这个描述要足够精确,让 Agent 能判断当前处于业务流程的哪个环节。

我采用的表征格式包含四个部分:页面标识(当前是什么页面)、可交互元素列表(每个元素的位置、类型、文本、状态)、关键内容区域(页面上的主要信息展示区)、异常信号(弹窗、错误提示、加载状态等)。

页面标识的判定不能只靠 URL,因为很多单页应用的路由和实际内容并不同步。我的做法是综合 URL、页面标题、关键元素组合来判断。比如一个页面同时包含“商品名称”“价格”“加入购物车按钮”这三个元素,基本可以判定是商品详情页。

可交互元素列表是表征的核心。每个元素需要记录:边界框坐标、元素类型(按钮/输入框/链接/下拉框等)、显示文本、当前状态(可用/禁用/选中/展开等)。这些信息一部分来自 DOM,一部分来自视觉识别,两者互相校验。

异常信号的捕捉往往被忽视,但实际很重要。一个突然弹出的广告弹窗、一个意料之外的错误提示,都可能让原本的路径规划失效。Agent 需要能识别这些异常并做出响应,而不是傻傻地继续执行原计划。

3. 测试路径规划的核心算法与策略

3.1 基于目标分解的路径生成思路

路径规划的第一步是把测试目标拆解成可执行的步骤序列。这个过程类似于项目管理中的任务分解:一个大目标拆成若干子目标,每个子目标再拆成具体动作。

举个例子,测试目标是“验证用户能够成功完成商品购买”。拆解后得到:进入商品列表页、选择商品、进入详情页、选择规格、加入购物车、进入购物车、确认订单、选择地址、提交订单、验证结果。每个子目标对应一个或多个界面操作。

拆解的关键在于粒度控制。粒度过粗,Agent 在执行时缺少明确指引;粒度过细,又失去了自适应调整的空间。我的经验是,拆到“一个子目标对应一个界面状态变化”这个粒度比较合适。比如“选择规格”是一个子目标,它可能包含点击规格按钮、选择具体选项等多个动作,但这些动作都在同一个界面区域内完成,不需要跨页面跳转。

拆解完成后,还需要标注子目标之间的依赖关系和可选性。有些步骤是必须按顺序执行的,有些步骤可以并行或跳过。这些信息帮助 Agent 在实际执行时做出灵活调整。

3.2 视觉锚点与语义锚点的协同定位

Agent 在执行每一步时,都需要在界面上找到对应的操作目标。这里用到两类锚点:视觉锚点和语义锚点。

视觉锚点是指通过图像特征来定位元素,比如按钮的颜色、形状、图标样式。语义锚点是指通过文本内容或功能描述来定位元素,比如“加入购物车”这个文本、“提交”这个按钮含义。

两类锚点各有适用场景。视觉锚点在文本缺失或文本不唯一时更有优势,比如一排只有图标的工具栏按钮。语义锚点在文本明确时更可靠,比如表单里的“用户名”“密码”输入框。

实际使用中,我通常让两类锚点互相校验。先用语义锚点找到候选元素,再用视觉锚点确认位置是否正确;或者反过来,先用视觉锚点圈定区域,再用语义锚点确认功能。两者一致时置信度高,不一致时触发进一步检查。

注意:锚点的稳定性会随界面变化而衰减。同一个按钮,今天在页面右上角,明天可能因为布局调整跑到左下角。所以锚点信息需要定期更新,不能一劳永逸。

3.3 动态界面下的路径重规划机制

界面不会乖乖按照预期变化,弹窗、广告、加载延迟、网络错误都是常态。Agent 必须具备路径重规划能力,在遇到意外时能调整策略。

重规划的触发条件主要有三类:预期元素未出现、出现了预期外的元素、操作结果与预期不符。第一类情况可能是加载慢或元素被遮挡,Agent 应该先等待或尝试滚动,而不是立即放弃。第二类情况可能是弹窗或提示,Agent 需要先处理这些意外元素再继续原路径。第三类情况可能是操作失败或界面跳转到了错误页面,Agent 需要判断是否需要回退或走替代路径。

重规划的策略我总结为“先局部后全局”。局部调整是指在不改变整体路径的前提下,处理当前步骤的异常。比如关闭弹窗后继续点击原目标。全局调整是指当前路径已经走不通,需要回到某个已知状态重新规划。比如提交订单失败后,回到购物车页面重新确认。

局部调整的成本低、成功率高,应该优先尝试。全局调整成本高,但能处理更复杂的异常。实际系统中,我会设置一个重试阈值:局部调整连续失败超过三次,就触发全局重规划。

4. 实操流程与关键环节实现

4.1 环境搭建与工具链选型

落地一套多模态 Agent UI 测试系统,环境搭建是第一步。我以自己最近做的一个项目为例,说明工具链的选型思路。

浏览器控制层用的是 Playwright。选它的原因是跨浏览器支持好、API 设计清晰、截图和 DOM 提取都很方便。相比 Selenium,Playwright 在处理异步加载和 iframe 方面更省心。

视觉理解层用的是开源的视觉语言模型,部署在本地 GPU 服务器上。选本地部署而不是调 API,主要是考虑数据安全和调用成本。模型规模选的是中等偏小的版本,在界面理解这个特定任务上做了微调。

路径规划层是自己写的一套规则引擎加状态机。没有直接用大模型做规划,是因为测试路径规划对确定性要求很高,大模型的输出不够稳定。规则引擎负责处理常见场景,状态机负责管理流程状态和异常处理。

结果验证层结合了截图比对和断言检查。截图比对用于验证界面视觉是否符合预期,断言检查用于验证具体的数据和状态。

整个工具链的代码结构大致如下:

class MultimodalAgent: def __init__(self, browser, vision_model, planner): self.browser = browser self.vision = vision_model self.planner = planner self.state = None def perceive(self): screenshot = self.browser.screenshot() dom_info = self.browser.extract_interactive_elements() self.state = self.vision.understand(screenshot, dom_info) return self.state def plan(self, goal): return self.planner.next_action(self.state, goal) def execute(self, action): if action.type == "click": self.browser.click_at(action.coordinates) elif action.type == "input": self.browser.type_text(action.coordinates, action.text) elif action.type == "scroll": self.browser.scroll(action.direction, action.amount) def run(self, goal): while not self.planner.goal_reached(self.state, goal): self.perceive() action = self.plan(goal) self.execute(action)

这个结构看起来简单,但每个环节都有大量细节需要处理。比如perceive里截图和 DOM 提取的时序问题,plan里异常状态的判断逻辑,execute里操作失败的重试机制。

4.2 测试用例的多模态描述规范

传统测试用例是写给人看的步骤列表,多模态 Agent 需要的测试用例格式不太一样。我设计了一套描述规范,包含以下字段:

字段说明示例
目标这条用例要验证什么用户能成功登录
起始状态执行前的界面状态登录页面,未输入任何内容
关键步骤必须执行的步骤序列输入用户名、输入密码、点击登录
预期结果执行后的界面状态跳转到首页,显示用户昵称
容错策略遇到异常时的处理方式弹窗出现时先关闭再继续
超时设置每步的最大等待时间单步 10 秒,整体 60 秒

这套规范的核心思想是:描述意图而不是描述操作。传统用例会写“点击 ID 为 submit-btn 的按钮”,多模态用例写“点击登录按钮”。前者依赖具体实现,后者依赖语义理解。这样界面改版时,用例不需要跟着改。

写用例时有个技巧:关键步骤不要写太细。比如“输入用户名”这一步,不需要指定点击哪个输入框、输入什么内容,Agent 会根据界面理解自己判断。但“点击登录”这种关键动作要明确写出来,因为这是流程的转折点。

4.3 执行过程中的监控与日志记录

Agent 执行测试时,必须留下完整的监控数据和日志,否则出了问题根本没法排查。我记录的日志包含以下内容:

每一步操作前,记录当前界面截图、界面状态表征、Agent 的决策依据。操作后,记录操作结果、界面变化、是否达到预期。整个流程结束后,生成一份执行报告,包含总耗时、成功步骤数、失败步骤数、重试次数、异常事件列表。

日志的存储格式我用的是结构化 JSON,方便后续分析和回放。每条日志包含时间戳、步骤序号、操作类型、操作参数、界面状态快照、决策理由等字段。

{ "timestamp": "2024-01-15T10:23:45", "step": 3, "action": "click", "target": "登录按钮", "coordinates": [640, 480], "state_before": "登录页面,用户名和密码已填写", "state_after": "首页,显示用户昵称", "decision_reason": "当前界面包含登录按钮,且用户名密码已填写,符合点击条件", "duration_ms": 1250 }

这些日志在排查问题时非常有用。有一次测试失败,看日志发现 Agent 在第三步点击了一个错误的按钮,原因是界面上有两个文本相似的按钮,视觉模型识别错了。根据日志里的截图和坐标,很快定位到了问题并调整了锚点策略。

实操心得:日志里一定要记录 Agent 的决策理由。很多时候失败不是操作错了,而是决策逻辑有问题。有了决策理由,才能判断是感知层识别错了,还是规划层判断错了。

5. 常见问题与排查技巧实录

5.1 元素识别失败的典型场景与对策

元素识别失败是最高频的问题,我整理了几种典型场景和对应的处理方式。

场景一:图标按钮无文本。界面上只有图标没有文字的按钮,视觉模型可能识别不出功能。对策是建立图标库,把常见图标(搜索、设置、关闭、返回等)预先标注,Agent 识别时先查图标库。

场景二:文本被截断或遮挡。按钮上的文字显示不全,或者被其他元素遮挡。对策是结合 DOM 信息补充文本,同时用视觉信息判断元素是否可点击。

场景三:动态内容加载中。界面还在加载,元素位置和内容都不稳定。对策是设置加载等待策略,检测到加载动画时先等待,加载完成后再做识别。

场景四:相似元素混淆。页面上有多个外观相似的按钮,Agent 选错了目标。对策是增加上下文信息,比如按钮所在的区域、周围的文本,帮助区分。

场景五:跨 iframe 元素。元素在 iframe 内部,截图能看到但 DOM 提取不到。对策是递归处理 iframe,把每个 iframe 的内容单独提取后再合并。

5.2 路径规划陷入死循环的排查思路

死循环是另一个让人头疼的问题。Agent 反复执行同一个动作,界面没有变化,但 Agent 认为还没达到目标。

排查死循环,我通常按以下顺序检查:

第一步,看界面状态表征是否在变化。如果每轮循环的状态表征完全一样,说明 Agent 没有感知到界面的实际变化,可能是截图或 DOM 提取出了问题。

第二步,看规划逻辑是否合理。如果状态在变但 Agent 还是执行同一个动作,说明规划逻辑有问题,可能是目标判断条件写错了,或者动作选择策略太单一。

第三步,看操作是否真的生效了。有时候 Agent 以为点击了按钮,但实际上点击坐标偏了或者被遮挡了,操作根本没生效。这种情况需要检查执行层的坐标计算和元素遮挡处理。

第四步,看是否有隐藏的状态依赖。有些界面操作需要满足特定前置条件才能生效,比如必须先勾选某个复选框才能点击提交按钮。Agent 如果不知道这个依赖,就会一直点提交但没反应。

解决死循环的根本方法是增加状态变化检测。每执行一步操作后,对比操作前后的界面状态,如果状态没有实质变化,就触发异常处理而不是继续循环。

5.3 多模态信息冲突时的仲裁策略

视觉信息和 DOM 信息不一致时怎么办?这种情况比想象中常见。比如 DOM 显示某个按钮是可用状态,但视觉上它是灰色的;或者视觉上有个弹窗,但 DOM 里找不到对应的元素。

我的仲裁策略是分场景处理:

冲突类型处理策略理由
视觉可见但 DOM 缺失以视觉为准,尝试操作可能是 Canvas 或跨域内容
DOM 存在但视觉不可见以视觉为准,跳过该元素可能是隐藏元素或未渲染
视觉和 DOM 状态不一致以 DOM 为准,但记录警告DOM 状态通常更准确
位置信息不一致以视觉为准视觉位置是实际可点击的位置

这个策略不是绝对的,需要根据具体项目调整。核心原则是:哪个信息源在当前场景下更可靠,就以哪个为准。同时,所有冲突都要记录日志,便于后续分析和优化。

5.4 提升执行稳定性的独家避坑技巧

最后分享几个我在实际项目中总结的稳定性技巧。

技巧一:操作前先做界面稳定检测。连续截两张图,如果两张图差异超过阈值,说明界面还在变化,等待后再操作。这个简单的检测能避免大量因界面未加载完成导致的操作失败。

技巧二:关键操作后加短暂延迟。点击按钮后不要立即进行下一步感知,等个几百毫秒让界面完成过渡动画。这个延迟看起来浪费时间,但能显著降低误判率。

技巧三:维护一个已知弹窗库。把常见的弹窗(广告、提示、更新通知)截图存下来,Agent 感知到界面时有弹窗特征就先关闭。这个库需要定期更新,因为弹窗样式会变。

技巧四:设置合理的重试上限。任何操作失败后重试不要超过三次,超过就标记为失败并继续下一步或终止。无限重试只会浪费时间,而且往往解决不了根本问题。

技巧五:定期回放失败用例。把失败的用例录屏保存,定期回放分析。很多问题不是偶发的,而是有规律的模式,回放能帮助发现这些模式。

技巧六:给 Agent 加一个“不确定”状态。当 Agent 对当前界面的理解置信度低于阈值时,不要强行操作,而是标记为不确定并请求人工介入或跳过。强行操作往往会导致更严重的错误。

这些技巧看起来都是小细节,但实际项目中,正是这些细节决定了整套系统能不能稳定跑起来。多模态 Agent 做 UI 测试,技术方案是一方面,工程细节的把控同样重要。我在实际使用中发现,把上面这些避坑技巧落实到位之后,测试用例的稳定通过率能从百分之六十多提升到百分之九十以上,剩下的失败案例也基本都能通过日志快速定位到原因。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询