Skip to the content.

CUA — Computer-Use Agent Infrastructure

來源:trycua/cua · GitHub(擷取於 2026-04-25)

簡介

CUA 是開源的 Computer-Use Agent 基礎設施,提供沙盒(Sandbox)、SDK、driver 與 Benchmark,用於訓練、部署、評估能控制完整桌面環境的 AI Agent。

GitHub Stars:15,732|Forks:975|主要語言:HTML、Python、Swift(cua-driver)

cua-driver 12 天連發 5 版(v0.1.1 → v0.1.5),專案進入快速 iterate 階段。


核心元件

元件 說明
Cua Driver 背景自動化,控制原生 macOS 應用,不搶佔游標焦點。Speaks MCP over stdio
Cua Sandbox 統一 API,跨 OS 管理 VM 與容器(Python 3.11+)
CuaBot 協作式沙盒環境,原生桌面視窗 + H.265 串流、共享 clipboard、audio
Cua-Bench Benchmark 套件與強化學習(RL)環境,整合 OSWorld、ScreenSpot、Windows Arena
Lume macOS/Linux VM 管理,Apple Virtualization.Framework,Apple Silicon 近原生效能

任務光譜:你真的需要 cua 嗎?

寫 agent 之前先看任務分布。Production agents 80% 場景,headless Chrome + CDP 就解決,比走 cua 路線更穩、更平行、更便宜。

任務類型 解法 頻率
純網頁(form fill / 爬資料 / OAuth) Playwright / CDP headless ~70%
Web 但偵測 headless(金流、ticketing) Headed Chrome in Xvfb container ~10%
Web + browser native dialog(file picker / print) Playwright file chooser API ~5%
原生桌面 app(Office / Excel / ERP / 自寫 desktop app) OS-specific(cua / UIA / Linux X11) ~10%
跨 app 工作流(File Explorer drag → app) OS-level 混搭 ~3%
遊戲 / 3D / DirectX / OpenGL 沒好解,HID stream + frontmost ~2%

→ 70–85% 的 agent 任務 headless Chrome 解決,cua 的價值集中在剩下 15–30% 需要 OS 級桌面控制的場景。


平台支援

Host(agent 跑在哪)

元件 限制
cua-driver macOS only(用 macOS 系統 API 控制原生 app)
Lume Apple Silicon only(M1/M2/M3)
cua-sandbox 跨平台(Linux / Windows / macOS host 都能跑)

完整 stack 最佳體驗:Apple Silicon Mac。Linux/Windows host 跑 sandbox 可,但拿不到 cua-driver 的 macOS 原生 app 控制與 Lume 的近原生 VM 效能。

Guest(agent 控制誰)

cua-sandbox 統一 API 支援多平台 target:

async with Sandbox.ephemeral(Image.linux()) as sb:    # Linux
async with Sandbox.ephemeral(Image.macos()) as sb:    # macOS
async with Sandbox.ephemeral(Image.windows()) as sb:  # Windows
async with Sandbox.ephemeral(Image.android()) as sb:  # Android
# BYOI: .qcow2 / .iso 自訂映像

整合方式(自寫 agent 接 CUA)

CUA 對自寫 agent 的角色是「Computer Use 工具的後端」 — agent 負責 LLM + planning,CUA 提供桌面/視窗操作。三條路:

Path A — MCP server(最通用)

cua-driver 本身是 MCP server,agent 走 MCP client 連線,把 cua-driver 提供的 tools 加進 LLM 的 tool list。

cua-driver mcp
# 或 Claude Code:
claude mcp add --transport stdio cua-driver -- cua-driver mcp

主要 tools:

適合:自己寫 orchestration loop,要能 swap LLM(Anthropic / OpenAI / 開源模型)。

Path B — Claude Code computer-use 相容模式(PR #1424,2026-05-02 merged)

如果 agent 後端是 Claude(用 native computer_20241022 tool),不用自己 wrap MCP:

claude mcp add --transport stdio cua-computer-use -- cua-driver mcp --claude-code-computer-use-compat

適合:agent 是 Claude based,最少黏合 code 直接跑。

Path C — Sandbox / Lume(隔離環境)

cua-sandbox 跨 OS 管 VM/container lifecycle,Lume 在 Apple Silicon 上跑 macOS/Linux VM。

lume run macos-sequoia-vanilla:latest

適合:production 部署、大量平行 agent runs、RL 訓練、避免污染本機。


Cua Driver 怎麼做到「不搶 focus」(macOS 內部機制)

cua-driver 30% 的 Swift code 是在處理「不搶游標 / 不切 frontmost / 不換 Space」這個問題。實際看了 source 後,技術重點:

1. 不走 HID tap,改 pid-routed delivery

macOS 一般合成事件(CGEvent.post(tap: .cghidEventTap))走 WindowServer 全域 HID stream,會搬游標、搶 focus、改 frontmost。cua-driver 拒絕這條路,改用直送目標 process mach port,雙路並發:

Path API 適用
公開 API CGEvent.postToPid(pid) AppKit-style targets,SkyLight 對它常 silent drop
私有 API SkyLightEventPost.postToPid(auth-signed) Chromium/Safari/Electron-family,AppKit 上不可靠

兩條路互補,driver 同時 fire 兩條,accept「事件可能到兩次」當代價(純 mach traffic,user 看不見)。完全不動真實游標、不 activate 目標。

2. 滑鼠:AX-first,pixel 路是 carve-out

有 AX? → AXUIElementPerformAction(純 RPC,背景視窗也 work)
沒 AX? → 合成 mouseDown/mouseUp pair @ pixel
        (Chromium 網頁 / Blender canvas / Figma / 遊戲)

非 AX 路最 tricky 的發現:NSEvent.mouseEvent(...).cgEvent 走 AppKit bridge,比直接建 raw CGEvent 多一個「trust marker」。Chromium renderer IPC layer 會把 raw-CGEvent 默默 filter 掉,但接受 NSEvent-bridge 的事件。Source comment 寫得很白:

Switching to the NSEvent-bridged path fixed Chromium web-content hit-tests on backgrounded targets.

座標系手動翻 y(Cocoa bottom-left ↔ Quartz top-left),bridge 後再翻回來。windowNumber 故意傳 0 — 傳真實 number 會被 HID-tap dispatcher reject。

3. 鍵盤:CGEvent + SkyLight auth envelope

4. 螢幕擷取:window-scoped capture

CGWindowListCreateImage / ScreenCaptureKit (SCStream) 抓特定 window image。視窗 minimize / 被遮擋 / 在另一個 Space / 完全 off-screen 都能抓 — 系統 Compositor 永遠維持每個視窗的 backing store。

5. 已知限制

像素路 right-click 進 Chromium 網頁內容會 land 成 left-click — Chromium 把非 HID-origin 的 pointer event coerce 回 primary button。

contextMenu 在網頁上要用 AX 路(AXShowMenu)才可靠。

6. Frontmost-only 例外

Blender、Unity、部分遊戲用 OpenGL/GHOST,只接 HID stream,pid-routed 進不去。fallback 到 .cghidEventTap + mouseMoved,代價搬游標。但只在目標已是 frontmost 才 trigger。

為什麼別人沒做到?


Windows UIA 實作機制(Windows 對等方案)

UI Automation(UIA)是 Microsoft 從 Vista 開始推的 accessibility framework,取代 MSAA。對 agent 的價值:UIA 的 InvokePattern.Invoke() 直接呼叫 control 的 command handler(透過 COM IPC 進到 target process),不是合成 input event — 所以不搬游標、不搶 focus、不切 frontmost,等同 macOS AX path。

1. 架構

[your agent process]                    [target app process]
     ↓                                          ↑
[UIAutomationCore.dll]  ←─── COM IPC ───→ [UIA Provider in target]
     ↓                                          ↑
[FlaUI / pywinauto / raw COM]            [內建 UIA support: WPF / WinUI / Win32]

2. 核心抽象

AutomationElement (UI tree node)
├── Name, AutomationId, ControlType, BoundingRectangle, Process ID
├── Patterns(可執行的介面,類似 Java interface)
│   ├── InvokePattern.Invoke()             — 按鈕、選單項、連結
│   ├── ValuePattern.SetValue("text")      — 輸入框直接灌值(不打字)
│   ├── TextPattern.GetText()              — 讀取 rich text 內容
│   ├── TogglePattern.Toggle()             — Checkbox
│   ├── SelectionItemPattern.Select()      — List / Tree item
│   ├── ExpandCollapsePattern.Expand()     — Tree node
│   └── WindowPattern.SetWindowVisualState — Minimize/Maximize/Close
└── TreeWalker / FindFirst / FindAll       — 找子元素

關鍵:你不是「點座標」,你是「找到 element → 呼叫它的 Pattern」。完全 logical layer,沒 input synthesis。

3. 三條實作路線

路線 語言 複雜度 推薦給
FlaUI C# / .NET 低 Windows-native agent,性能好
pywinauto Python 低 Python agent,原型快
Raw UIA COM C++ / Rust / Python via comtypes 高 自己寫 driver,效能優化

4. 程式碼

FlaUI(C#)— 推薦

using FlaUI.Core;
using FlaUI.UIA3;

var app = Application.Attach("notepad.exe");
using var automation = new UIA3Automation();
var window = app.GetMainWindow(automation);

var saveBtn = window.FindFirstDescendant(cf => cf.ByAutomationId("FileSaveButton"));
saveBtn.AsButton().Invoke();    // ← 不搶 focus

var textBox = window.FindFirstDescendant(cf =>
    cf.ByName("Username").And(cf.ByControlType(ControlType.Edit)));
textBox.AsTextBox().Text = "doro";   // SetValue,不打字

pywinauto(Python)— 原型最快

from pywinauto import Application

app = Application(backend="uia").connect(title="Calculator")
window = app.window(title="Calculator")

window.print_control_identifiers()    # debug:列出 tree
window.child_window(title="Five", control_type="Button").invoke()
window.child_window(title="Plus", control_type="Button").invoke()
window.Edit.set_text("123")

Raw UIA COM(Python via comtypes)— 效能極致

import comtypes.client
comtypes.client.GetModule('UIAutomationCore.dll')
from comtypes.gen.UIAutomationClient import (
    IUIAutomation, CUIAutomation,
    UIA_InvokePatternId, UIA_ButtonControlTypeId
)

uia = comtypes.client.CreateObject(CUIAutomation, interface=IUIAutomation)
root = uia.GetRootElement()

cond = uia.CreatePropertyCondition(UIA_ControlTypePropertyId, UIA_ButtonControlTypeId)
button = root.FindFirst(TreeScope_Descendants, cond)

ip = button.GetCurrentPattern(UIA_InvokePatternId)
ip.QueryInterface(IUIAutomationInvokePattern).Invoke()

5. 背景截圖(Windows 對應 CGWindowListCreateImage)

import win32gui, win32ui
from ctypes import windll
from PIL import Image

hwnd = win32gui.FindWindow(None, "Visual Studio Code")
left, top, right, bot = win32gui.GetWindowRect(hwnd)
w, h = right-left, bot-top

hwnd_dc = win32gui.GetWindowDC(hwnd)
mfc_dc = win32ui.CreateDCFromHandle(hwnd_dc)
save_dc = mfc_dc.CreateCompatibleDC()
bmp = win32ui.CreateBitmap()
bmp.CreateCompatibleBitmap(mfc_dc, w, h)
save_dc.SelectObject(bmp)

# PW_RENDERFULLCONTENT = 3,關鍵:對 Chromium / DWM-composed 視窗有效
windll.user32.PrintWindow(hwnd, save_dc.GetSafeHdc(), 3)

img = Image.frombuffer('RGB', (w,h), bmp.GetBitmapBits(True), 'raw', 'BGRX', 0, 1)

PrintWindow 重點:

6. 效能 — caching 是必修

UIA 慢的原因是每個 property access 都走 COM IPC。Tree 大(Office、Chrome 多 tabs)走一遍要幾百 ms。

// ❌ 慢:每個 property 一次 IPC
foreach (var e in elements) {
    Console.WriteLine(e.Name);          // IPC
    Console.WriteLine(e.AutomationId);  // IPC
}

// ✅ 快:批次預載
var cache = new CacheRequest();
cache.Add(AutomationElement.NameProperty);
cache.Add(AutomationElement.AutomationIdProperty);
cache.Add(InvokePattern.Pattern);
using (cache.Activate()) {
    var elements = root.FindAll(TreeScope.Descendants, condition);
    foreach (var e in elements) {
        Console.WriteLine(e.Cached.Name);    // 從 cache,0 IPC
        ((InvokePattern)e.GetCachedPattern(InvokePattern.Pattern)).Invoke();
    }
}

對 agent:每次 screenshot 後重新 walk tree(畫面變了)會炸效能。好 design 是 element-id-based — agent 第一次 query 拿到 ID list,後續 invoke(elem_id) 直接用 cached handle。pywinauto 預設不快取,自己包 wrapper 時要做。

7. 元素定位策略(穩定度)

最穩 ──────────────────────────────────────── 最脆
AutomationId → ControlType+Name → Name → BoundingRect → 像素座標

AutomationId 是 dev 自己設的(WPF x:Name、Win32 control ID),update UI 也不太會變。Name 容易因 i18n / 文案變動失效。

8. Inspect 工具(必裝)

寫 agent 第一步:用 Inspect.exe 看 target app 的 tree → 決定用哪個 pattern。

9. UIA support 實際狀況

App 類型 UIA 完整度 備註
WPF 🟢 99% framework 自動 expose,最理想
WinUI 3 / UWP 🟢 99% 同上
Win32(common controls) 🟡 80% UIA bridge 自動處理
Office 🟡 70% UIA + 自家 ribbon UI;複雜
Chromium / Electron 🟡 60% DOM 大致 OK,但 canvas / WebGL / 自繪 widget 沒
VSCode / Slack(Electron-heavy) 🔴 30% 大量自繪,重要按鈕常找不到
Java Swing / SWT 🔴 0% 有 Java Access Bridge 但要另裝
Qt 🟡 視 build 而定 Qt 6 + accessibility plugin OK
DirectX / Unity / Unreal 遊戲 🔴 0% 完全沒

Electron-heavy app 是最大痛點。VSCode 內 ribbon 按鈕找得到,但編輯區是 Monaco editor canvas,UIA 看不到 — 這時要 fallback 到 CDP(VSCode 有 debug protocol)或用 IPC(VSCode extension API)。

10. 包成 MCP server 的雛形

# uia_mcp_server.py(pseudo-code)
from mcp.server import Server
from pywinauto import Application

server = Server("uia-driver")
elements_cache = {}  # id → element handle

@server.tool()
def list_windows():
    """List all top-level windows with HWND, title, pid."""
    return [{"hwnd": h, "title": t, "pid": p} for h,t,p in walk_top_windows()]

@server.tool()
def get_tree(hwnd: int, max_depth: int = 5):
    """Walk UIA tree of window, return element list with IDs."""
    app = Application(backend="uia").connect(handle=hwnd)
    window = app.window(handle=hwnd)
    elements = []
    for e in window.descendants():
        eid = id(e)
        elements_cache[eid] = e
        elements.append({
            "id": eid,
            "name": e.window_text(),
            "control_type": e.element_info.control_type,
            "automation_id": e.automation_id(),
            "rect": e.rectangle().as_tuple(),
            "patterns": list_patterns(e),
        })
    return elements

@server.tool()
def invoke(element_id: int):
    elements_cache[element_id].invoke()

@server.tool()
def set_value(element_id: int, value: str):
    elements_cache[element_id].set_text(value)

@server.tool()
def screenshot(hwnd: int):
    """Window-scoped screenshot via PrintWindow PW_RENDERFULLCONTENT."""
    return capture_window(hwnd)  # → PNG bytes

agent 流程:list_windows → get_tree 拿到 element list → LLM 看 list + screenshot → 決定 invoke(id=42) → set_value(id=43, value="...") → 再 screenshot 看結果。

11. UIA 不夠時的 fallback layers

場景 Fallback
Chromium 內網頁互動 CDP(直接 attach Chrome debugger)
Electron canvas(VSCode Monaco) IPC / extension API
完全沒 UIA 的 legacy app PostMessage(WM_*) 到 HWND
上述都不行 SendInput + frontmost(搬 focus,accept)

真實 production agent 通常是 5 條路 layered:CDP → UIA → PostMessage → SendInput → 像素座標。每層失敗才 fallback 下一層。cua-driver 在 macOS 也是這個策略(AX → SkyLight → CGEvent.postToPid → cghidEventTap)。


跨平台替代方案

cua-driver 是 macOS-only 且要逆向 SkyLight 才寫得出來。Linux/Windows 上有更直接的路線。

Linux:Docker + Xvfb

Linux + Xvfb 環境下「使用者根本不在」,cua-driver 30% 的工程在解的問題直接消失。

CUA 元件 macOS 上 Linux + Docker + Xvfb
輸入合成 CGEvent.postToPid + SkyLight + AX xdotool / xte / pynput
螢幕擷取 CGWindowListCreateImage / SCStream xwd / scrot / FFmpeg + X11 grab
「不搶 focus」 reverse-engineer SkyLight 免費 — Xvfb 沒有真實使用者
隔離 cua-sandbox Docker 本身就是
VM mgmt Lume(AS-only) 不需要(用 container)
桌面串流 H.265 x11vnc + noVNC,或 FFmpeg → WebRTC

Linux 上「免費」拿到的:

注意事項:

推薦 stack:

[your Linux agent]
       ↓ MCP
[wrapper: xdotool + scrot/xwd + xwininfo]
       ↓ X11 socket
[Xvfb :99 inside Docker container]
       ↓
[target apps: chromium-headed, electron app, etc.]

現成方案:Selenium / Playwright + Chromium headed、PyAutoGUI in Xvfb、DesktopENV / OSWorld 的 Docker setup(學術界 computer-use benchmark 已這樣做)。

Fork CUA 做 Linux port 可行性:以 cua-sandbox 為核心加 LinuxDockerXvfbDriver plug-in,比 macOS port 簡單得多 — 不用碰 SkyLight、不用 reverse engineer trust marker、不用處理「使用者在用電腦」。估 1–2 週做到 80% 功能。

Windows:Playwright + UIA + pywinauto 混搭

實作細節見上「Windows UIA 實作機制」一節;本段聚焦 deployment / 技術選擇 trade-off。

Windows 跟 macOS 處境像但更難。沒有 SkyLight 等價物可逆向,Chromium 在 Windows 也 filter 掉非 HID 來源 input。

Windows 上「不搶 focus」的選項:

路線 對等於 macOS 哪條 不搶 focus? 限制
UI Automation InvokePattern.Invoke() AX path ✅ Yes 只 UIA-compliant app(modern Win32 / WPF / UWP);Chromium 算半 UIA
PostMessage(WM_LBUTTONDOWN, …) 到 HWND CGEvent.postToPid ✅ 不搶 focus 多數現代 app(Chromium / Electron / 自繪 GUI / 遊戲)會 ignore HWND message
SendInput cghidEventTap ❌ Steals focus 全域 HID stream,搬游標
DirectInput OpenGL/GHOST N/A 遊戲專用
WinAppDriver / Selenium — ✅ Microsoft 已 deprioritize;後端還是 UIA

關鍵 insight:

Windows 沒有 SkyLight 等價物:cua-driver 在 macOS 突破的關鍵是 reverse-engineer SkyLight 的 auth-signed pid-routed event,Chromium 收。Windows 沒有對應私有 framework 可逆向 — Chrome 的 input filter 在 Aura compositor 內部,沒「跳過 HID 直送」的機制。

推薦 Windows stack:

[your agent]
   ├─ if target 是網頁              → Playwright/CDP(headless 或 Xvfb headed)
   ├─ if target 是 UIA-compliant    → pywinauto / FlaUI(背景)
   ├─ if target 是 legacy Win32     → PostMessage + UIA 混搭
   └─ if target 是遊戲 / 3D         → SendInput + frontmost(搬 focus,accept)

第一步直接用 Playwright + pywinauto 就 90% 涵蓋。

為什麼不必 fork CUA 做 Windows port:

三平台對照總結

維度 macOS Linux + Xvfb Windows
「不搶 focus」 hard 嗎 🔴 hard,要 SkyLight 🟢 free,沒人在用 🟡 medium,UIA 可,pixel 不行
Chromium 控制 需 SkyLight + NSEvent bridge xdotool 直接過 只能用 CDP
Native app 控制 AX + cua-driver xdotool(少 native app) UIA / pywinauto
GPU / 3D OK(Metal) ❌ Xvfb 無,要 GPU 容器 OK(DirectX)
工具鏈成熟度 cua-driver 領先 xdotool / Playwright UIA 生態最成熟
Production 部署 需要 Mac fleet(貴) 容易(K8s + Docker) 容易(Windows containers)
自寫 driver 難度 🔴 高(逆向) 🟢 低(成熟工具) 🟡 中(API 多但分散)

自寫 agent 的決策樹

你的 target 主要是?
├─ 網頁                          → Playwright / CDP,不必碰 cua(80% 場景)
├─ Mac 原生 app                  → cua-driver MCP(甜蜜點)
├─ Linux 原生 app                → 自寫 xdotool wrapper + MCP
├─ Windows 原生 app              → pywinauto / FlaUI + 自寫 MCP wrapper
├─ Windows + Chromium 混合       → Playwright(網頁部分)+ pywinauto(native 部分)
└─ 跨 OS desktop benchmark / RL  → cua-sandbox + Image.* VM 是合理選擇

對 99% 的「我要做 SaaS agent」use case,headless Chrome + Playwright 就是答案,cua 整個 stack 反而 over-engineering。

cua 的真正價值集中在:

  1. Mac native app 控制(不搶 focus)
  2. Apple Silicon 上的 macOS / Linux VM lifecycle
  3. Cross-OS computer-use benchmark / RL 訓練資料蒐集
  4. research-grade 完整桌面 agent(OSWorld / ScreenSpot / Windows Arena)

使用場景


評估

優點

注意

對自寫 agent 的選擇