ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

ARTEMIS实战:AI Agent如何重构Android真机测试范式

ARTEMIS实战:AI Agent如何重构Android真机测试范式

如果你维护过一支几十台不同型号的 Android 真机池,一定对下面这个场景不陌生:同一套测试脚本,在 A 型号上跑得好好的,换到 B 型号上就找不到控件;明明只加了一个权限弹窗,脚本里的 xpath 就全线失效,维护成本比当初写脚本还高。这也是我看到 Google 将ARTEMIS开源出来时,第一反应是"这条路终于有人系统性地试了"——它把AI Agent和Android 真机测试结合到了一起,不再靠写死步骤来控制手机,而是让大模型像人一样"看着屏幕操作手机"。

这篇文章我会从 ARTEMIS 到底解决了什么问题讲起,然后拆解它的感知、决策、执行闭环,再给你一条从零部署到真机实测的完整路径。中间会穿插我在真机测试里踩过的坑:厂商定制 ROM 带来的路径权限问题、SystemUI 状态栏误触、进度条等待策略,以及一些关于选型落地的实在建议。无论你是测试架构师、Android 开发,还是刚开始折腾 AI Agent 的爱好者,都能从这里找到可直接复用的经验。

1. 真机测试的"欠账":为什么"脚本思维"走到了尽头?

1.1 模拟器再像,也补不上真机的坑

开发阶段大家当然喜欢用模拟器,启动快、快照方便、还能随便改分辨率。但一旦进入发布前的兼容性验证,模拟器就顶不住了:国内厂商的定制 ROM 会魔改通知栏、权限策略、后台杀进程逻辑;不同机型的屏幕比例、挖孔位置、导航手势方案各不相同;还有真机特有的传感器调用、电话短信打断、弱网切换、温控降频……这些场景模拟器根本模拟不出来,必须上真机。

真机测试的痛点还在"量"上。一台设备只能装一个状态,如果你负责的 App 要覆盖二十个机型、三个 Android 大版本,光是把手机充满电、解锁、装包、配账号这些前置操作就够一个测试专员折腾一上午。更麻烦的是,好不容易跑起来的自动化脚本,在换机型后经常因为控件 id 变化而崩溃——UI 自动化在真机矩阵面前,本质上是"用脚本的确定性对抗环境的不确定性",这场仗从一开始就很难打。

1.2 传统 UI 自动化的"死循环":写脚本、修脚本、再写脚本

我知道很多人会反驳:"我们用 Appium 不是跑得好好的吗?"确实好,Appium、UIAutomator、Espresso 这些框架在单机型单场景下非常可靠。但它们有一个共同前提:你必须预先知道界面长什么样。这就要写定位器、等待条件、断言表达式,本质上是在"翻译"人的操作逻辑。

问题在于,移动端 UI 的变更频率极高。产品加一个弹窗、换一个按钮文案、改一次布局层级,脚本立刻失效。失效后你做的不是写新用例,而是先花时间排查"是脚本 bug 还是真 bug"。等排查完,产品已经迭代了两轮。再加上真机矩阵里的厂商差异,同一个按钮在不同手机上可能叫btn_ok、button_1、tv_confirm,脚本里得有大量条件分支。这套东西越铺越大,最终会变成测试团队里最没人愿意维护的"遗产代码"。

我见过不少团队最后的妥协方案:核心功能用脚本回归,其余靠手工点。这其实就是承认了传统自动化的天花板——它能应对"已知路径的重复执行",但无法应对"界面变了、路径未知"的情况。

1.3 LLM 为什么被选中:从"执行脚本"到"理解目标"

ARTEMIS 的切入点很有意思:它不追求让机器复现人写好的步骤,而是让机器理解"人想要的结果"。比如给一句任务描述:"打开设置,把屏幕亮度调到最低",传统脚本要写清楚"点击设置图标、滑动进度条到最左、确认";而 Agent 路径只需要理解三个事实——当前屏幕上有什么、目标状态是什么、下一步该动哪里。

大模型正好提供了这三个能力:视觉模型可以把截图变成"能看懂的画面",LLM 可以根据截图和历史动作推理出下一步操作,最后通过 adb 之类的工具把动作下发到真机。这套"感知-决策-执行"闭环,本质上模拟了一个人类测试员的操作方式:看一眼屏幕、想一下、点一下、再看一眼。

所以 ARTEMIS 不是某个测试框架的小改版,而是把测试自动化的核心假设从"脚本复用"换成了"意图执行"。这也是它值得研究的原因——它绕开了让所有测试工程师头疼的"选择器维护"问题。

2. ARTEMIS 的感知-决策-执行闭环:AI Agent 怎样"看见"并操作 Android

2.1 感知层:把手机屏幕变成模型能"看见"的数据

Agent 操作手机的第一步,是搞清楚屏幕当前是什么状态。ARTEMIS 在这一层用了两条路线:一条是视觉路线,直接对设备截图,然后用视觉模型把截图里的 UI 元素标注出来——比如识别出"这里有一个按钮,文字是'登录'";另一条是结构路线,通过 Android 的 UI 层级信息(类似uiautomator dump拿到的 XML)把控件树转成文本标签。

两条路线各有适用场景。结构路线的优点是坐标精确、可读性强,拿到的是控件 id、文本、bounds,LLM 可以直接基于这些信息做决策;缺点是一旦 App 用自绘 View 或者游戏引擎渲染界面,控件树就是空的。视觉路线则更接近人眼,不管控件树有没有内容,只要截图上画得出来,模型就能"看见";但缺点是坐标精度依赖模型能力,有时候会点偏。

我在实际使用中有一个不成熟但有效的心得:优先让 ARTEMIS 同时拿两条路线的数据,以结构路线为主、视觉路线作为兜底。这样在原生控件场景下决策速度更快,遇到 Flutter、Unity 这类自绘界面时也不至于直接瞎掉。如果你自己搭 Agent,建议也按这个思路设计感知模块,纯视觉方案的幻觉率会明显更高。

2.2 决策层:LLM 不只是聊天,它是在"操作手机"

感知完成之后,屏幕上的元素、坐标、状态描述会被组装成一段上下文:当前任务目标有多条历史操作记录和对应的屏幕变化,以及"当前这一步有哪些动作可选"。ARTEMIS 通常把动作空间限制在一个合理的集合里:点击、输入文本、滑动、返回、回到桌面、等待、长按。这跟人类测试员能做的操作高度一致。

LLM 要输出的是"该执行哪个动作、作用于哪个坐标/元素"。为了减少自由文本带来的不稳定,这类系统一般会要求模型输出结构化指令,比如 JSON 格式的动作描述,再经过一层校验器语法检查,合法的指令才会真正下发。这一步非常关键:如果让模型自由发挥,它经常会突然"脑补"出一些系统里不存在的按钮,而当你把动作空间锁死,幻觉率会大幅下降。

决策链路里还有一个容易被忽视的细节:上下文管理。一次复杂测试可能要持续几十个操作步骤,模型不能每次只看当前屏幕,它需要记住自己之前做过什么,才能避免反复点同一个地方、或者在某个弹窗里打转。ARTEMIS 的做法是维护一个"目标-历史-当前状态"的对话窗口,这本质上是一种简化版的 Agent 记忆机制。自己实现 Agent 时,这个窗口长度和压缩策略需要反复调,窗口太长模型会迷失重点,太短则缺乏连续性。

2.3 执行层:从"下发指令"到"回收结果"的姿势很重要

决策层说"点击坐标 (512, 1280)",执行层就要真正把事件传进手机。ARTEMIS 底层通常通过 adb 命令或者 Android 的自动化接口来实现注入,常见的adb shell input tap x y、input swipe、input text都能完成任务。到这里,你已经能看到它和传统自动化脚本的根本差别:传统脚本是"一条路走到黑",Agent 则会根据执行结果不断调整。

执行完成后,系统会再次进入感知层——重新截图、重新取控件树、重新把新的屏幕状态交给 LLM。这个"行动-观察-再行动"的循环会一直持续,直到模型认为任务目标已经完成,或者达到预设的最大步数。为了评估任务是否成功,ARTEMIS 还会让模型对当前屏幕状态做一次"目标完成度"判断,而不是靠硬编码断言。这种软性评估在探索性测试、Bug 复现场景里尤其好用,因为没有人知道正确路径长什么样,只能靠 Agent 自己试验。

2.4 为什么"动作越少越好"的设计反而高效

ARTEMIS 锁死动作空间这个设计,很多第一次接触的人不理解,觉得"模型能力这么强,就应该让它自由操作"。实战下来我强烈建议你别这么干。动作空间过大,模型输出错误格式的概率会指数级上升,而且真机操作是有代价的——一个误触可能弹出系统设置页,整个会话就带偏了。

只保留 tap、type、swipe、back、home、wait 这几个原子动作,已经能覆盖 95% 的日常测试路径。长按和多媒体键这种低频操作可以后续再加。记住一句话:Agent 能不能完成任务,不取决于它会的动作多不多,而取决于它对"当前该做什么"的判断准不准。把动作范围收窄,本质上是给模型减少不必要的选择,反而能让它更专注。

维度传统脚本自动化ARTEMIS 式 Agent 测试
定位方式依赖控件 id/xpath依赖视觉+层级信息的动态判断
面对 UI 变更脚本失效,需人工维护重新感知后自适应
执行逻辑固定步骤顺序根据反馈动态调整
断言方式硬编码预期值模型判断目标完成度
适用场景回归、重复路径探索、冒烟、Bug 复现

3. 本地跑通 ARTEMIS:一台真机、一个任务、一次完整的 Agent 操作回放

3.1 环境准备:硬件、软件、模型三件套

要完整跑起来,你至少需要三样东西:一台能连接电脑的Android 真机、一套可用的LLM API(比如 Gemini,或者通过兼容接口接入其他模型)、以及一个能跑 Python 脚本的开发环境(Linux / macOS 都行,Windows 理论上也能跑但我没试通,老实用 Linux 省心)。

先说真机。强烈建议第一台机器用 Pixel 或者系统接近原生的机型,不要一上来就用国产定制 ROM。原因是 ARTEMIS 拿到的 UI 层级和坐标在原生系统上最规整,定制 ROM 会大幅增加变量。手机需要开启开发者选项和 USB 调试,最好还能保持至少 20% 电量,并在测试期间禁用锁屏—— Agent 在操作中途遇到锁屏界面,通常会被卡住很长时间。

代码方面,把 ARTEMIS 拉下来之后按 README 装依赖,核心就两件事:设置好模型 API 的访问凭证,确认adb devices能识别到你的手机。整个过程我实测在干净环境下半小时能搞定。遇到依赖装不上,九成是 Python 版本不对,建议直接用项目要求的版本创建虚拟环境,别拿系统自带的全局环境硬扛。

3.2 设备侧细节:USB 调试授权、分辨率和屏幕常亮

连接真机有个特别容易被新手忽略的坑:adb devices里显示unauthorized。这是因为手机上的"允许 USB 调试"弹窗需要手动确认。有些机器还默认只给"仅充电"模式,你需要手动切到"传输文件"模式,否则 adb 的服务根本起不来。我通常的习惯是接上线后先跑一句adb devices,看到device状态再开始后续操作。

分辨率这块也值得花一分钟处理。ARTEMIS 在拿到截图后会把图像缩放给模型,不同分辨率会影响元素标注的准确度。如果你用的设备是 2K 屏,建议在开发者选项里把"最小宽度"调到一个较低的 dp 值,这能减少渲染开销,同时让 UI 元素更大、更利于模型识别坐标。屏幕常亮也好设置:开发者选项里的"屏幕不休眠",或者直接adb shell svc power stayon true。真机测试最怕操作到一半屏幕熄灭,那整个 Agent 会话基本就凉了。

3.3 第一次真机实测:让 Agent 自己探索一个陌生 App

环境就绪后,第一个任务建议选一个你熟悉的、逻辑简单的应用。以计算器为例,任务可以这样写:"打开计算器,依次点击数字 1、2、3,然后按加号,再按 4、5、6,最后按等号,告诉我屏幕上的结果是什么。"

跑起来以后你会发现,Agent 的执行路径跟你想象的不一样。它可能不是从"识别计算器图标"开始的,而是先打开应用抽屉、找图标、进入应用,每一步都会产生一个新的屏幕状态,然后重新截图、重新决策。整个过程你能在终端里看到模型输出的动作 JSON,也能从手机画面里看到一次次的点击和滑动。第一次跑通这种"You tell it what to do, it figures out how"的体验,还是挺震撼的。

任务结束后,ARTEMIS 会输出一个结果判断:"任务是否完成"以及"最终屏幕状态描述"。我建议你在前几次实验里有意给它布置一些"半开放"任务,比如"在这个 App 里找到设置入口并截图"而不是"点击右上角第三个图标",这样才能真正体会 Agent 的灵活性。

3.4 第一次跑通常不会太顺利:模型、权限、时序三座山

如果你第一次跑就完美通过,那你运气是真的好。我遇到过的问题基本集中在三个层面:模型能力不足导致动作乱选、应用权限弹窗阻塞流程、以及时序问题导致点击时控件还没加载出来。

模型这层最简单,换更强的模型或调整 prompt 就好。权限弹窗稍微麻烦一点,因为在某些定制 ROM 上,系统级弹窗的"允许"按钮无法通过常规控件树识别到,这时候视觉路线的价值就凸显出来了。时序问题则需要给 Agent 配置合理的等待策略:ARTEMIS 默认的 wait 动作是固定秒数,但你可以在任务描述里写"操作后等待页面完全加载再进行下一步",模型会自己理解、适当放慢节奏。

这里我特别想说一个观点:第一次失败不可怕,Agent 的日志会完整记录每一步的感知结果、决策动作和屏幕反馈,你顺着日志能很快定位到问题出在感知层还是决策层。这个可排查性,其实比传统脚本的"黑盒失败"友好得多。

4. 真机测试的"骨感现实":文件路径、SystemUI、等待策略和厂商定制

4.1 厂商 ROM 里那些"权宜路径":fileprovider 与私有目录

真机测试跑久了你会遇到各种各样的路径问题,其中一类跟应用文件访问强相关。很多国产 App 会通过 ContentProvider 向外部暴露文件路径,日志里经常出现类似content://com.xxx.fileprovider/external_path/android/data/com这样的 URI。这类机制本意是安全合规,但在 Agent 场景下会带来麻烦:当任务涉及文件上传、下载、导入导出时,Agent 通过 adb 直接推拉文件往往走不通,因为你面对的不是一个普通路径,而是一套权限管理体系。

我的处理思路是,尽量不要让 Agent 直接跟这种 fileprovider 路径"硬刚"。把文件层面的操作提到 Agent 的感知范围之外:先用 adb push 把文件放到/sdcard/Download,然后让 Agent 在应用内通过"文件管理器/最近文件"的方式去选择,绕开 content URI 的解析。这看起来多了一步,但模型处理常规 UI 路径的成功率,远高于处理抽象 URI 的能力。

4.2 SystemUI 的"乱入":状态栏、通知面板和系统弹窗

真机测试里最让人血压升高的时刻,是 Agent 正在认真操作时,状态栏突然弹出一条通知,或者低电量警告冒出来,把原本的点击坐标全打乱了。传统脚本遇到这种情况,大多靠"强制等待 + 重新定位控件"硬撑;ARTEMIS 式 Agent 稍好一些,模型能认出"这是个系统弹窗,不是目标界面",然后自主地按下返回键把它关掉。

但"能处理"不代表"处理得好"。我实测下来,Agent 对系统弹窗的反应经常是"不知所措"——尤其是国产 ROM 的自定义权限弹窗、横幅通知、以及手势导航条的位置差异。一个实用的技巧是:在正式测试前,用 adb 命令把通知屏蔽掉,减少干扰项。还有更极端的做法是直接开飞行模式做单机测试,把网络弹窗、同步通知全部隔绝。记住一个原则:真机测试的稳定性不是靠 Agent 的临场应变,而是靠测试环境的"降噪"。

4.3 进度条与异步加载:Agent 最容易被"假加载"骗过去

很多 Android App 的加载过程是"假进度条":进度条已经跑满,但数据其实还在加载;或者界面卡在一个转圈动画上,数据请求已经失败。模型看着屏幕上的进度条,很可能傻傻地等待,浪费大量步数;更糟糕的是,它会误以为"进度条存在 = 在加载中 = 需要等待",然后反复执行 wait,直到任务超时。

我自己的处理策略是多管齐下:一方面在任务 prompt 里写清楚"等待新页面出现而不是等待进度条消失",让模型关注界面上的关键元素(如列表项、按钮文案)是否出现;另一方面在 Agent 框架里加一层"卡住检测"——如果连续 N 次截图画面变化极小,就直接触发当前界面截图并让模型重新评估状态,而不是无限等待。这两种方式结合,能明显减少 Agent 卡死在加载动画上的情况。

4.4 分辨率、字体大小与手势导航:不同机型的"排版变数"

最后聊一个经常被忽略的杀手:系统字体大小。同一台设备,字体切成"特大"之后,按钮文字可能换行、控件位置整体下移,模型标注出来的坐标偏离导致点击错位。还有全面屏手势导航和传统三键导航,底部区域的可操作空间完全不同,Agent 在滑动操作时容易误触返回手势。

在组建真机矩阵的时候,建议把所有设备的字体、显示大小、导航方式、屏幕超时先统一成同一套配置,这能让 Agent 的跨机型表现稳定很多。如果做不到完全统一,至少要在任务描述里告知模型"当前设备的屏幕类型和系统设置",给它一个适应上下文。别小看这个动作,它能让决策层的错误率下降一个量级。

5. ARTEMIS 的适用边界与团队落地建议:哪些场景赚到,哪些场景别浪费钱

5.1 最赚的场景:探索性测试、跨 App 流程和 Bug 复现

如果你问我 ARTEMIS 最强的场景是什么,我的答案不是标准回归,而是探索性测试。传统自动化擅长已知路径, Agent 恰好擅长未知路径。你可以给 Agent 一个模糊目标,比如"找出这个 App 里所有可能导致崩溃的操作路径",让它在真机上自由游走,这种测试的覆盖面积远超人工点几天手机。

跨 App 流程也是 Agent 的强项。比如"从微信复制一个文本,回到主 App,粘贴到输入框并搜索",这种涉及多个应用跳转、剪贴板读写的流程,传统脚本写起来极其繁琐,Agent 反而处理得游刃有余——它只需要理解目标,然后按人类直觉去操作。Bug 复现同样适用:把线上用户报告的"从 X 页面进入 Y 详情页再返回会出现白屏"翻译成自然语言任务,Agent 能按照你的描述去尝试,比开发手动复现高效得多。

5.2 最亏的场景:性能基准、严格断言和大规模回归

也别把 ARTEMIS 当成万能药。凡是需要精确数值、毫秒级响应、严格断言的场景,它都不合适。比如启动耗时基准测试、帧率统计、接口响应时间验证,这些必须用专门的性能测试框架,而不是让一个 LLM 去"目测"快慢。LLM 的输出天然带有随机性,让 Agent 去断言"页面是否正确展示了 3 条数据",它可能这次判断成功、下次判断失败。

大规模回归场景我也不建议直接上 Agent。原因很现实:成本。每次决策都要调用模型 API,一个复杂任务可能几十步、上百步,跑上千条用例的成本会高到吓人。更合理的做法是"分层测试":主干路径用传统脚本做快速回归,异常探索和跨 App 流程用 ARTEMIS 做补充覆盖,两者各司其职。

5.3 怎么跟现有测试体系共存:把它当"失败用例发现器"

在我自己的项目里,ARTEMIS 的最佳定位不是"替代 Appium",而是"失败用例发现器"。我每天会启动一个 Agent 任务池,让它在真机池里执行若干条探索任务,凡是 Agent 在中途发现异常(崩溃、白屏、卡死、无法返回)的场景,都会自动生成带截图的失败报告。然后由测试工程师分析这些报告,把高频问题转化成传统回归脚本里的正式用例。

这里有个很有意思的现象:传统脚本失败会让人觉得"脚本该修了",Agent 失败却往往会揭示出真实的产品问题。因为 Agent 的操作路径是动态生成的,它踩到的坑更像是真实用户会踩到的坑。这种"自主探索 -> 自动报告 -> 人工确认 -> 脚本固化"的流程,我觉得是当前阶段把 Agent 测试价值最大化的实践方式。

5.4 成本与投入:API 用量、真机集群、模型选型的账单

最后说点实际的,钱的事。ARTEMIS 一跑起来就是持续的 LLM API 费用。视觉分析、决策推理、结果判断都要消耗 token,一个复杂任务的成本可能是几毛钱到几块钱人民币不等。真机集群也不能忽视物理损耗——手机长期高负载测试,发热、电池损耗、数据线松动都会变成日常开支。

想控制成本的话,我的建议是给每个 Agent 任务设置最大步数上限(比如 30 步),超时就终止并标记失败;优先用便宜的模型组做初步探索,只有复杂任务才动用更强的模型。别忘了建一个真机管理平台,至少要做到设备状态自动检测和 adb 重连,不然测试跑着跑着断连一台,比模型出错还让人头疼。真正落地的时候,你会发现"稳定"比"智能"重要得多,而这恰恰需要工程化能力来兜底。

最后再分享一个我的个人体会:给 Agent 写任务描述时,越具体,它的表现越可靠。用"打开计算器,计算 123+456 的结果"比"帮我看看计算器怎么用"稳定十倍不止。这不是模型笨,而是目标越明确,决策层面的搜索空间越小。你把它当成一个"执行力很强但想象力有限的新员工"去交代任务,就对了。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进