Cua 核心架构与设计原理深度解析:为 Computer-Use Agent 打造的全栈基础设施

引子:当 Agent 学会「看屏幕」

2024 年底,OpenAI 推出 Operator,让 GPT-4o 直接「看浏览器截图 + 鼠标点击」,Computer-Use 赛道一夜之间成为 Agent 领域最热的方向。紧接着 Anthropic 发布 Claude Computer Use、Google 发布 Gemini Computer Use,国内的 Agent-S、UI-Tars 等项目相继登顶 OSWorld 排行榜。

但热闹背后有一个尴尬的事实:99% 的 Computer-Use 项目都是在「沙箱」上跑——而这个沙箱本身,没人帮你写。

你想让 Agent 操作一台 macOS 虚拟机截图、点击、输入?要么自己折腾 QEMU + macOS 镜像 + 远程控制协议(坑到怀疑人生),要么用 Docker 起一个 Linux 容器再装 X11(Linux 应用覆盖率不足 5%),要么买云端 VM 服务(贵 + 慢 + 难调试)。

trycua/cua(GitHub 17.9k stars,MIT 协议,2026-06-12 仍在活跃提交)就是冲着这个痛点来的——它不是另一个 Computer-Use Agent,而是一整套「让 Computer-Use Agent 跑起来」的全栈基础设施:跨平台沙箱(macOS/Linux/Windows/Android)、统一的 Computer 抽象层、LiteLLM 风格的多模型 Agent 适配器、可训练的 RL 基准(Cua-Bench)。

如果说 Agent-S 是「一辆造好的赛车」,那 cua 就是「赛道 + 加油站 + 维修站 + 教练团队 + 计时系统」——你既可以开它送的车(cua-agent),也可以开自己的车(接 OpenAI CUA / Claude / 自研 VLM)上它的赛道(Cua-Bench)。

本文会从分层架构、核心机制、源码解读、横向对比四个维度,把这套基础设施彻底拆给你看。


一、项目定位:「Computer-Use 时代的 Docker + Gym」

1.1 它解决的问题

cua 的官方口号是 “Build, benchmark, and deploy agents that use computers”——三个动词,恰好对应它解决的三个真实痛点:

痛点现状cua 的解决方案
想跑一个 macOS GUI Agent,但启动 macOS VM 极其痛苦手工 QEMU + macOS 恢复镜像 + VNC 拼凑,平均 3-5 天一行 lume run macos-sequoia-vanilla:latest 拉起 VM
Agent 在不同 OS 上的操作 API 完全不同pyautogui 只能控 X11、Quartz API 只服务 macOS、UIA 只服务 Windows统一的 Computer 接口:computer.click(x, y) / computer.screenshot() 跨平台一致
想训练/评测自己的 Computer-Use 模型,但缺基准OSWorld 注册麻烦、任务数据集封闭、AndroidWorld 数据集需手动配cua-bench 内置 KiCad / 文件管理 / 浏览器等多类任务,支持容器化并行
多个 VLM 模型接入写法各异OpenAI CUA 用 computer_use_preview、Claude 用 computer_20241022、自研模型走 vLLMLiteLLM 风格的 Agent 类 + Adapter 模式,30 行代码切换底层模型

1.2 它解决的问题

  • 不是单一最优 Agent:cua 自带的 cua-agent(基于 Claude / OpenAI CUA / 本地 VLM)OSWorld 得分约 48-52%,不如专门优化的 Agent-S(72.6%)或 UI-Tars。cua 的目标是「让你自己的 Agent 跑得更好」,而不是「cua 的 Agent 跑得最好」。
  • 不是端到端 SaaS:虽然有 trycua.com 云服务,但 80% 的价值在开源 SDK,可以完全自托管。
  • 不是 Computer-Use 协议:MCP 已经有 cua-mcp-server 把 cua 能力暴露给 Claude Code/Cursor,但 cua 本身定义跨 Agent 通信协议(那是 ACP / A2A 的事)。

1.3 数字说话

  • ⭐ 17,867 stars(2026-06-12 数据)
  • 🍴 1,152 forks
  • 📜 MIT + Apache-2.0 双协议
  • 📦 仓库大小 237 MB(包含 KVM 镜像、KiCad 任务定义、benchmark 截图)
  • 🗂️ 4,183 个文件,11 个子项目(cua-driver / lume / lumier / cua-bench / python / typescript / kasm / cuabot / xfce / qemu-docker / cua-driver-fixtures

二、整体架构:四层金字塔

cua 不是一个 Python 库,而是一个多语言、多进程、多硬件后端的分布式系统。我把它梳理成四层架构:

flowchart TB
    subgraph L1["第一层:Agent 层 (libs/python/agent)"]
        A1[cua-agent<br/>LiteLLM 风格多模型适配]
        A2[Adapter 体系<br/>CUAAdapter / AzureMLAdapter / HFAdapter / HumanAdapter]
        A3[Callback 体系<br/>OtelCallback / TrajectorySaver / BudgetManager]
    end

    subgraph L2["第二层:Computer 抽象层 (libs/python/computer)"]
        B1[Computer 类<br/>统一对外 API]
        B2[Interface 体系<br/>macos / linux / windows / android / generic]
        B3[Tracing & OTEL<br/>OpenTelemetry 全链路追踪]
    end

    subgraph L3["第三层:Provider 工厂层 (libs/python/computer/providers)"]
        C1[VMProviderFactory<br/>统一创建入口]
        C2[LumeProvider<br/>macOS 原生虚拟化]
        C3[DockerProvider<br/>Linux/Windows 容器]
        C4[CloudProvider<br/>云端 VM 池]
        C5[WindowsSandboxProvider<br/>Win10/11 沙箱]
    end

    subgraph L4["第四层:硬件后端层"]
        D1[Apple Virtualization.framework<br/>原生 macOS 沙箱]
        D2[Lume CLI (Rust)<br/>VM 生命周期管理]
        D3[QEMU-in-Docker<br/>x86_64 硬件加速]
        D4[KasmVNC<br/>Web 远程桌面]
        D5[真实硬件 / Lumier<br/>macOS GPU 直通]
    end

    L1 -->|操作指令| L2
    L2 -->|调用 provider| L3
    L3 -->|驱动后端| L4
    L4 -->|截图/事件| L2
    L2 -->|反馈观测| L1

四层的核心职责:

  1. Agent 层cua-agent):决策大脑,把「用户目标」分解成「点击/输入/截图」的循环。完全无状态,可水平扩展。
  2. Computer 抽象层:操作系统 API 翻译官。无论后端是 macOS VM 还是 Linux 容器,对 Agent 暴露的接口都长一样:screenshot() / click(x,y) / type(text)
  3. Provider 工厂层:VM/容器生命周期管理。负责「把一台电脑拉起来」+「把指令翻译成具体虚拟化技术调用」+「把虚拟机关掉」。
  4. 硬件后端层:实际干活的工具链。Apple Virtualization.framework(macOS 原生 API)、Lume(Rust 写的 CLI)、QEMU、KasmVNC(Web 远程桌面)。

数据流是双向的

  • 下行:Agent 决策 → Computer API → Provider → 虚拟化后端 → 真实 OS
  • 上行:真实 OS 截屏 → Provider 截屏钩子 → Computer.screenshot() → Agent 视觉输入

让我把每一层的源码都拆给你看。


三、深度拆解:从 Computer 抽象层到 Agent 决策循环

3.1 Computer 抽象层:统一跨平台 API

libs/python/computer/computer/computer.py 里的 Computer 类是整个系统的「门面」。看下它的构造函数签名:

1
2
3
4
5
6
7
8
9
10
11
12
class Computer:
def __init__(
self,
display: Union[Display, Dict[str, int], str] = "1024x768",
memory: str = "8GB",
cpu: str = "4",
os_type: OSType = "macos",
name: str = "",
image: Optional[str] = None,
shared_directories: Optional[List[str]] = None,
# ... 还有 20+ 参数
):

关键参数解读

  • os_type:枚举值 "macos" | "linux" | "windows" | "android"决定 Interface 走哪条路
  • image:如果传 None,Provider 拉起的是裸 OS;如果传镜像名(如 "macos-sequoia-vanilla:latest"),就是预装应用的 OS。
  • shared_directories:宿主 ↔ 虚拟机双向文件夹同步,让 Agent 读写文件就像操作本机。
  • display / memory / cpu:虚拟硬件配置(cua 内部会传给 QEMU 启动参数或 Virtualization.framework 配置)。

Computer直接操作任何虚拟化 API,它委托给两个内部组件:

1
2
3
# 来自 libs/python/computer/computer/computer.py
self.interface = InterfaceFactory.create(os_type, **kwargs) # OS 适配
self.provider = VMProviderFactory.create(os_type, **kwargs) # VM 生命周期

这两个工厂是 cua 设计的精髓——Computer 类的核心方法(screenshot/click/type)只跟 Interface 交互,Provider 负责「这台电脑从哪来」

3.1.1 Interface 体系:让 Python 调用跨平台

libs/python/computer/computer/interface/ 下有 5 个文件:

1
2
3
4
5
6
7
8
9
interface/
├── __init__.py
├── android.py # Android ADB/UIAutomator 适配
├── base.py # 抽象基类 BaseInterface
├── factory.py # InterfaceFactory.create(os_type)
├── generic.py # 通用 HTTP/Web 接口(cua-server 协议)
├── linux.py # X11 + AT-SPI 适配
├── macos.py # Quartz + Accessibility API 适配
└── windows.py # UIA + Win32 适配

每个 Interface 类都继承 BaseInterface,实现以下统一方法(节选自 interface/base.py):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class BaseInterface(ABC):
@abstractmethod
def screenshot(self) -> bytes:
"""返回 PNG bytes"""
...

@abstractmethod
def left_click(self, x: int, y: int) -> None:
"""在 (x, y) 左键单击"""
...

@abstractmethod
def type(self, text: str) -> None:
"""输入文本"""
...

@abstractmethod
def key(self, key: str) -> None:
"""发送按键(Enter / Cmd+C / F5 等)"""
...

@abstractmethod
def size(self) -> tuple:
"""返回屏幕 (width, height)"""
...

macOS 的实现(节选自 interface/macos.py):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 实际通过 Quartz 框架(PyObjC 桥接)
import Quartz # type: ignore

class MacOSInterface(BaseInterface):
def screenshot(self) -> bytes:
# CGWindowListCreateImage:截取整个屏幕
image_ref = Quartz.CGWindowListCreateImage(
Quartz.CGRectInfinite,
Quartz.kCGWindowListOptionOnScreenOnly,
Quartz.kCGNullWindowID,
Quartz.kCGWindowImageDefault,
)
return self._cgimage_to_png_bytes(image_ref)

def left_click(self, x: int, y: int) -> None:
# CGEventCreateMouseEvent:合成鼠标事件
down = Quartz.CGEventCreateMouseEvent(
None, Quartz.kCGEventLeftMouseDown, (x, y), Quartz.kCGMouseButtonLeft
)
up = Quartz.CGEventCreateMouseEvent(
None, Quartz.kCGEventLeftMouseUp, (x, y), Quartz.kCGMouseButtonLeft
)
Quartz.CGEventPost(Quartz.kCGHIDEventTap, down)
time.sleep(0.05) # 模拟人类操作间隔
Quartz.CGEventPost(Quartz.kCGHIDEventTap, up)

Linux 的实现(节选自 interface/linux.py)走完全不同的路——用 X11 的 python-xlib

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from Xlib import X, display
from Xlib.ext import xtest

class LinuxInterface(BaseInterface):
def __init__(self, display_name: str = ":0"):
self.d = display.Display(display_name)
self.root = self.d.screen().root

def left_click(self, x: int, y: int) -> None:
# XTest 扩展:合成伪输入
xtest.fake_input(self.d, X.ButtonPress, 1, x=x, y=y)
self.d.sync()
time.sleep(0.05)
xtest.fake_input(self.d, X.ButtonRelease, 1, x=x, y=y)
self.d.sync()

这就是 Interface 抽象的价值——Agent 写 computer.left_click(100, 200) 就行,完全不用知道自己跑在 macOS 还是 Linux 容器里。

3.1.2 观测增强:OpenTelemetry 包装

cua 在 Interface 之上套了一层 OtelInterfaceWrapperotel_wrapper.py),把每次 screenshot / click 都包装成 OTEL span:

1
2
3
4
5
6
7
8
9
10
11
12
class OtelInterfaceWrapper(BaseInterface):
def __init__(self, inner: BaseInterface, tracer):
self._inner = inner
self._tracer = tracer

def screenshot(self) -> bytes:
with self._tracer.start_as_current_span("computer.screenshot") as span:
start = time.time()
data = self._inner.screenshot()
span.set_attribute("screenshot.size_bytes", len(data))
span.set_attribute("screenshot.latency_ms", int((time.time()-start)*1000))
return data

这个设计有个隐藏好处——cua 跟 Langfuse / Arize Phoenix / OpenInference 完全兼容,可以直接接现成的 LLM 观测平台。

3.2 Provider 工厂层:让 VM 真的跑起来

如果说 Interface 是「对着一台已存在的电脑操作」,那 Provider 就是「把这台电脑从零拉到可操作状态」。

libs/python/computer/computer/providers/ 下的目录:

1
2
3
4
5
6
7
8
9
providers/
├── base.py # VMProviderType 枚举 + BaseProvider 抽象
├── factory.py # VMProviderFactory.create(os_type)
├── lume_api.py # Lume HTTP API 客户端
├── lume/ # Lume 本机 Provider(macOS 主机)
├── lumier/ # Lumier Provider(macOS GPU 直通)
├── docker/ # Docker 容器 Provider(Linux)
├── winsandbox/ # Windows 沙箱 Provider
└── cloud/ # 云端 VM 池 Provider

3.2.1 VMProviderType 枚举

providers/base.py 定义了 cua 支持的所有「VM 来源」:

1
2
3
4
5
6
7
class VMProviderType(str, Enum):
LUME = "lume" # 本地 macOS 虚拟化(Apple Virtualization.framework)
LUMIER = "lumier" # 远程 macOS(用 Lumier 服务暴露 Lume VM)
DOCKER = "docker" # Linux/Windows 容器(QEMU-in-Docker)
CLOUD = "cloud" # 远端云 VM 池
WINDOWS_SANDBOX = "windows_sandbox" # Windows 10/11 沙箱
ANDROID = "android" # Android 设备/模拟器

VMProviderFactory.create 是个标准的工厂模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class VMProviderFactory:
_registry = {
VMProviderType.LUME: LumeProvider,
VMProviderType.LUMIER: LumierProvider,
VMProviderType.DOCKER: DockerProvider,
VMProviderType.CLOUD: CloudProvider,
VMProviderType.WINDOWS_SANDBOX: WindowsSandboxProvider,
VMProviderType.ANDROID: AndroidProvider,
}

@classmethod
def create(cls, provider_type: VMProviderType, **kwargs) -> BaseProvider:
if provider_type not in cls._registry:
raise ValueError(f"Unknown provider: {provider_type}")
return cls._registry[provider_type](**kwargs)

3.2.2 Lume:macOS 上的 Apple Virtualization.framework 封装

Lume(Rust 写的 CLI)是 cua 的「镇馆之宝」——它把 Apple 在 macOS 11+ 推出的 Virtualization.framework(官方虚拟化 API)封装成了一个 lume run macos-sequoia-vanilla:latest 命令。

安装方式(macOS host):

1
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/trycua/cua/main/libs/cua-driver/scripts/install.sh)"

一行命令拉起 macOS VM

1
lume run macos-sequoia-vanilla:latest --cpu 4 --memory 8GB --display 1024x768

Python SDK 集成providers/lume/):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class LumeProvider(BaseProvider):
def __init__(self, name: str, image: str, **kwargs):
self._name = name
self._image = image
self._lume = LumeAPI() # HTTP 调用 lume daemon

async def start(self):
# 异步:调 lume daemon 启动 VM
await self._lume.run(self._name, image=self._image, **self._vm_config)
# 等到 VM 的 VNC/WebSocket 端口起来
await self._wait_ready(timeout=120)

async def stop(self):
await self._lume.stop(self._name)

def get_ip_and_port(self) -> tuple:
# 拿 VNC 端口给 Interface 用
return self._lume.get_endpoint(self._name)

Lume vs QEMU:QEMU 跑 macOS 是个 hack(需要 OVMF + macOS 恢复镜像 + 各种 patch),启动 5-10 分钟,且不支持 GPU 加速。Lume 走 Apple 原生 Virtualization.framework,冷启动 30-60 秒,支持 Metal GPU 直通(Lumier 项目可让 macOS VM 用上宿主 GPU)。

3.2.3 Docker Provider:Linux/Windows 容器化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class DockerProvider(BaseProvider):
def __init__(self, image: str, **kwargs):
self._image = image # e.g. "trycua/cua-ubuntu:latest"
self._container_name = f"cua-{uuid4().hex[:8]}"

async def start(self):
# docker run + 端口映射 + X11 socket 挂载
cmd = [
"docker", "run", "-d",
"--name", self._container_name,
"-v", "/tmp/.X11-unix:/tmp/.X11-unix", # X11 共享
"-e", "DISPLAY=host.docker.internal:0",
self._image
]
await asyncio.create_subprocess_exec(*cmd)
await self._wait_for_x11()

这是 cua 门槛最低的 Provider——任何装了 Docker 的 Linux 机器都能跑,缺点是 UI 应用覆盖率低(只能在 Linux 上跑 X11/Wayland 应用)。

3.3 Agent 层:LiteLLM 风格的多模型决策

libs/python/agent/cua_agent/agent.py 里的 ComputerAgent 是 cua 的「开箱即用大脑」。

3.3.1 核心循环

predict 方法的精简版(实际代码更长,但骨架是这样的):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class ComputerAgent:
async def predict(self, messages: Messages) -> AsyncGenerator:
# 1. 把消息标准化 + 加 system prompt
processed = await self._process_messages(messages)

# 2. 多轮决策循环(最多 self.max_steps 步)
for step in range(self.max_steps):
# 2a. 调 VLM 拿工具调用
response = await litellm.acompletion(
model=self.model, # "openai/computer-use-preview" / "claude-3-5-sonnet" / ...
messages=processed,
tools=self._get_tools(), # computer_use / bash / str_replace_editor
)
action = self._parse_action(response)

# 2b. 拦截 "computer use" 工具调用
if action.type == "computer":
# 拿当前截屏 + 执行
screenshot = await self.computer.screenshot()
processed.append(screenshot) # 给下一轮 VLM 看
await self.computer.execute(action)
elif action.type == "bash":
await self._run_bash(action.command)

# 2c. 终止条件
if action.type == "done":
yield action
return

注意 processed.append(screenshot) 这一行——这是 Computer-Use Agent 的核心:每一步把「上一步的截图」追加到消息历史,让 VLM 在下一轮决策时看到自己的行为后果

3.3.2 Adapter 模式:让 30 行代码切换底层模型

cua_agent/adapters/ 下的文件:

1
2
3
4
5
6
7
adapters/
├── base.py # BaseAdapter 抽象
├── cua.py # CUAAdapter: 接 trycua.com 云端 Computer-Use API
├── azureml.py # AzureMLAdapter: 接 Azure ML 端点
├── huggingface.py # HuggingFaceLocalAdapter: 接本地 vLLM / transformers
├── mlx_vlm.py # MLXVLMAdapter: 接 Apple Silicon 上的 MLX VLM
└── human.py # HumanAdapter: 真人接管(debug 用)

Adapter 的接口base.py):

1
2
3
4
5
6
7
8
class BaseAdapter(ABC):
@abstractmethod
async def predict(self, messages: Messages, tools: list) -> Action:
"""返回下一步动作"""

@abstractmethod
def supports_vision(self) -> bool:
"""是否原生支持图像输入"""

CUAAdapter 接 OpenAI 的 computer-use-preview 模型:

1
2
3
4
5
6
7
8
9
10
11
12
13
class CUAAdapter(BaseAdapter):
async def predict(self, messages, tools):
response = await openai.AsyncOpenAI().responses.create(
model="computer-use-preview",
input=messages, # OpenAI Responses API 格式
tools=[{
"type": "computer_use_preview",
"display_width": 1024,
"display_height": 768,
}],
truncation="auto",
)
return self._parse_openai_response(response)

HuggingFaceLocalAdapter 接本地 vLLM 跑 Qwen2.5-VL / UI-Tars:

1
2
3
4
5
6
7
8
9
10
11
12
class HuggingFaceLocalAdapter(BaseAdapter):
def __init__(self, model_path: str, **kwargs):
from vllm import LLM
self._llm = LLM(model=model_path, **kwargs)

async def predict(self, messages, tools):
# 把 messages 转换成 chat template 格式
prompt = self._tokenizer.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True
)
outputs = await self._llm.agenerate(prompt, sampling_params=...)
return self._parse_text_action(outputs[0].outputs[0].text)

切换模型的便利性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 用 OpenAI CUA
agent = ComputerAgent(computer=computer, model="openai/computer-use-preview")

# 用 Claude 3.5 Sonnet
agent = ComputerAgent(computer=computer, model="claude-3-5-sonnet-20241022")

# 用本地 Qwen2.5-VL
agent = ComputerAgent(
computer=computer,
model="huggingface-local/Qwen/Qwen2.5-VL-7B-Instruct",
)

# 真人接管
agent = ComputerAgent(computer=computer, model="human/human")

这就是 LiteLLM 范式的胜利——cua 把「不同 VLM 的 tool use 协议差异」全部吸收到 Adapter 里,让上层 API 保持极简。

3.3.3 Callback 体系:可观测 + 成本控制

cua_agent/callbacks/ 下的 8 个 callback 实现:

Callback职责
OtelCallback把 Agent 决策循环暴露为 OTEL span
TrajectorySaverCallback把每一步的 (screenshot, action, result) 落盘,用于回放
BudgetManagerCallback监控 token 消耗,超出预算自动停止
ImageRetentionCallback防止消息历史里塞太多图片导致 OOM
LoggingCallback结构化日志
TelemetryCallbackcua 自家的匿名遥测
OperatorNormalizerCallback把不同模型的 action 格式统一成 OpenAI CUA 协议
PromptInstructionsCallback注入 system prompt + 行为约束

Callback 注册

1
2
3
4
5
6
7
8
9
agent = ComputerAgent(
computer=computer,
model="claude-3-5-sonnet-20241022",
callbacks=[
OtelCallback(tracer=tracer),
TrajectorySaverCallback(save_dir="./trajectories"),
BudgetManagerCallback(max_tokens=100_000),
],
)

这种设计让 cua 很容易做 RL 训练数据收集——TrajectorySaverCallback 落盘的轨迹直接喂给 SFT/RLHF pipeline。

3.4 Cua-Bench:可训练的 RL 基准

libs/cua-bench/ 是 cua 区别于其他 Computer-Use 项目的杀手锏——它把「评测」和「训练环境」合并到一个框架。

3.4.1 任务定义

cua-bench/tasks/ 下有现成的任务集:

1
2
3
4
5
6
7
8
9
10
11
12
13
# tasks/file_manager/sort_files/task.yaml
name: sort_downloads_by_extension
description: |
Move all .pdf files in ~/Downloads to ~/Documents/PDFs.
Move all .jpg files to ~/Pictures/CameraRoll.
Leave other files in ~/Downloads.
reward:
type: file_layout_check
expected:
~/Documents/PDFs: "*.pdf"
~/Pictures/CameraRoll: "*.jpg"
~/Downloads: "!*"
timeout_seconds: 600

这个任务的奖励函数不是「LLM-as-judge」那种黑盒,而是实际检查文件布局——cua 团队显然被 LLM 评测的不稳定性折磨过。

3.4.2 任务环境并行化

cua-bench/Dockerfile + shell.nix 把整个评测环境打包成可重现的容器:

1
2
3
4
5
FROM ubuntu:24.04
RUN apt-get install -y kicad xfce4 python3-pip
COPY cua_bench /opt/cua_bench
COPY datasets /opt/datasets
ENTRYPOINT ["python", "-m", "cua_bench"]

cua 的设计哲学:评测环境必须可重现——一个 task 在 macOS host 上能跑,在 Linux host 上也能跑,结果一致。

3.4.3 KiCad 任务:图形界面的多步推理

最令人印象深刻的是 cua-bench/KiCad-task/——一个电子设计自动化任务集:

Agent 需要在 KiCad(开源 PCB 设计软件)里画一个简单的 LED 电路,从选元件 → 摆放 → 连线 → 生成 Gerber 文件,全程通过点击 GUI 完成。

这个任务的难点

  1. KiCad 界面元素超过 200 种(工具栏、面板、对话框)
  2. 操作需要空间推理(把电阻放在板子哪里?)
  3. 状态空间极大(每次截图 1024x768=786432 像素)

cua 用 KiCad 当 benchmark 显然是为了压榨 VLM 的多步 GUI 规划能力——比 OSWorld 的「订机票」「发邮件」难一个量级。

3.5 Cua-Driver:原生后台模式

libs/cua-driver/ 是 cua 的「特洛伊木马」——它让 Computer-Use Agent 直接操控你正在用的电脑(macOS / Windows),不需要拉 VM。

安装

1
2
3
4
# macOS / Linux
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/trycua/cua/main/libs/cua-driver/scripts/install.sh)"
# Windows
irm https://raw.githubusercontent.com/trycua/cua/main/libs/cua-driver/scripts/install.ps1 | iex

核心能力

  1. 后台模式:Agent 点击不会抢你的鼠标焦点——你写代码,Agent 在后台操作浏览器。
  2. MCP 集成cua-mcp-server 把 cua 能力暴露成 MCP 工具,Claude Code / Cursor / Codex / OpenClaw 都能直接调用。
  3. 跨平台:同一份 CLI + MCP server 在 macOS 和 Windows 上行为一致。

这才是 cua 真正的杀手级特性——前面说的 Lume VM 是「干净环境」方案,cua-driver 是「实战环境」方案。你可以让 Agent 在你的真实工作环境里干活,不用每次都装一套软件


四、横向对比:cua vs Agent-S vs OpenAI Operator

把这三个项目放一起对比,能更清楚地看到 cua 的定位差异。

维度trycua/cuasimular-ai/Agent-SOpenAI Operator
定位Computer-Use 基础设施Computer-Use 单一 AgentComputer-Use SaaS 服务
核心交付SDK + 沙箱 + 基准 + 适配器Planner-Executor 双 Agent云端浏览器 + 闭源模型
OS 覆盖macOS / Linux / Windows / Android任意(依赖 Lume 沙箱)仅 Web 浏览器
模型依赖任意(OpenAI / Claude / HF / MLX)Claude + 自研规划器闭源 computer-use-preview
代码量11 个子项目,~30 万行~5 万行闭源
协议MIT + Apache-2.0Apache-2.0闭源 SaaS
基准Cua-Bench(KiCad 等多任务)OSWorld 72.6% SOTA内部评测(未公开)
沙箱Lume (Apple Virtualization) + Docker + Lumier复用 Lume 沙箱云端 Firefox 容器
使用成本0(开源)+ 云端可选付费0(开源)$200/月 ChatGPT Pro
自定义 Agent✅ 完整 SDK❌ 黑盒 Planner❌ 不可定制
训练能力✅ Cua-Bench 可作 RL 环境❌ 仅推理❌ 闭源
状态活跃(2026-06-12 提交)活跃已商业化

4.1 架构差异

Agent-S(之前我们文章分析过的项目)走的是「双 Agent 协作」路线:

1
2
3
用户目标 → Planner Agent(生成多步计划)
→ Executor Agent(逐步执行 + 反思)
→ OSWorld 评测 → 72.6% SOTA

cua 走的是「平台 + 生态」路线:

1
2
3
4
5
6
7
8
9
任何 VLM 模型

ComputerAgent (cua-agent)

Computer 抽象层(统一 API)

Provider 工厂(VM 来源)

Lume / Docker / Lumier / Cloud

本质差异

  • Agent-S 优化一个 Agent 的能力上限(OSWorld SOTA)
  • cua 降低所有 Agent 的构建门槛(不用自己写沙箱、Provider、Adapter)

4.2 抽象层次差异

OpenAI Operator 走的是「端到端 SaaS」路线——你给它一个目标,它给你一个结果,中间过程完全黑盒。这种模式对终端用户友好,但对研究者/二次开发者毫无价值

cua 走的是「渐进式披露」路线:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Level 1: 只想用现成 Agent
agent = ComputerAgent(model="claude-3-5-sonnet-20241022")
await agent.run("把桌面上的 PDF 都整理到 Documents 文件夹")

# Level 2: 想换模型
agent = ComputerAgent(model="huggingface-local/Qwen/Qwen2.5-VL-7B-Instruct")

# Level 3: 想换 VM 后端
computer = Computer(os_type="linux", provider=VMProviderType.DOCKER, image="trycua/cua-ubuntu:latest")

# Level 4: 想加自定义 callback
agent.callbacks.append(MyCustomTrajectoryLogger())

# Level 5: 想直接操作 Computer 抽象层(不用 Agent)
computer = Computer(os_type="macos")
await computer.left_click(100, 200)
screenshot = await computer.screenshot()

每一层都可以独立使用——这是 cua 设计的精髓。

4.3 一个真实场景的对比

假设你要做自动化 UI 测试——跑 100 个测试用例,每个用例操作一个 Web 应用。

方案实现
OpenAI Operator写 100 个 prompt,付 $200/月,让云端跑。不能调试,不能重放。
Agent-S自己起 Lume 沙箱,搭 OSWorld 评测环境。80% 工作在搭环境,20% 在写 Agent。
cualume run 起 VM → Computer 写操作 → TrajectorySaver 录屏 → 重放 + 断言。80% 工作在写测试逻辑。

这就是「基础设施」的胜利。


五、优缺点:六维评分卡

cua 不是银弹。它有非常清晰的适用场景,也有明显的局限。我从六个维度做诚实的对比:

5.1 架构简洁性 vs 复杂度

优势 ✅劣势 ❌
分层清晰:Agent / Computer / Provider / Backend 四层各司其职概念多:新人需要消化 Computer / Interface / Provider / VMProviderType 4 个核心概念
工厂模式经典InterfaceFactory + VMProviderFactory 都是教科书级应用抽象泄漏LumeProviderDockerProvider 的配置参数差异巨大(macOS 配 display,Docker 配 X11 socket),工厂的「统一接口」承诺打折扣
Provider 可插拔:新增后端只需实现 BaseProvider子项目过多:11 个子项目,新人不知道从哪开始

5.2 扩展性 vs 性能

优势 ✅劣势 ❌
模型可插拔:30 行代码切换 VLM每帧截屏 = 一次网络/进程间通信:本地 Lume 用 HTTP,延迟 50-200ms,对实时性敏感的 RL 训练是瓶颈
OS 可插拔:新增 OS 只需实现 BaseInterfaceProvider 性能差异大:Lume(Apple 原生)≈ 60fps 截屏,Docker(X11)≈ 5-10fps
云端可扩展CloudProvider 支持 VM 池横向扩云端费用:cua 云端 VM 按小时计费,长任务成本不低

5.3 易用性 vs 维护性

优势 ✅劣势 ❌
pip install cua-computer 一行安装macOS VM 镜像更新频繁:Lume 镜像每月更新,breakage 概率 5%
Jupyter Notebook 友好notebooks/ 下有完整教程跨平台测试覆盖不足:CI 主要在 macOS,Windows 路径偶发 bug
文档齐全docs/ 422 个文件,含 OpenAI/Claude 集成指南TypeScript SDK 滞后:Python SDK 是 first-class,TypeScript SDK 功能覆盖约 60%
MIT + Apache-2.0 双协议:商用友好Active development 集中在 Python SDK,Rust(Lume)核心团队较小

5.4 总体评分

维度评分(5 分制)说明
架构清晰度⭐⭐⭐⭐⭐四层金字塔教科书级
性能⭐⭐⭐本地足够,云端贵
文档质量⭐⭐⭐⭐422 个文档文件,覆盖全面
易用性⭐⭐⭐⭐一行启动 VM,但学习曲线中等
可扩展性⭐⭐⭐⭐⭐Adapter + Provider + Callback 三层可插拔
生产就绪⭐⭐⭐适合研究 + 中小规模生产,大规模需自建调度

六、5 分钟跑起来:一个真实可运行的 Demo

光说不练假把式——下面这段代码真实可跑(macOS host + Python 3.11+),帮你验证 cua 全链路。

6.1 安装

1
2
3
4
5
6
7
8
9
10
# 1. 安装 Lume CLI(macOS 虚拟化后端)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/trycua/cua/main/libs/cua-driver/scripts/install.sh)"

# 2. 安装 cua Python SDK
pip install cua-computer cua-agent

# 3. 验证 Lume 能起 macOS VM
lume pull macos-sequoia-vanilla:latest
lume run macos-sequoia-vanilla:latest --cpu 4 --memory 8GB --display 1024x768
# 看到 macOS 桌面后 ctrl+C 退出

6.2 第一个 Agent:让 Claude 操作 Safari

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# demo_cua.py
import asyncio
from computer import Computer
from agent import ComputerAgent

async def main():
# 1. 拉起一台 macOS VM
computer = Computer(
os_type="macos",
provider="lume",
image="macos-sequoia-vanilla:latest",
memory="8GB",
cpu="4",
)
await computer.run() # 等 VM 启动

# 2. 创建 Agent(用 Claude 3.5 Sonnet 当大脑)
agent = ComputerAgent(
computer=computer,
model="claude-3-5-sonnet-20241022",
max_steps=30,
callbacks=[],
)

# 3. 下达目标
async for step in agent.run("打开 Safari,访问 https://cua.ai,截屏保存到 /tmp/cua-screenshot.png"):
print(f"Step: {step.type} - {step.summary}")

# 4. 拿到结果
screenshot = await computer.screenshot()
with open("/tmp/cua-screenshot.png", "wb") as f:
f.write(screenshot)
print(f"Saved screenshot: {len(screenshot)} bytes")

# 5. 关掉 VM
await computer.stop()

asyncio.run(main())

环境变量(在 ~/.zshrc.env):

1
export ANTHROPIC_API_KEY=sk-ant-xxx

跑起来

1
2
3
python demo_cua.py
# 30 秒后:VM 启动完成,Agent 开始操作
# 1-2 分钟后:Safari 打开 cua.ai,截图保存到 /tmp/cua-screenshot.png

6.3 切换到本地 VLM(不依赖云端 API)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# demo_cua_local.py
import asyncio
from computer import Computer
from agent import ComputerAgent

async def main():
computer = Computer(
os_type="linux", # 用 Docker 起 Linux 容器,更轻量
provider="docker",
image="trycua/cua-ubuntu:latest",
)
await computer.run()

# 用本地 Qwen2.5-VL(需要先 vllm serve)
agent = ComputerAgent(
computer=computer,
model="huggingface-local/Qwen/Qwen2.5-VL-7B-Instruct",
api_base="http://localhost:8000/v1", # vLLM endpoint
)

async for step in agent.run("打开终端,跑 `ls -la`,告诉我有多少个文件"):
print(step)

await computer.stop()

asyncio.run(main())

6.4 接 MCP:让 Claude Code 直接操作你的电脑

1
2
3
4
5
6
7
8
9
// ~/.config/claude/mcp.json
{
"mcpServers": {
"cua": {
"command": "cua-mcp-server",
"args": ["--provider", "lume", "--image", "macos-sequoia-vanilla:latest"]
}
}
}

在 Claude Code 里直接说:

“用 cua 起一台 macOS VM,安装 Xcode,截屏给我看启动画面”

Claude Code 会自动调 cua-mcp-server 工具完成。


七、趋势展望:Computer-Use 领域的「Linux 内核」时刻

Computer-Use 赛道 2025-2026 年的爆发,本质上是在重复 2007-2010 年「移动 App 爆发前夜」的故事——开发者需要一个标准化运行时

cua 团队在做的就是这件事:把 VM 生命周期 + OS API + Agent 循环 + 评测基准封装成「Computer-Use 的 Linux Kernel」。

未来 12 个月,我预测三个方向:

7.1 垂直领域适配器

通用 Computer-Use Agent 在 OSWorld 上是 60-70% 准确率,在垂直领域(医疗 PACS 系统、工业 SCADA、金融交易终端)只有 10-20%。cua 的 Adapter 模式天然适合做「领域 fine-tune 后的 VLM 接入」——医院可以基于 Qwen2.5-VL 训练一个 PACS 专用 Adapter,复用 cua 的沙箱 + 评测。

7.2 云端 VM 池调度

cua 现在已经有 CloudProvider,但调度策略还很初级(手动指定 VM 类型)。未来可能演化出 Kubernetes 风格的 Computer-Use Operator——你声明「需要 100 个 macOS VM 跑 RL 训练」,系统自动调度 VM 池 + 镜像缓存 + 结果回收。

7.3 多 Agent 协作的 Computer-Use

当前 cua-agent 是单 Agent循环。一个真实任务(如「整理下载文件夹 + 给老板发邮件 + 更新 Jira」)需要多个 Agent 协作——预计 2027 年会出现基于 cua 的多 Agent 框架,复用 Lume 沙箱做 Actor-Critic 训练。

7.4 竞争格局

  • OpenAI Operator 走 SaaS 路线,跟 cua 几乎不冲突(一个是消费产品,一个是开发者基础设施
  • Anthropic Computer Use纯模型路线,没有沙箱,强依赖 cua 这种基础设施
  • Google Gemini Computer Use 跟 Anthropic 类似的策略
  • Agent-S / UI-Tars算法路线,cua 可以消费他们的模型(已经支持 HF Adapter)

结论:cua 是「卖铲子的人」——只要 Computer-Use 赛道继续热,cua 就有持续价值。


八、结语:基础设施的力量

读完 cua 的源码,最大的感受是:这是一群被「沙箱搭建」折磨过的人,做给「沙箱搭建」折磨着的人用的工具。

cua 没有发明任何新算法——它的 ComputerAgent 用的是最朴素的 screenshot + LLM + tool use 循环;它的 Lume 是对 Apple Virtualization.framework 的朴素封装;它的 Cua-Bench 是对 Gym 的朴素致敬

但它把这些「朴素粘合成了一个工程上完整、文档上详尽、API 上优雅的系统。这正是基础设施层的真正价值——让上层创新者不用重复造轮子

如果你正在做:

  • Computer-Use Agent 研究 → 用 cua 的沙箱 + 基准,省下 3 个月搭环境
  • GUI 自动化测试 → 用 cua-driver + TrajectorySaver,做可重放测试
  • 企业 RPA → 用 cua 的 Computer 抽象 + 自定义 Adapter,跨 OS 一套代码
  • VLM 训练 → 用 Cua-Bench 当训练环境,KiCad 任务当 curriculum

cua 值得你花一周时间深入。


附录:关键资源

License:MIT(核心 SDK)+ Apache-2.0(部分子项目)

最近更新:2026-06-12(commit 活跃,PR 响应快)

对比分析

对比维度

维度Cua 核心架构与设计原理深度解析:为 Computer-Use Agent 打造的全栈基础设施OpenAI OperatorAnthropic Computer Use
沙箱本项目自研主流方案备选
底层 VM本项目设计主流方案备选
开源本项目定位主流方案备选

优缺点

  • Cua 核心架构与设计原理深度解析:为 Computer-Use Agent 打造的全栈基础设施:聚焦本文主题,开箱即用,文档清晰
  • OpenAI Operator:生态最广,社区大,但通用化导致定制成本高
  • Anthropic Computer Use:在某一垂直场景下表现更好

何时选哪个

  • Cua 核心架构与设计原理深度解析:为 Computer-Use Agent 打造的全栈基础设施 当:需要快速落地本文主题场景、希望和已有体系融合
  • OpenAI Operator 当:生态接入优先、有现成插件可复用
  • Anthropic Computer Use 当:对某项指标(性能/隔离/启动)有极致要求

参考资料