用 LLM 替掉 Appium:一个 Android 测试 Agent 的工程实践

83 阅读7分钟

一、Appium 的真实成本

我所在的团队负责一个 Android 端的社交 App,QA 团队几个人,维护着上百 case 的 Appium 回归套件。

听起来不多?但这是每个迭代都要跑一遍的回归套件,而且:

  • App 大版本两周一次,UI 改动几乎覆盖每个核心页面
  • Espresso / XCTest 写不动业务流(涉及多个 Activity / 多个 App 跳转),只能 Appium
  • 公司禁用三方测试云,只能自建设备农场

每次迭代上线前那两天,QA 团队的工作变成:

  1. 跑套件 → 130/200 红
  2. 查每个红 case:是真 bug,还是 selector 失效?
  3. 70% 是 selector 失效(resourceId 改了 / 页面层级变了 / 控件挪进了 RecyclerView 二级层级)
  4. 修 selector → 再跑 → 又有 30 红
  5. ...

每个迭代花在维护测试代码上的时间,超过写新 case 的时间。这件事持续了一年。

去年底我们盘了一下:"是不是该换条路?"


二、调研几个 LLM Agent 方案

LLM 出来后,"用 AI 跑 UI 测试"这个想法在 QA 圈讨论很多。我们花了三周认真试了几个方案:

DroidRun(github.com/droidrun/dr…,8.2k star)

德国人写的 Python 框架,多 LLM 支持,通过 ADB + Portal App 控设备。

优点:架构清晰,Portal App 思路(在设备上常驻一个服务收指令)启发我们后来的设计。 不行:用例必须用 Python 脚本写(写脚本不就回到 Appium 了?);定位是 workflow 自动化,没有 Suite / Run 报告概念;ADB 强依赖 → PC 和设备同网段。

Midscene.js(github.com/web-infra-d…,12.6k star)

字节出品。纯视觉方案 — 用 Set-of-Marks 在截图上标元素,让 VLM 直接选。

优点:跨平台、回放报告精致、SoM 思路优雅。 不行:在我们的产品 UI 上跑通率 30% 不到。视觉模糊场景(dialog 重叠、动画中、长 list scroll)特别拉;还是 ADB;YAML / JS SDK 写测试,对 QA 友好度不够。

AutoGLM(智谱 / 清华)

商业产品,基于 GLM 模型 + AccessibilityService 读 UI 树,分 Planner / Grounder 两层。

优点:精度高,中文 App 优化到位。 不行:商业 SaaS、不开源、不能自托管;对话式 agent,不是测试框架。

结论:三家都有亮点,但没一个是给 QA 团队设计的

DroidRun 是 workflow 工具,Midscene 是跨平台 UI 自动化框架,AutoGLM 是消费级 agent。没有一个是"端到端的 Android 测试平台" —— 从用例编写、套件管理、运行、回放、报告、对比,到 CI/CD 集成。

我们决定自己写。


三、Smart-AI-Bot 的 4 个关键架构决策

Smart-AI-Bot(MIT 开源)是这次自研的产物。下面这 4 个决策的具体技术细节、代码片段

后台页面.png

测试报告.png

决策 1:双感知(截图 + a11y 树),不走纯视觉

Midscene 的纯视觉路线在我们的产品上撞墙了。视觉模糊时模型猜错坐标的概率太高,没有"这一步执行的是哪个语义元素"的可解释性。

我们的做法:

  • 截图给视觉上下文(哪些是按钮、整体布局)
  • a11y 树(AccessibilityService 拿)给语义(每个元素的 className / resourceId / 中文 text)
  • 两路一起喂给 LLM,用 a11y 树挑元素,用截图二次确认

代价:a11y 树为空的页面(Canvas / Unity)需要 VLM fallback。换来 80%+ 标准 UI 上的稳定性提升 —— 我们生产套件 case 通过率从 30% 提到 85%。

决策 2:反向 WebSocket,不要 ADB

我们的目标是云端 server + 全球散布的设备:公司 WiFi 上的测试机、海外子公司机房的设备、同事家里的旧手机、4G/5G 直连。ADB 永远做不到这个

我们写了 Portal App(基于 droidrun-portal 的连接策略):设备启动后主动 WebSocket 连云端,能访问公网就行,不要求同网段。

效果:一个云端服务器,可以管理多台分布在不同网络的设备;设备掉线自动重连,30 分钟预算 + 终态错误识别(401/403 不重试);库级 ping/pong 30s 超时检出僵尸连接。

这一块的具体实现 — 重连预算怎么算、AtomicBoolean 怎么防风暴、还遇到一个奇葩的 StackOverflow bug — 在后面文章里有详细代码。

app截图.png

决策 3:Verifier 用双截图(而不是单截图)

最早 verifier 是单截图判定。一个真实翻车 case:

任务:领取每日奖励,确认领到 +443 经验值 Agent:我点了领取按钮,看到 +443 toast,任务完成 Verifier 单截图:屏幕上没有 +443,failed

看 case 就是 PASS — toast 真的弹出来过,只是 1 秒就消失了。

修复:让 verifier 同时看 两张图 —— A 帧(动作触发后 0.35s 立即截,捕捉瞬态 toast)+ B 帧(沉淀后截,看最终状态)。这一改动让 verifier 误判率从 25% 掉到 5% 以下。

拼图实现细节、prompt 怎么写让 LLM 自己挑哪张图当证据,第二篇文章。

决策 4:Agent 知道自己在哪个 Activity

第二个高频翻车:相似页面 agent 分不清,狂点同一个按钮 8 次。视觉无法区分两个长得像的页面

我们让 Portal App 在每次返回 UI 状态时附带当前 Activity 类名 + 最近 5 个 Activity 切换轨迹。Activity 类名是确定的、机器可读的,比让 LLM 从视觉里推断"我在哪"可靠两个数量级。这一改让 agent 的 stuck-loop 几乎消失。

报告回放.png

四、跟 DroidRun / Midscene 的快速对比

我们在自家产品的标准业务流 case(登录、设置、个人主页、信息流,不含游戏 / Canvas)上做过对比测试,观察到的大概数字:

  • DroidRun:单 case 跑通率约 30%。截图模糊 + selector 偶尔找不到。
  • Midscene:约 30%。纯视觉方案,在动画 / 弹窗叠加场景翻车多。
  • Smart-AI-Bot:约 80%+。a11y 树 + 截图双感知 + verifier 双截图 + page-aware 几个改动叠加的效果。

真正决定 ROI 的不是通过率,是维护成本

  • 旧 Appium 套件 — 每个迭代要修 30%+ selector
  • Smart-AI-Bot — UI 改了 agent 自己重新找路径,几乎不需要改 case

跑得慢一点(单 case 1-3 分钟,含 LLM 推理),但写得快、维护成本接近 0。对中小型 QA 团队来说,这个 trade-off 完全值得。


五、哪些 case 还跑不动

讲优势的同时讲清短板:

跑不动的

  • Canvas / Unity 游戏 UI:a11y 树为空,纯视觉 fallback 在动态游戏画面上稳定性还不行
  • 强依赖时间序的动画(必须在 2s 内连点 3 下):LLM 推理本身要 1-3s,赶不上节拍
  • 需要精确手势的玩法(多指、自由路径滑动):当前只支持基础 tap / swipe
  • 强反爬 / 滑块验证:模型识别能力到不了

跑得动但慢的

  • 大列表滚动找元素:要多次 scroll + screenshot,单 case 可能 5-10 分钟
  • 需要等服务器返回的 case(充值 / 提交订单):每个等待都吃 LLM 调用费

适合用的场景

适合:

  • 标准 UI(非游戏)的功能性测试
  • 跨页面的业务流(登录 → 设置 → 修改资料 → 验证)
  • 一次写、多版本跑(自动适应 UI 改动)

不适合:

  • 极致性能要求(单元 / API 测试还是别用)
  • Canvas / 游戏 UI(除非愿意在 VLM 上加预算)
  • 强反爬场景

六、开源 + 邀请

Smart-AI-Bot 完整开源在 github.com/rejigtian/S…(MIT),仓库里有:

  • 完整后端 + 前端 + Portal App 源码
  • 预编译 APKv1.0.0 release 直接下载)
  • 端到端 demo 视频(README 顶部内嵌,三栏:相机实录 + 投屏 + 报告页)
  • 6 个 LLM provider 集成(OpenAI / Anthropic / Gemini / 智谱 GLM / Groq / Ollama)
git clone https://github.com/rejigtian/Smart-AI-Bot.git
cd Smart-AI-Bot
./start.sh

设备端装 APK,Portal App 设置页填服务器 WS 地址 + Token,连上就能跑。


鸣谢

技术上受这三个项目启发:


下一篇预告

这篇讲了为什么整体决策。下一篇 zoom in 5 个具体的工程坑 —— 包括上面提到的双截图 verifier 实现、Activity-aware 的 prompt 设计、连接稳定性的 5 条策略、还有 SoM 标记被识别成"游戏内品"的奇葩翻车。

如果你也在 QA 团队、也被 Appium 维护成本折磨过,欢迎 star / issue / PR / 提反馈。