cua-bench 计算机使用 RL 任务环境搭建指南:用 Python 装饰器与 GUI 脚手架构建可评估的交互任务
【免费下载链接】cuaScale computer-use 2.0 with open-source drivers, cross-OS fleets, and benchmarks for training, evaluation, and data generation.项目地址: https://gitcode.com/GitHub_Trending/cua/cua
导读
本文基于 libs/cua-bench/datasets/cua-bench-basic/click-icon/CLAUDE.md 展开,完整讲解 cua-bench 中构建计算机使用(computer-use)强化学习任务环境的脚手架方法:通过@cb.tasks_config、@cb.setup_task、@cb.solve_task、@cb.evaluate_task四个装饰器定义任务的加载、环境搭建、求解与评估,并用 Tailwind + Iconify 模板编写gui/index.html交互界面。读完本文,你将能够从零搭建一个可被 AI Agent 求解、可产出 0.0~1.0 RL 奖励的任务环境,并理解其底层执行链路与最佳实践。
环境结构总览:main.py 与 gui/ 的双层骨架
cua-bench 用于创建计算机使用 RL 环境,每个任务环境是一个独立目录,固定包含两类文件:
main.py:Python 装饰器承载的任务逻辑(任务配置、环境搭建、求解、评估);gui/:HTML/CSS/JS 构成的 UI,渲染时会自动包含 Tailwind,并套入桌面 webview 窗口模板。
以数据集 libs/cua-bench/datasets/cua-bench-basic 为例,其中每个子目录(click-button、click-icon、fill-form、select-dropdown、drag-drop、color-picker、date-picker、toggle-switch、typing-input、spreadsheet-cell、right-click-menu、drag-slider、video-player等)都是一个独立任务环境,均遵循main.py+gui/index.html+pyproject.toml+CLAUDE.md的标准结构。
main.py中任务函数通过四个装饰器注册到环境注册表。从源码 decorators.py 可以看到,每个环境路径对应一个注册表,包含tasks_config、setup_task、solve_task、evaluate_task四个槽位。加载时,core.py 的 make 函数 会动态导入目标目录的main.py,随后 environment.py 的 make_from_module 遍历模块中带有_td_type标记的函数,按 split 匹配并装配成Environment实例。
四个核心装饰器:任务生命周期的骨架
四个装饰器对应任务的四个生命周期阶段,均支持两种用法:裸用(@cb.tasks_config)或带 split 参数(@cb.tasks_config("train")/@cb.tasks_config(split="test"))。装饰器会为函数附加_td_type与_td_split属性,供make_from_module在对应 split 下发现与装配(见 decorators.py)。
@cb.tasks_config:定义任务清单
返回list[cb.Task],其中description是 AI Agent 实际听到的任务描述(如 "Play 2048"、"Book a hotel"),metadata则保存任务参数(难度、游戏尺寸、系统类型等),用于生成变体:
return [cb.Task(description="Play 2048", metadata={"size": 4, "os_type": "linux"})]Task是定义在 core.py 中的 dataclass,除description和metadata外还支持task_id与computer字段。其中computer字段可以直接声明运行环境(provider 与 setup_config),让任务在reset()时自动创建沙箱,而不必在setup_task里手动调用。
@cb.setup_task:创建沙箱并启动窗口
该阶段只做环境搭建,保持最小化。文档示例:
global pid env.create_sandbox(provider="computer", setup_config={"os_type": "linux", "width": 800, "height": 600}) pid = env.launch_window(html=html_content, title="Game", width=400, height=400) # create webview window从源码看,create_sandbox在 environment.py 中按 provider 名称查找会话类(computers.py 的get_session),以DesktopSetupConfig启动会话,并实例化Bot助手。reset()流程(environment.py)会先读取任务配置,若Task.computer存在则自动创建沙箱,随后调用setup_task_fn,最后返回截图与当前任务供 Agent 观察。
@cb.solve_task:驱动 Agent 求解
从 GUI 侧的 AI 策略获取下一步动作,并用env.step或env.bot执行:
global pid action = env.execute_javascript(pid, "window.__next_move()") while action is not None and action["type"] != "done": if not action or action["type"] == "wait": env.step(WaitAction(seconds=1.0)) elif action["type"] == "click_element": env.bot.click_element(pid, f"#{action['element_id']}") # safest way to click an element elif action["type"] == "click_absolute": env.step(ClickAction(x=action["x"], y=action["y"])) # x,y must be in screen coordinates (requires offsetting by window.screenX and window.screenY) elif action["type"] == "type": env.step(TypeAction(text=action["text"])) action = env.execute_javascript(pid, "window.__next_move()") env.step(DoneAction())这里有几条铁律:
- 只能通过
env.step或env.bot执行求解动作; env.execute_javascript只能调用返回最优动作信息的辅助函数(如返回目标元素,或暴露了window.__next_move()的 AI 策略输出);- GUI 中的
window.__next_move()只应在任务未完成时返回下一步动作,不得自行执行任何动作或修改环境/状态——动作由外层env.step/env.bot执行; window.__next_move()通常由@cb.solve_task装饰的函数循环调用,直至任务完成。
底层链路:env.bot.click_element(bot.py)通过 provider 的 bench-ui 桥接获取元素在屏幕坐标系下的矩形,计算中心点后派发ClickAction;env.step(environment.py)则负责执行动作、记录step:before/step:after轨迹事件(截图 + 窗口快照)、维护step_count,并在超过max_steps时抛出MaxStepsExceeded。
@cb.evaluate_task:从 GUI 状态产出奖励
返回 0.0~1.0 的奖励(RL 偏好该区间):
global pid score = env.execute_javascript(pid, "window.__score") return [float(score)] # 0.0-1.0 range preferred在 environment.py 的 evaluate 方法 中,评估结果会写入 trace 的evaluate事件,并上报遥测:数值结果以>= 0.5作为成功阈值,bool 结果直接映射,dict 结果读取success字段。
gui/ 前端开发规范:语义化、响应式与全局状态
所有游戏/任务逻辑都放在gui/中。HTML 将渲染在 Tailwind + Iconify 模板的桌面 webview 窗口中,不要使用<html>或<body>标签(模板已提供)。
关键模式:
- 语义化 HTML + ARIA 描述:使用
<main>、<section>、<button>、<nav>等语义元素,并添加aria-label、aria-describedby、role属性,既提升可访问性,也便于 Agent 识别元素; - 紧凑响应式设计:使用最小化的 padding/margin(
p-1、p-2、gap-1、gap-2),布局需在弹窗尺寸(300x200)到全桌面尺寸之间自适应;避免固定宽高,使用min-h-0、overflow-auto,确保视口缩小时关键元素仍可见; - 全局状态:将当前得分存入
window.__score(0.0~1.0,供 RL 使用); - AI 基线:在 JavaScript 中实现 AI 策略,通过
window.__next_move()暴露; - 窗口填充:根元素使用
class="flex h-full w-full"填满整个窗口,所有元素保持紧凑响应式(HTML 通常渲染在桌面 webview 窗口或小尺寸移动屏幕中); - 图标:使用
<iconify-icon icon="prefix:name"></iconify-icon>。
以 click-icon/gui/index.html 为例:根元素为<main class="flex flex-col h-full w-full p-6">并带role="main"与aria-label;6 个图标按钮均使用id="icon-{Name}"、aria-label与data-icon-name标记;<script>中将点击结果写入window.__clickedIcon供评估读取——这是"全局状态供评估"模式的典型实现。
Action 类型清单:env.step()可用的动作原语
所有 Action 均为 dataclass,定义在 types.py,并通过cua_bench.__init__从import cua_bench as cb暴露。
鼠标类:
| Action | 参数 | 说明 |
|---|---|---|
ClickAction | x, y | 单击 |
RightClickAction | x, y | 右键单击 |
DoubleClickAction | x, y | 双击 |
DragAction | from_x, from_y, to_x, to_y, duration=1.0 | 拖拽 |
ScrollAction | direction="up\|down", amount=100 | 滚动 |
源码中还提供了MiddleClickAction(x, y)与MoveToAction(x, y, duration=0.0),可作为扩展动作使用。
键盘类:
| Action | 参数 | 说明 |
|---|---|---|
TypeAction | text="hello" | 输入文本 |
KeyAction | key="Enter" | 按键 |
HotkeyAction | keys=["ctrl", "c"] | 组合快捷键 |
控制类:
| Action | 参数 | 说明 |
|---|---|---|
DoneAction | — | 标记任务完成 |
WaitAction | seconds=1.0 | 等待 |
Iconify 图标使用
在 GUI 中使用iconify-icon元素渲染可缩放矢量图标:
<iconify-icon icon="eva:people-outline"></iconify-icon> <iconify-icon icon="mingcute:ad-circle-line" width="24" height="24"></iconify-icon> <iconify-icon icon="mdi:play" class="text-blue-500" style="font-size: 2rem;"></iconify-icon>- 图标会被自动处理并替换为内联 SVG;
- 支持所有 iconify 图标集(eva、mingcute、mdi 等)。
在 click-icon 任务中,图标即任务本体:mdi:home、mdi:settings、mdi:account、mdi:bell、mdi:email、mdi:star分别对应 Home、Settings、Profile、Notifications、Messages、Favorites 六个待点击目标(见 click-icon/main.py)。
屏幕尺寸(Screen Size):setup_config 的分辨率约束
屏幕尺寸在env.create_sandbox的setup_config参数中指定。StandardScreenSize联合类型完整定义于 types.py,覆盖桌面、移动端与历史分辨率:
StandardScreenSize = Union[ # Standard Desktop Resolutions tuple[Literal[1920], Literal[1080]], # Full HD (current default) tuple[Literal[1366], Literal[768]], # HD (laptop standard) tuple[Literal[2560], Literal[1440]], # 2K/QHD tuple[Literal[3840], Literal[2160]], # 4K/UHD tuple[Literal[1280], Literal[720]], # HD Ready tuple[Literal[1600], Literal[900]], # HD+ tuple[Literal[1920], Literal[1200]], # WUXGA tuple[Literal[2560], Literal[1600]], # WQXGA tuple[Literal[3440], Literal[1440]], # Ultrawide QHD tuple[Literal[5120], Literal[1440]], # Super Ultrawide # Mobile/Tablet Resolutions tuple[Literal[1024], Literal[768]], # iPad (portrait) tuple[Literal[768], Literal[1024]], # iPad (landscape) tuple[Literal[360], Literal[640]], # Mobile portrait tuple[Literal[640], Literal[360]], # Mobile landscape # Legacy Resolutions tuple[Literal[1024], Literal[600]], # Netbook tuple[Literal[800], Literal[600]], # SVGA tuple[Literal[640], Literal[480]], # VGA # Additional Common Resolutions tuple[Literal[1440], Literal[900]], # Custom laptop tuple[Literal[1680], Literal[1050]], # WSXGA+ tuple[Literal[1920], Literal[1440]], # Custom 4:3 ratio tuple[Literal[2560], Literal[1080]], # Ultrawide Full HD tuple[Literal[3440], Literal[1440]], # Ultrawide QHD tuple[Literal[3840], Literal[1080]], # Super Ultrawide Full HD ]完整实战案例:click-icon 任务剖析
以 click-icon 为例,演示四个装饰器的组合用法。tasks_config通过列表推导将 6 个图标场景 × 操作系统变体展开为任务清单,并在Task.computer中声明 provider 为native、分辨率 1024x768、背景色#c0c0c0:
return [ cb.Task( description=scenario["description"] + ".", metadata={"icon": scenario["icon"], "name": scenario["name"]}, computer={ "provider": "native", "setup_config": { "os_type": os_type, "width": 1024, "height": 768, "background": "#c0c0c0", }, }, ) for os_type in os_types for scenario in icon_scenarios ]setup_task读取gui/index.html并启动一个 500x400 的 webview 窗口;solve_task直接根据任务 metadata 中的目标图标名,用session.click_element(pid, f"#icon-{icon_name}")点击对应按钮;evaluate_task读取window.__clickedIcon,与期望图标名比对,返回[1.0]或[0.0]。
值得注意:文档中的env.create_sandbox/env.launch_window/env.step是脚手架指南的同步 API 形态,而实际任务代码已演进为异步的session.launch_window、await session.execute_javascript、await session.click_element风格(session即 computers.py 中的DesktopSession)。两者在概念上一一对应,编写新任务时以仓库内实际任务的异步写法为准。
运行与调试
数据集 README 提供两种运行方式:
# 运行指定任务环境 python -m cua_bench.interact click-icon/main.py # 示例 python -m cua_bench.interact click-button/main.py交互模式下(core.py 的 interact)会关闭 headless、开启动作打印,加载环境后自动执行reset()完成 setup,用户按回车后执行evaluate()输出评估结果。任务环境也可通过cb.interact(__file__)(如 click-icon/main.py 所示)直接以脚本方式启动。更完整的批量化评估可通过 runners.py 中的run_benchmark、run_single_task驱动,产出结构化BenchmarkResult/TaskResult。
最佳实践清单
- 保持
main.py最小化:只放装饰器与基础逻辑(环境搭建、任务加载等); - AI 策略放在
gui/的 JavaScript 中,通过window.__next_move()暴露; - 用
window.__score提供 RL 奖励(0.0~1.0 区间); - 通过 Task metadata 参数化变体(难度、尺寸、OS、轮数等);
- 避免滥用
WaitAction:除非任务确实需要(如等待页面加载或等待下一步动作可用)。env.bot助手会自动推进环境(包含等待元素变为可点击的可行动性逻辑); - 坐标约定:所有
x,y均为屏幕坐标(0,0 在屏幕左上角),用window.screenX和window.screenY获取浏览器视口左上角到屏幕左上角的偏移; - 按任务与环境选择合适的分辨率。
小结
cua-bench 的脚手架把"任务定义—环境搭建—Agent 求解—自动评估"压缩为四个装饰器 + 一份 GUI 文件,配合Task.computer声明式沙箱配置与StandardScreenSize分辨率约束,可以快速产出跨 OS、跨分辨率、可参数化的计算机使用 RL 基准任务。本文所讲模式在 cua-bench-basic 的 13 个基础任务(点击按钮、填写表单、选择下拉、拖拽滑块、日期/颜色选择、右键菜单、视频控制等)中均有对应落地实现,可作为进一步参考与复用的起点。
【免费下载链接】cuaScale computer-use 2.0 with open-source drivers, cross-OS fleets, and benchmarks for training, evaluation, and data generation.项目地址: https://gitcode.com/GitHub_Trending/cua/cua
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考