agent-desktop 是一个专为 AI 代理设计的原生桌面自动化 CLI 工具,使用 Rust 编写。它通过操作系统无障碍树(accessibility tree)为 AI 代理提供对任意应用程序的结构化访问——不需要截图、像素匹配或浏览器。
核心理念:观察 → 决策 → 执行(OBSERVE. DECIDE. ACT.)
核心特性
高性能原生实现
- 纯 Rust 编写的单个二进制文件,无运行时依赖
- 提供 C-ABI cdylib 动态库(libagent_desktop_ffi),可从 Python、Swift、Go、Ruby、Node、C 等语言加载调用,避免每次调用都启动新进程
- 58 个命令名称,54 个操作命令:涵盖观察、交互、键盘、鼠标、通知、剪贴板、窗口管理、会话生命周期等
- 适用于 Finder、Safari、系统设置、Xcode、Slack 等任何支持无障碍树的应用程序
- 渐进式骨架遍历(Progressive skeleton traversal):对密集型应用可实现 78–96% 的 Token 缩减
- 浅层概览 + 定向下钻,AI 代理只需获取必要的上下文
- 快照 ID + 限定元素引用:@s8f3k2p9:e1、@s8f3k2p9:e2
- 引用在操作时重新识别目标,支持移动、变化后的元素重新定位
- 多个匹配目标时返回 AMBIGUOUS_TARGET 而非随意选择
- 机器可读的响应格式,包含错误码和恢复提示
- 通过 launch --cdp 为 Chromium 应用(Slack、VS Code、Discord、Obsidian、Notion)打开 Chrome DevTools Protocol 端点
- 可与 Playwright、Puppeteer、agent-browser 等任何支持 CDP 的框架集成
人人都说AI操控电脑就该用截图,但这件事错得离谱!
让AI看懂电脑屏幕,根本不需要“看”!
AI操控电脑的底层逻辑,正在被一个15MB的Rust程序彻底推翻。当全世界都在教大模型“看图识按钮”的时候,有人发现操作系统早就把答案写在了明处——只是没人去看。
截图操控电脑,这个思路一开始就歪了
过去两年,所有让AI替你操作电脑的工具,走的是同一条路:截图,识别,点坐标,再截图。
这套逻辑听起来很直觉——人怎么用电脑,AI就怎么学。人看屏幕,AI也看屏幕;人点按钮,AI也算坐标。完美模仿,对吧。
但问题出在一个没人细想的地方:人不是靠“看图”来操作电脑的。
人看到的是一个按钮,知道它叫“发送”,知道点了它会发消息。AI看到的是一堆像素,它要干的是从这堆像素里猜出哪个区域对应“发送”这个语义。中间隔着一层巨大的鸿沟。
更麻烦的是,这套截图-识别-点坐标的循环,每一步都在累积误差。屏幕分辨率变了怎么办。窗口拖动了怎么办。深色模式和浅色模式切了一下怎么办。按钮被键盘焦点高亮了一下怎么办。
每多一个变量,AI就多一分猜错的可能。而每一次猜错,都要重新截一张图、重新识别一遍、重新算一次坐标。
这套玩法能跑起来,全靠大模型硬扛。但硬扛是有代价的——慢,贵,脆。
操作系统早就有答案,只是没人当回事
有个东西叫“无障碍树”(accessibility tree)。
屏幕阅读器靠它给视障用户读屏。系统设置里的“辅助功能”靠它让键盘操控界面。这个树里装着当前屏幕上每一个UI元素的角色(按钮、输入框、复选框)、名称(“发送”“取消”“保存”)、状态(可用、禁用、选中)、层级关系。
换句话说,操作系统一直都知道界面上有什么、在哪里、能干嘛。 它只是没主动告诉你。
而所有截图-识别-点坐标的方案,都在干同一件蠢事:放着现成的语义信息不用,非要让大模型从像素里反向推断这些信息。
这就像面前摆着一本已经翻译好的书,非要去破译原版天书。
agent-desktop做的事情极其简单:直接读这棵无障碍树,把里面的信息用JSON格式吐出来。
agent-desktop snapshot --app Finder -i
就这一行命令,Finder里所有按钮、菜单、输入框的完整结构,带着编号,整整齐齐摆在面前。AI不需要猜,不需要识别,不需要算坐标。读就行了。
一棵树能省掉96%的Token,这事谁敢信
但无障碍树也有个问题——它有时候太tm大了。
Slack的完整无障碍树,轻松超过5万个Token。一个快应用(Electron应用)的树又深又吵,全塞给大模型,光是“看清界面”这一步就能烧掉小半条上下文。
agent-desktop的解法叫“渐进式骨架遍历”(progressive skeleton traversal)。
第一轮只返回浅层结构——深度3层,容器节点只告诉你“这里头有N个子元素”,不展开。就像一个地图,先只看主干道,不标每条小巷子。
AI看完浅层结构,说“我对第三层那个叫‘消息列表’的容器感兴趣”。于是agent-desktop只展开那一块,其他区域保持折叠。
一轮浅层概览加几轮定向下钻,Token消耗比全量dump少了78%到96%。
在Slack、VS Code、Notion这些Electron应用上,这个数字稳定得可怕。
这意味着什么。意味着AI操控桌面应用的成本,从“烧钱”变成了“几乎不花钱”。意味着可以把桌面自动化塞进任何一个大模型的上下文里,而不用心疼那点Token。
引用系统:让AI不再“手抖”
截图方案还有一个致命伤:坐标是死的。
AI算出了“发送”按钮在(450, 720)。但窗口被拖动了100像素。或者列表滚动了一下,按钮位置变了。或者弹出了一个对话框,整个界面布局都变了。
坐标还是那个坐标,但按钮已经不是那个按钮了。
agent-desktop的解法是给每个元素发一个“身份证号”。
一次snapshot命令会生成一个快照ID(比如s8f3k2p9),树里每个可交互元素会分配一个引用(比如@e1、@e12)。AI想点“发送”按钮,就说click @e12 --snapshot s8f3k2p9。
引用绑定的是元素在无障碍树里的身份,不是坐标。窗口拖动了。列表滚动了。界面重绘了。只要这个元素还在树上,agent-desktop就能重新找到它。
如果元素真的消失了,会返回STALE_REF错误码,附带恢复建议。AI收到后重新snapshot一次,拿到新引用,继续操作。
稳定的身份,胜过任何精确的坐标。
一个15MB的二进制,干掉了整个截图流水线
agent-desktop是一个Rust写的命令行工具,单个二进制文件,大约15MB,没有任何运行时依赖。
安装只需要一行:
bash
npm install -g agent-desktop
或者不安装直接用npx:
bash
npx agent-desktop snapshot --app Finder -i
58个命令名称,54个可操作命令——观察、交互、键盘、鼠标、通知、剪贴板、窗口管理,全齐了。
更狠的是它还提供了一个C-ABI动态库(libagent_desktop_ffi)。这意味着Python、Swift、Go、Ruby、Node、C都可以直接加载这个库,在进程内调用,而不是每次操作都启动一个新进程。
python
import ctypes
lib = ctypes.CDLL("./lib/libagent_desktop_ffi.dylib")
lib.ad_init(3)
adapter = lib.ad_adapter_create()
# snapshot -> 解析引用 -> execute
lib.ad_adapter_destroy(adapter)
进程内调用 vs 每次fork新进程。前者快一个数量级。对于需要频繁操作的AI代理来说,这不是优化,是必需品。
Chromium应用:一个例外,但被完美接住了
Electron应用(Slack、VS Code、Discord、Obsidian、Notion)的无障碍树有一个特点:又深又吵。
agent-desktop对这类应用开了一扇后门——launch --cdp。
这个命令会为Chromium应用打开一个Chrome DevTools Protocol端点。之后任何支持CDP的框架——Playwright、Puppeteer、agent-browser——都可以驱动Web内容,而原生菜单、对话框、窗口仍然走无障碍树路径。
Web部分交给CDP,原生部分交给无障碍树。 各取所长,不打架。
Finder会撒谎
agent-desktop真正让人意外的,不是发现了CDP这条捷径。而是在处理真正难的问题时,用了几个反常识的设计决策。
第一个反常识决策:不相信应用的返回码。
大多数自动化工具的逻辑是:调用一个API,检查返回值,成功就继续,失败就重试。但agent-desktop的作者发现了一个令人不安的事实——应用会撒谎。
Finder对一个已经成功的操作返回错误码,对一个什么都没做的操作返回成功码。如果自动化工具迷信返回码,就会出现两种情况:要么报告失败但实际上成功了,要么报告成功但实际上什么都没发生。这对AI来说是灾难性的——AI会根据错误的反馈做出错误的决策,一路错下去。
agent-desktop的做法是:不看返回码,看界面状态变化。一次点击不是一次API调用,而是一条有序的链——AXPress、AXOpen、激活内部单元格、写入选择、AXConfirm。每一步只在元素支持时才执行,成功与否的判断标准是应用的状态是否发生了变化。哪个机制先产生可观察到的效果,哪个就是赢家。
这就像跟一个人说话,不看嘴型,只看有没有按照说的去做。嘴型可以骗人,动作骗不了。
第二个反常识决策:不返回完整树。
无障碍树的结构化信息虽然比像素强,但有一个问题——太大了。Slack的一棵完整无障碍树可以轻松超过五万个token。把五万个token塞进上下文窗口,让AI在里面找一个按钮——这是在逼AI玩大家来找茬。
agent-desktop的方案是渐进式骨架遍历。第一次快照只返回深度为3的浅层树,深层容器被截断并标注孩子数量。有名字的容器获得引用ID,AI可以针对性地请求某个子树的详细信息。操作完成后,AI只需要重新查询被操作的那个区域,而不是重新扫描整个应用。
78%到96%的token节省。这不是优化,这是把不可能变成可能。
第三个反常识决策:引用不是指针,是身份证据。
大多数自动化工具用指针或坐标来标记元素。指针在UI变化后会失效,坐标在窗口移动后会偏移。agent-desktop的引用是一组身份证据:角色、路径、稳定文本、边界哈希。每次操作前,系统拿这组证据去和当前的实时界面做匹配。
如果界面变了,返回STALE_REF。如果两个元素都匹配,返回AMBIGUOUS_TARGET。它从不猜测。
从不猜测这四个字,是整件事的核心。
但有一个问题,agent-desktop暂时回答不了
以上所有能力,目前只在macOS上完整可用。
Windows和Linux的无障碍树支持、点击输入、鼠标操作、截图、剪贴板、窗口管理、通知——全部标记为“Planned”(计划中)。
一个跨平台CLI,目前还不是真跨平台。
但这恰恰是最有意思的地方——不是技术做不到,而是没人做。 Windows有UIA(UI Automation),Linux有AT-SPI,都是现成的无障碍树接口。agent-desktop的架构从一开始就做了平台抽象(PlatformAdapter trait),Windows和Linux的适配层是现成的空壳,只等人去填。
问题变成了:谁会去填。什么时候填。填完之后,Windows和Linux的桌面自动化格局会变成什么样。
没人知道答案。但可以确定的是,一旦这三个平台全部打通,截图操控电脑这条路径,就彻底沦为一种行为艺术。
盲人摸象和X光片
把这一切串起来看,agent-desktop做的事情很简单:把桌面自动化从一个视觉问题还原成了一个结构化数据问题。
截图方案的本质是让AI扮演盲人摸象的角色——摸到鼻子说像蛇,摸到腿说像柱子。无障碍树方案的本质是直接给AI一张大象的X光片——骨骼、肌肉、血管,清清楚楚。
整个行业花了三年时间,用最先进的大模型去做最原始的图像识别,而操作系统早就把答案摆在桌面上没人看。
为什么会这样?因为让AI看屏幕这个叙事太有诱惑力了。它符合人类对智能的直觉——能看懂屏幕的才是真智能。但智能不等于模仿人类的感知方式。一个能读懂无障碍树的AI,和一个需要靠截图猜坐标的AI,哪个更智能?答案显而易见!