移动端自动化测试做了这么多年最大的感受就是选对路线比优化执行重要得多。这系列前面几篇聊完 Web 和接口今天把镜头转到移动端重点拆解一条我认为目前比较有生命力的技术路线——LLM 驱动的移动端自动化尤其是 Mobile-Agent-v3 这种智能体方案以及我们团队自研的 GUI-Owl 模型在其中的定位。文章会包含方案拆解、模型设计思路、落地流水线、评测数据和踩坑记录适合正在做移动端测试平台建设、或者对 LLM Agent 落地感兴趣的测试开发和算法工程师。1. 移动端自动化为什么绕不开“视觉 智能体”1.1 传统自动化测试的三座山传统移动端自动化最让人头疼的不是写脚本而是脚本活不过一个版本迭代。第一座山是元素定位不稳定。很多 App 喜欢用自绘 UI比如地图、直播、游戏化界面整个屏幕就是一块大画布你找不到稳定的控件树更找不到固定的 resource-id。就算拿到了 XML 结构同等语义的按钮在不同机型、不同系统版本上的节点路径也可能完全不一样脚本动不动就挂在某台测试机上。第二座山是场景状态复杂。移动端不像 Web 那样有比较清晰的页面跳转链路权限弹窗、升级弹窗、弱网加载、前后台切换、登录态过期这些状态随时会乱入。我之前处理过一个很典型的例子测试脚本走到下单页结果被一个新手引导层挡住点击坐标落在引导气泡上用例失败。这种问题在传统脚本里只能不停加“如果出现 XX 就关闭”的兼容逻辑加的越多脚本越脆。第三座山是回归成本高。一个中大型 App 的自动化用例可能上千条每个用例都绑定具体元素和流程业务一改维护工作量成倍增加。很多时候测试团队不是没能力写自动化而是写了之后没人愿意维护最后变成一堆躺在 CI 里的废代码。这三座山本质上是同一个问题测试脚本耦合了太多业务实现的细节缺少一层能“看屏幕、懂意图”的抽象能力。1.2 LLM 带来的范式转换LLM 出现之后移动端自动化的思路终于可以换了。过去我们写的是“点这个按钮再等 3 秒再输入文本”现在只需要给模型一个目标“完成一笔金额为 10 元的充值”。这个范式转换的核心是把测试脚本从“固定路径的步骤集合”变成“有意图的任务描述”由模型根据当前屏幕状态实时决定下一步动作。这种转换最直观的表现就是多模态大模型开始被引入到移动端测试链路里。模型读取截图理解屏幕上的文字、图标、层级关系然后输出一个动作比如点击、滑动、输入、返回。整个交互过程很像一个真人测试员拿着手机在操作先看一眼屏幕想一下该做什么用手指执行再看一眼结果判断有没有做对。Mobile-Agent-v3 这类方案本质上就是在模拟这个过程。当然范式转换不意味着没有代价。LLM 推理的延迟、模型幻觉、动作执行的可重复性、在 CI 里的稳定性这些都是新问题。但只要把步骤的生成和执行解耦让模型负责“决定做什么”让测试框架负责“把它做掉”就已经比传统脚本方案前进了一大步。2. Mobile-Agent-v3 拆解从“看屏幕”到“想清楚再做”2.1 系列演进v1 到 v3Mobile-Agent 系列给我的印象像是一个移动端智能体的成长史。v1 阶段解决的问题是“让模型看懂屏幕并执行单步指令”当时最核心的突破是把多模态大模型接入了手机屏幕截图让模型可以输出“点击某个位置”或“滑动到某处”的动作。但单步操作离真实测试需求太远因为一个完整的业务用例往往需要十几次甚至几十次连续操作模型很容易中途忘了自己在哪、做到哪了。v2 开始引入任务规划和执行跟踪让模型能先把大任务拆成若干子步骤然后在执行过程中一边看截图一边标记进度。这个阶段的方案已经能跑通一些中长流程但问题是模型一旦遇到预期之外的弹窗或者页面变化就容易陷入死循环反复执行同一个错误动作。v3 在我看来补上了最关键的一块反思和长期记忆。它不再仅仅依赖单次截图做决策而是把每一步操作的输入、动作、截图、结果反馈组合起来放进上下文里做闭环。执行失败或者偏离目标的时候模型会自我总结原因并把这个教训写进记忆供后续任务参考。这个机制非常接近一个测试工程师的成长方式踩了一次坑下次就不再犯同样的错。2.2 v3 的核心闭环感知、规划、行动、反思Mobile-Agent-v3 的闭环可以拆成四个阶段。第一阶段是感知模型会拿到当前屏幕截图同时获取界面上的关键元素信息包括文字内容、图标类型、坐标位置。这里的重点不是简单地把整张图给模型看而是要提取出“这个按钮是什么、在哪”的显式信息降低模型的理解难度。第二阶段是规划模型需要结合任务目标和当前状态决定这一步该做什么。比如页面上有“确认支付”和“返回修改”两个按钮模型需要判断当前任务处于哪个阶段然后选择合适的动作。规划之后是行动模型输出一个结构化的动作指令例如点击某个坐标、输入一段文本或者滑动一段距离交给底层的执行模块去完成。第四阶段是反思。动作执行完以后系统会重新截图并判断状态是否发生了变化如果变化符合预期就进入下一步如果不符合模型会尝试分析原因。这里有一个很实用的设计把执行结果和预期结果同时放进提示词里要求模型输出“是否完成任务”和“失败原因”。这个反思结果不只在当前任务里生效还会被写入一个经验池在后续同类任务中直接复用减少重复试错。2.3 怎么接入现有测试体系聊到接入我的建议是不要想着用 Mobile-Agent-v3 替换现有框架而是把它作为智能决策层放到脚本和框架之间。具体做法是保留原来的移动设备管理、截图、手势执行等能力只让 LLM 和 GUI 模型接管“下一步做什么”的决策执行动作仍然走我们已有的底层接口。这样做的好处是原有的稳定性、多机调度、报告系统全部不用动引入 LLM 的风险被限制在决策层。在任务编排上可以把一个长流程拆成多个原子任务每个原子任务配一个自然语言描述由智能体逐个完成。比如“登录”是一个任务“进入个人中心”是另一个任务“修改昵称”是一个任务。这样单个任务的上下文长度可控就算中间某个环节失败也不至于把整个 case 毁掉。配合 CI 的话我是把智能体模块做成一个独立服务通过消息队列接收任务完成后回调结果和现有的测试平台解耦后续升级模型也不会影响主流程。3. 自研 GUI-Owl 模型路线为什么非做不可3.1 通用大模型在 GUI 任务上的短板最初我也尝试过直接用现成的通用多模态大模型来做 GUI 理解发现有三个很难绕开的短板。第一是空间定位精度不够通用模型擅长描述“屏幕上有什么”但不擅长确认“这个东西的精确坐标在哪里”。在测试场景里点击一个按钮如果偏差几十像素可能就点到了旁边的广告位这种误差不是靠提示词能解决的。第二是延迟和成本控制不住。移动端测试一个用例往往要几十轮交互每一轮都要传截图给大模型做推理单次耗时虽然可以接受但累加起来会让整个回归任务的执行时间变得不可控而且商用接口的调用成本会随用例量线性增长。内部跑上千条用例的时候这个成本是任何一个测试团队都要认真评估的。第三是私有化部署和一致性难保证。通用模型迭代快输入端稍微变化输出格式就可能变而测试工具最怕的就是“行为不可预期”。与其花大量精力去适配外部模型的各种小变化不如在关键路径上放一个我们自己能控制的、轻量的 GUI 感知模型。这就是 GUI-Owl 立项的初衷把“理解屏幕元素”这件最基础的事从大模型手里摘出来做成一个专用组件。3.2 GUI-Owl 的模型结构与训练路径GUI-Owl 的定位不是替代大模型而是做 GUI 任务的“前端感知器官”。它的输入是屏幕截图和可选的任务提示词输出的是一份结构化的界面元素列表包括每个元素的文本、类型、坐标和可交互性。生成这份列表的任务在学术上叫 GUI Grounding也就是把自然语言或者视觉特征映射到屏幕坐标上。模型结构上我们参考了比较成熟的“视觉编码器 文本解码器”范式但针对移动界面做了几个调整。一是输入分辨率不能压得太低至少保留原始宽度的 40% 左右否则小号文字和图标会糊成一团二是输出不只是坐标还要带一个“操作类型”头告诉上层这个元素适合点击、输入还是滑动三是增加了一个轻量的 OCR 辅助分支专门识别手写风格按钮和艺术字这些内容靠通用视觉编码器经常漏掉。训练路径分为两步。第一步是在海量 GUI 数据集上做预训练让模型学会从截图中定位可交互元素目标函数可以简单理解成“预测每个元素框的坐标和类别”。第二步是在带任务语义的数据上做指令微调让模型根据“需要完成 XX 任务”的提示词优先输出当前步骤相关的元素而不是把所有元素都列出来。这样 GUI-Owl 就不再是一个单纯的元素检测器而是一个能感知任务上下文的 GUI 解析器。3.3 训练数据的三类来源与成本控制做 GUI 模型最贵的是数据。我们的数据来源分三类第一类是从公开的移动端 UI 数据集中获取截图和标注这一部分用来打底能把元素检测的基础能力拉起来成本几乎为零。第二类是自动遍历生成我们用脚本在测试手机上随机操作并记录截图、控件树和动作路径再把控件树转换成伪标注虽然质量有些噪声但胜在量大可以覆盖很多长尾界面。第三类是人工作标针对自动遍历覆盖不到的、或者模型经常预测错的界面截图由测试人员手动框选元素并标注功能含义。人工作标是我们成本的大头所以只能用来解决最痛的问题。我一般建议先跑一版自动标注数据训练出来的模型在真实任务集上找出预测错误最多的前 20 类界面再定向补人工作标这样每一份人工数据都能带来收益而不是盲目堆量。成本控制上还有一个小技巧优先标注“按钮、输入框、滑动条”这些可交互元素不标纯展示文本因为测试真正关心的只有能操作的东西。另外图像去重要有同一个界面的不同机型截图只保留少数几张避免模型过拟合背景样式反而丢了通用能力。4. 落地实操搭建一条可落地的 LLM 移动端自动化流水线4.1 组件选型与整体调用链我们最终搭出来的流水线核心由四个组件组成设备管理服务、GUI-Owl 推理服务、LLM 规划器、动作执行器。设备管理服务负责连接所有的测试手机统一提供截图、应用安装、手势执行等基础能力。GUI-Owl 推理服务跑轻量模型把截图转成结构化元素列表。LLM 规划器负责读任务描述和元素列表决定下一步动作。动作执行器负责把动作发回设备并确认结果。整条调用链是这样的首先测试平台下发一个任务比如“完成一笔金额为 10 元的充值”设备管理服务截取当前屏幕传给 GUI-OwlGUI-Owl 返回屏幕元素列表LLM 规划器结合任务目标和元素列表输出一个动作指令动作执行器收到指令后在手机上执行执行完成后再次截图进入下一轮。关键点在于大模型不需要直接看原始截图它看到的是经过 GUI-Owl 处理后的结构化状态这能大幅压缩 token 数量也减少了感知层面的幻觉。组件选型上我个人建议用 Python 写任务调度和推理逻辑因为模型推理生态最成熟队列用轻量级的消息中间件就行没必要一开始就上重型框架。GUI-Owl 的推理服务可以做成 HTTP 接口单独部署和主测试平台分开方便后续扩容。如果你的团队已经有一套移动端测试框架不要推倒重来把 GUI-Owl 和 LLM 规划器嵌进去做成一个决策服务是最平滑的落地方式。4.2 关键环节实现细节落地过程中有三个环节最容易出错截图、坐标映射、动作回放。截图这一步要特别注意分辨率。手机屏幕原始分辨率往往超过模型输入尺寸直接压缩会导致小元素丢失。我们的做法是保留原始截图同时按比例生成一个模型可接受的缩放图并记录缩放系数。GUI-Owl 输出的坐标统一用归一化坐标也就是 0 到 1 之间的比例值这样就不依赖具体分辨率。后续执行动作时再通过缩放系数换算回原始像素坐标误差可以控制在很小范围内。坐标映射还有一个容易被忽略的坑不同手机的系统状态栏和底部导航高度不一样。如果截图时没有裁掉这些区域模型输出的坐标很可能偏移。我们在设备管理服务里统一按屏幕显示区域截图并在截图上去掉状态栏和导航栏保证 GUI-Owl 看到的区域和用户可操作区域一致。动作回放方面我们定义了一套最小动作集只保留了 5 种原子动作点击、长按、滑动、输入文本、返回。每次模型输出动作时必须带上动作类型和参数比如点击需要带坐标输入文本需要带文本内容和目标坐标。执行器会先做一次参数合法性校验坐标越界或者文本超长直接拦截防止模型幻觉导致误操作。以下是一个动作指令的简化格式{ action: click, coordinate: [0.623, 0.418], element_id: btn_confirm, description: 点击确认充值按钮 }4.3 评测指标与结果量化评测体系我建议分成两层模型层和任务层。模型层主要看 GUI-Owl 的元素定位准确率、元素类型分类准确率、OCR 文本识别准确率。任务层主要看完整流程的成功率、平均操作步数、平均执行耗时、失败原因分布。任务层指标直接反映业务价值模型层指标则能帮我们定位是感知问题还是规划问题。在一组内部测试任务集上我们对比了三种方案传统脚本、通用大模型直接决策、GUI-Owl LLM 规划器。数据集包含 12 个典型业务任务覆盖登录、搜索、下单、设置修改等核心流程每类任务执行 20 次。方案任务成功率平均操作步数单任务平均耗时传统脚本54%8.238 秒通用大模型直接决策61%11.596 秒GUI-Owl LLM 规划器82%7.652 秒数据其实反映了两个事实第一纯 LLM 直接决策虽然有成功率但步数偏多、耗时高说明模型在“理解屏幕”上浪费了太多试错第二加上 GUI-Owl 做感知以后成功率显著提升耗时也降到接近传统脚本的水平。这说明感知层的专用模型不是多余的投资而是控制延迟和稳定性的关键。5. 常见问题与避坑实录5.1 截图分辨率与坐标映射问题这个坑几乎每个第一次做视觉自动化的人都会踩。我们最初直接把高分辨率截图压缩到模型输入尺寸结果模型输出的坐标总是偏左下角排查了很久才意识到是截图时没有处理系统导航栏导致视觉区域和操作区域错位。解决方法是统一从“去掉状态栏和导航栏的显示区域”开始截图并使用归一化坐标作为中间层。还有一个常见问题是动态弹窗导致的状态突变。模型刚生成点击坐标下一秒弹窗出现原来的按钮被顶到下面去了。我们在动作执行后增加了一次状态校验对比执行前后截图的关键区域是否发生变化如果发现异常会丢弃当前进度并重新规划而不是硬着头皮继续点击。这套机制能拦截掉大量定时弹窗造成的失败。5.2 动作空间设计与任务不可达动作空间设计直接决定任务上限。早期为了限制模型行为我们只开放了点击和滑动结果很多任务根本做不完比如修改昵称需要先点输入框再输入文本再点保存没有输入动作就永远卡住。后来我们把动作集扩充到上面的 5 种原子动作任务成功率立刻涨了一截。动作空间也不是越自由越好。如果允许模型自由组合所有参数它可能会生成一些底层的操作比如“在任意位置连续点击三次”这种动作在真实业务中很难断言对错。我的经验是动作类型应该枚举化动作参数应该结构化每个参数都做范围校验。模型只能在预定义的动作集合里选参数必须符合设备接口的约束。这样既给智能体留足空间又不会让执行端变得不可控。5.3 数据迭代优先级与回归污染数据迭代上最容易犯的错误是看到哪个界面预测不准就去标哪个结果标了一套数据模型在旧任务上反而变差了。这是典型的回归污染。我们后来强制规定不管新增多少数据每次模型更新之前都必须跑一遍完整的回归任务集成功率不低于上一个版本才能发版。优先级的判断标准也比较朴素先处理失败频率最高的界面再处理影响任务链路最长的界面。比如登录页面的按钮识别错误会导致所有依赖登录的任务全部失败那登录页面的标注优先级一定是最高的。反之某个冷门设置页识别错误只影响一个低频任务就可以往后排。数据迭代是个持续工程一定要有版本管理和回归机制否则模型只会越改越乱。另外GUI-Owl 发布后最好保留每个版本的推理日志。遇到线上问题可以快速确认到底是因为“界面没看懂”还是“规划错了”再去决定是补数据还是调提示词。只凭感觉改模型是我见过最多的失败路径。最后给想入坑的朋友一句实在话不要一开始就想着自研一个完美的 GUI 模型先把手头的测试框架和 LLM 规划器跑通把动作空间、数据回流、评测指标这些基础打好。等真实跑了一两个月你才会清楚瓶颈到底在感知层还是在规划层再决定要不要往 GUI-Owl 这条路线投入。我个人走过一遍以后最大的体会是LLM 驱动移动端自动化的价值不在“无人值守”而在把测试人员从重复的脚本维护里解放出来让机器去理解和执行用户的真实意图测试工程师只需要坐在那里看报告、定方向就够了。这个方向后续还可以继续往多设备协同、跨 App 业务流程、异常路径自动探索这些方向扩展想象空间确实不小。