实战 📋 6 个步骤 第 594 / 599 篇

用 Vercel agent-desktop 让编码 Agent 直接操作桌面应用(无障碍树,不靠截图)

agent-desktop 是 Vercel Labs 开源的跨平台桌面自动化 CLI,通过操作系统无障碍树让 AI Agent 读取并操作任意桌面应用——不截图、不猜像素、用稳定 ref 点按输入,比视觉方案更稳、更省 token。

2026.11.04· 18 分钟阅读· 约 2029 字· 🖥️ Vercel agent-desktop / 🤖 编码智能体

你有没有遇到过这种情况:想让编码 Agent 帮你点一下桌面上的某个软件、填个表单、导个文件,但它只会写代码,碰不了图形界面?传统做法要么截屏丢给视觉模型猜坐标(又慢又容易点错),要么上重型 RPA(部署成本高)。

Vercel Labs 开源的 agent-desktop 换了一条路:它直接读取操作系统本身提供的「无障碍树」(macOS Accessibility API、Windows UI Automation、Linux AT-SPI),把桌面应用的真实结构变成一份 JSON 快照,每个可操作元素都带一个稳定的 ref。Agent 按 ref 点击、输入、滚动,再拍一张新快照验证结果——不截图、不猜像素、可安全重试。在复杂的 Electron 应用上,官方称能把 token 用量降低 78–96%。

🧩 本教程适合:想给编码智能体(Claude Code / Codex / Cursor 等)接上「操作桌面应用」能力的开发者、做桌面 RPA 替代方案的工程师。你只需要一台能上网的电脑和 Node.js(用它装 CLI)。

先搞懂:为什么无障碍树比截图稳?

每个主流操作系统都会给屏幕阅读器暴露一份「应用 UI 结构树」:每个按钮、输入框、菜单项都有角色(role)、名称(name)、可做的动作(action)。agent-desktop 把这份树当作「观察与交互的事实来源」。

对比维度截图 + 视觉模型无障碍树(agent-desktop)
观察成本一张高清图几百到上千 token一份文本树小得多,可用 --skeleton/--compact 再压
稳定性布局一动就坐标漂移、点错元素在,ref 大概率不变,点击不漂移
失败处理猜错只能重来返回 STALE_REF / AMBIGUOUS_TARGET,引导重新快照

它不是视觉方案:agent-desktop 不「看」屏幕,它问操作系统「现在有什么、能点什么」。所以它能稳定引用元素,但也意味着它依赖应用暴露无障碍信息——极少数完全不暴露无障碍属性的老旧软件会拿不到元素。

Step 1:安装并验证

1 一条命令装好 agent-desktop

agent-desktop 是 Rust 写的单二进制,官方推荐用 npm 全局安装(也可等官方 Homebrew / Scoop 包)。装完先验证版本,确认拿到 1.0.x:

# 全局安装
npm install -g agent-desktop

# 验证安装(应显示 1.0.2 或更新)
agent-desktop --version

# 查看帮助,确认命令可用
agent-desktop --help
💡 如果在公司网络下 npm 装得慢,可先设国内镜像;装好后 agent-desktop 应直接可用。本教程命令以 1.0.2 为准,旧版(0.10.0 之前)已移除 ad_get_tree / ad_find / ad_launch_app 等入口,抄老示例会直接报错。

Step 2:给 Agent 授予桌面权限

2 让操作系统允许它「读界面、点按钮」

无障碍能力是系统级权限,必须显式授权,否则快照拿不到元素:

# macOS:系统设置 → 隐私与安全性 → 辅助功能
#   把运行 agent-desktop 的终端 / 你的 IDE 加进允许列表
# Windows:UI Automation 默认开启,无需额外设置
# Linux:需安装并启用 AT-SPI(多数桌面环境默认开)
#   如遇权限问题,可跑权限引导,逐个勾选要授权的应用
agent-desktop

权限是安全边界,别给太宽:只把你确实需要自动化的应用加入允许列表即可。agent-desktop 默认以无头(headless)方式操作——不移动鼠标、不抢焦点;只有在你显式加 --headed 时才做物理输入,那会真的移动你的鼠标指针,操作时别去动电脑。

Step 3:给桌面应用拍一张无障碍树快照

3 一条 snapshot 拿到带 ref 的 JSON

用 snapshot 给某个应用拍快照。-i 让输出更易读,快照里每个可操作元素都带 ref_id(形如 @s8f3k2p9:e8)和 available_actions(这个元素能做什么):

# 给「访达 / Finder」拍快照(-i 人类可读)
agent-desktop snapshot --app "Finder" -i

# 对复杂应用,先用 --skeleton 看骨架,token 更省
agent-desktop snapshot --app "Slack" --skeleton

# 钻进某个区域再细看(用上一步拿到的 ref)
agent-desktop snapshot --app "Slack" --root @s8f3k2p9:e8

返回的 JSON 里,一个节点大概长这样:"role": "treeitem", "name": "Documents", "ref_id": "@s8f3k2p9:e8", "available_actions": ["Click"]。记下这个 ref_id,下一步就靠它操作。

🔑 关键技巧:快照 ID 是 ref 的一部分。Agent 点元素时必须带上完整 ref(含快照 ID),否则会被拒。换句话说,每次「观察—操作—再观察」都要先 snapshot,再拿最新 ref 去操作。

Step 4:按 ref 操作应用(点击 / 输入 / 滚动)

4 用 ref 精确操作,不靠坐标

拿到 ref 后,用 click / type / scroll 等操作它,操作完再拍一张快照验证结果。这就是 agent-desktop 的核心循环:

# 点击某个元素
agent-desktop click @s8f3k2p9:e8

# 在输入框里打字
agent-desktop type @s8f3k2p9:e9 "[email protected]"

# 滚动某个区域
agent-desktop scroll @s8f3k2p9:e10 --amount 200

# 操作完立刻复查,确认变成了预期状态
agent-desktop snapshot --app "Finder" -i

不要缓存 ref:ref 与快照生命周期绑定,UI 一变(哪怕只是列表刷新)旧 ref 就失效,操作必报 STALE_REF。正确做法是每次操作前重新 snapshot 取最新 ref,把「再观察」作为循环的固定一步。

Step 5:处理失败信号与重试

5 读懂错误码,让 Agent 自己恢复

agent-desktop 的命令统一返回 JSON envelope(含 ok / data / error 与重试建议)。常见失败信号:

错误信号含义Agent 该怎么做
STALE_REFref 对应的快照已过期(UI 变了)重新 snapshot,取最新 ref 再试
AMBIGUOUS_TARGET元素歧义,不止一个匹配加 --root 缩小范围,或先用 --skeleton 定位
INVALID_ARGSref 缺了快照 ID(只写了 @e8)补全为 @快照ID:元素ID 再调用
💡 把「错误码 → 重试动作」写进你的 Agent 提示词,它就能在失败时自动恢复,而不是卡死。这也是它比「截图猜坐标」更省心的地方:失败是结构化的、可处理的。

Step 6:把 agent-desktop 接进你的编码 Agent

6 包成一个 computer-use 工具

agent-desktop 是 CLI,最稳的接法是把它包成一个「操作桌面」工具,让编码 Agent 在「观察—操作—再观察」循环里调用。下面是一段最小 Node 封装(调用子进程跑 CLI,把 JSON envelope 原样返回给 Agent):

// desktop-tool.mjs
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
const run = promisify(execFile);

export async function desktop(action, args) {
  // action: snapshot | click | type | scroll
  const { stdout } = await run('agent-desktop', [action, ...args], { maxBuffer: 1e8 });
  return stdout; // JSON envelope: { ok, data, error, retry }
}

// Agent 调用示例(伪代码):
// 1) desktop('snapshot', ['--app','Finder','-i'])
// 2) desktop('click', ['@s8f3k2p9:e8'])
// 3) desktop('snapshot', ['--app','Finder','-i'])  // 验证结果

把这个工具注册成你 Agent 的 computer-use 能力(Claude Code 的 MCP tool、Codex 的 function、或 Cursor 的 command 都行),Agent 就能自己决定「先看看、再点哪、点完确认」。想让操作真的动鼠标,加 --headed;想压低 token,给稠密应用加 --skeleton 或 --compact。更完整的 60 个命令参考见官方文档站 agent-browser.dev/desktop。

隐私红线:快照、剪贴板读取、截图都可能包含你桌面上的私密内容(聊天、文件、密码框)。切勿把桌面快照原样写进公网日志、或上传给第三方服务。只在本地、可信的 Agent 运行环境里使用,必要时先关掉敏感窗口再跑自动化。

预期效果与常见问题

预期效果:跑完上面六步,你的编码 Agent 应该能对着一个真实桌面应用完成「打开 → 定位元素 → 点击/输入 → 验证」的闭环,而且每次操作都有结构化错误可处理。在 Finder、Slack、VS Code 这类暴露无障碍信息的应用上尤其顺滑。

你遇到的现象大概率原因与解决
snapshot 拿不到任何元素Step 2 权限没给到运行 CLI 的终端 / IDE,去系统辅助功能里补授权
点击报 STALE_REF用了旧 ref,重新 snapshot 取最新 ref 再点
操作会动我的鼠标误加了 --headed;默认无头不会,去掉该参数即可
稠密应用 token 太高先用 --skeleton 看骨架,再用 --root 钻进具体区域
← 返回教程中心