做LLM自动化测试也有一阵子了,今天接着写系列的第二篇。上一篇聊了怎么用LLM设计用例和生成断言,这一篇我们换个角度,聊聊真正让LLM“接手”自动化测试的底座问题。很多人一开始会很天真:要么觉得LLM看屏幕截图就能搞定一切(视觉路线),要么觉得抓一把DOM喂给模型就行(语义路线),还有一拨人迷Computer Use,觉得Agent能自己操作电脑就万事大吉。实际上,这三条路线各有各的天花板,单独拿出来都撑不起一个稳定、可靠的LLM测试方案。真正能落地的是把它们统一到一个技术底座上,按需调度、互相兜底。
这篇文章会把“视觉定位 / DOM语义化 / Computer Use”这三块拆开揉碎,讲清楚它们各自解决的问题、适用的场景、实操中怎么配参数、怎么规避坑,最后用一个真实的登录用例演示怎么在统一底座里融合三者。适合正在做LLM自动化测试、想从Demo走向工程化的朋友参考。
1. 为什么需要一个“统一技术底座”:从LLM测试的痛点说起
1.1 三种路线各管一段,搅在一起就会翻车
先说说我踩过的坑。最早做LLM自动化测试的时候,我试过纯视觉方案:把页面截图交给多模态模型,让它返回一个坐标,然后驱动鼠标去点击。看起来很美,实际上翻车率很高。模型确实能“看”到页面,但在密集的表单页面里,坐标预测的误差经常导致点错元素。尤其是分辨率复杂的页面,同一张截图在不同缩放比例下,模型给出的坐标就不一样。后来我又试纯DOM方案,把整个document.body的内外HTML全部塞给模型,让它基于DOM结构定位元素。这个方案在结构清晰的页面上表现不俗,但一旦遇到动态渲染、shadow DOM、iframe或者超长列表,上下文直接爆炸,模型开始胡言乱语。
真正的转折点是开始研究Computer Use。这个方向看起来很前沿,让Agent自动操作浏览器、桌面应用,但落地时发现它依赖一个关键前提:Agent必须有一双“准确的眼睛”和一份“可读的菜单”。如果没有统一的元素表达能力,Agent的每一步操作都像盲人摸象。这时我才逐渐意识到,视觉定位、DOM语义化、Computer Use不是三选一的关系,而是一个三层配合的关系。视觉负责感知兜底,DOM语义化负责结构建模,Computer Use负责动作执行,三者需要被封装成同一个底座对外提供服务。
1.2 统一底座的核心:把“看、读、动”变成可编排的能力
所谓统一技术底座,说白了就是让测试框架对外只暴露一套交互接口,对内则可以灵活切换感知引擎。LLM不直接操作坐标,也不直接解析DOM,而是面向一种“元素描述语言”做决策。这种语言里,每个可交互元素都有统一的ID、类型、语义标签和位置信息,无论它来自视觉识别还是DOM解析。
这个设计解决了好几个实际问题。第一,屏蔽了不同运行环境的差异——同样的一个登录按钮,在Web里是<button>,在原生App里可能是一个复杂View组件,在桌面上可能是一个UIAElement,但在LLM看来都是“登录按钮”,这极大降低了模型的认知负荷。第二,提高了容错能力:视觉定位偶尔会偏差,但DOM语义化可以提供精确的结构确认,两者互相校验。第三,让Computer Use的决策变得可追踪——模型输出的每个动作都对应一个元素ID,执行结果可以通过元素的状态变化断言,这比纯坐标点击可靠得多。
我把这个底座理解为三件套:感知层(视觉+DOM)、语义层(统一元素表示)、执行层(Computer Use动作编排)。下面三章分别展开,最后再讲它们如何协同。
2. 视觉定位:让模型像人一样“看图找按钮”
2.1 视觉定位是怎么工作的
视觉定位最早的形式是让多模态LLM直接看截图,输出“点击(x, y)”指令。但现在成熟的做法不是让模型输出裸坐标,而是采用“标记式”提示(Set-of-Marks)。具体是这样的:先把页面截图交给视觉模型,让它检测画面中的所有可交互元素,并为每个元素打上一个数字标记(在图片上绘制文本标签,比如1、2、3),然后让模型根据这些数字选择要操作的目标。这样模型不再需要脑内做坐标换算,只需回答“点击数字5”即可,这大大降低了定位误差。
实现这个能力的几个关键点是:截图预处理、模型推理、坐标映射。截图预处理阶段,需要把原始截图缩放到模型训练时适配的尺寸(常见的是768或1024像素宽度),同时保持宽高比,避免元素变形。推理阶段,模型输出的是一个JSON数组,包含元素编号、元素类型、元素代表的语义描述(比如“登录按钮”),以及相对于缩放后图像的边界框。最后,坐标映射阶段,把边界框按缩放比例还原到原始屏幕坐标,交给自动化框架去执行点击。
这里有一个细节很多人忽略:视觉模型有“原生存档点”的概念,也就是它对屏幕截图的理解受限于训练时的典型UI分布。如果你的页面有大片留白或者非常规布局,模型可能会把留白识别成按钮。所以视觉定位适合作为“兜底方案”——当DOM无法解析(比如Canvas渲染的图表、游戏界面、视频播放器)或者需要验证纯视觉样式(比如某个元素是否被遮挡)时,视觉定位是唯一选择。
2.2 实操中视觉定位的关键参数与翻车点
我实际跑视觉定位时,最常调的参数有三个:截图清晰度、元素最小尺寸阈值、置信度阈值。截图清晰度不必追求越高越好,太高会增加API延迟和成本,一般宽度768px就够用了。元素最小尺寸阈值建议设为12px,小于这个尺寸的按钮在视觉上边缘模糊,强行标注反而误导模型。置信度阈值我习惯设为0.65,低于这个值的元素宁可丢给DOM层去补查,也不要让模型硬猜。
翻车点主要集中在三类情况:第一,动态刷新区域的截屏竞态。比如页面有一个实时刷新的Loading动画,截图时刚好定格在半透明状态,模型可能把Loading层误判为弹窗。解决办法是截图前等待网络空闲,或者采用重试机制,连续两次截图对比相似度超过95%再进入识别。第二,多显示器环境下的坐标偏移。如果测试机有多个显示器,截图的坐标系与主屏幕坐标系不一致时,映射会整体偏移几个像素。这个问题在macOS下尤为突出,我是通过强制全屏模式规避的。第三,深色模式与高亮态干扰。页面处于深色模式时,有些深色按钮在截图里几乎看不见,模型会漏报。我会在视觉识别前置一个“统一主题”操作——把页面强制切成浅色模式,虽然改状态有成本,但识别成功率能提升20%以上。
3. DOM语义化:把页面“翻译”成模型看得懂的文本
3.1 从原始DOM到语义化结构:信息压缩五步法
视觉定位解决的是“有没有”,DOM语义化解决的是“是什么”。对Web自动化来说,DOM语义化往往比视觉定位更精确,因为元素结构、属性、文本都在那里,不依赖模型的视觉幻觉。但原始DOM直接喂给LLM是行不通的——一个中等复杂度的后台页面,HTML可能有几十KB甚至上百KB,就算硬塞进上下文,模型也会被噪音干扰。
我常用的信息压缩五步法,可以把一个页面DOM压到5KB以内,同时保留模型决策所需的全部信息。第一步是去掉装饰性节点:<script>、<style>、<link>、注释、隐藏元素(display:none、visibility:hidden、aria-hidden="true")全部过滤。第二步是标准化属性:把class、style、>[ { "ref": "el_1", "type": "textbox", "label": "用户名输入框", "placeholder": "请输入用户名", "dom_id": "username", "path": "#app > form > div.input-group:nth-child(1)" }, { "ref": "el_2", "type": "button", "label": "登录按钮", "text": "登录", "dom_id": "loginBtn", "path": "#app > form > div.btn-group > button" } ]
我给模型的任务指令里,只让它面向ref做动作,而不是直接写CSS选择器。因为CSS选择器可能因为页面重构而失效,但语义标签描述的是业务意图,比如“登录按钮”不管样式怎么变,它始终是登录按钮。这样做的好处是,即使页面结构微调,只要语义没变,测试脚本依然能跑。
3.2 语义化与视觉定位的边界划分
DOM语义化并非万能。我总结了一个边界划分原则:如果页面是标准的Web DOM并且结构相对稳定,优先使用DOM语义化;如果页面里有Canvas、WebGL、SVG动画,或者有大量绝对定位叠加的弹层,DOM语义化会丢失和误读,这时必须用视觉定位辅助。更具体地说,弹层遮挡场景是DOM语义化的重灾区:一个按钮在DOM里存在,但它的位置被另一个遮罩层挡住,用户根本点不到,如果只依赖DOM语义,模型就会发出一个无效点击。这种时候,需要视觉定位来判断元素是否真的可见、可点。
实际上,很多LLM测试框架把DOM语义化作为主通道,把视觉定位作为第二验证通道。操作一个元素前,会先做一次视觉确认,比对边界框和语义描述是否一致。比如“登录按钮”在DOM里宽高是200x50,但视觉识别到的实际区域被弹窗挡住了三分之一,那么框架就会判定该元素“不可交互”,自动调整策略——先关闭弹窗,再点击登录。
这个“语义+视觉”的校验成本不高,却能把误操作率降低一个数量级。我的经验是,宁可每个动作多花200毫秒做交叉验证,也不要等脚本跑完才发现点错了地方。
4. Computer Use:让模型真正“动手操作”的Agent能力
4.1 Computer Use的本质:模型与环境的闭环
Computer Use听起来很玄乎,其实本质是让LLM在真实环境中通过“观察-规划-执行-再观察”的闭环来完成一系列操作。它比传统自动化测试的“录制回放”高级在:不再依赖固定的定位器,而是基于对页面的理解动态决策。这就像一个刚入职的新员工,不熟悉业务系统,但能通过“看看都有什么按钮、想想该点哪个、点了之后看结果对不对”来逐步完成任务。
在实际工程中,Computer Use需要定义三件事:动作空间、观察空间、策略模型。动作空间是Agent能执行的操作全集,例如点击、双击、输入、按键、滚动、拖拽、悬停、等待、跳转、快照。观察空间是Agent每步能获得的信息,包括截图像素数据、DOM语义化之后的元素列表、当前页面的URL和标题。策略模型则是一个LLM实例,它接收观察信息,输出动作序列。模型不直接调操作系统API,而是通过我们封装的执行器来操作——执行器就像“机器人的手脚”。
一个关键问题是:动作空间怎么设计才能让模型少犯错?我的做法是对动作做参数化,每个动作都绑定一个目标,比如click(ref="el_1")相比click(x=100, y=200)更容易让模型理解,也更容易做合法性校验。这样框架可以在执行前就检查“el_1当前是否可见?是否可交互?”,如果不可直接通过,就触发重试机制。
4.2 动作空间设计与安全护栏
Computer Use在自动化测试里最大的风险不是模型不会用,而是“用过头”。LLM偶尔会做出意料之外的操作,比如点击一个“退出登录”按钮或者在文本输入框里填入一段看似无害但改变业务状态的字符。因此安全护栏是必须的。
我通常会设置四道防线:第一,操作白名单和黑名单。白名单允许模型操作那些被标记为“测试友好”的元素(比如输入框、一级按钮),黑名单禁止模型触碰“删除”、“清空”、“重置”之类的高风险元素。第二,动作频率限制——每步操作之间至少间隔200毫秒,防止模型连点导致的竞态。第三,步骤上限控制——单个任务最多执行50步,超过步数强制终止并标记失败,避免模型陷入死循环。第四,人工确认点——在某些关键节点(比如提交订单、修改配置)设置确认开关,测试脚本可以暂停并需要人工批准才继续。
另外一个容易忽略的点是“无头模式下的视觉反馈”。如果你的执行器是无头浏览器,屏幕截图会是一片空白的虚拟视口,但DOM都在。这时Computer Use的观察空间最好以DOM语义化为主,视觉验证可以关闭。但有头模式(真实浏览器窗口)能更真实地模拟用户环境,尤其适合做端到端验收测试。我一般给 Computer Use 提供一个配置开关,让测试用例指定使用“视觉模式”还是“语义模式”,而不是往里塞一堆逻辑。
5. 统一调度:三者在真实测试任务里的融合策略
5.1 一次真实登录用例的完整流程
光说不练假把式。我用一个最常见的登录用例,展示统一底座运行时到底发生了什么。假设我们要测一个后台管理系统的登录功能,测试目标是“用正确的账号密码登录成功”。传统脚本可能会写死#username和#loginBtn,但在LLM底座里,流程完全不同。
第一步,底座启动,自动化框架加载目标URL,并截取一张初始页面快照。第二步,感知层并行工作:DOM语义化模块抽取元素列表(元素描述如上一节所示),视觉模型对截图生成边界框标记。管理器将两者合并,生成一个统一的“当前页面状态”对象,发给LLM。第三步,LLM接收到任务提示和状态对象,开始推理。提示词大概长这样:
你是一名测试执行者,请完成以下任务:验证登录功能。 当前页面可用元素列表: 1. 用户名输入框 (el_1) 2. 密码输入框 (el_2) 3. 登录按钮 (el_3) 4. 记住我复选框 (el_4) 请输出一个动作序列,格式为JSON数组。示例: [{"action":"input","target":"el_1","value":"admin"},...]第四步,LLM输出动作序列。在执行前,安全模块对这个序列做合法性校验:el_1和el_2是否在白名单内?input动作的value是否合规?如果校验通过,执行器依次执行。每执行一步,都会重新触发一次感知层快照,用于判断页面状态是否发生变化。第五步,当所有动作执行完毕,断言模块从最新状态对象中查找“登录成功”的用户提示、跳转URL或界面上出现的目标元素。如果匹配,测试通过;如果不匹配,则记录现场日志和截图,供人工排查。
这个流程让人感觉LLM像是一个“会思考的手”,而底座负责给它提供眼睛和大脑需要的信息。传统自动化测试断言的是代码逻辑,这个方案断言的是业务结果,这更接近一个测试工程师真实的操作方式。
5.2 选择策略与优先级判断
统一底座并不是每一步都要同时启用三种技术,那样成本太高。我根据页面特征制定了一个“优先级矩阵”。对于静态Web页面,如果DOM语义化抽取结果完整且元素可见性判断准确,就直接走DOM单通道,不动用视觉。对于动态页面(尤其是表单校验、弹窗提示频繁的页面),先DOM语义化,但关键操作(点击按钮)时叠加视觉验证。对于纯视觉页面(Canvas、SVG、视频界面),直接启用视觉定位,并补充OCR识别文本来辅助理解。对于桌面应用(Windows窗口、Mac原生应用),只能走视觉定位加系统控件树(类似UIA)的组合,Computer Use的动作调用系统级API。
这个优先级选择可以做成一个函数,输入页面类型和当前能力,输出“感知模式”。我把它写成配置项放在框架里,每个测试用例可以显式声明:
perception: primary: dom fallback: visual verify: visual max_retries: 2这套配置看起来简单,但节省了大量token和时间。没有统一底座的时候,我什么都用视觉,一个月光API费用就两千多块。改造之后,只有20%的用例需要始终开启视觉,其他用例大多在DOM通道就解决了,费用直接降了60%。这算是一个额外收获——统一底座不只是提高稳定性,还能控制成本。
6. 常见问题与排查技巧实录
6.1 六类高频问题速查表
为了让大家少走弯路,我整理了一份高频问题速查表,覆盖我在实际项目中遇到的最多的六类问题。
| 症状 | 根因 | 排查思路 | 解决方案 |
|---|---|---|---|
| 视觉模型点击坐标偏了几个像素 | 截图缩放比例和实际屏幕DPI不匹配 | 检查坐标映射函数,确认缩放因子来源 | 使用元素中心点而非左上角,叠加DOM边界框修正 |
| LLM输出的动作格式偶尔不合法 | 当前Prompt里动作枚举不明确 | 检查模型对动作参数的理解,比如是否有单位歧义 | 在提示词中给出正反示例,并用JSON Schema校验输出 |
| DOM语义化列表太长,超出上下文窗口 | 页面元素过多,过滤规则过于宽松 | 统计压缩后的元素数量,定位过滤无效的节点 | 增加“可交互性过滤”,只保留按钮、输入框、链接等可操作元素 |
| 点击登录按钮后页面无响应 | 页面采用了异步请求,点击后状态变化延迟 | 观察执行后的网络请求是否发出,或页面是否有Loading | 执行点击后插入一个显式等待,直到URL变化或出现目标元素 |
| 视觉和DOM获取到的元素ID对应不上 | 动态渲染导致DOM加载完成后元素顺序变化 | 比较两者的边界框,确定是否是截屏时机问题 | 在DOM加载完成事件后延迟200ms再拉取DOM |
| 模型点击了“退出登录”这种副作用按钮 | 安全护栏未覆盖该操作 | 检查白名单配置,是否漏掉了高风险元素 | 把所有标记为“href=/logout”或“οnclick=logout”的元素加入黑名单 |
这些问题的共同教训是:LLM测试不是一锤子买卖,你需要建立一套反馈循环。每次测试失败,都要把失败时刻的状态对象、模型输出、执行日志存下来,作为后续调优的语料。比如我跑了一阵子后,会定期回放失败的LLM输出,看它是误判了语义,还是动作顺序有问题,然后针对性地优化提示词或护栏配置。
6.2 三个只有实战才能总结出的坑
除了上述速查表,还有三个更隐蔽的坑,值得单独拿出来说一下。
第一个坑是“视觉模型对空区域的猜测”。在截图里,一个大面积的空白区域(比如一个输入框下方的大段留白)往往会被视觉模型想象成“一个按钮”。如果页面上还有透明状态的覆盖层,那就更容易被误读成一个交互区。解决方式很笨但有效:对视觉模型标记的元素,强制要求它输出边界框的面积比例,如果某个元素面积超过视口面积的50%,我直接丢弃它。这个规则能过滤掉90%的空白误判。
第二个坑是“DOM语义化里隐藏的iframe”。很多系统都嵌入了第三方登录组件或者支付组件,这些内容在iframe里,主页面DOM是看不到的。你只做主页面DOM语义化,会发现“登录按钮”永远找不到。办法是让DOM语义化模块同时扫描所有可见iframe,并把iframe里的文档插入到一个虚拟父节点下,这样元素引用ID就带上了iframe标识,比如frame_1 > el_3。否则,就算视觉能定位到按钮,执行点击时也不知道该投递到哪个frame。
第三个坑是“动作重试导致重复提交”。在一次表单提交测试中,模型第一次点击提交按钮后页面没有立刻加载完成,模型认为点击没生效,又点了一次,结果重复提交了两笔订单(幸好是沙箱环境)。这个问题的根源是Agent缺乏“动作后验证”意识。我的对策是:在动作执行后增加一个状态对比步骤,观察页面是否有新出现的元素或请求是否触发,如果状态已经变化,就终止当前动作循环。这相当于给Agent补了一个“你刚才已经做过这件事”的短期记忆。
结个尾,说点个人体会。做LLM自动化测试这两年,我最深的感受是:不要把希望全押在单一技术上。视觉定位、DOM语义化、Computer Use 这三者,本质上分别对应人的眼睛、阅读力、和手。单靠眼睛容易看不清,单靠阅读容易忽略遮挡,单靠手容易乱操作。真正的统一底座,不是某种算法的胜利,而是把这三项能力放在一个可靠的框架里,让它们相互校准、互相兜底。如果你也在做类似的尝试,我的建议很简单:先把DOM语义化做扎实,把视觉定位当作校验手段,再把Computer Use的动作空间约束清楚——你会发现,LLM自动化测试并没有想象中那么玄幻,它更像一个需要耐心编排的工程系统。这套底座搭好之后,后面再扩展复杂的测试场景,就会轻松很多。