首页
/ 使用 @ui-tars/cli 驱动 ADB 操作 Android 设备:UI-TARS 多模态 GUI Agent 的命令行实战指南

使用 @ui-tars/cli 驱动 ADB 操作 Android 设备:UI-TARS 多模态 GUI Agent 的命令行实战指南

2026-09-08 18:42:03作者:袁立春Spencer

@ui-tars/cli 是 UI-TARS 开源多模态 Agent 技术栈(packages/ui-tars/cli)中面向命令行场景的轻量入口。它把「视觉大模型推理 + 界面操作执行器(Operator)」封装成一条命令,让你无需打开桌面应用,就能在终端里下达自然语言指令,由 Agent 自动完成点击、输入、滑动等 GUI 操作。读完本文,你将掌握 npx @ui-tars/cli start 的完整参数用法、模型 Presets/本地配置两种接入方式,并理解其底层如何通过 ADB 与 Android 真机交互、如何支持中文输入等关键原理。

快速开始:一条命令让 Agent 帮你操作手机

@ui-tars/cli 官方的使用方式极其简洁。在电脑上连接好 Android 设备(开启 USB 调试)后,直接运行 README 给出的命令即可:

npx @ui-tars/cli start -p 'your config' -t adb -q "Help me add Tom to my contacts. His phone number is 12345678900."

这条命令会启动一个 UI-TARS GUI Agent,让它自主完成「把 Tom 及其手机号 12345678900 添加到联系人」这一整串任务——包括观察屏幕截图、定位输入框、唤起键盘、逐字输入并最终保存。全程无需预写任何点击坐标或 UI 自动化脚本。

命令定义 可以看到,start 子命令总共支持三个核心选项:

短参数 长参数 说明 示例
-p --presets <url> 指向一份远程 YAML 模型配置预设的 URL -p 'https://example.com/preset.yaml'
-t --target <target> 指定执行目标 Operator,当前可选 adb(Android 真机)或 nut-js(桌面电脑) -t adb
-q --query <query> 直接通过命令行传入任务指令,跳过交互式输入 -q "打开设置并开启飞行模式"

此外还支持不带任何参数的 ui-tars start——此时 CLI 会进入交互模式,逐步引导你填写模型配置与任务指令(详见下文)。

接入你的视觉模型:Presets 远程预设与本地配置文件

Agent 的「大脑」来自视觉语言模型(VLM)。CLI 支持两种配置方式,核心实现位于 start.ts 配置加载逻辑

方式一:通过 -p 传入远程 YAML Preset

当传入 -p 时,CLI 会用 node-fetch 拉取该 URL 内容,并按 YAML 解析为配置:

# 一份适用于 @ui-tars/cli 的模型 preset 示例
vlmBaseUrl: https://your-endpoint.huggingface.cloud/v1
vlmApiKey: your_api_key
vlmModelName: your_model_name
useResponsesApi: false

字段到运行时配置的映射关系如下(见 start.ts):

Preset YAML 字段 运行时字段 作用
vlmBaseUrl baseURL VLM 服务地址(OpenAI 兼容 /v1 结尾的 Endpoint)
vlmApiKey apiKey 访问密钥
vlmModelName model 使用的模型名称
useResponsesApi useResponsesApi 是否走 Responses API,缺省为 false

仓库里的 examples/presets/default.yaml 是配套 UI-TARS Desktop 的完整示例预设,除上述模型字段外还包含 vlmProviderreportStorageBaseUrlutioBaseUrl 等桌面端专属字段——CLI 加载预设时只消费与模型推理直接相关的四个字段,其余字段会被忽略,这也意味着同一份预设可以按需在桌面端与 CLI 之间复用。

方式二:本地配置文件 + 首次交互引导

如果不带 -p,CLI 会优先读取用户主目录下的 ~/.ui-tars-cli.json

{
  "baseURL": "https://your-endpoint.huggingface.cloud/v1",
  "apiKey": "your_api_key",
  "model": "your_model_name",
  "useResponsesApi": false
}

若本地不存在该文件(或缺少 baseURL/apiKey/model 任一字段),CLI 会通过 @clack/prompts 弹出三个交互式输入框,收集 baseURL、apiKey 与模型名,并在完成后把配置自动回写保存~/.ui-tars-cli.json(写入失败时仅打印错误,不中断流程),实现「首次交互填写、之后免配置」的体验。注意:交互收集到的配置不会包含 useResponsesApi,如需开启该开关,建议改用 Presets 方式或手动编辑本地 JSON。

选择执行目标 Operator:adb 与 nut-js

Agent 的「手脚」由 Operator 承担。CLI 当前内置两种目标,选择逻辑见 start.ts

  • -t adb:通过 @ui-tars/operator-adb 驱动 Android 真机。CLI 会先调用 getAndroidDeviceId() 枚举设备:
    • 执行 adb devices 并解析输出(跳过首行说明文字,按制表符切分提取设备序列号);
    • 若未检测到任何设备,直接报错退出(No Android devices found...);
    • 若检测到多台设备,则会弹出列表让用户选择要调试的那一台,避免误操作。
  • -t nut-js(默认):通过 @ui-tars/operator-nut-js 操作电脑桌面。从源码的 switch 结构看,当目标不是 adb 时一律落到 NutJSOperator,因此它也是不传 -t 时的兜底默认值;browser(浏览器操作)在源码中以注释形式预留为 TODO,尚未实现。

需要特别说明的是:即便不传 -t,交互模式下 CLI 也会弹出「Please select your operator target」让用户二选一,因此实际使用中 -t 主要用于脚本化、无人值守的场景。

底层原理:ADB Operator 如何执行每一条 Agent 动作

深入 @ui-tars/operator-adb 的 Operator 实现,可以看到 ADB 目标对模型暴露的完整动作空间(ACTION_SPACES),也就是 Agent 在每轮推理中可以选择的「原语」,见源码第 61-73 行

  • click(start_box='[x1, y1, x2, y2]') —— 在框定区域内点击;
  • type(content='') —— 输入文本;
  • swipe(start_box='[x1, y1, x2, y2]', end_box='[x3, y3, x4, y4]') —— 从起点滑动到终点;
  • scroll(start_box='[...]', direction='down or up or right or left') —— 以 start_box 为锚点向指定方向滚动;
  • hotkey(key='') —— 物理按键,可用键包括 enter/back/home/backspace/delete/menu/power/volume_up/volume_down/mute/lock
  • wait() —— 等待 2 秒并重新截屏观察变化;
  • press_home() —— 回到桌面;
  • finished() —— 宣布任务完成;
  • call_user() —— 任务无法独立解决或需要用户协助时提交并求助。

这些动作在执行阶段(execute 方法)被翻译为一条条真实的 adb shell 命令,例如:

  • clickadb -s <deviceId> shell input tap x y(坐标由模型输出的归一化 box 经 parseBoxToScreenCoords 换算得到);
  • swipe/dragadb shell input swipe ...,并在起止坐标间做 300ms 滑动;
  • scroll → 基于 start_boxdirection 计算终点偏移(上/下 100px、左/右 100px)后调用同样的 swipe 原语;
  • press_homeadb shell input keyevent KEYCODE_HOME
  • hotkey → 按 key 映射到对应 KEYCODE_* 键码(如 backspace 为 67、delete 为 112、lock 为 26 等)。

整个 GUI 循环遵循通用的「截屏 → 视觉模型推理 → 执行动作 → 再截屏验证」范式:每次 screenshot() 通过 adb exec-out screencap -p 抓取真机画面并编码为 base64(scaleFactor: 1)交给模型,模型以多模态输入理解当前界面并产出下一个动作原语。SDK 层的编排则由 @ui-tars/sdkGUIAgent 承担——CLI 在 start.ts 中只负责把模型配置、Operator 实例与中止信号(AbortSignal)组装起来,然后 await guiAgent.run(instruction) 驱动整个任务闭环。

中文输入:需要 ADBKeyBoard 配合

真机输入(type)是 ADB Operator 中最特殊的一环。adb shell input text 本身不支持中文,因此实现中内置了 ADBKeyBoard 协作逻辑(对应源码):

  1. 首次输入时,通过 settings get secure default_input_method 探测当前输入法;
  2. 若待输入文本包含 CJK 汉字(Unicode 范围 0x4e000x9fff)且未启用 AdbIME,则自动执行 adb shell ime set com.android.adbkeyboard/.AdbIME
  3. 若 AdbIME 不可用(报 cannot be selected),会输出引导性错误并中止该轮,避免静默失败;
  4. 输入内容会先转义 '"\ 等特殊字符,再通过广播 ADB_INPUT_TEXTadb shell input text 下发。

因此若你的任务涉及中文输入,需先在设备上完成 ADBKeyBoard 安装与激活,官方操作见 @ui-tars/operator-adb README

# 安装 ADBKeyBoard
adb install /path/to/AdbKeyboard.apk
# 激活 ADBKeyBoard 输入法
adb shell ime set com.android.adbkeyboard/.AdbIME

交互模式、取消与错误处理

CLI 从设计上同时照顾了「一次性脚本」与「人机交互」两类用法:

  • 指令来源:传入 -q 时直接使用该字符串作为任务指令;否则弹出 Input your instruction 文本输入框(见 start.ts)。
  • 中断控制:程序监听 SIGINT(即终端 Ctrl+C),触发后调用 abortController.abort() 将中止信号传递给 GUIAgent,从而优雅终止正在进行的任务(start.ts)。
  • 错误处理:构造 GUIAgent 时注入的 onError 回调会把异常与相关数据打印到终端(源码中另有被注释掉的 onData 钩子,可用于逐轮观察模型输出的结构化数据,方便调试);start 命令的顶层 try/catch 捕获到致命错误时会打印堆栈并以非零码退出(commands.ts)。
  • 取消保护:所有交互式 @clack/prompts 组都注册了 onCancel,用户按 Esc 会提示取消并正常退出进程,而不是抛出不友好的异常。

在仓库中本地构建与开发

@ui-tars/cli 与仓库内的其余包一样基于 rslib 构建,package.json 中提供了标准的开发脚本:

  • npm run build —— 一次构建产物(dist);
  • npm run dev / build:watch —— rslib watch 模式,改动源码即增量重建,适合本地联调;
  • npm test —— 运行 vitest 测试。

其直接依赖包括 commander(命令行解析)、@clack/prompts(交互式提示)、js-yaml(解析 Presets)、@ui-tars/sdk(Agent 编排核心)、@ui-tars/operator-adb@ui-tars/operator-nut-js(两种执行器)。由于这些 Operator/SDK 在仓库内以 workspace:* 形式引用,若要在本地跑通完整链路,建议在 monorepo 根目录先安装依赖并构建上游包,再进入本包目录启动;而对于一般使用,直接 npx @ui-tars/cli 即可从 npm registry 拉取已发布版本。

参考资料与进一步阅读

总体而言,@ui-tars/cli 把「多模态 GUI Agent + ADB」封装为一条可复制的命令行,适合脚本化调用、CI 集成或快速验证模型在真实设备上的操作能力;配合 Presets 远程配置,还能做到「模型配置与代码分离、随时热切换」,是体验 UI-TARS Agent 能力成本最低的入口之一。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
34
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.21 K
2.81 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
945
1.86 K
docsdocs
暂无描述
Markdown
906
5.84 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
537
607
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
864
1.36 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
4.28 K
1.03 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.39 K
1.48 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
550
401
flutter_flutterflutter_flutter
本仓库是 Flutter SDK 与 Flutter Engine 的 OpenHarmony 适配版本,由 CPF-Flutter 团队维护。开发者可使用熟悉的 Flutter 技术栈开发 OpenHarmony 应用,3.35.7 及以后的适配版本可基于本仓库源码构建支持 OpenHarmony 的 Flutter Engine。
Dart
1.19 K
347