恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
LLM角色级拆分:移动端自动化测试的架构升级实践
首页
资讯中心
/
LLM角色级拆分:移动端自动化测试的架构升级实践
LLM角色级拆分:移动端自动化测试的架构升级实践
发布时间:2026/10/18 15:52:16
移动端自动化测试的维护成本一直是测试团队最头疼的问题之一。这周项目组在推进 LLM 驱动自动化测试体系时把移动端这块单独拆出来重新设计了架构核心变化是放弃了过去“一个大模型从头干到尾”的路径改成了角色级模型拆分。今天这篇就把这次改造的思路、角色划分、提示词设计以及踩过的坑完整记录下来给正在做同类方向的同行一个参考。1. 为什么一定要把 LLM 从“全能选手”拆成“协作团队”1.1 移动端自动化的老问题LLM 没法直接解先说说传统移动端自动化的痛点。用过这类框架的人都有体会脚本本身不难写难的是跟着版本走下去。某个页面改了布局、某个按钮的 resource-id 变了、某个弹窗的时机不对一串用例就倒下。这些问题的根源在于传统脚本把“意图”写死在了“元素定位”上——测试人员真正关心的是“用户能不能登录成功”但脚本表达的是“点击 id 为 xxx 的按钮”。引入 LLM 之后我们一度以为可以用自然语言直接把意图描述映射成操作序列省掉维护成本。第一批实验效果确实惊艳给一个大模型一段目标描述和当前页面信息它确实能生成基本合理的操作步骤。但用了一段时间后发现这种“单模型全链路”的模式在工程化落地时问题不少。最大的问题是上下文膨胀。要完成一次移动端用例模型需要同时看到用户意图、App 的功能信息、当前页面的 UI 层级、截图特征、历史操作记录。这些信息全塞进一个上下文里很快就把窗口撑满。而且移动端的 UICatalog 本身又长又杂一个稍微复杂的页面动辄几百个节点清理完仍然非常庞大。模型在长上下文里很容易“迷失”前期步骤执行的偏差会在后续步骤中被不断放大最终跑出一个看似合理、实则完全偏离目标的流程。另一个问题是调试困难。单模型方案里如果一条用例失败你很难说清楚到底是意图理解错了还是步骤规划错了还是 UI 定位错了还是断言条件写错了。所有环节的信息都在同一个黑盒里日志打出来也是一长串定位成本非常高。1.2 分工协作移动端测试的“团队化”思路后来我们参考了真实测试团队的工作方式把一个全能模型拆成了几个专职角色测试组长负责理解需求输出“这条测试到底要验证什么”资深测试设计负责把目标拆成一步步可执行的测试步骤测试执行员负责按照步骤操作手机屏幕定位控件、点击、输入质检员负责在关键节点确认当前状态是否和预期一致这就是这次设计的核心角色级模型拆分。在 DroidRun我们的内部代号对应跨平台版的另一套代号叫 Mobilerun里我用四个独立模型实例分别承担这四个角色它们之间通过结构化的数据协议协作而不是共享一个对话上下文。拆分带来的好处是肉眼可见的。首先每个角色的输入输出都标准化了上下文被控制在合理范围内不会再出现“所有信息堆一起”的窘境。其次任何一个环节出错都可以直接定位到对应的角色日志清晰可查。再就是提示词的设计可以高度专职化——规划角色的提示词只需要关心“如何把目标拆成步骤”执行角色的提示词只需要关心“如何读懂当前页面”互相不干扰迭代起来特别快。2. DroidRun 的角色划分与协作机制2.1 四个核心角色各自守住一段职责在 DroidRun/Mobilerun 的设计里四个角色的分工非常明确。任务理解角色内部命名 Task Parser只做一件事把用户的那句自然语言描述转成结构化的测试意图。它不关心具体页面长什么样也不关心操作细节只管回答几个问题测试目标是什么、前置条件有哪些、验收标准是什么。这个角色的输入通常是非常口语的一句话比如“试试看错误的验证码会不会被拦下来”输出是一份干净的 JSON。它存在的意义是把模糊的需求变成后续角色可以执行的定义。步骤规划角色Step Planner拿到任务理解角色的输出再结合 App 的功能模块描述生成有序的步骤列表。每个步骤包含操作类型、目标描述、预期结果和兜底策略。这个角色相当于测试设计人员它只规划“要做什么”不关心“控件在哪”。规划角色的输出是一份树状或线性的步骤链每步都带预期结果这是后续验证环节能跑起来的基础。UI 执行角色UI Executor是真正接触手机屏幕的角色。它接收规划角色的单个步骤读取当前的 UI 层级摘要和截图输出一个最具体的 UI 操作指令通过什么定位方式、执行什么动作、参数是什么。执行角色是四个角色里请求频率最高、对速度和稳定性要求也最高的它的输出直接决定测试能不能顺畅跑下去。结果验证角色Verifier负责把关。它在关键步骤执行后触发输入是当前页面状态和规划时预设的预期结果输出是 pass/fail 判定、置信度和证据描述。移动端的验证和接口测试不同页面状态变化往往是视觉层面的所以这个角色会结合 UI 层级、截图特征、Toast 文本、数据层变化等综合判断。2.2 角色间如何协作结构化协议与状态传递四个角色不能各自为政它们之间需要一套明确的协作机制。在 DroidRun 里我定义了一套轻量的 JSON 消息协议每个角色的输出都以标准格式传给下个角色。一次完整的用例执行流程是这样走的用户输入原始需求Task Parser 解析成测试意图格式类似{goal: ..., preconditions: [...], acceptance_criteria: [...]}Step Planner 拿到测试意图结合 App 业务清单生成步骤列表每一步包含step_id、action_type、target_desc、expected、fallbackUI Executor 按顺序执行步骤每执行一步就把页面状态快照UI 树摘要 截图存起来同时回传执行结果当某一步涉及关键断言点或步骤本身带预期结果时触发 Verifier输出验证结论全部步骤执行完且验证通过报送测试完成这里有一个关键的工程设计细节角色之间的状态传递不是靠共享对话历史而是靠“状态快照”。每次 UI Executor 执行完一个操作都会生成一个精简的状态快照包含当前页面经过剪枝后的 UI 元素列表、关键坐标、截图路径、时间戳。这个快照只保留对下一步执行有影响的信息不会把完整的 UI 树和历史记录一起传下去。协作机制还要支持异常回退。如果 UI Executor 在执行某一步时找不到目标元素会先触发自身的重试逻辑重试仍然失败的会把失败状态连同当前快照传回 Step Planner让规划角色根据最新页面状态重新生成后续步骤。这种“执行反馈驱动再规划”的机制是角色拆分后才有能力做到的——在单模型方案里你很难判断哪部分内容该触发重新规划。3. 角色级提示词设计与上下文管理实操3.1 任务理解角色把口语需求“翻译”成结构化意图Task Parser 的提示词设计核心是防止“过度解读”。用户描述测试需求时经常带模糊表达模型很容易自行脑补条件导致后续步骤跑偏。我给 Task Parser 的提示词模板大致包含三块约束只能输出 JSON不允许附带解释性内容三个字段必须给出goal、preconditions、acceptance_criteria遇到信息不足时允许输出unknown禁止自行假设举个实际例子。用户输入“试一下错误的验证码能不能被拦下来”正确的解析结果是{ goal: 验证登录页对错误验证码的拦截能力, preconditions: [App 处于未登录状态, 已知测试账号], acceptance_criteria: [输入错误验证码后停留在登录页, 出现验证码错误提示] }这里我给模型加了一条强制规则如果用户没有明确提到账号密码就不要默认去猜而是输出unknown并在后续流程里通过预置测试数据补全。这个规则非常重要避免了很多理解偏差。Task Parser 用的模型可以不用太大中等规模就够用因为它的任务本质是信息提取和格式化。我在实践中发现即使是参数规模较小的模型只要提示词约束够明确也能稳定输出。这也体现了拆分的一个好处——按角色需求选模型而不是所有人共用一个大模型。3.2 规划角色与执行角色的衔接步骤要“可落地”Step Planner 的提示词设计核心是让步骤规划结果能被执行角色无缝接住。这要求每一步的描述必须包含足够信息但又不能依赖具体的 UI 控件 ID——因为规划角色不接触真实页面。我给 Step Planner 定的输出格式如下[ { step_id: 1, action_type: tap, target_desc: 底部导航栏的“我的”入口, expected: 进入个人中心页显示头像和用户名, fallback: 如果找不到底部导航尝试从首页左上角入口进入 } ]这里的关键是target_desc字段它描述的是“语义目标”而不是控件坐标。执行角色会拿着这个描述到真实页面里去匹配具体节点。这种区分是角色拆分的精髓规划角色用业务语言描述执行角色负责翻译成技术语言。执行角色 UI Executor 的提示词要解决的是“语义到 UI 节点”的映射。它的输入包括规划步骤、当前页面的 UI 树摘要、当前页面截图。提示词里我明确了定位优先级优先匹配 content-desc 或 text 完全等于语义描述的节点次选包含关键字的节点再次通过截图分析判断区域位置都不行时触发 fallback 逻辑执行角色的输出是最终的操作指令格式也很固定{ locate_strategy: by_text, locate_value: 我的, action: click, params: {} }在 UI Executor 的提示词里我特别强调了一条如果模型觉得步骤描述和当前页面不匹配要优先输出page_mismatch信号而不是硬找一个相似节点执行。因为移动端页面经常出现相似控件硬匹配很容易点到错误位置。宁可停一下触发重新规划也比执行错了强。3.3 上下文管理拆了角色还得控制好每一步的信息量角色拆完之后上下文窗口的压力确实小了很多但 UI 树的信息量仍然是个问题。一个典型的中型页面原始 UI 树可能有几百个节点直接传给模型既浪费 token 又干扰判断。我们在 UI Executor 前面加了一层轻量级的“节点剪枝”逻辑规则很简单只保留 visible 为 true 的节点过滤掉纯布局容器节点仅用于布局、无可交互属性合并同一区域内的冗余子节点保留节点的 key 字段resource-id、text、content-desc、bounds剪完之后一个页面的节点一般能压缩到原来的三成到五成上下文压力小很多。另外在状态传递上我们不直接传历史对话记录而是传一份精简的“执行轨迹”。执行轨迹里只包含最近三步的操作摘要和当前快照加上一个自增的版本号。角色间每次交互都带上这个版本号一旦发现版本不一致说明状态已经漂移后续步骤就必须基于最新快照重新规划。DroidRun 的整个上下文管理现在基于这套机制虽然没有很复杂的缓存策略但实际跑下来效果稳健。核心经验就是宁愿多写一点结构化 JSON 的解析逻辑也要严格控制进入模型的信息量——信息少而准确远比信息多而混乱要可靠。4. 落地过程中的常见问题与排查心得4.1 角色“漂移”输出格式变形和职责越界角色级拆分后最常遇到的问题就是角色“漂移”。具体表现为两种一种是模型偶尔不按约定的 JSON 格式输出夹杂解释文字导致下游解析失败另一种是某个角色开始做不属于自己的事比如 Step Planner 在规划时去猜测具体控件 ID或者 UI Executor 在找不到节点时自己改了测试逻辑。输出格式变形的问题我在两套方案里都试过有效的处理。第一是在提示词里给出严格的正反示例只给一份样例往往不够一定要给一个“错误输出长什么样”的负例。第二是做一层轻量的输出修复写一个 JSON 抽取函数能从模型输出里截取合法的 JSON 片段再做解析。这两手配合格式问题基本可以做到百分之百不出错。职责越界的问题靠的是在提示词里反复强调边界。我在每个角色的提示词里都放了一句固定话术“你只负责 X其余任何问题都不要处理。如果遇到超出职责范围的情况输出特定错误码。”这个话术不是摆设实测能有效减少模型“自作主张”的情况。4.2 UI 定位失败的三大诱因与重试策略移动端自动化跑得多了会发现定位失败是家常便饭。我们把失败诱因归纳成三大类分别对应不同的处理策略。第一类是元素短暂不可见。App 页面切换有动画或者列表数据在异步加载目标控件要等一会儿才出现。处理策略是 UI Executor 内置逐步重试每次等待固定时间后重新解析页面最多重试五次。第二类是元素结构演化。同一个按钮在某个版本里 text 是“登录”下个版本变成了“登 录”或者改成了图标没有文本描述。这种情况靠语义匹配往往失效。处理策略是启用 OCR 辅助对截图做文字识别后再匹配。我们在实践中发现OCR 匹配对中文文本的鲁棒性比 UI 树纯文本匹配要高不少特别是遇到文本带空白字符的情况。第三类是页面结构特大导致节点缺失。长列表页面或者 WebView 混合页面目标节点可能在当前视口之外。处理策略是引导执行角色触发滚动动作把目标找出来。我在提示词里加了一条指令如果当前页面没有目标节点优先考虑目标是否在屏幕外尝试向上滑动查找而不是直接判定失败。4.3 拆分前后效果对比不只是准确率提升做架构调整不能只凭感觉。我们把拆分方案和早期单模型方案在同一个业务 App 上做了对比测试样本是一批历史真实用例一共五十条覆盖登录、注册、下单、退款、客服会话等核心流程。对比结果有几个值得关注的维度对比维度单模型全链路角色级拆分用例整体通过率62%84%平均单条用例耗时96 秒78 秒失败用例可定位率30%95%上下文峰值占用约 4 万 token约 1.2 万 token单条用例模型调用成本基准约下降 40%最让我意外的是平均耗时不升反降。原来以为拆成多个角色会增加调用次数总耗时会更长。实际上单模型方案在长上下文下模型首字生成延迟很高整体反而更慢。拆分后每个角色的输入都很精简响应速度大幅提升串联起来的整体节奏反而更快了。失败用例的可定位率提升是最明显的一项。拆之前一条用例失败了要么看一屏日志猜测要么重跑一遍加日志拆之后每个角色的输入输出都有记录直接看是哪个环节的输出不符合预期就行。这在调试排障时节省了大量时间。4.4 小团队落地 DroidRun 的几点建议如果你也想在自己团队里落地类似的方案我的建议是不要一上来就把四个角色全部接好而是按阶段推进。第一个阶段只搭 Task Parser 和 Step Planner。先把“自然语言到步骤规划”这一环跑通用已有的测试用例做输入人工检查生成的步骤是否合理。这个阶段不需要接真实设备成本低能快速验证核心链路。第二个阶段接入 UI Executor。先让执行角色只在真实设备上跑人工预置的脚本化步骤主要验证“语义描述到 UI 节点匹配”的准确性。这个阶段会暴露大量的页面识别问题也是最需要投入打磨的阶段。建议做一个失败样本库每一条定位失败的案例都记录下来定期复盘补充提示词规则。第三个阶段才接入 Verifier 和完整的重试、回退机制。验证角色非常依赖业务规则前期数据不足时误判率会比较高所以放到最后。我自己在推进过程中最深刻的体会是角色拆分方案的价值不只是准确率的提升而是让整个系统从黑盒变成了透明管线。过去我们改造一个测试系统最怕的就是改完不知道哪里坏了现在每个环节的输入输出都是结构化的跑一遍就能看到问题出在哪一环。对于一个要长期演进的自动化体系来说这种可观测、可定位、可迭代的架构比任何单点优化都更值得投入。如果后面有机会我会把 Verifier 的证据链设计单独写一篇——那是整个四角色体系里目前最吃经验的部分。这次的分享就先到这里。