首页 / 资讯中心 / 文章详情

通用Agent框架下沉移动端自动化测试的关键改造与实践

通用Agent框架下沉移动端自动化测试的关键改造与实践 ★ FEATURED ARTICLE
这几年的LLM Agent热潮让不少团队误以为从此告别了“写脚本”的苦日子。任务规划、工具调用、自我纠错一套能力组合拳打下来看上去什么都能干。可一旦真把一套通用Agent框架直接搬进移动端自动化测试问题马上就来了。我见过不少团队用一两周时间搭出惊艳的Demo然后在接下来的几个月里被各种边缘Case反复教做人。这个系列写到第九篇移动端部分也到了第五篇正好卡在“通用Agent框架如何下沉到测试场景”这个坎上。这篇文章只聊一件事当一套原本面向通用任务的Agent框架被放到移动端自动化测试里会发生什么、需要改什么、以及怎么让它从“看着很聪明”变成“用着很稳”。里面所有经验都来自我这边实际的落地过程不是纸上谈兵。通用Agent框架“下沉”前先想清楚测试场景的特殊性1.1 通用Agent的标准能力栈到底是哪几板斧主流的通用Agent框架核心能力大致可以拆成四块。第一块是任务规划给一个大目标模型会把目标拆解成若干子步骤比如“打开首页 → 进入登录页 → 输入账号 → 输入密码 → 点击登录”。第二块是工具调用框架定义了若干函数或者接口模型根据当前状态选择合适工具并生成对应参数。第三块是自我反思执行完一步之后模型会观察执行结果判断有没有达到预期如果没达到就开始重试或者换一条路径。第四块是自然语言交互使用者可以直接用“帮我验证一下登录流程是否正常”这种话去驱动整个系统。这套能力放在通用场景里确实好用比如让Agent帮你去查资料、整理文档、做数据分析。但问题在于通用Agent的设计目标是“完成用户意图”而自动化测试的设计目标是“验证系统行为是否符合预期”。这两个目标听起来接近实际上差着十万八千里。1.2 测试场景的四个硬约束任何一个出问题都是灾难我做了几年移动端自动化回头总结下来测试场景对Agent的约束可以归纳成四个词可重复、可判定、可定位、可审计。可重复指的是同一条用例跑十次步骤顺序、操作参数、断言逻辑都应该保持一致。Agent的规划能力在这里反而容易帮倒忙因为LLM天然带有随机性同样的Prompt可能生成不同的执行路径。可判定指的是每一步或者最终状态都需要有一个明确的“通过/失败”标准。通用Agent可以告诉你“我觉得执行成功了”但测试系统需要的是硬邦邦的断言结果。可定位指的是操作和错误必须能对应到具体的页面元素、控件或者接口方便排查。可审计指的是每一次运行都要有完整的日志、截图、调用记录出了问题能回溯到是哪个环节导致的。这四个约束每一项都在和“通用Agent的天性”做斗争。1.3 为什么“什么都能干”反而测不好我一直觉得通用Agent在测试场景里的最大敌人不是能力不足而是“太过聪明”。模型在规划的时候会本能地选择“看起来最合理”的路径而不是“脚本里规定好的那条路径”。举个我实际遇到的例子让Agent验证登录失败时的错误提示它第一次跑的时候直接绕过了错误步骤理由是“当前页面并未出现用户名输入框因此无法继续执行”。听起来很有道理但这条用例已经稳定跑了大半年问题出在页面加载动画还没结束、元素树还不完整的时候Agent就开始行动了。还有一个更隐蔽的问题就是Agent会“自证清白”。如果上下文里带着“登录成功”的历史信息模型在执行断言阶段很容易被之前的步骤影响倾向于得出“一切正常”的结论。这个现象在心理学上叫“确认偏差”在LLM上表现得尤其明显。所以通用Agent框架“下沉”到测试场景时我方的核心任务不是怎么教它做更多事而是怎么给它划清楚边界哪些地方允许自由规划哪些地方必须机械执行。下沉改造的关键设计把“会规划”改造成“会测试”2.1 工具集重构别给Agent一堆“万能工具”很多团队在接Agent平台时第一反应是把所有自动化能力都暴露成工具函数给模型调用启动应用、点击坐标、输入文本、滑动屏幕、截图应有尽有。结果就是模型经常选不对工具或者参数填得乱七八糟。我这边做了两轮改造效果立竿见影。第一轮是给每个工具都加上强类型的参数结构不让模型自由发挥。比如点击操作不允许直接传像素坐标而是要求传“通过元素ID定位”或者“通过文本内容定位”把定位方式明确限定为几种。第二轮更彻底直接把工具按“动作类”和“断言类”分开。动作类工具负责操作页面点击、输入、滑动、返回、等待。断言类工具负责验证状态断言元素存在、断言文本匹配、断言控件可见。两类工具在定义上严格隔离模型想通过“动作工具”去断言是做不到的想通过“断言工具”去执行点击也做不到。这一条看着简单实际操作下来能省掉一半的脑洞Bug。2.2 状态感知OCR、布局树、截图三种通道缺一不可移动端Agent和Web端Agent相比最大的难点在于端上页面没有统一的DOM结构可以拿来做语义解析。iOS是一套体系Android是一套体系自研引擎的App又完全不一样。所以想让Agent“看懂”屏幕需要至少三条信息通道。第一条是布局树或者说控件树。Android有无障碍节点iOS有可访问性快照这些数据能提供控件的类型、文本、坐标、可见性等结构化信息相当于给模型一张“带标注的地图”。第二条是OCR文字识别。布局树经常拿不到图片类内容的文本信息比如背景图上的Banner文字、营销活动里的金句文案、验证码图案这时候OCR就派上用场了。但OCR的结果没有坐标关系也识别不了控件边界只能作为辅助。第三条是截图本身。模型需要看截图来判断视觉布局、颜色状态、弹窗样式尤其是页面出现非预期弹窗时截图往往是唯一能发现异常的通道。我现在的方案是三步走先拉布局树再根据布局树的坐标区域截取局部图做OCR最后把整屏截图和布局树叠加交给模型。整个过程要控制上下文数据量不能每次把所有截图都塞进Prompt否则成本会爆炸。2.3 断言权限要单独拿出来让Agent替“不容易”我之前踩过一个特别典型的坑Agent跑完一条用例之后在总结里写“断言通过”但日志里根本没有调用任何断言工具。去翻才发现模型在思考链路里自己给了一个“看起来像是断言”的判定并没有真正执行断言函数。这个问题的本质是把“验证”这个动作交给了模型的主观判断。后来我规定了一条铁律Agent必须通过断言工具来结束一个阶段的任务工具返回的结果是什么报告就写什么Agent不得在上下文里自行“总结”断言结论。同时断言结果要求强制结构化输出包含布尔值、置信度、快照地址、原始消息四部分。这样即便模型的结论和真实断言不一致系统也能用结构化结果去比对把主观干扰降到最低。2.4 安全护栏让Agent在笼子里跳舞通用Agent框架最吓人的一点是它在执行任务时可能做出一些越界操作。移动端测试场景里常见的风险包括在登录状态下误点了“退出登录”、在支付页面误触了支付按钮、在填写表单时把线上数据改掉甚至在某些App里触发了注销账号的流程。我的做法是给Agent加了三层护栏。第一层是操作白名单在Init的时候注入一套任务指令集只有白名单内的控件类型才能被指定为操作目标比如允许点击按钮、允许输入文本框但禁止点击“注销”“删除”“退出登录”这类危险控件除非显式加进白名单。第二层是沙箱环境所有自动化运行都在专用的测试包和测试账号下执行线上包和真实数据绝不接入。第三层是熔断机制每个任务设定步数上限与时间盒一旦超限立即停止并生成崩溃报告不允许Agent无限重试下去。实操一套“提问—规划—执行—复核”四段式流程3.1 四段式总览把自由裁量权压缩最小直接拿通用Agent的ReAct循环去跑移动端测试日志会非常难看因为模型一会儿思考、一会儿调用工具、一会儿观察结果整个轨迹缺乏仪式感。我在项目里把流程重构成四个明确阶段每个阶段都有专属的上下文模板和输出格式。第一阶段叫“提问”人类测试工程师用自然语言描述用例目标同时附上前置条件、测试数据、必走路径和预期结果。第二阶段叫“规划”Agent输出一条结构化的执行计划每条计划由动作、目标控件、预期结果、下一步四个字段组成。规划结果要给人看能人工修改后再进入执行。第三阶段叫“执行”按照规划逐条调用动作工具每执行完一步就抓取新一轮页面状态。第四阶段叫“复核”Agent调用断言工具验证最终状态并输出结构化报告。这四个阶段的核心思想很简单把“自由发挥”限制在“规划”这个环节把“执行”变成机械过程把“判定”完全交给工具。3.2 一个完整的虚拟用例拆解登录后领取新人券拿“某电商App登录后领取新人券并确认卡包数量增加”这条用例来跑一遍四段式流程。提问阶段注入的信息是这样的前置条件使用测试账号A登录账号已注册但从未领过新人券。 必走路径首页→个人中心→登录→新人券专区→领取→卡包。 预期结果卡包内券数量1页面出现“领取成功”样式。规划阶段Agent给出的执行计划大致是启动应用等待首页加载完成。进入个人中心检查当前登录态通过断言工具是否存在“未登录”字样。如果存在未登录字样点击登录按钮输入测试账号、密码点击确认。返回首页进入新人券专区。点击“领取新人券”按钮。断言页面出现“领取成功”提示。进入卡包断言券数量较领取前增加1。执行阶段系统逐条执行计划里的步骤。这里有一个小细节规划结果在真正执行前会先渲染成人类可读的列表如果Agent在规划时漏掉了“检查登录态”这一步测试工程师可以直接修改改完再跑。这样既保留了Agent的规划效率也加入了人的经验校验。复核阶段Agent分别调用“断言文本出现”“断言控件数量变化”等工具最后输出一个JSON格式的结论包括每一条断言的布尔值、截图路径、失败原因。整个过程下来只有“规划”这一步使用了LLM能力执行和断言全部走的是确定性代码这保证了用例的高稳定性。3.3 提示词模板设计的几个关键细节四段式流程能不能跑通一半取决于提示词模板设计。我说几个踩坑后总结出来的细节比具体的模板文字更值得收藏。第一个细节是上下文里不要塞太多“无关业务规则”。最开始我把App的完整业务说明都放在System Prompt里面结果模型执行规划时老是脑补出一些不存在的功能比如在没有搜索框的页面上规划“使用搜索功能”。后来改成只注入用例相关的最小上下文规划准确率反而上升。第二个细节是动作工具的命名和描述要符合“测试语言”习惯不要用“通用语言”。比如一个点击操作不要描述成“按下元素”要描述成“点击目标控件并等待页面响应返回结果中包含控件是否存在的信息”。第三个细节是要显式告诉模型哪些步骤“不允许跳过”。通用Agent在遇到页面没有立即出现目标元素时可能会自动决定“跳过等待并继续下一步”这在测试里是致命问题。在提示词里加一条硬性约束任何目标控件在超时阈值内未出现必须报告失败不允许跳步。第四个细节是失败回传的信息要格式统一。我在模板里规定执行步骤失败后回传的内容必须包含步骤序号、失败类型控件未找到/断言不匹配/页面弹窗冲突、当前页面截图、当前页面布局树摘要。统一格式的好处是下一次任务规划可以基于历史失败报告做针对性避让坏处是模型会偷懒只贴截图链接所以需要做一次格式校验不合格就重新跑。3.4 数据回流报告、快照、日志构成闭环一套Agent框架在测试场景里真正产生价值的标志是它能把每一次运行的报告沉淀成结构化的语料反哺后续的规划能力。我这边目前跑下来的闭环包含三个产出物。一个是JSON格式的执行报告记录每条用例的规划路径、动作序列、断言结果、耗时与Token消耗。一个是失败快照库保存截图、OCR结果、布局树和错误日志按失败类型打标。最后一个是从失败样本中抽取的“避坑经验集”经过人工筛选后注入到下一次规划的提示词里形成一个持续进化的小型知识库。闭环跑起来之后最大的感受是“同类错误会越来越少”。比如第一次运行时Agent因为页面弹窗遮挡而找不到按钮失败样本被标记后后续规划阶段就会自动在动作序列里加上“检查并关闭弹窗”作为前置步骤。常见问题与排查技巧实录4.1 问题速查表常见问题典型现象排查方向落地解法Agent定位控件“迷路”元素树存在但Agent报告找不到控件树是否包含可点击信息OCR是否误读布局树与OCR双通道交叉校验断言被跳过用例绿了但无断言日志检查模型是否自行“脑补”了结论断言必须走独立工具禁止自然语言总结回放不稳定同一条用例时绿时红动画、加载时序、截图时机不一致增加稳定等待器统一截图时机测试数据被污染用例第二次跑就失败全局状态或账号状态未重置数据注入与清理阶段强制隔离Prompt泛化失控改一个页面就废一片用例提示词塞了过多业务规则最小化上下文约束只保留结构性规则Token成本飙升一条用例跑出几百万Token每一步都在调用LLM把规划结果缓存为可复用执行计划4.2 定位控件“迷路”的深层原因与处理移动端页面的动态特性是Agent定位控件的第一杀手。页面上有轮播图、下拉刷新、局部刷新、弹窗这些动态区域会让控件树持续变化模型拿到的布局树和截图很可能不是同一帧的状态。我这边的一个比较有效的做法是给Agent定义一个“稳定等待器”工具。这个工具不做任何业务判断只负责监听页面是否进入“稳定状态”无网络请求、无动画执行、控件树连续两次抓取结果一致才判定稳定。所有动作执行之前先调用稳定等待器至少能避免一半的时序问题。另外一个与此相关的问题是OCR识别的准确率。OCR经常把按钮文字里的“领取”识别成“领收”或者把倒计时数字拆成乱码。所以在设计用例时我要求Agent在断言文本时优先用布局树中的控件文本OCR的结果只作为视觉证据存在不作为主要断言依据。4.3 如何强制“不跳过断言”跳过断言这个问题渗入了很多团队的Agent测试项目里因为它隐蔽。Agent会认为“页面已经显示了成功提示”于是就直接在总结里写上“断言通过”而不去调用断言工具。我处理这个问题用了两个办法。第一个办法是前面提到的工具隔离把断言工具单独放在“只读工具组”里并且规定每个阶段的结束必须以一次断言工具调用为标志没有断言结果就不允许进入下一个阶段。第二个办法是结果校验执行完一条用例后程序去翻阅工具调用日志统计断言工具的执行次数如果为0就把整条用例标记为“异常通过”直接打断机器人。除此之外我还会在用例结束时检查截图与操作日志人工抽看几条防止模型用一些“合法但不合理”的方式逃避断言比如明明断言目标是“券数量1”模型却断言“页面出现‘卡包’标题”这种无关内容来凑数。4.4 Prompt泛化失控的具体案例与对策泛化失控这个词有点抽象我举一个具体的例子。最初做登录场景的Agent用例时我在提示词里写了很多关于App的业务细节比如“登录按钮位于页面右下角”“老版本登录流程中有短信验证码步骤”。后来App改版登录页彻底重做结果Agent在规划时依然会莫名提到短信验证码还试图在页面上寻找不存在的“验证码输入框”。这个问题的根源在于提示词里塞了“场景化描述”而模型无法区分“规则”和“知识”。“登录按钮位置”是知识是会被版本迭代推翻的“目标控件必须存在才能操作”是规则是所有页面通用的。我现在做提示词的思路是规则尽量写全知识尽量不写。所有业务相关的细节全部放在首轮“提问”阶段的用例描述里垂直版本的更新不会影响提示词的稳定性。4.5 成本控制让LLM只在“关键判断点”出现自动化测试的用例数量很大如果每条用例的每一步都去调用LLM那Token消耗会到令人惊讶的数量级。我做过一次统计一条包含15个动作步骤的用例如果规划、执行、反思每一轮都调大模型跑一次的成本相当于写了几万字的文本一个月下来团队预算根本扛不住。后来我们做了一个执行计划缓存层。同一个测试用例如果在多次运行中规划结果完全一致就直接复用历史规划进入纯脚本化执行模式。只有两种情况会触发重新规划一是页面结构变化导致执行失败二是“避坑经验集”里新增了需要调整路径的信息。这样一来日常回归的成本能降到原来的十分之一左右Agent只在关键时刻介入决策稳定性和成本都变得可控。工具选型与工程化落地心得5.1 选型现成Agent框架、改造半成品、还是自研轻量编排我见过很多团队在“要不要选一个现成的通用Agent框架”这个问题上反复纠结。我的看法是要根据团队对“可控性”的要求来做决策。如果团队只是做技术预研验证一下LLM能不能理解测试场景那直接用现成的Agent编排框架完全没问题一两天就能搭出Demo。但如果要进入真实项目、每天跑几百条回归用例现成通用框架大概率不够用因为它们的工具调用机制、上下文管理、重试策略都是面向通用任务设计的没有“稳定等待器”“断言隔离”“操作白名单”这类测试场景专用的原语。我这边最终选择了“自研轻量编排”只保留通用Agent框架的核心规划能力把执行、断言、截图、日志、检视全部用代码实现。这样做的代价是前期工作量稍大但换来的是测试脚手架和Agent能力的解耦。就算后续换一家底层模型整个框架也无需重写只需改模型接入层。5.2 工程化必须做的三个动作第一个动作是搭建离线评测集。从历史用例中抽一批结构完整、断言清晰、业务价值高的用例固化成“黄金数据集”。每次改Agent框架或换模型先跑一遍金数据集的通过率低于基线就说明改动有回归。这个动作能防止团队在调Prompt时“拆东墙补西墙”。第二个动作是“时间盒”和“步数盒”的强制约束。任何一条用例都不能无限跑下去。我这边规定单条用例的步数上限是30步时间上限是5分钟超过就直接判失败并保存现场快照。没有上限的Agent遇到页面卡死或流程死循环时会一直烧钱烧时间得不偿失。第三个动作是失败样本的标注回路。每次Agent运行失败生成的报告要自动进入一个待标注队列由测试工程师判断错误类型是“应用缺陷”还是“框架缺陷”。应用缺陷转给开发团队框架缺陷则用来反哺提示词和工具定义。这个回路跑起来后整套系统的稳定性是逐步上升的而不是每次都要从零开始排查。5.3 测试团队的角色变化从写脚本到写提示词接入Agent之后测试工程师的角色会发生一些变化这个变化比技术本身更有意思。以前写一条自动化用例至少要写几十行代码维护成本主要花在定位器更新和等待策略调整上。现在写一条用例本质上是在写一段高度结构化的“任务描述数据约束断言规则”维护成本变成了提示词版本管理和执行计划复核。这意味着测试团队要把“提示词”当作代码一样去做版本管理。我在内部推行了一个小规范每条Agent用例都有一个专属的提示词配置文件包含版本号、修改人、修改原因和关联的用例编号。每次模型版本升级后都会用这个配置文件做回归看看规划质量有没有下降。5.4 确定性执行层Agent的“刹车”和“保险”最后再讲一个核心心得无论Agent能力多强都要保留一个确定性执行层。每次规划结果生成后我都会把规划解析成机器可校验的中间表示相比之下解析成JSON格式的步骤序列。这个步骤序列在执行前还会经过一个静态检查器检查是否存在“点击不可点击控件”“输入框类型不匹配”“断言目标为空”等明显错误。这个确定性执行层承担着两个职责一是“刹车”当Agent的规划明显离谱时静态检查器会直接拦截防止错误速度被执行二是“保险”当Agent因为环境异常而陷入重试循环时执行层会强制回到最近的成功状态点而不是让Agent自由发挥去“摸索”。我个人在实际操作中的体会是把Agent当“搭档”而不是“自动驾驶”是它在测试场景里真正稳定下来的关键。Agent负责从自然语言目标到步骤序列的转换、负责失败后的策略调整和异常原因的总结但绝不负责不受约束地乱跑一通。每一层都要有代码在把关每一环都要有日志在回溯。这个系列做到这里移动端自动化也进入深水区了。后续我大概率会基于这次的下沉经验单独聊一聊如何把Agent的“避坑经验集”做成自动化的知识库让它摆脱人工维护。那是一条完全不同的路径但起点正是这几个月里踩过的每一个坑。
阅读完成 · 觉得有帮助?
咨询建站