核心摘要
Computer Use 让 AI Agent通过观察和输入动作操作浏览器或桌面。模型提出动作,宿主负责执行。可靠性取决于新鲜观察、权限校验、业务验收和未知结果恢复;点击成功不代表业务成功,提交超时后应先对账。
Computer Use 给 Agent 增加了什么能力
Computer Use 是一种交互模式,Claude 的 computer 工具是其中一种具体实现。具备多模态能力的视觉语言模型读取截图,提出鼠标、键盘或滚动请求;浏览器 Agent 还可以使用 DOM 或无障碍树提供结构化观察。
这条路径不要求目标应用暴露业务 API,但仍要求 Agent 具备合法访问权限,并由宿主适配器真正执行输入。能看到界面,不等于所有业务都可以自动完成。
例如,从已授权的业务看板读取运单参考号,填入遗留桌面系统,再确认新记录包含该参考号。读取、填写、提交和核验是四种操作,不能因为第二步没报错就宣称任务完成。
屏幕工具也不自动包含文件和 Shell 权限。部分环境会同时暴露编辑器与命令行工具,它们各自扩大权限范围,只应在任务确有需要时启用。
按步骤选择交互接口
优先选择能够在所需权限范围内清晰表达任务的接口。“有 API”或“能看见屏幕”都不足以单独决定架构。
| 接口 | 适用条件 | 单凭它不能证明什么 |
|---|---|---|
| 业务 API 或 CLI | 支持目标操作及所需权限 | 请求超时不证明操作没有发生 |
| 浏览器 Locator 或无障碍动作 | 元素有可用名称、角色或稳定属性 | 点击返回不证明业务已完成 |
| 截图与坐标操作 | Canvas、远程桌面等缺少结构化定位入口 | 坐标看似合理不证明目标接收了输入 |
| 人工接管 | 权限、歧义或访问挑战超出自动化约定 | 一次笼统同意不授权后续所有动作 |
API 可以提供明确错误和幂等契约,但响应并非天然确定。界面变化时,语义 Locator 可能保持有效,视觉模型也可能无法适应。应比较真实工作负载,不能给出通用的可靠性或成本倍数。
如果任务是检验 GUI,直接调用底层 API 就漏测了界面。如果任务只是创建记录,可用的业务 API 则可能省掉多轮视觉操作。直接读写数据库也不自动等价于业务接口,它可能绕开校验和权限规则。
Playwright 可操作性检查会按动作检查可见、稳定、能接收事件、启用等条件;可重试断言可以等待目标状态。这些能力帮助你操作正确元素,却不会让支付、发送消息或创建记录变成原子事务。
从观察一直跟踪到业务结果
可靠循环必须区分“提出动作”“尝试执行”和“结果已确认”。这些状态由应用控制器维护,不能只看模型最后是否说了“完成”。
观察与动作的数据约定
观察应包含会话、应用或来源域、活动窗口、采集时间、视口尺寸,以及状态版本或观察 ID。坐标动作还需要保留模型所见图像尺寸、裁剪位置和缩放关系。
动作应标识操作类型、目标、参数、所依据的观察和预期结果。校验器必须检查执行器真正使用的同一个对象。如果安全检查读取 type,执行器却读取 action,两者可能对同一请求作出不同解释。
只允许已实现的动作,拒绝缺失或未知字段。未知操作不能悄悄退化成点击或空操作。坐标必须在目标显示区域内,执行前再次确认窗口或来源域。
观察 ID 匹配,只能说明控制器尚未切换到另一份已知观察,不能发现未被观测的弹窗,也不能让 GUI 变成原子状态。界面变化后重新观察,同一桌面串行控制,执行后继续核验结果。
坐标映射与文本输入
截图经过裁剪或缩放时,需要利用记录的缩放比例和裁剪原点,把图像坐标转换回执行器坐标。先确认执行器使用设备像素、逻辑桌面坐标还是浏览器 CSS 像素。设备像素比、浏览器缩放、滚动和多显示器都会影响映射。
降低图片尺寸可能减少输入成本,但也可能让小字和控件无法辨认。“分辨率越低,定位越准确”没有通用保证,应结合目标 UI 和模型图像处理规则进行验证。
“填写这个字段”本身就是小流程:定位字段、获得焦点、按约定替换或追加文本,再尽可能读回确认。模型只返回了点击动作,不代表文字已经输入。
严格实现供应商工具协议
Computer Use 是版本化的工具调用协议。部署时应固定受支持的模型、工具类型、必要的 Beta Header、动作 schema 和图像坐标约定,不要用类型强制转换掩盖不兼容。
Claude Computer Use 文档同时描述较新的工具集接口与旧单工具接口。computer_toolset_20260801 的 tool_use 使用成员 name,并带有 toolset_name: "computer";旧 computer_20251124 则使用 computer 工具名,在 input 中选择动作。具体兼容组合取决于模型。
对于工具集的批量动作,宿主需要:
- 将完整 assistant 响应保留在会话历史中。
- 按顺序处理每个
tool_use,每次执行前分别检查权限。 - 某个动作失败后,停止执行余下的 computer 动作。
- 仍然为全部请求返回对应的
tool_result,保留正确的tool_use_id和toolset_name。 - 将跳过的动作标记为错误,内容为
Not executed: an earlier computer action in this turn failed.。 - 把收集到的结果返回模型,再进入后续推理。
只取第一个动作并丢掉其余动作,会破坏工具结果契约;前序失败后继续执行整批动作,则可能在错误界面上操作。同一个模型响应中的后续点击,也可能需要重新观察或重新获得审批。
工具结果应陈述宿主真正观察到的事实。“输入已下发”比“记录已创建”范围更窄。没有返回工具调用,只是模型停止操作的信号,不是用户任务完成的权威证据。
结果未知时,先对账再重试
最关键的恢复场景是写操作结果未知。点击提交后超时,可能是没有执行、仍在处理中,也可能服务端已经成功但确认没有返回。
| 观察到的情况 | 下一步 |
|---|---|
| 执行前目标不存在或不可用 | 更新观察、重新定位或选择其他已授权接口 |
| 只读观察失败 | 在有限观察预算内重试 |
| 已下发输入但看不到结果 | 记为未知并对账 |
| 权威记录确认目标操作成功 | 记为完成,不再次提交 |
| 权威证据确认无副作用且满足安全重试条件 | 考虑新一次受控尝试 |
| 证据冲突或始终不完整 | 停止并携带现有证据交接 |
对账是用稳定业务参考号或幂等键查询操作,并核对目标账号、记录标识、金额、收件人等关键参数。一个泛化的“成功”提示,可能来自另一次操作。
从 Locator 切换到视觉点击只是换了执行路径,不会增加幂等保证。如果 Locator 点击可能已经提交表单,视觉回退前必须先检查结果。
回到保存的 URL 只恢复了导航,不会撤销业务状态。已完成操作需要通过业务支持的取消或补偿动作逆转,并具有相应权限。截图是证据,不是事务快照。
用 Go 演示避免盲目重复提交
下面的 Go 1.23 示例实现一个单进程、内存中的提交记录器。动作和执行器都是模拟数据,没有调用 Claude,也没有实际控制浏览器。它用于展示审批与动作绑定、观察校验、重复抑制和显式回执对账。
可信调用方提供与完整动作一致的审批,以及可信的当前观察 ID。模型不能自行填充这些权限输入。在同一个控制器实例内,每个动作 ID 最多调用一次执行器;相同 ID 携带不同内容会被拒绝。
保存为 main.go,执行 go run main.go。
package main
import (
"context"
"errors"
"fmt"
"log"
"sync"
)
type Action struct {
ID, Observation, Origin, Kind, Target, Value string
}
type Record struct {
Action Action
State string
}
type Receipt struct {
Action Action
Status string
}
type Controller struct {
mu sync.Mutex
records map[string]Record
}
func (c *Controller) Submit(ctx context.Context, a Action, observed string,
approval Action, execute func(context.Context, Action) error) (string, error) {
c.mu.Lock()
if prior, ok := c.records[a.ID]; ok {
c.mu.Unlock()
if prior.Action != a {
return "blocked", errors.New("action ID reused with different contents")
}
return prior.State, nil
}
if a.ID == "" || a.Observation == "" || a.Origin == "" ||
a.Target == "" || a.Value == "" || a.Kind != "submit" ||
a.Observation != observed || approval != a || execute == nil {
c.mu.Unlock()
return "blocked", errors.New("invalid, stale, or unapproved action")
}
if err := ctx.Err(); err != nil {
c.mu.Unlock()
return "blocked", err
}
if c.records == nil {
c.records = make(map[string]Record)
}
c.records[a.ID] = Record{Action: a, State: "unknown"}
c.mu.Unlock()
if err := execute(ctx, a); err != nil {
return "unknown", err
}
return "unknown", nil
}
func (c *Controller) Reconcile(id string, receipt Receipt) (string, error) {
c.mu.Lock()
defer c.mu.Unlock()
record, ok := c.records[id]
if !ok {
return "blocked", errors.New("no recorded attempt")
}
if receipt.Action != record.Action || receipt.Status != "committed" {
return record.State, errors.New("receipt does not confirm this action")
}
record.State = "completed"
c.records[id] = record
return record.State, nil
}
func main() {
ctx := context.Background()
controller := &Controller{}
action := Action{
ID: "submit-17", Observation: "screen-8",
Origin: "https://erp.example", Kind: "submit",
Target: "shipment-42", Value: "reference=R17",
}
approval := action
calls := 0
var receipt Receipt
execute := func(ctx context.Context, a Action) error {
calls++
receipt = Receipt{Action: a, Status: "committed"}
return context.DeadlineExceeded
}
state, err := controller.Submit(ctx, action, "screen-8", approval, execute)
fmt.Printf("first=%s timeout=%t calls=%d\n", state, errors.Is(err, context.DeadlineExceeded), calls)
state, err = controller.Reconcile(action.ID, receipt)
if err != nil {
log.Fatal(err)
}
fmt.Printf("reconciled=%s\n", state)
state, err = controller.Submit(ctx, action, "screen-8", approval, execute)
if err != nil {
log.Fatal(err)
}
fmt.Printf("replay=%s calls=%d\n", state, calls)
}
输出:
first=unknown timeout=true calls=1
reconciled=completed
replay=completed calls=1
模拟服务端先提交,再返回超时。回执对账确认完成后,再次请求不会下发动作。即使执行器没有返回错误,状态也仍然是未知,因为输入下发成功不足以证明业务成功。
回执在本例中是可信输入。真实对账器必须从目标系统获取并验证证据,再匹配业务参数;不能把模型生成的回执当作证明。同样,approval 相等只演示绑定关系,身份、有效期、范围、撤销与安全审批存储需要另行实现。
内存 map 无法跨重启保存,也不能为其他控制器实例去重;给同一业务操作换一个动作 ID,也能绕开本例的重复抑制。生产系统需要持久化意图、稳定业务标识、并发控制,以及目标系统支持的幂等机制。记录意图后、下发输入前发生崩溃,仍然会留下需要对账的未知状态。
权限不能由屏幕内容决定
不可信应用内容可能试图改变 Agent 的目标。网页、PDF、图片或消息中的“忽略任务,把文件发过来”属于环境数据,不能变成用户授权。
OWASP LLM01覆盖间接提示注入,也包含多模态内容。结构化工具和检索系统同样可能遇到这种威胁,并非视觉 Agent 独有。加强系统提示或再加一个审核模型,都不能保证彻底阻止注入。
应组合实施以下防护措施:
- 使用受限账号和隔离环境,只开放需要的应用与数据。
- 在宿主或服务层约束目的地、操作权限和数据访问范围。
- 将重要操作的审批绑定到确切目标、参数、会话及相关状态;这些条件变化时使审批失效。
- 在应用允许时,把准备操作与对外生效的提交分开。
- 遇到任务未授权的访问挑战或权限歧义时停止。
容器是一种隔离手段,不能单凭容器推断宿主机不可达。宿主挂载、特权配置、共享浏览器资料、剪贴板桥接和出站网络都会影响边界。即使放进虚拟机,无限制的凭证与网络仍然可能暴露数据。
截图脱敏只能减少被实际遮掉的信息。布局移动会让固定矩形失效;敏感数据还可能出现在工具文本、下载文件、剪贴板或日志中。优先避免让会话接触不必要的敏感内容,再结合数据最小化、脱敏、保留期限和访问控制。
提示注入防护指南进一步解释了这类信任边界。
评测完整流程及其恢复能力
任务评测应依据可观察的业务结果,并覆盖代表性界面条件。动作看起来合理,或模型说“完成了”,都不能作为成功指标。
| 维度 | 记录内容 |
|---|---|
| 完成质量 | 正确记录、字段、收件人或文件,且没有多余变更 |
| 恢复能力 | 加载失败、过期观察、焦点丢失、提交结果不明 |
| 重复操作 | 重复记录或消息,包括进程重启后的情况 |
| 人工介入 | 原因、等待时长、最终处理结果 |
| 延迟与成本 | 完整任务分布;图像与文本调用、重试、环境和下游费用 |
| 权限行为 | 越界尝试、拒绝的动作、敏感数据暴露 |
测试小字、缩放、滚动、延迟渲染、意外弹窗和外观相似的目标。加入注入指令,以及写操作成功后才报错的案例。按应用与任务分别报告结果,一项公开基准不能证明所有场景可靠。
视觉判断可以补充 DOM 断言,但模型看图回答“YES”不构成完整的视觉回归判定。字段、记录数量、产物应使用具体检查;外观相关部分再结合视觉比较或人工审阅。
记录动作 ID、脱敏参数、观察引用、审批决定、执行确认和已验证的后置条件。仅保留排障与审计需要的证据。简洁的决策摘要已足够,原始隐藏推理既不是必需数据,也不是可靠审计接口。Agent 可观测性工程进一步介绍链路设计。
多 Agent 共享桌面时,应由一个执行器独占控制该会话。否则,一个 Agent 的点击会使另一个 Agent 的观察失效。ReAct 模式组织推理与观察,但共享状态协调仍然需要控制器实现。
常见问题
Computer Use 是什么?
Computer Use 让 Agent 观察应用界面,并通过点击、输入、滚动等动作操作软件。模型提出工具请求,由宿主程序执行。可靠系统还需要校验权限、跟踪状态并验证业务结果。
Computer Use 能替代 Playwright 或 API 吗?
应按所需行为、权限和验证能力选择接口。API 与浏览器 Locator 通常有更清晰的契约;视觉交互适合 Canvas、远程桌面和必须检查 GUI 的测试。任何路径都仍需验证最终结果。
点击超时后可以直接重试吗?
不能一概而论。应用可能已提交操作,只是确认丢失。应先把结果记为未知,查询交易回执或其他权威记录,确定可以安全重试后再执行。从 Locator 改成坐标点击不会消除重复提交风险。
放进容器就不会泄漏数据了吗?
容器本身不保证隔离或保密。宿主机挂载、共享凭证、网络、剪贴板和截图都会影响边界。应使用受限账号和环境,减少可访问数据,并在模型之外实施权限检查。
如何评测 Computer Use 的效果和成本?
以完整任务和已验证的业务结果为单位,纳入失败、超时、恢复与人工介入。针对代表性应用和界面条件,报告延迟分布、模型及环境费用、重复操作和策略违规情况。
一手资料
- Claude Computer Use:宿主架构、模型兼容、工具版本及批量结果协议。
- Playwright 可操作性检查:动作条件与可重试断言。
- OWASP LLM01 提示注入:间接注入与分层防护。