UI-TARS 源码解析 #8:桌面端与移动端 Prompt 差异:为什么 mobile 要支持 open_app、press_home、press_back?
在前几篇文章中,我们已经分析了 UI-TARS 的 Prompt、动作空间,以及Thought + Action输出格式。
其中,prompt.py里最重要的三个模板是:
COMPUTER_USE_DOUBAO MOBILE_USE_DOUBAO GROUNDING_DOUBAO上一篇文章我们重点讲了Thought + Action为什么是 GUI Agent 的最小决策闭环。
这一篇,我们继续深入prompt.py,比较桌面端和移动端 Prompt 的差异。
很多人第一次看 UI-TARS 的移动端 Prompt 时,会注意到它多了几个特殊动作:
open_app press_home press_back long_press而桌面端 Prompt 里则有:
hotkey left_double right_single这背后不是简单的 API 差异,而是桌面端和移动端交互范式的根本不同。
一、先看两个 Prompt 的共同点
在prompt.py中,COMPUTER_USE_DOUBAO和MOBILE_USE_DOUBAO的开头基本一致:
You are a GUI agent. You are given a task and your action history, with screenshots. You need to perform the next action to complete the task.两者的输出格式也一样:
Thought: ... Action: ...源码中可以看到,桌面端和移动端模板都要求模型在每一步先输出Thought,再输出Action。这说明无论是操作电脑还是操作手机,UI-TARS 都把任务执行看成一个连续的 Agent Loop,而不是一次性脚本生成。
它们共同的基本逻辑是:
当前任务 ↓ 历史动作 ↓ 当前截图 ↓ Thought 判断 ↓ Action 执行 ↓ 下一轮截图也就是说,桌面端和移动端的共同基础是:
根据当前截图和任务历史,输出下一步动作。
真正的差异出现在 Action Space。
二、桌面端 COMPUTER_USE 的动作空间
COMPUTER_USE_DOUBAO的动作空间包括:
click(point='<point>x1 y1</point>') left_double(point='<point>x1 y1</point>') right_single(point='<point>x1 y1</point>') drag(start_point='<point>x1 y1</point>', end_point='<point>x2 y2</point>') hotkey(key='ctrl c') type(content='xxx') scroll(point='<point>x1 y1</point>', direction='down or up or right or left') wait() finished(content='xxx')官方 README 也说明,COMPUTER_USE推荐用于 Windows、Linux、macOS 等桌面环境,支持单击、双击、右键、拖拽、快捷键、文本输入、滚动等常见桌面操作,适合浏览器、办公软件和文件管理等任务。
这些动作明显带有桌面端特征。
比如:
双击文件打开 右键文件弹出菜单 Ctrl+C 复制 Ctrl+V 粘贴 Ctrl+S 保存 Alt+Tab 切换窗口这些都是电脑用户非常熟悉的操作。
所以桌面端 Prompt 的核心不是“点屏幕”,而是模拟一个熟练的电脑用户。
三、移动端 MOBILE_USE 的动作空间
MOBILE_USE_DOUBAO的动作空间是:
click(point='<point>x1 y1</point>') long_press(point='<point>x1 y1</point>') type(content='') scroll(point='<point>x1 y1</point>', direction='down or up or right or left') open_app(app_name='') drag(start_point='<point>x1 y1</point>', end_point='<point>x2 y2</point>') press_home() press_back() finished(content='xxx')官方 README 明确说明,MOBILE_USE推荐用于移动设备或 Android 模拟器,包含long_press、open_app、press_home、press_back等移动端特有动作,适合启动 App、滚动页面、填写输入框和在移动应用中导航。
和桌面端相比,移动端少了:
left_double right_single hotkey wait增加了:
long_press open_app press_home press_back这就是本文的重点。
为什么手机端需要这些动作?
四、桌面和移动端的交互方式完全不同
电脑的交互设备通常是:
鼠标 键盘 触控板 多窗口桌面 文件系统 菜单栏 右键菜单 快捷键手机的交互设备通常是:
触摸屏 手势 单窗口 App 返回键 主页键 应用启动器 长按菜单 系统导航栏也就是说,两者虽然都属于 GUI,但操作习惯完全不同。
在桌面端,用户经常通过键盘快捷键提高效率。
例如:
Ctrl+C 复制 Ctrl+V 粘贴 Ctrl+S 保存 Ctrl+F 搜索 Alt+Tab 切换窗口所以桌面端 Prompt 必须支持hotkey。
在移动端,用户没有传统键盘,也没有右键菜单,更没有双击打开文件这种统一习惯。
移动端更常见的是:
点按 长按 滑动 返回 回主页 打开 App所以移动端 Prompt 必须支持long_press、press_back、press_home和open_app。
这不是 UI-TARS 随便加的几个动作,而是根据真实设备交互方式做出的动作空间差异化设计。
五、为什么 mobile 需要 open_app?
open_app的格式是:
open_app(app_name='')这是移动端 Prompt 中非常关键的动作。
因为手机任务经常从“打开某个 App”开始。
例如:
打开微信,给某人发消息 打开地图,搜索附近餐馆 打开设置,关闭蓝牙 打开浏览器,搜索资料 打开相册,选择一张图片如果没有open_app,模型只能通过屏幕点击来打开 App。
这会带来很多问题:
App 图标可能不在当前桌面页 桌面可能有多个分页 App 可能在文件夹里 图标位置因设备不同而不同 用户可能刚好停留在某个 App 内部也就是说,单纯依赖click打开 App,会让任务变得非常不稳定。
open_app则把“启动应用”抽象成一个系统级动作。
模型只需要输出:
Action: open_app(app_name='Chrome')外层执行系统就可以通过移动端自动化接口启动对应 App。
这比让模型在桌面图标里找 Chrome 稳定得多。
所以,open_app的本质是:
把移动端任务中高频的“启动应用”动作,从视觉点击提升为系统级动作。
六、为什么桌面端没有 open_app?
有人可能会问:
电脑端也要打开应用,为什么
COMPUTER_USE没有open_app?
这是一个很好的问题。
从理论上说,桌面端也可以增加类似动作:
open_app(app_name='Chrome') open_file(path='xxx') switch_window(title='xxx')但 UI-TARS 当前COMPUTER_USE_DOUBAO的设计更偏基础 GUI 操作层。
它用这些动作覆盖桌面任务:
click double click right click drag hotkey type scroll wait finished在桌面环境中,打开应用通常可以通过多种方式完成:
点击桌面图标 双击快捷方式 打开开始菜单搜索 使用快捷键 从任务栏启动 从文件管理器打开而移动端的 App 启动更像一个标准系统动作。
因此,open_app对移动端更必要。
当然,如果你基于 UI-TARS 做桌面自动化产品,完全可以扩展一个桌面版open_app,但那就需要同步修改 Prompt、Parser 和执行层。
七、为什么 mobile 需要 press_home?
press_home()表示按下手机主页键。
这个动作在移动端非常重要。
因为手机通常是单窗口 App 交互,用户经常需要从当前 App 回到系统主页,再打开另一个 App。
例如:
从微信回到桌面 打开浏览器查资料 再回到微信发送内容如果没有press_home,模型只能依赖界面上的返回按钮或者系统手势。
但不同 App 的界面差异很大:
有的 App 左上角有返回按钮 有的 App 底部有 Tab 有的 App 返回键会关闭弹窗 有的 App 返回键会退出页面 有的 App 没有明显的返回入口主页键则是一个更稳定的系统级操作。
它不依赖当前 App 的 UI 布局。
所以press_home的价值是:
让 Agent 能从复杂 App 状态中跳回一个确定的起点。
这对移动端多步骤任务非常有用。
例如:
当前停留在某个深层页面 不知道如何返回主界面 先 press_home() 再 open_app(...)这个组合非常常见:
press_home() open_app(app_name='Settings')它相当于给 Agent 提供了一个“重置导航状态”的能力。
八、为什么桌面端没有 press_home?
桌面端没有统一意义上的“主页键”。
在 Windows、macOS、Linux 上,用户可以:
最小化窗口 切换窗口 打开开始菜单 点击 Dock 回到桌面 使用 Alt+Tab 使用任务栏但这些不是同一个抽象动作。
桌面系统是多窗口并行环境,不像手机那样以单个前台 App 为核心。
所以桌面端更需要:
hotkey click double click right click drag而不是press_home。
这也说明,动作空间设计必须尊重平台交互模型。
不能简单地把手机动作搬到电脑上,也不能把电脑动作硬塞到手机里。
九、为什么 mobile 需要 press_back?
press_back()是移动端最重要的导航动作之一。
在 Android 中,返回动作承担了很多功能:
返回上一页 关闭弹窗 关闭键盘 退出当前页面 回到上一个 App 取消当前操作手机用户非常依赖返回键。
例如:
进入详情页后返回列表 打开设置子页面后返回上一级 弹窗出现后按返回关闭 输入完成后返回收起键盘如果没有press_back,模型只能寻找界面上的返回按钮。
但返回按钮的位置和样式并不统一:
有的在左上角 有的是箭头图标 有的是文字“返回” 有的页面没有明显返回按钮 有的返回按钮被隐藏在系统手势里所以press_back是移动端 Agent 非常关键的系统导航能力。
它可以让模型在不依赖具体 UI 元素的情况下完成回退操作。
这也是为什么MOBILE_USE_DOUBAO必须把它放进动作空间。源码中可以看到,移动端模板明确包含press_back(),而桌面端模板没有对应动作。
十、press_back 和 scroll、click 的关系
press_back并不是替代click。
它们解决的问题不同。
click: 操作界面中的具体元素。 scroll: 查看更多内容。 press_back: 执行系统级返回。例如:
当前页面:商品详情页 目标:回到商品列表 方案一: 点击左上角返回箭头 方案二: press_back()如果返回箭头清晰可见,模型可以 click。
如果按钮不可见、界面复杂,或者返回逻辑是系统级的,press_back更稳。
所以移动端 Prompt 同时保留了click和press_back。
一个负责视觉元素操作,一个负责系统导航。
十一、为什么 mobile 需要 long_press?
long_press的格式是:
long_press(point='<point>x1 y1</point>')长按是移动端非常常见的交互。
例如:
长按消息复制 长按图片保存 长按图标弹出菜单 长按文本选择 长按文件进行多选桌面端通常用右键实现类似功能。
比如:
桌面端:右键文件 → 弹出菜单 移动端:长按文件 → 弹出菜单所以你会看到一个很自然的对应关系:
桌面端 right_single 移动端 long_press这两者底层动作不同,但交互语义相似:
打开某个对象的上下文操作菜单。
这正体现了 UI-TARS 论文中 Unified Action Modeling 的思想:跨平台动作应该尽量抽象到语义层面,而不是死盯某个具体设备 API。论文摘要中也提到,UI-TARS 通过统一动作建模把跨平台动作标准化到统一空间,并结合 grounding 实现精确交互。
十二、桌面端为什么需要 hotkey?
桌面端 Prompt 里有:
hotkey(key='ctrl c')源码注释还要求快捷键用空格分隔、使用小写,并且不要在一次 hotkey 动作中使用超过 3 个按键。
这是桌面端非常重要的能力。
因为很多电脑操作中,快捷键比鼠标点击更高效、更稳定。
例如:
复制:ctrl c 粘贴:ctrl v 保存:ctrl s 查找:ctrl f 全选:ctrl a 切换窗口:alt tab如果没有 hotkey,模型可能需要通过菜单路径完成操作:
点击 Edit 点击 Copy这在不同软件里菜单位置可能不同。
而快捷键在很多桌面软件中更统一。
所以桌面端必须支持hotkey。
移动端没有传统物理键盘环境,因此MOBILE_USE_DOUBAO没有hotkey。
这不是能力缺失,而是平台交互习惯不同。
十三、桌面端为什么需要 left_double 和 right_single?
桌面端 Prompt 里还有:
left_double(point='<point>x1 y1</point>') right_single(point='<point>x1 y1</point>')这两个动作在电脑环境里非常常见。
双击:
打开文件 打开文件夹 启动桌面程序 进入列表项右键:
打开上下文菜单 复制文件 重命名文件 删除文件 另存为 查看属性在移动端,这两个动作通常不成立。
手机上没有鼠标右键。
双击也不是通用的“打开”动作,更多是特定 App 内部手势,比如图片放大、地图缩放等。
所以移动端不需要把left_double和right_single放进基础动作空间。
相反,移动端用:
long_press press_back press_home open_app来表达自己更常见的操作。
十四、两套 Prompt 体现的是“共享动作 + 平台扩展”
把桌面端和移动端放在一起看,会发现 UI-TARS 并不是完全设计了两套无关动作。
它们有共享部分:
click drag type scroll finished这些动作在桌面和移动端都成立。
它们也有平台特有部分。
桌面端特有:
left_double right_single hotkey wait移动端特有:
long_press open_app press_home press_back这种设计可以总结为:
共享动作解决跨平台通用交互; 平台动作解决设备特有交互。这正是 Unified Action Modeling 的工程化落地。
论文中把 UI-TARS 描述为仅依赖截图输入、执行类似人类键盘鼠标操作的 native GUI agent,并强调其核心能力包括 perception、action、reasoning 和 memory;其中 action 能力要求模型在预定义动作空间内准确预测并 grounding 动作。
十五、为什么移动端更需要系统级动作?
桌面端的很多操作可以通过可见 UI 完成。
例如:
菜单栏 任务栏 窗口按钮 右键菜单 快捷键 文件路径移动端则更依赖系统导航。
原因有几个。
第一,手机屏幕空间小。
很多功能不会同时显示在屏幕上,需要进入多层页面。
第二,手机通常是单前台 App。
用户不是同时操作多个窗口,而是在一个 App 内不断前进、返回、切换。
第三,系统导航承担重要角色。
返回、主页、打开 App 是手机用户每天都在用的基础操作。
第四,App UI 差异更大。
同样是“返回”,不同 App 可能有不同按钮位置,但系统返回动作更统一。
所以移动端 Prompt 必须提供系统级动作。
如果只提供 click、type、scroll,Agent 很容易被困在某个 App 的深层页面里。
十六、一个移动端任务示例
假设用户任务是:
打开浏览器,搜索 UI-TARS。移动端 Agent 可能这样执行:
Thought: 当前不确定是否在浏览器中,我需要先打开浏览器 App。 Action: open_app(app_name='Chrome')然后:
Thought: 浏览器已经打开,我需要点击搜索框输入关键词。 Action: click(point='<point>520 130</point>')接着:
Thought: 搜索框已经获得焦点,现在输入关键词并提交搜索。 Action: type(content='UI-TARS\n')如果任务完成:
Thought: 搜索结果已经显示,任务完成。 Action: finished(content='已完成搜索。')如果用户还要求回到主页:
Thought: 当前搜索已经完成,现在需要回到手机主页。 Action: press_home()可以看到,open_app和press_home让移动端 Agent 不必完全依赖图标和页面按钮。
这会让任务更稳定。
十七、一个复杂移动端切换任务示例
再看一个更能体现移动端差异的任务:
从浏览器复制一段内容,然后打开微信发给朋友。移动端 Agent 可能需要:
open_app(app_name='Chrome')找到页面内容后:
long_press(point='<point>480 650</point>')选择复制后:
press_home()再打开微信:
open_app(app_name='WeChat')进入聊天界面后:
click(point='<point>420 720</point>') type(content='...')如果进入了错误页面,可以:
press_back()这里如果没有:
open_app press_home press_back long_pressAgent 就很难完成这种跨 App、多页面、需要系统导航的任务。
十八、二次开发时如何扩展桌面端和移动端动作?
如果你想基于 UI-TARS 做自己的自动化项目,动作空间可以扩展,但要遵循一个原则:
Prompt、Parser、Executor 必须同步修改。
比如你想给桌面端增加:
open_app(app_name='') switch_window(title='') close_window()那就需要:
1. 在 prompt.py 中增加动作说明 2. 在 action_parser.py 中增加解析逻辑 3. 在执行层实现对应动作 4. 增加测试用例 5. 增加安全限制如果只改 Prompt,模型可能会输出新动作,但程序无法执行。
如果只改执行层,模型不知道这个动作存在。
动作空间本质上是三方协议:
模型知道可以输出什么; Parser 知道如何解析; Executor 知道如何执行。所以扩展动作必须成套进行。
十九、哪些动作适合加入桌面端?
如果做桌面自动化,比较适合扩展的动作包括:
open_app(app_name='') switch_window(title='') activate_window(title='') close_window() copy_selected_text() paste_text(content='') open_file(path='') run_command(command='')但要注意,高风险动作需要谨慎。
例如:
delete_file(path='') send_email(...) submit_payment(...)这类动作最好不要直接让模型执行,而是加用户确认。
因为 GUI Agent 操作的是真实系统,一旦误执行,可能造成数据丢失或安全问题。
二十、哪些动作适合加入移动端?
如果做移动端自动化,可以考虑扩展:
press_enter() swipe_up() swipe_down() switch_app() open_notification_panel() input_otp(code='')但同样要谨慎。
例如:
确认支付 删除聊天记录 发送消息 授权隐私权限这类动作最好做安全拦截。
移动端任务经常涉及账号、聊天、支付、定位和隐私,因此比普通桌面点击更需要权限控制。
二十一、从 Prompt 差异看 UI-TARS 的设计思想
通过比较COMPUTER_USE_DOUBAO和MOBILE_USE_DOUBAO,可以总结出 UI-TARS 的一个重要设计思想:
动作空间应该统一,但不能僵化。
统一的地方在于:
都用 Thought + Action; 都用函数调用式 Action; 都用 point 表示坐标; 都把动作限制在可解析的集合里; 都通过 finished 表示任务结束。差异化的地方在于:
桌面端保留右键、双击、快捷键; 移动端保留长按、打开 App、返回、主页。这就是好的跨平台 Agent 设计。
不是强行让所有设备使用同一套动作,而是在统一协议下保留平台特性。
总结
这篇文章我们对比了 UI-TARS 中桌面端和移动端 Prompt 的差异。
桌面端COMPUTER_USE更强调:
hotkey left_double right_single drag wait因为电脑用户常用键盘快捷键、右键菜单、双击打开和多窗口操作。
移动端MOBILE_USE更强调:
open_app press_home press_back long_press因为手机任务高度依赖系统导航、单前台 App、触摸手势和跨 App 切换。
所以,open_app、press_home、press_back不是可有可无的小功能,而是移动端 GUI Agent 能否稳定执行任务的关键动作。
从更高层看,这体现了 UI-TARS 的动作空间设计原则:
共享动作保持统一; 平台动作保留差异; 模型输出保持可解析; 执行层动作保持可落地。