Codex Computer Use 实机体验记录

Codex Computer Use 实机体验记录

日期:2026-09-24
被测对象:codex-cua(把 Codex 的 Windows Computer Use 封装成的 MCP server)
目的:作为后续与 windows-mcp 对比的基线


一、被测对象的来路

项 值
MCP server D:\codex-cua-mcp\server.mjs(手写 JSON-RPC over stdio,零依赖)
载荷 D:\Codex-26.917\app\resources\cua_node\bin\node_modules\@oai\sky
链路 WindowsHelperTransport → codex-computer-use.exe → codex app-server(经 CODEX_CLI_PATH) → UIA + SendInput + Windows.Graphics.Capture
来源 官方 MSIX OpenAI.Codex_26.917.9434.0_x64(Microsoft Store 交付通道,SHA-1 校验通过)
工具数 13

二、测试任务

用 codex computer use 走完整流程:写文章 → 打开 Gridea 新建 → 填入标题正文 → 找封面 → 提交 → 同步上线。

分工

  • Gridea 的 GUI 全流程:codex computer use(约 30+ 次工具调用)
  • 浏览器部分:另配的 chrome-devtools-edge MCP(codex 的浏览器路径被策略闸门锁死,见第五节)

结果

全部完成。文章已发布并推送上线(commit 384c08b)。


三、操作过程记录

3.1 无阻碍的部分

Gridea 从启动到同步,30+ 次调用零失误:

  • launch_app 启动 → list_windows 定位窗口
  • get_window_state(include_text + include_screenshot) 读无障碍树 + 截图
  • 坐标点击:新文章按钮、标题框、正文区、文章设置、封面字段、发布、同步
  • type_text 输入约 4000 字中文正文(一次性输入,无丢字)

无障碍树质量很好,带元素索引和本地化标签:

6 按钮 最小化
7 按钮 恢复
8 按钮 关闭

3.2 感知层开销

单次 get_window_state(截图 + 无障碍树):

  • 耗时 339ms
  • 无障碍树 252 字符
  • 截图 1440×853(jpeg,base64 约 357KB)

四、★ 人工观察反馈:鼠标运动

这是本次体验中主观感受最强的一点。

Codex MCP 是真实鼠标控制。传入鼠标位置(从一点到另一点)时,它会流畅地把鼠标从这一点移到另一点,而不是瞬移,并且感觉像是沿着一条设计过的曲线,像人在移动。作为观看者看起来非常爽。

佐证

这个观察在二进制里能对上证据。codex-computer-use.exe 的字符串里有:

CODEX_CUA_CURSOR_FORCE_WARPF

WARP 在 Win32 里正是「瞬间置位光标」的系统调用(SetCursorPos 语义)。存在一个 FORCE_WARP 开关,说明默认行为不是瞬移,而是插值/动画移动;只有显式强制时才降级为 warpf。

也就是说,「像人一样移动」不是错觉,是默认实现。

为什么这点重要

  • 可观测性:观看者能看清 agent 正要做什么,而不是光标突然闪现
  • 可控感:中途能反应过来去按 Esc 打断
  • 信任感:动作有过程、可预期,不像「背后有人瞬间接管了机器」

对做 CUA 产品来说,这是一个容易被忽略但感知极强的体验维度 —— 它不提升任务成功率,但显著影响人的观感。

待后续验证

等 windows-mcp 跑同一流程时,重点观察它的光标是「瞬移」还是「移动」。如果它瞬移,就构成一个明确的体验差异点。


五、发现的硬限制:浏览器策略闸门

对浏览器窗口调 get_window_state 直接被拒,且 retry 无效:

Computer Use has been stopped for this turn because it could not determine
the current browser URL on Windows with enough confidence to enforce policy.

错误文案还要求「停止继续下发输入」。

这是刻意设计的安全闸门:浏览器场景下,helper 必须先确定当前 URL 才能判断该不该放行;确定不了就直接终止整个 turn。

结论:通过这条通道做浏览器自动化基本不可用。Codex 把浏览器交给独立的 Chrome 插件(需要 Chrome + ChatGPT 扩展 + 原生宿主三件套,本机 Chrome Canary 未装该扩展),桌面应用才走 computer use。


六、API 层面的两个坑

6.1 click 必须给坐标

文档说 element_index 与坐标二选一,但实际单独传 element_index 报:

ERROR: parse click params: missing field `x`

这个构建里坐标是必填的,索引只是补充。全程只能用截图定位坐标。

6.2 审批通道是硬依赖

helper 强制要求宿主提供 elicitation 回调,否则任何触碰具体 app 的调用都被拒:

Computer Use requires app approval but elicitations are unavailable

设计上审批是逐应用且执行中途反向发起的:list_apps 不需要审批;一旦要碰某个 app,helper 在调用过程中弹一次 Allow Codex to use X?。我的 server 实现了这条通道(默认拒绝,CUA_AUTO_APPROVE=1 放行 + 审计日志)。


七、环境层面踩的坑(与工具本身无关)

问题 根因 处理
同步失败 proxyconnect 127.0.0.1:7892 refused Gridea 站点配置里写死了失效代理 改 E:\documents\Gridea\config\setting.json 的 proxyURL → 7890
同步失败 Invalid username or token GitHub token 过期 用户补新 token
Gridea 不认裸 Windows 路径当封面 封面字段只对 URL 渲染预览 改用图片 URL

特别记一笔:代理那个坑排查花了不少轮次,因为环境变量看起来是对的(HTTP_PROXY 已是 7890),误导性很强。实际是 Gridea 自己的 setting.json 里存了 proxyEnabled + proxyURL,优先级高于环境变量。


八、小结:codex computer use 的能力画像

强项

  • 非浏览器桌面应用全流程稳定,无障碍树质量高
  • 感知层轻(339ms / 252 字符树 / 一次截图)
  • 逐应用审批,安全边界清晰
  • ★ 鼠标运动拟人化,观感好

限制

  • 浏览器完全不可用(策略闸门,非配置问题)
  • click 坐标必填,与文档不符
  • 依赖 codex app-server 在背后跑
  • 载荷不公开分发,只能从官方安装包解出来

九、后续对比要点

让 windows-mcp 跑同一流程时,重点比对:

  1. 鼠标运动方式 —— 瞬移还是插值?这是本次最突出的人工感受差异点
  2. 定位方式 —— 它的 Click 也支持 label 走 UIA,和 codex 的索引/坐标双寻址对比
  3. 感知开销 —— 它的 Snapshot 是整屏还是单窗口?token 量级对比
  4. 浏览器能力 —— 它没有策略闸门,理论上能跑浏览器部分;看它怎么处理
  5. 流程顺畅度 —— 有没有卡顿、误点、需要人工救场

十、★ 人工观察反馈:交互通道断裂问题

这是比鼠标运动更根本的一个问题,来自用户的直接反馈。

现象

Agent 用 computer use 接管鼠标期间,用户看不到 Claude Code 的对话窗口 —— 他的注意力在屏幕上被自动化的那个应用上。

于是形成一个结构性矛盾:

  • Agent 如果在聊天里停下提问 → 用户看不到 → 等于对着空气说话
  • 用户也不敢打断 agent → 怕影响正在进行的鼠标操作

结果:需要询问时,沟通通道实际上是断的。

用户提出的正确做法

应当弹一个弹窗,或者浮一个模态窗在上面询问。

为什么模态窗是对的(用户自己点出了关键)

浮出这模态窗,我就知道你暂时不需要鼠标控制权了,我就可以使用鼠标来回复你。

这是很精确的洞察:模态窗在这里不只是"显示一段文字",它同时是一个控制权交接信号。

  • 模态窗出现 = agent 已释放鼠标 = 用户可以安全接管
  • 不需要用户去猜"我现在能不能动鼠标"

设计含义

CUA 的询问通道不能复用聊天界面。它必须是一个:

  1. 可见的 —— 出现在用户当前正在看的屏幕上(置顶/模态)
  2. 可交互的 —— 用户能用鼠标直接回复
  3. 有控制权语义的 —— 它的出现本身就宣告"鼠标空出来了"

本质上:询问 UI 就是控制权交接协议。

与实现的关联

codex-cua 的 server 里已经有一条 elicitation 通道(globalThis.nodeRepl.config.createElicitation),当前实现是「默认拒绝 / CUA_AUTO_APPROVE=1 放行 + 审计日志」。这条通道天然就是挂模态窗的正确位置 —— 它本来就是在动作执行中途、由 helper 反向发起、需要人回答的询问点。

「默认拒绝 / 自动放行」这个二选一恰恰是当前实现的缺陷:它没有第三条路「弹窗问人」。补上模态窗,既解决了本节的交互问题,又让逐应用审批真正可用(不必靠 CUA_AUTO_APPROVE=1 全放开)。

待后续验证

windows-mcp 跑同一流程时,观察它是否需要中途询问、以及用什么形式呈现。如果它只会在聊天里问,那就是同一个断链问题。