背景:网页任务不是”会点击”就能上线
Computer-use Agent 的价值在于,它可以像用户一样观察网页、移动鼠标、点击按钮、输入文本和滚动页面。相比只调用后端 API 的 Agent,它能覆盖大量没有标准接口、接口权限不完整或仍依赖后台页面的业务流程,例如后台录入、信息核对、订单查询、票据下载和测试环境巡检。
但问题是,浏览器 UI 是一个高噪声环境。按钮可能被弹窗遮挡,列表可能分页,页面可能异步加载,验证码和登录态会打断流程,模型也可能把相似按钮看错。把这类能力直接接入生产系统,常见结果不是”自动化效率提升”,而是出现大量难以复现的误点击和半完成任务。
因此,生产级 Computer-use Agent 不应只关注模型能力,而应关注可执行边界、动作回放、DOM 断言、人工接管和失败恢复。模型负责判断下一步,人写的执行器负责限制动作、校验状态和留下证据。
核心原理:模型决策,执行器兜底
一个稳定的浏览器 Agent 通常由四层组成:
| 层级 | 职责 | 关键能力 |
|---|---|---|
| 观察层 | 提取页面状态供模型理解 | 截图、URL、标题、可见文本、DOM 摘要、可访问性树、网络状态、历史动作 |
| 决策层 | 模型输出结构化候选动作 | 点击、输入、滚动、等待、选择文件、读取页面、请求人工确认 |
| 执行层 | 用浏览器自动化框架执行动作 | Playwright/Selenium/CDP 执行、选择器解析、可点击性检查、超时控制、域名白名单、DOM 断言、截图留存 |
| 治理层 | 记录全链路可审计证据 | 动作日志、截图、trace、失败原因、人工接管记录、最终产物 |
关键点是:不要让模型直接拥有无限浏览器控制权。模型可以建议动作,但执行器必须决定动作是否允许、是否需要确认、是否满足前置条件。
工程落地:从一次性点击变成可审计流程
1. 为每一步动作建立结构化信封
生产系统中,不建议让模型只返回”点击提交按钮”。更稳的做法是要求模型返回动作信封,包含动作类型、目标元素、预期状态、风险等级和失败处理方式。
{
"step_id": "step_008",
"action": "click",
"target": {
"role": "button",
"name": "Search",
"fallback_selector": "button[type='submit']"
},
"preconditions": [
"current_url_host == 'admin.example.com'",
"input[name='keyword'] is visible"
],
"expected_after_action": [
"result table is visible",
"network idle or loading spinner disappears"
],
"risk_level": "low",
"handoff_required": false,
"timeout_ms": 8000
}
这个结构有两个作用。第一,执行器可以在动作前拒绝越权动作。第二,失败后可以明确知道失败发生在”找不到元素""元素不可点击""点击后状态不符合预期”还是”模型目标判断错误”。
2. 用 DOM 断言降低视觉误判
截图适合帮助模型理解页面,但生产执行不能只依赖坐标点击。坐标点击在页面缩放、滚动位置、广告插入、弹窗和响应式布局下都容易漂移。
更稳的路径是:模型提出目标,执行器优先映射到 DOM 或可访问性节点。例如通过 role、label、text、test id、CSS selector 或 XPath 找到元素,再由浏览器自动化框架检查元素是否可见、稳定、可接收事件和已启用。
import { expect, Page } from "@playwright/test";
type AgentAction = {
step_id: string;
action: "click" | "type" | "wait";
target?: { role?: string; name?: string; fallback_selector?: string };
value?: string;
timeout_ms?: number;
};
export async function executeAgentAction(page: Page, action: AgentAction) {
const timeout = action.timeout_ms ?? 8000;
if (action.action === "click") {
const locator =
action.target?.role && action.target?.name
? page.getByRole(action.target.role as any, { name: action.target.name })
: page.locator(action.target?.fallback_selector ?? "");
await expect(locator).toBeVisible({ timeout });
await expect(locator).toBeEnabled({ timeout });
await locator.click({ timeout });
return;
}
if (action.action === "type") {
const locator = page.locator(
action.target?.fallback_selector ?? "input, textarea"
).first();
await expect(locator).toBeVisible({ timeout });
await locator.fill(action.value ?? "", { timeout });
return;
}
if (action.action === "wait") {
await page.waitForLoadState("networkidle", { timeout });
}
}
这里的重点不是代码复杂度,而是执行策略:模型不直接操作坐标,执行器先找到可验证的页面对象,再执行动作。
3. 把动作回放作为一等产物
浏览器 Agent 最难排查的问题是”昨天能跑,今天失败;日志只说点击失败”。生产环境要把每一次执行都保存成可回放轨迹。
建议至少记录以下信息:
- 任务输入、模型版本、系统提示词版本
- 每步的页面 URL、截图、DOM 摘要
- 模型输出的动作与执行器实际执行的动作
- 断言结果、网络错误、控制台错误
- 人工接管点和最终结果
动作回放不是为了”看热闹”,而是为三类问题提供证据:
- 页面变化:按钮文案、DOM 层级、分页逻辑或登录流程变了
- 模型误判:把取消按钮当成确认按钮
- 执行器问题:选择器过宽、等待条件不稳定或超时时间过短
4. 用人工接管处理不可逆动作
网页 Agent 很容易遇到不可逆操作:提交订单、发送邮件、删除记录、改配置、授权登录、下载含隐私的数据。这类动作不应让模型自动完成。
更合理的做法是把动作分成三类:
| 风险等级 | 示例 | 处理方式 |
|---|---|---|
| 低风险 | 搜索、翻页、打开详情、读取状态 | 自动执行 |
| 中风险 | 批量导出、保存草稿、更新非关键字段 | 规则校验后执行 |
| 高风险 | 支付、删除、提交正式表单、发送外部消息、访问敏感账户 | 暂停并交给人工确认 |
人工接管不是失败,而是系统设计的一部分。接管界面应展示任务目标、当前截图、模型计划、待执行动作、风险说明和可选按钮:批准、拒绝、改写指令、手动完成、终止任务。
5. 用失败分类驱动重试,而不是盲目重跑
浏览器自动化失败后,不应直接从头重跑。重跑可能放大副作用,例如重复提交、重复下载、重复发送。
建议把失败分为以下几类:
| 失败类型 | 说明 | 建议处理 |
|---|---|---|
| 观察失败 | 截图或 DOM 获取失败 | 短暂重试 |
| 定位失败 | 目标元素找不到 | 刷新观察后让模型重新判断 |
| 动作失败 | 元素不可点击、被遮挡、超时 | 尝试关闭弹窗、滚动或等待 |
| 断言失败 | 动作执行了但页面状态不符合预期 | 停止并进入人工复核 |
| 权限失败 | 登录、403、验证码、二次认证 | 直接人工接管 |
| 副作用不确定 | 点击后网络中断或页面无响应 | 查询结果状态,不能盲目重试提交 |
这个分类决定了系统是否重试、是否恢复、是否人工接管,以及是否把样本加入回归集。
适用场景
适合的场景:
- 后台系统没有稳定 API,但有可操作页面
- 流程存在页面变化,需要模型读懂语义
- 任务频率中等,但人工重复成本高
- 业务允许人在关键节点确认
- 失败后可以通过回放定位原因
不适合的场景:
- 高频低延迟交易
- 强一致写操作
- 验证码密集流程
- 需要绕过网站限制的任务
- 含大量敏感数据的页面
- 缺少审计能力的内部系统
常见误区
-
把浏览器 Agent 当作”万能 RPA”:RPA 强在确定性流程,Computer-use Agent 强在处理变化和语义判断。把所有稳定流程都交给模型,成本和风险都偏高。
-
只保存最终结果,不保存过程:没有动作回放,失败样本无法复现,也无法判断是模型问题、页面问题还是执行器问题。
-
让模型直接执行高风险动作:只要涉及钱、权限、外部发送、删除、正式提交,就应设置人工确认或双人审批。
-
只用截图,不用 DOM:截图有助于理解,但生产执行最好落到可验证元素和断言上,否则页面小变化就会导致坐标漂移。
-
把重试当作可靠性方案:浏览器任务有副作用,失败后必须先确认状态,再决定是否重试。
上线检查清单
执行边界
- 是否使用独立浏览器、虚拟机或容器环境
- 是否配置域名白名单和下载目录限制
- 是否禁止模型访问密码、Cookie、密钥和个人隐私文件
- 是否区分只读、低风险写入和高风险写入
动作治理
- 每一步动作是否有结构化记录
- 是否优先使用 DOM、role、label、test id 或可访问性节点执行
- 是否有动作前置条件和动作后断言
- 是否对不可逆动作强制人工确认
失败恢复
- 是否区分观察失败、定位失败、动作失败、断言失败和副作用不确定
- 是否能从失败步骤恢复,而不是只能从头重跑
- 是否保存截图、DOM 摘要、trace、网络错误和控制台错误
- 是否能把失败样本转成回归测试用例
安全与审计
- 是否记录模型版本、提示词版本和策略版本
- 是否能查询每个任务谁发起、谁审批、执行了哪些动作
- 是否对下载文件、上传文件和跨域跳转做额外审查
- 是否有手动中止、暂停和接管机制