再让 Agent 操作桌面

上一篇我们让 Agent 在浏览器里练熟了“打开→看→动→再看”,这一篇把手伸出浏览器,去操作真正的桌面应用:打开计算器算一道题,在文件管理器里找到一个文件夹,给一个应用换一个设置。

工具也换了:浏览器那篇的主角是 agent-browser,这一篇的主角是它的姊妹工具 agent-desktop,同一家 Vercel Labs 出的开源命令行工具,Apache-2.0 协议,用 Rust 写的。它管的是桌面应用而不是网页,循环还是同一套,变的只是读的树从网页换成了操作系统。

先说一句重要的区别:浏览器那一步练错了,关掉浏览器就行;桌面这一步练错了,可能会改掉一个文件、发出一条消息。所以这一篇的练习,只在备用机或小号上做,只碰练习用的应用和文件,第一篇的安全底线在这里一字不改。

一、浏览器和桌面,差在哪一步

浏览器是个半封闭的盒子,桌面可不是:

  • 浏览器里 Agent 只能碰网页。 出不了浏览器,动不了你电脑上的文件和别的软件,练错了也最容易收场。
  • 桌面上 Agent 碰的是整个系统。 它能打开任何应用、点任何按钮、改任何设置,能力大得多,点错的代价也大得多。
  • 桌面上的界面更杂。 网页大多带着现成的无障碍树,桌面应用却不一定:有的应用把界面元素交代得清清楚楚,有的自绘界面,系统根本认不出里面的按钮。

所以桌面这一篇的规矩比上一篇更严:动手之前先看清,动手之后再确认,拿不准的步骤先停下来问人,而不是接着往下走。 浏览器那篇的循环到了桌面上,一步都不能省。

二、无障碍树:系统自带的那份清单

第一篇讲过两条技术路线,桌面这一篇走的是其中手最稳的那一条:无障碍树加元素引用。

无障碍树是操作系统本来就给每个界面元素准备的一份结构化清单,最早是给读屏软件用的,里面写着每个按钮、输入框、菜单是什么、在哪里、当前是什么状态。agent-desktop 读的就是这份清单:

  • 每个能操作的元素都有一个编号。 快照里一个元素长这样:{"role": "treeitem", "name": "Documents", "ref_id": "@s8f3k2p9:e8", "available_actions": ["Click"]},意思是这是一个叫 Documents 的树形条目,可以点,编号是 @s8f3k2p9:e8。
  • 编号前面那串字符是快照的编号。 @s8f3k2p9:e8 里的 s8f3k2p9 是这一次快照的编号,e8 是元素在快照里的序号。浏览器那篇的编号只有 @e1,桌面这里多了一截,意思是:编号只在它自己的那张快照里有效。
  • Agent 按编号动手,不猜坐标。 点哪个按钮、往哪个框里输字,都只认编号。按钮挪了位置也不怕,怕的是编号过期——下面第四节会讲。

为什么这条路线手稳?因为 Agent 不用看图猜“按钮在哪个像素”,系统直接告诉它按钮是谁、在哪。好处是点得准、还省 token;坏处也一样:看不见无障碍树的应用,它就操作不了,比如有些自绘界面的软件,只能换截屏路线,或者干脆别用 Agent 操作它。

agent-desktop 在三个系统上走的都是同一条路,只是调的系统接口不同:macOS 上是 AX API,Windows 上是 UI Automation,Linux 上是 AT-SPI。支持的系统是 macOS 13 及以上、Windows 10 1809 及以上、Ubuntu 24.04 及以上。它本身不是 Agent,也没有内置模型,只是一双“手”,脑子还是你用的那个编程助手,Claude Code、Codex、Cursor 这些都能直接调它。

三、装好它:两条命令,加一个权限

装 agent-desktop 比装浏览器那篇多一步:装完工具,还要在系统里给它开一个权限。

  1. 先装工具本身。 在终端里运行 npm install -g agent-desktop,这一步是装命令行工具。macOS 和 Linux 上也可以用 brew install agent-desktop,效果一样。
  2. 再看一眼状态。 运行 agent-desktop status,它会打印一个 JSON,里面有当前平台、每项权限的状态、支持哪些操作面。看 data.permissions 下面每一项的 state:是 denied 的先处理掉,不要带着没开的权限往下走。JSON 挤成一坨不好读的话,在命令后面接上 | python3 -m json.tool,它会把 JSON 排整齐了再显示,macOS 自带 python3,不用另装。
  3. 在 macOS 上开无障碍权限。 运行 agent-desktop permissions --guide,它会一步一步带你去系统设置里打开无障碍(Accessibility)授权。没有这个授权,它读不到任何应用的无障碍树,快照会是空的。这一步是你亲手在系统设置里点的,Agent 自己开不了这个权限,也别让任何工具替你绕过它。

装完先别急着干活,先确认它能正常工作。运行 agent-desktop snapshot --app Finder -i,能看到一串 JSON,里面有这次快照的编号和一棵元素树,就说明装好了。如果哪一步报错,先看报错里写的是什么,缺依赖就补依赖,不要跳过报错直接往下走。

有一点要先说清楚:每条命令只打印一个 JSON 信封,里面是 ok 加 data,或者 ok 加 error。 出错的时候不要只看“失败了”,把信封里的错误码和建议读完再决定下一步,错误码会直接告诉你该重拍快照还是该换个做法。

四、核心循环:看→动→再看,桌面版

桌面上的循环和浏览器那篇是同一套,只是命令换了,编号变长了:

  1. 看快照。 agent-desktop snapshot --app Finder -i,读 Finder 这一个应用的无障碍树,只列出能互动的元素,每个元素带一个编号。快照里还会告诉你这次快照的编号和元素总数,先对上号再动手。
  2. 按编号动手。 agent-desktop click @s8f3k2p9:e8,点快照里的 8 号元素。往框里输字用 type,改一个确定的值用 set-value,开关、勾选、展开、滚动也都有对应的命令,一共 60 个命令名,其中 56 个能直接用。动手只认编号,不认坐标。
  3. 再看一次。 动完之后再跑一次 agent-desktop snapshot --app Finder -i,确认刚才那一下真的生效了。没有这一步,你就不知道 Agent 是办成了还是点错了。

记住这条铁律,和浏览器那篇一字不差:每次动手之前,先看快照;每次动手之后,再看一次。

桌面版多出两条要刻进脑子里的规矩,都是编号的规矩:

  • 编号只在自己的快照里有效。 拿着上一张快照的编号去点,工具会直接拒绝:光秃秃的 @e8 会报 INVALID_ARGS,因为它缺了快照编号;界面一变、旧编号对不上号了,会报 STALE_REF 或者 AMBIGUOUS_TARGET。这三个报错都不是坏消息,它们是在拦你点错。正确做法只有一个:重新跑一次快照,用最新的编号动手。
  • 界面太密,先画骨架再钻进去。 有的应用界面元素太多,一整棵树读下来又长又费 token。先用 agent-desktop snapshot --app Slack --skeleton -i --compact 只看骨架,找到你要的那一块,再用 snapshot --root @s8f3k2p9:e3 -i --compact 只展开那一块。先看全貌,再钻细节,token 省下来,点错的概率也小。

还有一条是桌面独有的:默认不动你的鼠标和焦点。 agent-desktop 的编号操作走的是无障碍接口,不会移动指针、不会抢焦点,除非你主动加上 --headed 才允许它做真实的鼠标键盘输入。练手的时候就用默认的这一档,别急着开 --headed。

五、三件真活,都走同一套循环

打开计算器算题、找文件、改设置,看起来是三件不同的事,在 agent-desktop 这里其实是同一个循环换了三次内容:

  1. 打开计算器算一道题。 先跑 agent-desktop snapshot --app Calculator -i,找到数字键和加号、等号的编号,按顺序点下去:点 7、点加号、点 8、点等号。每点一下都可以再跑一次快照确认,最后一次快照里读显示区域的值,确认答案真的是 15。这是最适合练手的第一件活:算错了没有任何后果,答案一眼就能验证。
  2. 在文件管理器里找一个文件。 打开 Finder,先跑 snapshot --app Finder -i,找到你要进的文件夹的编号,点进去,再跑一次快照确认当前在哪个文件夹。重点不是找得快,而是每一步都有快照作证:进的是这个文件夹,看到的真是里面的东西。只在练习用的文件夹里练,别拿装着重要文件的文件夹练手。
  3. 给一个应用换一个设置。 打开一个练习用的应用,先跑快照找到设置入口的编号,点进去,再跑快照找到你要改的那一项,改完再跑一次快照,确认那一项的值真的变了。改设置之前先记下原来的值,练完改回去——改完不确认、改完不恢复,都是练手时最容易留下的尾巴。

三件事的共同点是:动手之前有快照,动手之后有验证,验证不对就停下来,而不是接着往下走。 桌面上的 Agent 最容易出的错,和浏览器上一样,就是第一步错了,后面每一步都照着错的结果继续跑。

六、卡住怎么办:三种常见情况

第一次练桌面,十有八九会在这三种地方卡住,都是正常的:

  • 快照是空的,什么元素都没有。 先看 agent-desktop status,十有八九是无障碍权限没开,或者开给了别的程序。按第三节那一步重新走一遍授权,再跑快照。如果权限开了还是空的,可能是这个应用根本不提供无障碍树,那就换一个应用练,别硬来。
  • 编号过期了,旧编号点不动。 界面一刷新、一跳转,快照里的编号就可能重新排,工具会报 STALE_REF。解决办法只有一个:重新跑一次快照,用最新的编号动手。 不要图省事复用旧编号,也不要把报错当成“再试一次就能好”。
  • 好几个窗口长得一样,分不清点哪个。 工具会报 AMBIGUOUS_TARGET,快照里会列出候选窗口的编号。这时候用 --window-id 指定其中一个窗口,再跑快照。分不清就先关掉多余的窗口,只留一个练手的窗口,界面越干净,Agent 越不容易点错。

这三种情况的共同解法,都是“停下来,重新看一次”,而不是“再试一次旧命令”。重新看一次的成本很低,点错一次的成本可能很高,桌面上尤其如此。

七、安全提示:桌面上的规矩更严

浏览器那篇的四条规矩,到了桌面上全部适用,再加三条桌面独有的:

  1. 只在备用机或小号上练。 没有备用机,就用虚拟机,或者至少换一个不装重要资料的小号。桌面 Agent 的手能碰到整个系统,练熟之前不要让它碰你的主力环境。
  2. 登录、付款、发消息、删东西,永远人来做。 这一篇只练计算器、找文件、改练习用的设置。遇到这四类步骤,停下来,自己输密码、自己点确认,不要让 Agent 代劳。
  3. 快照和剪贴板里可能有你的隐私。 agent-desktop 的官方说明里专门提醒过:快照、剪贴板读取、截图、命令输出里都可能带有桌面上的私人内容,不要把这些东西贴进公开的日志和上传记录里。 练手用的快照,看完就删,别随手发出去。
  4. 要输密码或密钥,别让它出现在命令里。 type、set-value 这些命令支持 --stdin 传文字,就是为了让敏感内容不留在命令记录里。非要输敏感信息的时候,用 --stdin,不要直接写在命令行上。

这四条和第一篇的底线是同一套,只是落到了桌面上。下一篇操作手机,规矩只会更严,不会更松。

练一次:让 Agent 帮你打开计算器算一道题

不用准备什么,十五分钟就够,全程只碰计算器这一个应用:

  1. 先在终端里装好 agent-desktop,再运行 agent-desktop status,确认权限那一项是开的;如果没开,先按第三节走完 permissions --guide。
  2. 打开计算器,跑 agent-desktop snapshot --app Calculator -i,在快照里找到数字 7、加号、数字 8、等号这四个元素的编号。
  3. 按顺序点下去:点 7、点加号、点 8、点等号,每点一下都可以再跑一次快照确认。最后一次快照里读显示区域的值,确认答案真的是 15。
  4. 走完之后问自己三个问题:每一步动手前,我看了快照吗?动手后,我确认结果了吗?中间有没有哪一步是我凭猜测点的?最后把计算器关掉。练完就关,不要让一个能替你点鼠标的工具一直开着。

走完这四步,桌面这一步就算练成了。下一篇文章,我们把手伸到手机上:让 Agent 操作手机,收发消息、整理相册,规矩是人必须在回路里点头才放行。