资讯动态

通用Agent框架下沉移动端测试:从自由探索到固定任务的场景化改造

发布时间:2026/10/19 1:04:42 来源:尧图企业网站定制
如果你做过一段时间的移动端自动化测试大概率对两件事印象深刻一是UI自动化用例的脆弱二是LLM在这件事上前所未有的吸引力。前几期我们聊过LLM做测试用例生成、错误分析、元素匹配也专门讲过移动端的取流、控件定位和稳定性策略。这一期系列第9篇移动端第5篇把话题指向一个更偏架构的方向当一套面向通用任务的Agent框架真正下沉到移动端测试场景会发生什么。所谓下沉不是把Agent聊天界面换成一个App就完事而是说把大模型驱动的任务规划、工具调用、状态感知、自我反思这套能力折叠进测试执行器里让它在移动端UI自动化的真实约束下干活。开头先下个结论通用Agent很强但不会原样适合测试能在测试场景里站住脚的是对Agent做了一整套场景化改造后的产物。这篇文章就把这套改造过程拆开讲适合正在做LLM加移动端自动化的团队和个人参考。1. 为什么通用 Agent 框架到了测试场景必须重新改造1.1 场景诉求的反转从“探索开放目标”到“完成固定任务”通用Agent的设计初衷是面对一个开放式目标例如“帮我规划一次周末旅行”它自己去拆步骤、选工具、判断中间结果是否合理。它的能力假设里藏着几件事目标可以是模糊的允许试错环境反馈足够丰富单次会话结束就算交付。移动端自动化测试把这几条几乎全部反过来了。测试用例的目标不是模糊的而是明确的登录要走到首页下单要出现订单号设置里改完开关状态要持久化。试错是被强烈禁止的一套回归用例跑十次历史问题不该因为Agent某次“尝试”新路径而被漏掉。环境反馈不仅不丰富而且噪声极大权限弹窗、广告位、启动动画、网络抖动都在干扰判断。最重要的一点是测试要讲究可复现和可审计一个用例跑过之后你得能回答“它到底点了哪里、为什么认为结果正确”。这就导致了一个结构性矛盾通用Agent的强项是自由探索测试场景最不需要的恰恰就是自由探索。把通用Agent不做改造直接接到移动端设备上它会很自然地去做许多测试人员不想让它做的事情比如点掉一个系统弹窗、滑到页面底部看有没有新内容、对着广告位产生兴趣。这些行为对普通助手来说是“智能”对测试执行来说是灾难。1.2 为什么“加一句 Prompt”解决不了下沉问题有人可能会说下沉无非是把Agent接到设备控制工具上再加一句“你是一个专业的测试工程师请严格按照用例执行”。这句话单独看没错实际用起来却远远不够。原因是Prompt只能影响模型的输出倾向改变不了它决策的信息来源和执行约束。一个Agent在移动端设备上做决策时需要知道“当前屏幕上有什么、哪些是可点的、哪些是文本输入框”这些东西来自设备侧的UI层级快照。而测试场景要求Agent不能去点系统状态栏、不能误触广告位、不能在没有等到页面稳定时连续点击这些约束写在系统提示词里当然可以但模型并不会逐条遵守尤其在上下文很长、前面已经执行了几十个步骤之后模型很容易忘记早期的边界设定。所以下沉的本质工作是两件第一在Agent的感知层和执行层之间插入一套测试场景特有的过滤器让模型只看到它应该看到的第二把“允许自由决策”的边界用规则显式写死让Agent在边界内规划而不是在每个动作上等待它自觉。这件事靠Prompt做不干净必须从框架层面动手。提示判断一个方案是“真下沉”还是“套壳”就看它在感知层和执行层有没有引入测试语义。如果只是给模型加了一段测试工程师角色设定那只能算是聊天Demo接了个鼠标键盘。2. 把测试用例翻译成 Agent 能执行的任务剧本这一步别偷懒2.1 任务描述从“一句目标”升级为“结构化剧本”通用Agent的输入可以是一句话比如“帮我把这个App的登录流程跑通”。但移动端测试用例落到执行层面至少要让Agent知道四个维度的信息当前设备处于什么状态、操作目标是什么、哪些界面元素可以作为操作对象、最终拿什么标准来判定成败。我们内部把一个测试用例改写成结构化剧本字段大致长这样字段示例值作用前置状态App冷启动未登录决定Agent第一步从哪里开始起始页面登录页帮助Agent建立“当前坐标”操作目标完成账号密码登录并进入首页驱动规划层拆解原子步骤预期断言首页出现用户名文本执行结束后由规则断言器判定约束条件跳过隐私协议弹窗不点击任何广告位限制Agent的行为边界超时控制单步10秒整条用例90秒避免在异常状态里无限循环这个模板看起来像是传统测试用例的字段扩充但它的关键区别在于这些字段是给规划器用的而不只是给人看的文档。前置状态和起始页面决定了Agent第一次感知时应该期望看到什么预期断言决定了Agent结束执行后框架要检查什么约束条件实际上会被编译成执行器侧的动作拦截规则。我们实践下来发现如果省略“约束条件”这个字段Agent在场景里被系统弹窗或广告带走几乎是必然的。因为从模型的视角看弹窗上的“允许”按钮和业务页面里的登录按钮地位相同都是可点击节点。你不提前告诉它哪些区域不许碰它就真的会碰。2.2 规划输出必须结构化目标必须以语义描述为中心Agent拿到任务剧本后的第一件事是生成规划。为了不让这个规划变成一段“看起来有道理但无法执行”的自然语言我们在输出侧做了强约束。规划被定义为JSON数组每个步骤包含动作类型、目标描述、执行后校验点。{ plan: [ { step: 1, action: tap, target: 登录页账号输入框, check: 出现键盘输入光标 }, { step: 2, action: input, target: 登录页账号输入框, text: test_user_001, check: 输入框文本变为test_user_001 }, { step: 3, action: tap, target: 登录页登录按钮, check: 页面跳转到首页 } ] }这里有两个细节值得展开。第一target字段写的是“登录页账号输入框”而不是具体的“控件ID”或“坐标值”。坐标在UI微调后立刻失效ID在跨平台和动态渲染场景里经常拿不到而语义描述可以在执行时通过UI层级摘要做匹配对细微的布局变化有更强容忍度。定位这件事真正落地时是用“语义描述”去匹配实时UI快照而不是由模型直接拍一个坐标出来。第二每个步骤自带check字段相当于把传统自动化里的“执行后断言”提前到了规划阶段。它可以是一个页面跳转判断也可以是一个文本变化判断。执行器每完成一步先跑该步的check再决定是继续下一步还是让Agent反思修复。这个机制把“规划”和“校验”解耦了即使Agent规划的路径有问题执行器也能在中间步骤发现问题而不是一路错到底。3. 移动端 UI 状态怎么喂给 LLM场景感知与动作空间设计3.1 从原生层级到UI摘要控制信息密度比堆信息更重要移动端的UI状态感知最原始的做法就是把设备侧的视图层级整包丢给模型。iOS侧拿到的视图树、Android侧拿到的View节点树一个复杂的页面动辄上千个节点其中包含大量不可见、不可交互、纯用于布局的节点。把这些原样塞给LLM会出现两个问题一是token消耗会瞬间爆炸一个页面几万token很常见跑一条用例几十步成本完全失控二是信息噪声会显著拉低模型的判断准确率模型会盯着哪些隐藏节点或非业务区域的文本反而忽视真正该操作的目标。我们的处理流程分三步先过滤再摘要最后叠加截图。过滤规则只保留“可见且可交互”的节点剔除不可见、透明、宽高为0、纯容器节点。接着把剩余节点按页面区块归纳成结构化文本形成一页UI摘要。最后对于视觉信息占主导的页面例如图片轮播、卡片式信息流再附上一张降采样截图给多模态模型兜底。一份UI摘要长这样当前页面登录页 可见控件 - 输入框: 账号placeholder: 请输入手机号 - 输入框: 密码placeholder: 请输入密码 - 按钮: 登录支持点击 - 链接: 忘记密码 - 弹窗: 隐私协议按钮: 同意、拒绝 坐标信息账号输入框(540,320,700,100)密码输入框(540,460,700,100)登录按钮(540,620,700,100)注意摘要里保留了坐标但坐标在这里是给“执行器”用的不是给“模型规划”用的。模型读到的是控件的语义类型和文本执行器拿到模型选择的语义描述后再去摘要里匹配对应坐标完成点击。这种分层各取所长的做法比让模型直接输出坐标要稳定得多。3.2 动作空间必须收窄成最小可靠原子集通用Agent的工具面通常很宽能打开网页、查数据库、发请求、调用代码解释器工具之间还能自由组合。但这种宽泛放到移动端测试场景里不是优势模型在工具选择上多花一次决策就多一分选错的风险。我们最终把动作空间收敛成9个原子动作每个动作对应设备侧一个确定的执行函数。动作参数说明taptarget点击一个语义目标long_presstarget, duration长按触发上下文菜单inputtarget, text输入文本swipestart, end, duration按坐标滑动scrolldirection, distance列表滚动back无返回上一页waitseconds显式等待用于页面稳定capture无截图并生成UI摘要assertexpected规则断言不开放给Agent自由评断为什么没有提供更多动作比如双击、拖拽、摇晃设备因为这些动作在测试主流程里出现频率极低多放一个动作进来模型在下一次决策时就要多一个候选复杂页面里很容易选错。动作空间越窄Agent的行为越可预期排查问题也越容易。工具不是越多越好是越贴合场景越好。输入动作值得单独说一句。移动端输入相比Web端的type操作有一个隐蔽的坑系统输入法和第三方输入法会改变键盘形态直接type的文本经常因为键盘切换而丢失。我们的做法是优先使用剪贴板方案把文本写入剪贴板再通过长按输入框选择“粘贴”。这个方案能绕开大部分输入法兼容问题但也要注意剪贴板权限弹窗弹窗出现时仍然会被执行器拦截逻辑接住。每个动作执行完设备侧需要返回一个统一格式的结果对象里面包含执行状态、当前UI摘要、截图路径和需要给到模型的关键信息。这个统一结果结构是后续所有反思、重试、失败分析的基础没有它Agent就是一个只能发指令、听不到回音的瞎指挥。{ action: tap, status: success, target: 登录页登录按钮, evidence: { screenshot: /evidence/shot_001.png, ui_snapshot: /evidence/ui_001.txt } }4. 稳定性设计与状态校验把 Agent 的“自由发挥”关进笼子4.1 先感知后行动执行前校验是规则代码不是LLM自评Agent的规划输出里目标描述是“登录页登录按钮”它并不知道这个按钮在当前屏幕上对应哪个坐标。坐标解析发生在执行器里执行器拿到UI摘要后用语义匹配把“登录页登录按钮”映射到具体坐标点然后才执行点击。这个环节里最关键的一个设计是如果当前UI摘要里根本找不到Agent描述的目标执行器绝不猜测一个近似位置去点而是直接把“目标不可见”的结果反馈给Agent并附带当前UI摘要让Agent重新感知和规划。这个“找不到就不执行”的原则是我们踩了很多次“模型幻觉导致乱点”之后总结出来的。LLM有一种倾向在上下文不完整时会“脑补”出它认为应该存在的元素。比如它认为这一步之后应该进入设置页就可能在当前页面没有设置入口的情况下仍然输出“点击设置按钮”。如果执行器直接按文本去匹配匹配不到就报错那Agent会得到正确的反馈但如果你为了“提升执行成功率”加了一个模糊匹配让它去点最接近的元素那就可能点到完全不相干的功能。测试场景最怕这种静默错位错误往往到很后面才会暴露。所以“先感知后行动”是一条强制性原则。ActionDescriptor只作为期望能否执行完全以实时感知结果为准。所有语义匹配逻辑全是确定性规则代码不允许模型在“目标是否存在”这个问题上自行判断。模型能做的是在匹配失败后调整策略例如滚动一下页面或者回头审视自己的规划是否出了问题。4.2 断言与证据链信任规划能力但绝不信任自我评价另一个容易踩的坑是让LLM自己判断执行是否成功。模型偏低估失败、倾向乐观让它对着截图说“这个步骤已经完成”经常得到错误的“成功”结论。我们现在的分工是规划能力信任LLM校验结论交给规则。规则断言可以是元素的显隐判断、文本内容匹配、控件属性值校验也可以是页面截图的像素差异分析。这些断言必须能在毫秒级完成不能依赖模型推理。每条用例结束时的预期断言默认全走规则框架。如果规则断言通过了整条用例判为通过如果断言不通过才轮到LLM介入分析失败原因。证据链是这套设计的另一个支撑。每执行一个动作设备侧就自动生成一张截图、一份UI摘要、一条动作日志。用例结束时如果失败框架会把完整证据包自动打包包括动作序列、每一步的截图压缩包、UI摘要变化记录、设备侧系统日志和崩溃栈信息。我们在实际排查问题时发现这个证据链的价值甚至高于LLM的失败分析本身。传统自动化失败时要靠人去复现Agent模式下的执行本身就产出了足够详细的现场记录人工排查时间能压缩到一个非常小的量级。evidence/ 001_tap_login_button_ok.png 001_ui_snapshot_ok.txt 002_input_account_ok.png 002_ui_snapshot_ok.txt 003_tap_submit_fail.png 003_ui_snapshot_fail.txt crash.log device_sys.log5. 成本与并发Agent 进入移动端测试规模化的两道坎5.1 token成本拆解一条用例究竟吃掉多少上下文移动端自动化不像Web端那样可以用一个长文档把所有页面元素塞给模型。每个页面都需要实时感知每次感知都意味着新的token消耗。我们做过一次粗略估算一个30步操作的回归场景假设每步需要UI摘要约300token带上历史上下文约800token模型回复约200token单次操作就要消耗约1300token整个场景跑完约4万token。再加Agent反思和重试实际消耗翻一倍并不稀奇。这个成本模型决定了任何“每步都调用最强模型”的做法都不能规模化。降本手段有三个方向。第一是感知层降本UI摘要里只保留模型决策真正需要的节点能用规则过滤的就不进模型能用文本OCR解决的就不上多模态。第二是上下文压缩相同页面的UI摘要加哈希缓存页面没变就直接复用不重复生成。第三是模型分层页面摘要、元素分类这类简单任务用开源小模型处理只有规划、反思、失败分析这类高难度任务才调用大参数模型。注意成本优化目标不一定是最低单次消耗而是让一整轮完整执行的总成本可控。单纯压低单步成本如果导致重试率上升整体成本反而更高。判断标准应该看“每百条用例有效通过所需的总token数”。5.2 多设备并发的调度Agent规划一次设备执行N次移动端测试的日常场景里设备往往不是一个而是一批真机集群、模拟器云平台动辄几十台。如果按“每台设备跑一个Agent实例”的粗放方式做并发模型调用量会随设备数量线性膨胀而且各设备执行结果不一致的概率也会放大。更合理的思路是给Agent分层Model层只做规划、反思、失败分析Device层只做确定性执行。一个Agent在Host侧完成规划把结构化脚本下发给一组设备设备执行期间不依赖模型只在失败时把本机证据包传回Host由Agent解释失败原因并决定是生成修正脚本还是标记缺陷。这样模型调用量从“设备数乘步骤数”降为“规划一次加失败分析若干次”整体成本下降一个数量级执行一致性也大幅提升。这套“Agent规划、设备执行、云端回溯”的分层设计是通用Agent框架下沉到测试场景时最值得做的架构调整之一。它的本质是把大模型的“生成能力”从执行管线里剥离出来让它只负责创造性部分把重复性、确定性部分留给规则引擎。6. 踩坑实录通用 Agent 下沉到移动端测试时的五个典型问题6.1 五类高频问题的现象与解法问题现象根因分析我们的解法Agent 点击了系统弹窗的“允许”按钮系统弹窗节点在UI树中可见模型无法区分系统级和业务级控件系统弹窗坐标黑名单UI摘要中直接剔除Agent 被截图里的广告横幅带偏目标广告区域视觉权重高多模态模型易误判为业务内容广告区域蒙版UI摘要中剔除该区块输入中文后页面状态迟迟不更新第三方输入法覆盖了原生控件信息UI树读取不完整输入后强制隐藏键盘并等待层级稳定再取快照页面轻微变化导致整页重新感知没有页面指纹每次操作后全量重新生成UI摘要页面哈希缓存命中后直接复用摘要模型自评“成功”但实际断言失败LLM存在乐观偏差倾向于在信息不足时判定成功规则断言优先失败证据必须由框架收集这个表格里的坑前两个都是典型的“模型看到了不应该看到的东西”。下沉改造的核心工作之一就是在感知层帮模型做减法。系统弹窗、广告位、诱导浮层这些在通用对话场景里无关紧要的内容在测试场景里就是必须屏蔽的噪声。我们在UI摘要生成阶段就把它们剥掉模型根本没机会决策要不要点它们。6.2 当前沉淀下来的参考架构与动手建议经过这几轮改造我们最后沉淀下来的参考结构大致呈四层任务输入层负责把测试用例转成结构化剧本规划层由LLM负责生成路径、反思异常、给出修复建议校验层用规则引擎做元素匹配、断言执行、UI摘要缓存执行层只负责调用设备侧的原子动作并采集证据。一条用例的形态也随之变化它从一段挺长的代码脚本变成一份声明式的YAML任务描述配上规划器生成的执行计划再配上全套证据链。设备上的用例描述大概是这种样子case_id: login_001 precondition: app_state: cold_start login_state: not_logged start_page: 登录页 goal: 完成账号密码登录并进入首页 assertions: - element: 首页用户名 condition: visible - element: 首页用户名文本 condition: text_equals 测试用户001 constraints: skip_system_dialog: true ad_area_blocked: true timeout: step_timeout: 10s case_timeout: 90s如果你正打算把通用Agent框架往移动端测试场景引我的建议是先别急着上最复杂的场景。挑一条高频却稳定复现的登录用例手工整理出它的剧本、动作空间、UI摘要格式和断言规则把这条路走通。然后让Agent连续重复跑这同一条用例二十次重点观察三个指标规划成功率、重试率、模型自评与规则断言的一致率。这三个数字基本能反映出你的下沉改造做到什么程度了。我个人在实际操作中的体会是通用Agent框架下沉到移动端测试场景最难的并不是把LLM接进来而是把自由空间收窄到一个测试工程师愿意签字放行的范围。我们踩过最大的坑从来不是模型能力不够而是太相信模型自主判断。现在这套方案里凡是跟最终结果相关的地方基本都是规则兜底LLM负责生成路径、解释异常、补全描述。这个分工一旦清晰落地速度反而快了很多。下一步我打算继续做的是把失败证据包和用例历史数据回流成更好的评估集用来持续衡量Agent在测试场景下的真实退化而不是只看它今天跑了多少通过率。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑