LLM自动化测试的三大底座:视觉定位、DOM语义化与Computer Use实战

发布时间:2026/11/3 8:57:56
LLM自动化测试的三大底座:视觉定位、DOM语义化与Computer Use实战 做LLM自动化测试也有一段时间了这个系列写下来发现大多数团队卡在同一个地方LLM到底怎么“看懂”被测界面传统的Selector、XPath模型用不惯直接丢一张截图过去又经常定位不准试了几次就放弃了。系列第01篇聊过整体架构选型这篇把最核心的“统一技术底座”掰开讲清楚——视觉定位、DOM语义化、Computer Use这三板斧才是LLM自动化测试能不能在团队里落地的关键。先把结论说透模型聪明不聪明不是瓶颈这三块底座稳不稳才是。下文全部是我实际跑过的路径和踩过的坑按可以直接复现的标准写。1. 传统定位方式的痛点LLM为什么需要一个新底座1.1 老一套玩法为什么让人心力交瘁做过UI自动化的人都知道传统定位方式的核心是“找特征”。找一个稳定ID找不到就拼XPathXPath太脆就上CSS Selector再不行就加一堆># 以视觉定位服务为例传入截图返回候选区域 def vision_locate(screenshot_path: str, instruction: str): with open(screenshot_path, rb) as f: response vision_service.detect( imagef.read(), textinstruction, top_k3, # 返回最可能的3个候选区域 need_labelsTrue, # 让模型顺带输出每个候选区域的标签 ) # 返回示例 # [ # {box: [210, 340, 90, 40], label: 登录按钮, confidence: 0.97}, # {box: [210, 340, 90, 40], label: 登录按钮(悬停态), confidence: 0.86}, # ] return response # 拿到坐标后交给执行层做真实点击 def click_at_point(page, box): x, y, w, h box center_x x w / 2 center_y y h / 2 page.mouse.click(center_x, center_y)关键参数就三个top_k候选数量、confidence置信度阈值、box_format坐标格式。建议top_k设成3而不是1因为模型偶尔会有多个相似目标比如两个“登录”入口多候选能配合后续决策逻辑做兜底。置信度阈值我一般设0.85低于这个值宁可放弃本次识别也不要硬点点错一次的代价比等一轮重试大得多。2.3 视觉定位的三个实战雷区第一个雷区是分辨率适配。截图如果直接用视口尺寸比如1920×1080而视觉模型内部会把图缩放到固定尺寸返回的坐标可能和原始截图对不上。解决办法很简单请求视觉服务时带上你的视口宽高让服务端返回的坐标统一缩放回原尺寸或者你在客户端自己按比例做一次坐标映射。我踩过这个坑坐标偏移一整块都点不中排查了半天发现是缩放没还原。第二个雷区是动态遮挡。页面有悬浮层、弹窗、动态动画时截图里的目标元素可能被遮挡一半。视觉模型有时候会幻觉出完整目标给一个错误的框。应对办法截图前先做一次“页面静止”处理关闭所有动画和过渡效果必要时强制等requestAnimationFrame轮询结束再截图。第三个雷区是成本控制。多模态视觉识别单次调用比纯文本贵一个量级而且延迟通常在2到5秒。别傻傻地每个元素都用视觉定位那样一次用例跑下来光视觉调用就几十次时间和钱都受不了。我的做法是先用下一章的DOM语义化去定位只有语义化结果置信度低时才走视觉兜底这样视觉调用占比能控制在10%以内。3. DOM语义化实操把页面翻译成LLM的语言3.1 为什么原始HTML不能直接喂给模型很多人一开始图省事直接把page.content()拿到的HTML丢给LLM分析。我强烈不建议这么干。一个中型页面的原始HTML轻松几万甚至几十万个字符直接撞爆上下文窗口先不说即使塞得下模型也会被里面海量的布局噪声带偏。原始HTML里包含大量与用户意图无关的东西布局用的div嵌套、样式容器、脚本标签、注释、隐藏节点。这些噪声对测试来说毫无价值却会稀释模型对真正交互元素的注意力。打个比方你要吩咐一个人去按电梯按钮结果给了一整栋楼的建筑图纸上面标了每个房间的下水管道位置。这不是帮忙是添乱。DOM语义化要做的事就四个字降维提炼。从“布局树”里提取“意图树”只保留和测试动作相关的信息可点击的按钮、可输入的框、可选的选项、可跳转的链接、弹窗、表单控件。这个步骤做完一个几万字符的页面能被压缩成几百到一两千字符的轻量描述并且全是有效信息。3.2 用Accessibility Tree构建“交互元素清单”具体怎么做语义化优先用浏览器自带的可访问性树Accessibility Tree。这个方案的出发点很简单浏览器已经帮我们把DOM解析成了语义角色按钮就是按钮输入框就是输入框弹窗就是弹窗。我们要做的只是把这些角色按LLM友好的格式重新组织一下。以Playwright为例获取语义快照非常直接from playwright.sync_api import sync_playwright with sync_playwright() as p: browser p.chromium.launch() page browser.new_page() page.goto(https://your-target-page.com) # 方案A页面自带的accessibility tree快照 snapshot page.accessibility.snapshot() print(json.dumps(snapshot, ensure_asciiFalse, indent2))拿到Accessibility快照之后还要做一轮“交互元素过滤”只保留满足以下任一条件的节点——role为按钮、链接、输入框、下拉框、单选框、复选框、选项卡、对话框、菜单项或者节点自带onclick、tabindex、href等可交互属性。过滤完之后再按层级关系压缩成缩进结构。我习惯的最终输出格式类似这样[页面] 登录页 [输入框] 用户名 (placeholder: 请输入手机号) [输入框] 密码 (placeholder: 请输入密码) [复选框] 记住我 [链接] 忘记密码 [按钮] 登录 (primary) [文字] 注册即同意《用户协议》这种格式就是给LLM的“菜单”。模型拿到菜单以后只需要在给定选项里选而不是凭空创造。后者正是幻觉的主要来源。实测下来同一页面原始HTML大约45KB语义化压缩后只有800多字符Token消耗直接降了一个量级模型准确率反而高了。因为它不用再顶着噪声找重点。3.3 DOM语义化与传统选择器定位的直观对比为了让你看得更清楚我把四种定位方式的差异放在一张表里定位方式输入对前端改版的抗性Token成本维护成本典型场景ID定位唯一标识极差无高老系统、结构稳定XPath/CSS路径表达式极差无高传统自动化脚本DOM语义化可访问性树/角色描述强低低LLM测试的主力定位视觉定位截图指令极强高极低复杂渲染、兜底方案用同一个登录页面做实验前端改版把按钮从btn-login改成submit-btn-primaryID和XPath全部失效DOM语义化输出的还是“按钮登录”完全不受影响。这就是LLM测试和传统测试的本质区别——模型理解的是语义不是实现细节。顺带说一句很多团队问要不要给DOM加>def run_test_agent(task: str, page, max_steps10): history [] for step in range(max_steps): # 1. 观察获取语义快照必要时补充截图 snapshot get_semantic_snapshot(page) screenshot page.screenshot() # 2. 理解 决策让LLM输出下一步动作 action llm.plan( tasktask, snapshotsnapshot, # DOM语义化底座 screenshotscreenshot, # 视觉定位底座兜底用 historyhistory, ) # action示例{type: click, target: 登录按钮, reason: 点击登录提交表单} # 3. 执行动作翻译成浏览器操作 result execute_action(page, action, snapshot) # 4. 反馈观察新状态并记录 history.append({action: action, result: result}) # 5. 判断任务是否完成 if is_task_done(snapshot, task): return PASS, history return TIMEOUT, history这里最关键的一步是execute_action。它不能直接拿LLM的文本去执行得先做一层“动作映射”把LLM输出的目标描述比如“登录按钮”在语义快照里匹配到具体元素引用再调用page.click(element)或者page.locator(...).click()。这样即使同页面有两个“登录”字样一个在导航栏一个在表单底部也能靠上下文语义正确区分。我在实验项目里跑通过一个最常见的登录流程输入用户名、输入密码、点击登录、断言URL跳转。用这套Agent循环中间不需要写任何固定选择器。把页面语义化做扎实之后换两套不同的前端UI都能跑过这就是底座的威力。4.3 安全与稳定Computer Use落地必须加的“保险丝”Computer Use最让人担心的是失控。模型下一个错误指令脚本可能点了删除按钮、退出登录甚至批量操作。所以落地时一定要加四道保险一是动作白名单。按项目风险等级配置允许执行的动作类型高风险操作如删除、清空、提交订单默认禁止除非测试任务里明确包含该动作且经过人工确认。二是确认回滚机制。执行任何破坏性动作之前Agent必须先把“准备做某事”写入日志并生成操作前状态快照。一旦后续步骤发现状态异常立即回滚到上一个稳定状态。三是步骤上限。所有Agent任务必须设置最大步数我一般给10到15步。超过上限强制失败并输出完整历史方便排查是任务描述不清还是Agent绕圈。四是人工审核模式。系统上线初期每跑的N条用例随机抽1条完整回放操作序列让人工确认Agent的决策链路是否合理。等你积累了足够的回放数据再逐步降低抽检比例。这些“保险丝”看着繁琐但它们是Computer Use能走进稳定测试环境的前提。没有约束的Agent拿来做Demo可以进CI门禁迟早出事。5. 三套方案怎么选能力对比与落地路径5.1 一张表看懂三种能力的适用边界很多朋友问我三者到底怎么选。先给一张我常用的对比表你对着场景判断就行能力输入形态抗UI变化定位精度成本延迟适用场景DOM语义化可访问性树文本强高明确元素低低常规表单、列表、CRUD页面视觉定位截图极强中坐标框高高Canvas、WebGL、自定义渲染、无DOM场景Computer Use决策指令强由前两者决定中中端到端流程、多步骤任务、探索性测试注意看“定位精度”这一行。DOM语义化虽然抗变化强但遇到一个元素动态生成的不同实例比如一排相同结构的卡片它只能给出“第3个卡片”这样的位置描述视觉定位能给精确坐标但坐标本身不等于稳定UI一改就得重新识别。所以精度维度上二者各有取舍。成本维度上DOM语义化基本可以忽略不计一个快照加上过滤就是毫秒级视觉定位则要想清楚调用频率。我见过一些团队把所有元素识别都走视觉一个月账单跑下来够买三年内部测试机这种做法不建议盲目复制。5.2 场景化选型什么时候该优先用哪套选型不用搞复杂记住三条经验法则第一能语义化别上视觉。90%的Web页面Accessibility Tree都能提供足够的交互元素信息。先走语义化命中不了再降级。第二无DOM场景直接上视觉。Electron里的Canvas画布、WebGL报表、视频播放器内部控件、图像编辑器的画布区域这些组件在DOM树里就是一块空白不截图连“目标长什么样”都不知道。这种场景视觉定位几乎是唯一选择。第三复杂流程任务用Computer Use统一调度。单个元素的定位选语义化或视觉但一旦用例有多个步骤、有分支判断、有异常兜底就需要Computer Use这一层来做“动作编排”。它不关心底层是哪个定位器给的坐标。我还给团队画过一条极简决策链页面是否有可交互DOM节点有用DOM语义化没有用视觉定位需要在多个步骤间动态决策挂Computer Use。三个问题走完方案就定了。5.3 团队落地三步走第一步搭底座做验证。先只实现DOM语义化快照跑通一个最简单的登录用例让团队熟悉LLM测试的基本工作流。这一步不用上视觉和Computer Use把地基打牢。第二步补视觉兜底。挑一条语义化搞不定的用例比如canvas绘制的流程图上点某个节点接入视觉定位服务让用例跑通。这一步的产出是建立降级策略语义化失败时自动切换视觉。第三步上Computer Use做编排。把单条用例改写成任务描述式验证Agent能自主完成多步骤操作再逐步把用例池往里迁。同时把日志、回放、审计这些配套功能完善起来。三步走完LLM测试底座就算真正落地了。整个过程不建议跳步尤其不要一上来就全量上Computer Use——没有语义化快照托底Agent的容错空间很小。6. 高频踩坑记录定位不准背后的真实原因6.1 坐标点到了却总是点不中这是视觉定位最常见的坑九成原因是坐标系不一致。截图用的视口尺寸是1920×1080视觉模型服务内部把图缩放到1024返回的坐标基于缩放后的坐标系直接拿去做mouse.click自然点偏。解决方式是在调用视觉服务前约定好坐标基准。我个人习惯是让视觉服务返回“归一化坐标”0到1区间客户端再乘回实际视口尺寸。归一化坐标的好处是和分辨率完全解耦无论浏览器窗口怎么缩放坐标都不会偏。# 归一化坐标转换示例 norm_x, norm_y 0.32, 0.55 viewport_width page.viewport_size[width] viewport_height page.viewport_size[height] real_x int(norm_x * viewport_width) real_y int(norm_y * viewport_height)另外注意浏览器缩放比。如果页面整体缩放不是100%截图和实际点击的物理坐标也有偏差。跑用例前先统一page.set_viewport_size和DPI设置把变量控制住。6.2 模型选错元素幻觉怎么破这是LLM测试特有的问题。模型明明知道要点击“登录”结果在候选列表里选中了“注册”。传统框架不会出现这种事因为选择器写死了。我的排查经验核心是缩小模型的“决策面”。做法包括给语义快照里的每个元素加编号让模型输出编号而不是自由文本每个候选元素附带简短描述减少歧义给任务描述加上“必须从候选列表中选择”的硬性约束。还有一个容易被忽略的因素历史上下文污染。Agent跑过多步之后历史记录里堆积了大量界面对话模型容易被早先的旧状态误导误以为当前元素还存在于页面上。解决办法是只保留最近2到3轮的状态快照以及在上一步动作完成后的新快照上重新决策。6.3 Token成本和响应延迟怎么控LLM测试跑一次用例Token消耗比普通API调用大很多响应延迟也高。控制的关键是“少喂、快断”。少喂语义快照只保留交互元素背景文字、装饰性段落、非交互区域一律过滤。截图只在视觉兜底时使用不为每个动作都截图。历史记录做滚动窗口超过3轮的旧记录及时截断。快断设置动作决策超时我通常给8到10秒超过直接降级。降级链是语义化快照 → 候选元素列表 → 视觉定位 → 人工确认失败。每降一级响应时间换个数量级。另外强烈建议做Token预算巡检。一条用例跑完统计每个环节的Token消耗你会惊讶地发现50%的Token浪费在重复获取未变化的页面上。优化思路是加“页面状态指纹”如果语义快照的哈希值没变化就直接复用上一次的决策结果不再调模型。6.4 动态内容下的等待与重试策略LLM测试和普通自动化一样逃不开动态加载问题。页面异步渲染、接口返回慢、加载动画遮挡都会导致Agent在错误的状态下做决策。我的等待策略用了“三静”原则网络静、动画静、元素静。网络静是指监听networkidle事件确保没有在途请求动画静是指关闭过渡样式或等待动画完成元素静是指目标元素在连续两次轮询中位置不变。三个条件都满足才把当前状态喂给模型。重试策略上我不建议对单动作无限重试。标准做法是每个动作最多重试2次每次重试前先刷新语义快照确认页面状态是否真的变了。如果快照没变说明问题不在等待而在模型决策本身这时候继续重试就是白烧Token应该立即把用例状态置为“待人工排查”。这套等待和重试策略在稳定性上帮了大忙。加了“三静”约束之后Agent误判率大概下降了六成主要原因是模型拿到的不再是“半成品”页面而是一个稳定可理解的界面状态。我个人在实际操作里的体会是LLM自动化测试的难点从来不在模型选型而在怎么把界面信息稳定地抽象出来喂给模型。视觉定位、DOM语义化、Computer Use这三个底座本质上就是在做这件抽象工作。先把它们打磨稳再谈聪明的Agent否则一切上层能力都是空中楼阁。最后分享一个我常用的组合拳DOM语义化先快速框定候选集视觉定位对候选集做精确认证Computer Use统一执行动作三套配合起来准确性、成本、速度才能同时兼顾。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询