移动端自动化测试这件事,真正上手做过的人都清楚,最难的从来不是写脚本,而是脚本写完之后的维护。一个页面元素改个 id,几十条用例集体飘红;一个弹窗时序变了,整个回归流程卡死。前几年大家靠 UI Automator、Appium 这类工具把操作跑通了,但"跑通"和"跑得稳、跑得省心"之间还隔着一条很宽的河。这两年大模型能力下沉到测试领域,我一直在尝试把 LLM 接进移动端自动化链路里,前面几篇聊过整体思路,这一篇专门讲一个我踩了不少坑才想明白的设计:角色级模型拆分,也就是把"看屏幕""做决策""写断言"这几件事交给不同的模型角色去干,而不是指望一个大模型从头包到尾。
这个思路对应的落地形态,我把它叫做 DroidRun / Mobilerun 的双层结构——名字不重要,重要的是它解决了一个非常具体的问题:单模型驱动移动端自动化时,上下文又长又杂,模型既要理解截图、又要记住历史操作、还要生成可执行代码,结果就是又慢又不准。角色拆分之后,每个模型只干一件窄事,准确率和响应速度都能明显改善。下面我把这套东西从设计动机到落地细节完整拆一遍,适合已经写过移动端自动化脚本、想进一步用 LLM 提效的测试开发和客户端工程师参考,小白也能看懂大框架,但动手前最好有点 Appium 或类似工具的基础。
1. 为什么单模型驱动移动端自动化总是差一口气
1.1 移动端任务的上下文天然又长又脏
先说说移动端自动化和 Web 端自动化最本质的区别。Web 端你拿到的是 DOM,结构清晰、层级明确、元素有稳定的选择器,模型看一眼 HTML 就能定位。移动端不一样,你能拿到的东西通常是这几种:一张屏幕截图、一份 UI 层级树(accessibility tree)、以及当前 Activity 或页面栈信息。这三样东西各有各的毛病。
截图信息量最大,但它是像素,模型得靠视觉能力去"猜"哪个是按钮、哪个是输入框,遇到自定义控件、图标按钮、无文字标签的悬浮球,猜错的概率相当高。UI 层级树看起来结构化,但移动端的树经常又深又乱,一堆无语义的容器节点嵌套,真正可点击的节点藏在第五六层,而且不同机型、不同系统版本渲染出来的树还不一样。页面栈信息只能告诉你"现在在哪个页面",但页面内部的动态内容它一无所知。
把这三样东西一股脑塞给一个模型,再叠加历史操作记录,上下文轻松就上万 token。上下文一长,模型注意力就涣散,前面看到的元素位置到后面就记混了,这是单模型方案第一个绕不过去的坎。
1.2 一个模型同时干三件事,等于三件事都干不好
我早期最朴素的方案就是"一个模型包打天下":把截图和层级树丢进去,让它输出下一步该点哪里、该输入什么,顺便把断言也写了。跑起来之后问题非常集中:
- 决策漂移:模型在长上下文里容易"忘记"当前任务目标,本来是要完成登录,点着点着跑去点广告弹窗的关闭按钮了。
- 定位不稳:同一个按钮,这次它用坐标点,下次用文本匹配,再下次用层级路径,生成的操作方式五花八门,脚本没法复用。
- 断言敷衍:让模型顺便写断言,它经常写出"页面应该正常显示"这种没法执行的废话,或者断言条件过于宽松,等于没断言。
- 响应慢:每次决策都要处理完整的长上下文,单步耗时高,一个几十步的流程跑下来,光模型推理就得好几分钟。
这三件事——感知(看屏幕)、决策(下一步做什么)、生成(写出可执行操作和断言)——对模型能力的要求其实完全不同。感知需要强视觉理解,决策需要强推理和任务规划,生成需要强代码能力和对框架 API 的熟悉度。硬塞给一个模型,它只能样样通样样松。
1.3 角色拆分的核心直觉:让专业的人干专业的事
角色级模型拆分的直觉特别朴素:既然这三件事要求不同,那就拆成三个角色,每个角色配一个最合适的模型。感知角色可以用视觉能力强的多模态模型,决策角色可以用推理能力强、上下文管理好的模型,生成角色可以用代码能力强、对测试框架熟悉的模型。每个角色的输入都被裁剪到最小必要范围,上下文短了,准确率和速度自然就上来了。
这就像一个小团队:有人负责看,有人负责想,有人负责写。一个人全包,累死还出错;分工之后,每个人只盯自己那一摊,反而又快又稳。下面这张表是我实测下来三个角色的典型分工和选型倾向,供参考。
| 角色 | 核心职责 | 输入 | 输出 | 选型倾向 |
|---|---|---|---|---|
| 感知角色 | 理解当前屏幕,抽取可交互元素 | 截图 + 精简层级树 | 结构化元素列表 | 视觉理解强、支持图像输入 |
| 决策角色 | 规划下一步动作 | 任务目标 + 元素列表 + 历史摘要 | 动作指令(语义级) | 推理强、长上下文管理好 |
| 生成角色 | 把语义动作翻译成可执行代码 | 语义动作 + 框架 API 约定 | 可执行脚本片段 | 代码能力强、熟悉测试框架 |
注意:角色拆分不是越多越好。我试过拆成五个角色,结果角色之间的通信开销和状态同步成本反而拖慢了整体,三个是性价比最高的分法。
2. DroidRun 与 Mobilerun 的双层结构到底怎么分工
2.1 上层 Mobilerun:负责"想清楚要做什么"
Mobilerun 这一层我把它定位成"大脑",它不直接碰屏幕像素,也不直接生成代码,它只做一件事:把用户的自然语言任务(比如"登录后进入个人中心,检查昵称是否显示正确")拆解成一步步的语义动作序列。所谓语义动作,就是"点击登录按钮""在用户名输入框填入测试账号""断言昵称文本等于预期值"这种人类能读懂、但不绑定具体框架 API 的指令。
这一层为什么独立出来?因为任务规划和屏幕感知是两种完全不同的能力。规划需要的是对业务流程的理解、对异常分支的预判、对步骤顺序的合理安排。比如"登录"这个任务,有经验的测试会想到:先检查是否已经登录、处理可能出现的权限弹窗、处理网络异常提示。这些是业务逻辑层面的思考,跟当前屏幕长什么样没关系。把它独立成一层,模型可以专注于业务推理,不受屏幕细节干扰。
Mobilerun 的另一个关键设计是维护一份任务状态摘要。每执行完一步,它会把"已经做了什么、当前处于什么状态、还剩什么没做"压缩成一段简短摘要,而不是把全部历史操作原样带着走。这样决策角色的上下文始终保持在可控长度,不会随着步骤增加而无限膨胀。
2.2 下层 DroidRun:负责"看清楚屏幕上有什么"
DroidRun 这一层是"眼睛",它的唯一职责是把当前屏幕状态转成结构化的、决策层能直接用的元素列表。它接收截图和原始层级树,输出一份清洗过的元素清单,每个元素包含:语义类型(按钮/输入框/文本/图标)、可读标签、稳定的定位依据(resource-id 优先,其次文本,最后才是坐标)、以及是否可交互。
这一层最容易被低估,但恰恰是稳定性的关键。原始层级树里噪音太多,直接丢给决策模型,它会浪费大量注意力在无语义的容器节点上。DroidRun 做的事情本质上是"信息提纯":把一棵又深又乱的树,压成一份十来个元素的干净清单。我实测下来,经过这一层清洗后,决策模型的定位准确率能提升一大截,因为干扰项少了。
2.3 两层之间的接口约定:语义动作协议
两层之间靠一套语义动作协议通信,这是整套设计里最需要花心思的地方。协议定义了一组标准动作,比如tap(target)、input(target, text)、swipe(direction)、assert(target, condition, expected)、wait(condition)。Mobilerun 只输出这些标准动作,DroidRun 只负责把target解析成当前屏幕上真实可操作的元素。
这套协议的好处是解耦。上层不需要知道下层用什么方式定位元素,下层也不需要理解上层的业务意图。哪天换了定位策略(比如从 resource-id 换成图像匹配),只要协议不变,上层完全不用动。这跟微服务之间定好 API 契约是一个道理,契约稳定,两边各自演进。
{ "action": "input", "target": {"type": "input", "label": "用户名"}, "text": "test_user_001", "reason": "填写登录表单的用户名字段" }上面这个就是一条典型的语义动作。注意target用的是语义描述(类型 + 标签),不是具体的坐标或 id,具体怎么定位交给 DroidRun 去解决。reason字段是可选的,但强烈建议保留,出问题时排查起来能省很多事。
2.4 为什么是"双层"而不是"单层多角色"
有人会问,既然都是角色拆分,为什么不干脆做成一层里塞三个角色,非要分成上下两层?我的体会是,分层解决的是"职责边界",分角色解决的是"能力匹配",两者是正交的。Mobilerun 和 DroidRun 之间是清晰的上下游关系,有明确的数据流向和接口契约;而每一层内部,如果需要,还可以再细分角色。比如 DroidRun 内部,视觉理解和层级树解析可以是两个子角色,一个负责从截图里识别图标按钮,一个负责从树里提取文本元素,最后合并去重。
分层带来的最大好处是可测试性。DroidRun 这一层可以单独测:给它一张截图和一棵树,看它输出的元素列表准不准,完全不需要跑完整流程。Mobilerun 也可以单独测:给它一个任务和一份模拟的元素列表,看它规划的动作序列合不合理。两层各自可测,整体出问题时定位范围就小很多。
3. 感知角色的工程细节:把屏幕信息提纯到能用的程度
3.1 截图和层级树到底该信谁
这是我在感知层踩的第一个大坑。一开始我迷信层级树,觉得结构化数据总比像素靠谱。结果发现层级树有两个致命问题:一是很多自绘控件、游戏化界面、Flutter 渲染的页面,层级树里根本没有有效节点,全是空白容器;二是同一份树在不同分辨率下节点坐标会变,但语义信息不变,如果模型依赖坐标就会翻车。
后来我的策略是以层级树为主、截图为辅。层级树能提供稳定的 resource-id 和文本,这是定位的首选依据;截图用来补充层级树缺失的信息,比如识别纯图标按钮、判断某个元素是否真的可见(有些节点在树里存在但被遮挡或在屏幕外)。两者结合,感知的召回率和准确率都能兼顾。
具体做法是:先用层级树提取所有带 resource-id 或文本的节点,形成基础元素列表;再用视觉模型扫一遍截图,找出层级树里没有但视觉上明显可交互的区域(图标按钮、悬浮控件),补充进列表;最后做一次去重和可见性过滤,把屏幕外的、被遮挡的、尺寸过小的节点剔除。
3.2 元素定位的优先级策略
定位策略的优先级直接决定了脚本的稳定性。我总结的优先级从高到低是:
- resource-id:最稳定,只要开发不改,跨版本跨机型都不变。但很多团队不给测试留 id,这是现实。
- accessibility 文本 / content-desc:比较稳定,适合有明确语义的按钮。缺点是会随文案改动而变。
- 文本内容:适合文本按钮和标签,但同样受文案影响,且多语言场景下会失效。
- 相对位置:比如"用户名输入框下方的第一个输入框",比绝对坐标稳,但依赖布局结构。
- 绝对坐标:最不稳定,只在万不得已时用,且必须配合截图校验。
感知角色输出元素时,应该把这几级定位依据都带上,让下游按优先级选用。我见过太多脚本因为死磕坐标,换个机型就全废,这个优先级策略能救回不少稳定性。
3.3 处理动态内容和异步加载
移动端页面大量使用异步加载,感知角色拿到的可能是一个"半成品"屏幕。如果这时候就急着输出元素列表,决策层基于残缺信息做判断,很容易出错。我的处理方式是给感知层加一个稳定性判定:连续两次采样(间隔几百毫秒)得到的元素列表如果基本一致,才认为页面稳定,可以输出;如果还在变化,就继续等待,直到超时。
这个机制听起来简单,但能挡掉大量"点了没反应"的假故障。很多所谓的脚本不稳定,本质上是页面还没加载完脚本就动手了。让感知层承担这个"等页面稳下来"的责任,比在每个操作前手动加 sleep 优雅得多,也可靠得多。
提示:稳定性判定的间隔和超时时间要按业务调。列表页、详情页加载快,间隔可以短;涉及网络请求的页面,超时要给足。我一般设间隔 300ms、超时 5s 起步,再根据实测调整。
3.4 感知层的输出格式设计
感知层的输出格式设计得好不好,直接影响决策层的使用体验。我试过好几种格式,最后固定成一份 JSON 元素列表,每个元素包含这些字段:
{ "elements": [ { "type": "button", "label": "登录", "locators": [ {"by": "id", "value": "com.example.app:id/btn_login"}, {"by": "text", "value": "登录"} ], "bounds": [540, 1200, 810, 1290], "visible": true, "enabled": true } ], "screen_summary": "登录页面,包含用户名、密码输入框和登录按钮" }locators是个数组,按优先级排列,下游按顺序尝试。screen_summary是一句人话总结,给决策层快速建立场景认知用。bounds保留但只作为兜底,不作为主定位依据。这套格式我用了大半年,决策层解析起来很顺,基本没出过格式层面的问题。
4. 决策角色的上下文管理:让模型始终记得自己要干什么
4.1 任务状态摘要怎么压缩才不丢信息
决策角色最大的敌人是上下文膨胀。一个二十步的流程,如果把每步的完整信息都带着,上下文很快就爆了。我的解法是维护一份滚动摘要,每执行完一步就更新,只保留三类信息:任务目标(始终保留原文)、已完成步骤的结论(不是过程)、当前待办和已知的异常状态。
关键在于"结论而非过程"。比如"点击登录按钮"这一步,摘要里记的是"已点击登录,页面跳转到首页",而不是把点击时的元素列表、坐标、耗时全带上。过程信息用完即弃,只留结论。这样即使跑五十步,摘要也就几百字,上下文始终清爽。
我踩过的坑是摘要写得太简,丢了关键状态。有一次流程里出现过一次"网络异常弹窗",摘要里只记了"处理了一个弹窗",没记是什么弹窗,结果后面又出现类似弹窗时,决策模型以为是同一个,处理逻辑就错了。所以摘要要记清楚异常的类型和当时的处理方式,不能含糊。
4.2 决策的粒度:一步一动还是批量规划
决策粒度是个需要权衡的点。一步一动(每次只决定下一个动作)的好处是能及时响应屏幕变化,坏处是调用次数多、慢,而且模型容易"短视",只盯着眼前一步。批量规划(一次规划好几步)的好处是效率高、有全局观,坏处是屏幕一变,规划就作废,得重新来。
我的折中方案是分层规划:Mobilerun 先出一个粗粒度的阶段规划(比如"填写表单 → 提交 → 验证结果"三个阶段),每个阶段内部再一步一动地决策。阶段规划不轻易变,除非遇到重大异常;阶段内的单步决策灵活调整。这样既有全局观,又能应对局部变化。
4.3 异常分支的预判与处理
移动端自动化的异常分支特别多:权限弹窗、升级提示、广告插屏、网络异常、登录态失效。如果全靠决策模型临场反应,它很容易懵。我的做法是在决策角色的提示里预置一份常见异常处理策略,让它遇到这些情况时优先按策略处理,而不是自由发挥。
比如预置策略里写清楚:遇到权限弹窗,一律点"允许";遇到升级提示,点"以后再说";遇到广告,找关闭按钮,找不到就返回键。这些策略是业务经验的沉淀,写死在提示里比让模型每次重新推理靠谱得多。模型只在遇到策略没覆盖的新异常时,才需要真正"思考"。
4.4 决策角色的提示工程要点
决策角色的提示我改了很多版,最后稳定下来的结构是这样的:先给角色定位("你是一个移动端测试的决策模块"),再给任务目标和当前阶段,然后给当前屏幕的元素列表和摘要,最后给输出格式要求和异常处理策略。顺序很重要,任务目标要放在靠前的位置,因为模型对开头和结尾的信息记得最牢。
输出格式我强制要求 JSON,且只允许输出协议里定义的动作。早期我允许它输出自然语言解释,结果它经常在解释里夹带"我觉得应该……"这种模糊表述,解析起来很麻烦。后来改成"只输出 JSON,不要任何额外文字",干净多了。如果确实需要它说明理由,就放到 JSON 的reason字段里。
5. 生成角色的落地:把语义动作翻译成能跑的代码
5.1 为什么生成角色要独立出来
生成角色独立出来的理由很实在:决策和编码是两种能力。决策模型擅长的是"想清楚做什么",但让它直接输出 Appium 或 UI Automator 的代码,它经常写出语法对但 API 用错的代码,比如参数顺序搞反、方法名记混、等待逻辑缺失。而一个专门做代码生成的模型,配上框架 API 的约定和示例,输出的代码质量高得多。
更重要的是,生成角色可以复用。同一套语义动作协议,可以配不同的生成后端:要 Appium 就配 Appium 的生成器,要 UI Automator 就配 UI Automator 的生成器,要跨端框架就配对应的。决策层完全不用改。这种可替换性在工程上价值很大。
5.2 语义动作到框架 API 的映射规则
映射规则要提前定好,不能全靠模型自由发挥。我一般会准备一份映射表,把每个语义动作对应到目标框架的具体 API 调用,连同参数约定、等待策略、异常处理一起写清楚。生成角色拿着这份映射表和语义动作,做的是"填空"而不是"创作",出错概率大大降低。
| 语义动作 | Appium 映射 | 等待策略 | 异常处理 |
|---|---|---|---|
| tap(target) | find_element(...).click() | 显式等待元素可点击 | 超时重试 2 次 |
| input(target, text) | find_element(...).send_keys(text) | 等待元素可见 | 清空后输入 |
| assert(target, condition, expected) | 取属性后断言 | 等待元素存在 | 失败截图留存 |
| swipe(direction) | swipe 或 W3C actions | 无 | 记录滑动前后状态 |
有了这张表,生成角色输出的代码风格统一,可维护性也好。新人接手时看这张表就能理解整套脚本的约定。
5.3 生成代码的健壮性加固
模型生成的代码,哪怕映射规则给得再细,也经常缺一些健壮性处理。我总结了几条必须加固的点,每次生成后都要过一遍:
- 显式等待:模型默认喜欢用固定 sleep,必须强制改成显式等待,等元素出现再操作。
- 重试机制:单次操作失败很常见,要包一层重试,重试前先刷新页面状态。
- 失败截图:断言失败或操作超时时,自动截图留存,方便事后排查。
- 日志埋点:每个动作执行前后打日志,记录元素定位依据和耗时,出问题时能快速定位。
这些加固逻辑我一般做成生成器的"模板后缀",每次生成代码时自动附加,不依赖模型主动写。模型负责业务逻辑,模板负责健壮性,各司其职。
5.4 生成结果的校验与回填
生成角色输出的代码不能直接信,得校验。我的校验分两层:静态校验检查语法和 API 调用是否符合约定,动态校验则是在真实设备上跑一遍,看能不能执行。静态校验能挡掉大部分低级错误,动态校验兜底。
校验通过后,还有一个回填动作:把这次成功的语义动作和对应代码存进案例库。下次遇到类似的语义动作,可以直接从案例库里取,不用再调模型生成。用得越久,案例库越丰富,模型调用越少,整体成本和耗时都往下走。这是这套方案能长期跑下去的关键,不然每次都全量调模型,成本扛不住。
6. 角色间通信与状态同步的坑
6.1 状态不一致是怎么发生的
三个角色各自维护自己的状态,很容易出现不一致。我遇到过最典型的一次:感知层报告"登录按钮可见",决策层基于这个信息决定点击,但生成层执行时页面已经跳转,按钮没了,操作失败。根因是感知和生成之间有时间差,页面在这期间变了。
这类问题的本质是状态快照的时效性。感知层给的是某一时刻的快照,但决策和生成需要时间,等真正执行时快照可能已经过期。解法有两个方向:一是缩短链路,让感知到执行尽量快;二是执行前做一次轻量校验,确认目标元素还在,不在就重新感知。
6.2 用版本号给状态快照打标
我最后采用的是快照版本号机制。每次感知层输出元素列表时,带一个递增的版本号。决策层基于某个版本做决策,生成层执行前检查当前版本号是否还是那个版本,如果变了,说明页面动过,就回退让决策层重新决策。
这个机制实现起来不复杂,但能挡掉大量"元素找不到"的偶发失败。代价是偶尔会多一次决策,但比起失败重跑整个流程,这点开销完全值得。
6.3 超时与重试的边界
重试不是万能的,得有边界。我的原则是:可重试的错误才重试,不可重试的错误立即上报。元素暂时找不到、网络抖动这类可以重试;断言失败、业务逻辑错误这类重试也没用,直接标记失败并截图。
重试次数也要控制,一般 2 到 3 次。重试太多次会掩盖真实问题,让脚本看起来"能跑"但实际很脆弱。我见过有的脚本重试十几次,跑一次要十几分钟,最后发现是定位策略根本不对,重试只是碰运气。这种"假稳定"比直接失败更危险。
6.4 日志与可观测性设计
三个角色协作,出问题时如果没日志,排查就是灾难。我的日志设计原则是每个角色的输入输出都留痕,且用统一的 trace id 串起来。一次流程跑下来,能按 trace id 把感知、决策、生成三层的日志拉出来,一眼看出是哪一层出的问题。
日志里我特别关注几个字段:感知层的元素数量和版本号、决策层选的动作和理由、生成层实际执行的代码和耗时。这几个字段一摆出来,问题基本就定位了。别小看日志,这套系统能稳定跑起来,一半功劳在日志。
7. 实测效果与几个反直觉的发现
7.1 拆分前后的对比数据
我在一个中等复杂度的 App 上做了对比测试,流程包含登录、列表浏览、详情查看、表单提交、结果校验,大约三十步操作。单模型方案和角色拆分方案的对比大致是这样:
| 指标 | 单模型方案 | 角色拆分方案 |
|---|---|---|
| 单步平均耗时 | 较高 | 明显降低 |
| 定位准确率 | 一般 | 显著提升 |
| 流程成功率 | 偏低 | 明显改善 |
| 脚本可维护性 | 差 | 好 |
| 单次流程模型调用成本 | 高 | 中等 |
具体数字因模型和场景而异,但趋势很稳定:拆分之后,单步耗时降下来了(因为每个角色的上下文短了),准确率上去了(因为每个角色只干窄事),整体成功率自然改善。成本方面,虽然角色多了,但每个角色的调用都短,总成本反而比单模型的长上下文调用低。
7.2 反直觉发现一:感知层比决策层更值得投入
我原本以为决策层是核心,应该花最多精力。实测下来,感知层的质量对整体成功率的影响更大。感知层输出干净准确,决策层就算弱一点也能做对;感知层输出一堆噪音,决策层再强也会被带偏。所以如果资源有限,优先打磨感知层,把元素提纯做到位,收益最明显。
7.3 反直觉发现二:模型不是越强越好
我试过给每个角色都配最强的模型,结果发现有些角色用强模型是浪费。感知层需要的是视觉能力,决策层需要的是推理能力,生成层需要的是代码能力,各自匹配对应强项的中等模型,效果往往比统一用最强模型更好,而且成本和速度都更优。能力匹配比绝对能力更重要,这是角色拆分的精髓。
7.4 反直觉发现三:案例库比模型更值钱
跑了一段时间后我发现,真正让这套系统越用越顺的,不是模型升级,而是案例库的积累。常见操作就那么些,案例库覆盖之后,大部分语义动作直接查表,模型只处理新情况。案例库是团队自己的资产,模型是通用能力,前者才是长期竞争力。所以从第一天起就要有意识地积累案例库,别等系统跑顺了才想起来。
8. 落地时最容易翻车的几个细节
8.1 别让决策层直接看截图
这是我早期犯的错。为了省事,我让决策层直接看截图做判断,结果决策层被视觉细节干扰,经常纠结于"这个图标到底是不是按钮"这种感知层该解决的问题。正确的做法是决策层只看感知层输出的结构化元素列表,把视觉理解完全隔离在感知层。职责边界一旦模糊,两层都会退化。
8.2 语义动作协议要早定、少改
协议是两层之间的契约,改一次两边都要动。我吃过协议频繁变更的亏,改到最后两层的代码都乱套了。后来我定了个规矩:协议只在确实必要的时候改,且改之前先评估影响面。初期宁可多花点时间把协议设计周全,也别边跑边改。
8.3 异常策略要沉淀成配置而非硬编码
异常处理策略我一开始是硬编码在提示里的,后来发现不同 App、不同业务线的异常处理需求不一样,硬编码改起来很麻烦。改成配置文件之后,不同项目配不同的策略文件,灵活多了。策略配置化是这套方案能复用到多个项目的前提。
8.4 别忘了给模型调用加缓存
同一个屏幕状态、同一个任务阶段,决策结果往往是相同的。如果不加缓存,每次都调模型,成本和耗时都上去了。我加了一层基于"屏幕元素列表哈希 + 任务阶段"的缓存,命中率相当高,尤其在同一条用例反复跑的时候。缓存是降本增效的利器,别忽略。
9. 从这套结构里能带走的东西
角色级模型拆分这套思路,说到底就是把一个复杂任务按能力需求切成几块,每块配最合适的模型,块与块之间用清晰的协议通信。它不只适用于移动端自动化,任何"感知 + 决策 + 生成"的任务都能套这个框架,比如桌面端自动化、接口测试的用例生成、甚至一些 RPA 场景。
我在实际项目里最大的体会是:LLM 落地测试领域,工程结构的价值往往大于模型本身。模型能力大家都能用,但怎么组织这些能力、怎么管理上下文、怎么保证稳定性,才是拉开差距的地方。DroidRun 和 Mobilerun 这套双层结构,本质上就是一套工程约束,把模型的自由发挥限制在可控范围内,让它稳定地产出可用的结果。
如果你正准备把 LLM 接进移动端自动化,我的建议是从感知层做起,先把屏幕信息提纯这件事做扎实,再往上搭决策和生成。感知层稳了,上面两层才有发挥空间。另外,案例库和异常策略配置从第一天就建起来,这两样东西越早积累越值钱。至于模型选型,别迷信最强模型,按角色能力需求匹配,中等模型往往就够用,还省钱省时间。