Opposable 是一款 Android 应用,它通过无障碍服务读取屏幕,并在任何其他应用中点击和输入。Claude、ChatGPT 或 Codex 可以从电脑上驱动它,而当它们都没有连接时,一个 20 亿参数的屏幕模型会在手机上运行同样的循环,无需服务器参与。

设备端智能体打开时钟并切换到秒表,手机之外没有任何模型。Android 模拟器,实时,右侧显示每一步的耗时。

TL;DR

该模型是 GUI-Owl 1.5 2B,在 llama.cpp 上以 4 位量化运行。在 4 线程的 Mac M2 CPU 上,一步耗时 7.3 s,从 10.6 s 降下来,在我们 36 屏测试集上精度相同。这一步有一半是视觉编码器,而在 Galaxy S25 的 NPU 上,编码器运行耗时 236 ms,相比之下 M2 上是 3.9 s。

循环中的一步,以 Mac M2 CPU 上的真实速度播放动画:编码 3.6 s,预填充 2.5 s,解码 1.1 s,然后点击。

模型与运行时

GUI-Owl 1.5 来自阿里巴巴的 Mobile-Agent 团队。它是一个 Qwen3-VL 微调模型,查看截图并回答一个动作。我们在应用中通过 llama.cpp 及其多模态库运行它,量化为 4 位:语言模型 1.05 GB,视觉编码器 445 MB。两者只加载一次,并在各步之间保留在内存中。

模型只看到应用无法用其他方式完成的任务。大约四十个常见任务,比如设置闹钟、给联系人发短信或打开 Wi-Fi,以固定代码运行,不使用模型;而大型智能体先前摸索出的例程则从屏幕上的文本回放。

CPU 上的单步耗时

一步分为三个阶段。视觉编码器将截图转换为图像 token,语言模型读取这些 token 以及任务(预填充),然后写出约 45 个 token:一句说明它打算做什么的话,然后是一个 JSON 工具调用。在未做任何优化的情况下,M2 上编码器耗时 4.6 s,预填充 4.3 s,解码 1.7 s,每步 10.6 s,模型在 36 个评分屏幕中答对了 27 个。

M2 CPU 上按阶段划分的单步耗时,CPU 优化前后。我们在 36 屏评分集上的测量结果。

裁剪截图中的状态栏、导航栏和键盘,在编码前就缩小了图像。经过编码器后,不与任何内容相邻的平坦背景图块对应的 token 被丢弃,其余 token 保留原始网格位置,因此模型看到的布局相同,但 token 数减少了 25% 到 40%。这将准确率提升到 36 个中的 28 个。900 token 的系统提示词只预填充一次,并保留其 KV 缓存。在应用使用的 400 个图像 token 下,一步耗时 7.3 秒,得分为 36 个中的 27 个。

简化后的屏幕。状态栏和导航栏在编码前被裁剪,与相邻内容无关的平坦背景 token 在预填充前被丢弃。

模型在给出坐标之前先陈述其意图,例如“Action: Click the Files app icon.”。当该句子与无障碍树中的恰好一个元素匹配时,应用会点击该元素并停止生成。在模拟器上,这些步骤的解码时间为 0.8 到 1.3 秒,而非 2 到 4 秒。在所有这些措施到位后,编码器占用了 7.3 秒中的 3.6 秒。

当模型的句子与屏幕上的恰好一个元素匹配时,应用会点击它,坐标永远不会被生成。

NPU 上的视觉编码器

我们只将 GUI-Owl 的视觉塔导出为 ONNX:一个带 merger 的 24 层 ViT,约 4 亿参数,固定输入为 416 × 960 像素。该尺寸下的一屏为 5420 亿次乘加运算。Qualcomm AI Hub 将其编译用于 Galaxy S25(Snapdragon 8 Elite),并在 Qualcomm 设备实验室的一台真实 S25 上运行。

M2 CPU 上按阶段划分的一步,以及仅在 M2 和 S25 的 NPU 上运行的视觉编码器。

在 fp16 下,编码器运行耗时 236 毫秒,全部 873 个操作都在 NPU 上,比 M2 的 3.9 秒快约 16 倍。8 位权重配 16 位激活更快,为 213 毫秒,但偏离参考输出,余弦相似度为 0.978 到 0.985,而 fp16 为 0.992 到 0.996;模型的点击依赖于细微的屏幕细节,因此应用使用 fp16。完全 8 位和 4 位版本得分为 0.67 到 0.90。首次加载需要 72 秒,期间 NPU 准备计算图,每次安装仅一次,之后为 0.39 秒。

Galaxy S25 NPU(Qualcomm AI Hub)上的编码器精度:推理时间,以及输出与参考值的接近程度。fp16 是唯一高于应用所要求的 0.99 的版本。

NPU 返回的浮点数组与 llama.cpp 自带的编码器相同,因此剪枝、位置、缓存和提前退出都能照常工作。启动时,应用先尝试 NPU,再通过 LiteRT 尝试 GPU,最后尝试 CPU;只有当编码器通过针对内置截图的自我测试(与 CPU 编码器的余弦相似度达到 0.97 或更高)且比 CPU 更快时,才会被采用。640 token 的输入尺寸在 NPU 上编译失败,因此需要该尺寸的步骤仍在 CPU 上编码。

手机如何最终得到一个编码器。每个候选编码器都必须在首次加载时通过自我测试,而 CPU 路径始终可用。

留出任务上的准确率

在八个模型从未被调优过的任务上,每个任务在模拟器上各运行两次,让它完成整个任务分别成功了 4 次和 3 次。每次只给它一个子目标,并在进入下一个子目标前对照无障碍树核验每个声称的成功,两轮都成功了 6 次。

Android 模拟器上的八个留出任务,每轮两轮,分别在采用带屏幕核验的子目标之前和之后。

局限性

目前只有 Snapdragon 有 NPU 构建。Pixel 手机需要针对 Tensor 单独编译,MediaTek 和 Exynos 也需要各自的构建,因此这些手机回退到 GPU 或 CPU。对于它没见过的应用,该模型也比云端模型弱得多,当连接了 Claude、ChatGPT 或 Codex 时,应用会把这类任务交给它们。

试用

该 Android 应用在 getopposable.com 免费提供。屏幕模型需从其设置中下载,大小为 1.5 GB,同一屏幕会显示你的手机选择了哪个编码器,以及编码一屏需要多长时间。欢迎通过 hello@getopposable.com 告诉我你手机上的这两项信息。