第 27 章:Computer Use

Computer Use 让 Agent 获得"眼睛"和"手",像人一样看屏幕、点鼠标、敲键盘。这是突破 API 边界的终极武器——但也是最容易失控的能力,生产环境必须加沙箱和人工确认点。


你的 Agent 需要帮用户填一个内部报销表单。

问题是——这个表单在一个十年前的老 OA 系统里,没有 API,只有网页界面。开发团队早就离职了,没人敢碰后端代码。

传统 Agent 遇到这种情况只能说:"抱歉,我无法帮您操作这个系统。"

但 Computer Use 改变了游戏规则。它让 Agent 能像人一样:打开浏览器、看到界面、找到输入框、填入数据、点击提交。

我第一次见到这个能力时,有点震惊。Agent 真的在"看"屏幕——它能识别出登录按钮在哪、输入框在哪、下拉菜单怎么操作。这已经不是调 API 了,这是在"使用电脑"。

当然,这也是我见过最危险的 Agent 能力。你想想:一个能随意点击任何按钮的 Agent,如果判断错误,点了"删除所有数据"怎么办?所以这一章我们不仅讲怎么实现,更要讲怎么控制。


27.1 什么是 Computer Use

从 API 调用到界面操作

传统 Agent 通过预定义的 API 与外部系统交互:调用搜索接口、读取数据库、发送消息。每一个操作都有明确的输入输出格式,结果可预测。

但现实世界中,大量应用没有开放 API:

场景例子为什么没有 API
企业老旧系统10年前的 OA/ERP开发团队已离职,没人敢改
桌面软件Excel、Photoshop设计时就不是给程序调用的
第三方网站竞品官网、政府网站人家不想让你自动化
内部工具公司自建的小工具没预算做 API

Computer Use 的本质是:把界面操作这件事,从"人类专属"变成"Agent 也能做"

传统Agent                     Computer Use Agent
    |                              |
    v                              v
+----------+                 +--------------+
| API调用  |                 | 截屏->理解界面|
| 预定义接口|                 | 坐标->点击/输入|
| 结构化响应|                 | 反馈->验证结果|
+----------+                 +--------------+

传统 Agent vs Computer Use Agent

核心能力分解

Computer Use 不是单一能力,而是四个能力的组合:

能力描述技术实现典型失败场景
视觉理解解析屏幕截图,识别 UI 元素多模态 LLM界面元素太小、颜色对比度低
坐标定位确定点击/输入的精确位置边界框检测分辨率/缩放不一致
键鼠操作模拟用户的输入行为浏览器自动化页面加载慢、元素位置变化
状态验证确认操作结果是否正确截屏对比异步加载、动画效果

说白了,Computer Use 就是让 Agent 具备"眼手协调"能力。看到什么,决定做什么,做完再看结果。

和传统自动化的区别

你可能会问:这不就是 Selenium/Playwright 嘛?

不完全一样。传统自动化是"脚本驱动"——你写死了"点击 id=submit-button"。如果按钮 ID 变了,脚本就挂了。

Computer Use 是"视觉驱动"——Agent 看到屏幕上有个蓝色的"提交"按钮,它就去点。按钮换了位置、换了样式,只要还长得像"提交"按钮,它还能找到。

特性传统自动化 (Selenium)Computer Use
定位方式CSS/XPath 选择器视觉识别
脚本依赖必须提前编写Agent 自主决策
界面变化脚本失效自动适应
适用范围只能操作 DOM任何可见界面
成本低(本地计算)高(每帧视觉模型调用)

当然,这种灵活性是有代价的:每一次"看屏幕"都是一次多模态模型调用,成本比 Selenium 高两个数量级。


27.2 架构设计

感知-决策-执行循环

Computer Use 的核心是一个持续的循环,和 ReAct 模式很像,只不过"观察"变成了"看屏幕":

+-----------------------------------------------------------+
|                    Computer Use Agent                      |
+-----------------------------------------------------------+
|  +-----------+    +-----------+    +-----------+          |
|  |   感知层  |--->|   决策层  |--->|   执行层  |          |
|  |  Perceive |    |   Decide  |    |   Execute |          |
|  +-----------+    +-----------+    +-----------+          |
|        |               |               |                   |
|    截屏/OCR         规划/推理       点击/输入              |
|    元素识别        坐标计算        键盘/鼠标              |
|    状态理解        错误处理        结果验证              |
|                       |               |                   |
|        |               |               |                   |
|        +---------------+---------------+                   |
|                   循环继续                                  |
+-----------------------------------------------------------+
                             |
                             v
+-----------------------------------------------------------+
|                    浏览器/桌面环境                          |
|  +--------+  +--------+  +--------+  +--------+           |
|  | Browser|  | Desktop|  |Terminal|  |  Apps  |           |
|  +--------+  +--------+  +--------+  +--------+           |
+-----------------------------------------------------------+

Computer Use Agent 感知-决策-执行循环

三层解耦

在生产系统中,我建议把 Computer Use 分成三层:

Agent 层:负责理解任务、做决策。这是"大脑"。

用户: "帮我在 OA 系统提交报销申请"
Agent:
1. 打开 OA 系统
2. 登录(可能需要用户确认)
3. 导航到"报销申请"
4. 填写表单
5. 提交并验证

工具层:提供基础的浏览器操作能力。这是"手脚"。

# 工具定义
tools = [
    screenshot(),    # 截取当前屏幕
    click(x, y),     # 点击指定坐标
    type(text),      # 输入文本
    scroll(dir),     # 滚动页面
    wait(seconds),   # 等待
]

沙箱层:隔离执行环境,防止越权操作。这是"护栏"。

执行环境:
- 独立的浏览器实例
- 网络隔离(只能访问白名单域名)
- 文件系统隔离
- 超时和资源限制

在多 Agent 系统中的定位

Computer Use 通常作为一个专门的"浏览器 Agent"存在,由 Orchestrator 调度:

+-----------------------------------------------------------+
|              Orchestrator                                  |
|                                                           |
|  任务: "提交报销申请"                                       |
|      |                                                    |
|      v                                                    |
|  +----------------+  +----------------+  +----------------+|
|  | Research Agent |  | Browser Agent  |  | Summary Agent ||
|  | (搜索信息)      |  | (Computer Use) |  | (生成报告)    ||
|  +----------------+  +----------------+  +----------------+|
|                            |                               |
+----------------------------|-------------------------------+
                             | gRPC/HTTP
+--------------------------v---------------------------------+
|           Browser Automation Service                       |
|  (Playwright / CDP / Puppeteer)                           |
+-----------------------------------------------------------+

多 Agent 系统中的 Browser Agent 编排


27.3 多模态模型集成

模型能力要求

Computer Use 需要多模态模型——既能理解图像,又能输出结构化指令。不是所有模型都能做这个。

在 Shannon 的模型配置中,我们标记了哪些模型支持视觉:

# 摘自 config/models.yaml
model_capabilities:
  multimodal_models:
    - gpt-5.1
    - gpt-5-pro-2025-08-07
    - claude-sonnet-4-5-20250929
    - gemini-2.5-flash
    - gemini-2.0-flash

时效性提示 (2026-01): 多模态模型能力变化很快。上面的列表基于 2025 年底的情况,请查阅各厂商官方文档获取最新支持信息。

视觉理解工具设计

工具定义需要包含截屏、点击、输入等基本操作。以下是概念示例:

# 概念示例:Computer Use 工具定义

class ScreenshotTool(Tool):
    """截取当前屏幕或浏览器窗口"""

    def _get_metadata(self) -> ToolMetadata:
        return ToolMetadata(
            name="screenshot",
            description="Capture current screen or browser window",
            category="computer_use",
            requires_auth=True,
            rate_limit=30,  # 每分钟最多30次截屏
            timeout_seconds=5,
            dangerous=False,
            cost_per_use=0.01,  # 视觉模型调用成本
        )


class ClickTool(Tool):
    """在指定坐标执行鼠标点击"""

    def _get_metadata(self) -> ToolMetadata:
        return ToolMetadata(
            name="click",
            description="Click at specified coordinates",
            category="computer_use",
            requires_auth=True,
            rate_limit=60,
            timeout_seconds=2,
            dangerous=True,  # 可能触发不可逆操作
            cost_per_use=0.0,
        )

注意 dangerous=True 标记——点击操作可能触发不可逆的副作用,需要额外的安全检查。

视觉理解的提示词设计

让多模态模型理解屏幕并输出操作指令,需要精心设计的提示词:

# 概念示例:视觉理解提示词

COMPUTER_USE_PROMPT = """
你正在帮助用户完成一个界面操作任务。

当前任务: {task}
历史操作: {history}

请分析当前屏幕截图,决定下一步操作。

输出格式 (JSON):
{
    "observation": "对当前屏幕状态的描述",
    "reasoning": "为什么选择这个操作",
    "action": {
        "type": "click|type|scroll|wait|done",
        "x": 100,  // 如果是 click
        "y": 200,  // 如果是 click
        "text": "要输入的内容",  // 如果是 type
        "direction": "up|down",  // 如果是 scroll
    },
    "confidence": 0.9,  // 对这个操作的信心 (0-1)
    "needs_confirmation": false  // 是否需要用户确认
}

注意:
- 如果看到登录页面,设置 needs_confirmation=true
- 如果看到"删除""提交""付款"等关键按钮,设置 needs_confirmation=true
- 如果对操作位置不确定,设置 confidence 较低值
"""

27.4 浏览器自动化实现

Playwright + Vision LLM 实战

这是一个完整的浏览器自动化循环。注意:这是概念示例,展示核心思路:

# 概念示例:视觉驱动的浏览器自动化

from playwright.async_api import async_playwright
import base64

async def browser_agent(task: str, client, max_iterations: int = 20):
    """视觉驱动的浏览器自动化 Agent"""

    history = []

    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=False)
        page = await browser.new_page()

        for iteration in range(max_iterations):
            # 1. 截图并转换为 base64
            screenshot_bytes = await page.screenshot()
            screenshot_b64 = base64.b64encode(screenshot_bytes).decode("utf-8")

            # 2. 发送给 Vision LLM
            response = await client.messages.create(
                model="claude-sonnet-4-5-20250929",  # 支持视觉的模型
                max_tokens=1024,
                messages=[
                    {
                        "role": "user",
                        "content": [
                            {
                                "type": "image",
                                "source": {
                                    "type": "base64",
                                    "media_type": "image/png",
                                    "data": screenshot_b64,
                                }
                            },
                            {
                                "type": "text",
                                "text": COMPUTER_USE_PROMPT.format(
                                    task=task,
                                    history=history[-5:]  # 只保留最近5步
                                )
                            }
                        ]
                    }
                ]
            )

            # 3. 解析并执行动作
            action = parse_action(response)
            history.append(action)

            # 4. 检查是否需要人工确认
            if action.needs_confirmation:
                confirmed = await request_human_confirmation(action)
                if not confirmed:
                    continue

            # 5. 执行动作
            if action.type == "done":
                break
            elif action.type == "click":
                await page.mouse.click(action.x, action.y)
            elif action.type == "type":
                await page.keyboard.type(action.text)
            elif action.type == "scroll":
                await page.mouse.wheel(0, 300 if action.direction == "down" else -300)
            elif action.type == "wait":
                await asyncio.sleep(action.seconds)

            # 6. 等待页面稳定
            await page.wait_for_load_state("networkidle")
            await asyncio.sleep(0.5)  # 额外等待动画

        await browser.close()

坐标校准:一个被忽视的大坑

不同设备的分辨率和 DPI 缩放不同。模型看到的是 1920x1080 的截图,但实际屏幕可能是 2880x1620(Retina 显示器)。

我见过太多项目在这里翻车:Agent 明明"看到"按钮在 (500, 300),点下去却点到了旁边。

# 概念示例:坐标校准

class CoordinateCalibrator:
    """处理不同分辨率和缩放比例"""

    def __init__(self, screen_width: int, screen_height: int, scale: float = 1.0):
        self.screen_width = screen_width
        self.screen_height = screen_height
        self.scale = scale  # DPI 缩放

    def normalize(self, x: int, y: int) -> tuple[float, float]:
        """归一化坐标 (0-1)"""
        return (x / self.screen_width, y / self.screen_height)

    def to_screen(self, norm_x: float, norm_y: float) -> tuple[int, int]:
        """归一化坐标转实际屏幕坐标"""
        x = int(norm_x * self.screen_width * self.scale)
        y = int(norm_y * self.screen_height * self.scale)
        return (x, y)

最佳实践:总是使用归一化坐标 (0-1) 在 Agent 和执行层之间传递位置信息。实际的像素坐标只在执行层计算。


27.5 安全与风险控制

这是整章最重要的部分。Computer Use 赋予 Agent 巨大的能力,也带来巨大的风险。

风险矩阵

风险类型描述后果缓解措施
误操作点击错误按钮删除数据、发送错误邮件关键操作人工确认
信息泄露截图包含敏感信息密码、个人信息被记录敏感区域遮盖
注入攻击恶意网页诱导 Agent执行危险操作沙箱隔离、白名单
失控循环Agent 陷入无限重试资源耗尽、成本失控最大迭代限制
越权访问访问未授权的系统安全审计问题域名白名单

关键操作需要人工确认

在 Shannon 的设计理念里,有些操作 Agent 不应该自动执行:

# 概念示例:需要人工确认的操作

DANGEROUS_PATTERNS = [
    "delete", "删除", "remove",
    "submit", "提交", "confirm",
    "pay", "付款", "purchase",
    "send", "发送", "email",
    "logout", "登出", "sign out",
]

def needs_confirmation(action: dict, page_text: str) -> bool:
    """判断操作是否需要人工确认"""

    # 1. 模型自己说需要确认
    if action.get("needs_confirmation"):
        return True

    # 2. 点击操作在危险区域
    if action["type"] == "click":
        # 检查点击目标周围的文本
        target_text = extract_text_around(action["x"], action["y"])
        for pattern in DANGEROUS_PATTERNS:
            if pattern in target_text.lower():
                return True

    # 3. 输入敏感信息
    if action["type"] == "type":
        if looks_like_password(action["text"]):
            return True

    return False

OPA 策略保护

可以用 OPA 策略限制 Computer Use 的行为。这是 Shannon 风格的安全边界:

# computer_use.rego

package computer_use

# 禁止的危险区域 (屏幕坐标百分比)
dangerous_zones := [
    {"name": "system_tray", "x_min": 0.9, "y_min": 0.0, "y_max": 0.05},
    {"name": "start_menu", "x_min": 0.0, "x_max": 0.05, "y_min": 0.95},
]

# 禁止的文本输入模式
dangerous_inputs := [
    "sudo", "rm -rf", "format", "DELETE FROM", "DROP TABLE",
]

# 点击坐标检查
deny[msg] {
    input.action == "click"
    zone := dangerous_zones[_]
    in_zone(input.x, input.y, zone)
    msg := sprintf("Click blocked: in dangerous zone '%s'", [zone.name])
}

# 输入内容检查
deny[msg] {
    input.action == "type_text"
    pattern := dangerous_inputs[_]
    contains(lower(input.text), pattern)
    msg := sprintf("Input blocked: dangerous pattern '%s'", [pattern])
}

# 域名白名单
allow[msg] {
    input.action == "navigate"
    input.url == allowed_domains[_]
    msg := "Navigation allowed"
}

27.6 错误恢复与验证

Computer Use 操作可能失败——页面没加载、元素不见了、点错地方了。健壮的系统需要验证循环。

视觉验证循环

# 概念示例:带验证的操作执行

class ComputerUseAgent:
    """带验证的 Computer Use Agent"""

    async def execute_with_verification(
        self,
        action: dict,
        expected_result: str,
        max_retries: int = 3,
    ) -> bool:
        """执行操作并验证结果"""

        for attempt in range(max_retries):
            # 1. 截屏获取当前状态
            before_screenshot = await self.take_screenshot()

            # 2. 执行操作
            await self.execute_action(action)

            # 3. 等待页面响应
            await asyncio.sleep(1.0)
            await self.page.wait_for_load_state("networkidle")

            # 4. 截屏验证结果
            after_screenshot = await self.take_screenshot()

            # 5. 使用视觉模型验证
            verification = await self.verify_action(
                before=before_screenshot,
                after=after_screenshot,
                expected=expected_result,
            )

            if verification["success"]:
                return True

            # 6. 失败则分析原因并尝试恢复
            if attempt < max_retries - 1:
                recovery_action = await self.plan_recovery(
                    verification["error"],
                    before_screenshot,
                    after_screenshot,
                )
                if recovery_action:
                    await self.execute_action(recovery_action)

        return False

常见失败模式和恢复策略

失败模式检测方法恢复策略
元素未加载截图对比无变化等待更长时间
点击位置偏移预期元素未响应重新定位元素
弹窗遮挡识别到弹窗先关闭弹窗
页面跳转URL 变化导航回正确页面
超时操作未完成减少并发、重试

27.7 成本控制

Computer Use 的成本主要来自视觉模型调用。每一帧截图都是一次 API 调用。

成本估算

假设一个简单的表单填写任务,需要 15 步操作,每步都需要截屏分析:

每次截屏分析:
- 输入: ~2000 tokens (图片编码)
- 输出: ~200 tokens (决策)
- 成本: ~$0.01 (使用 claude-sonnet)

15 步操作:
- 截屏分析: 15 * $0.01 = $0.15
- 验证截屏: 15 * $0.01 = $0.15 (如果每步都验证)
- 总计: ~$0.30 per task

对比传统自动化:
- Selenium: 几乎免费 (本地计算)

优化策略

  1. 减少截屏频率:不是每个动作都需要截屏。输入连续文本时,可以一次输入完再截屏验证。

  2. 使用更便宜的模型:简单的元素定位可以用小模型,复杂的决策才用大模型。

  3. 缓存界面状态:如果界面没变化,不需要重新分析。

  4. 批量操作:把多个简单操作合并成一次决策。


27.8 实现方案对比

市面上有几种 Computer Use 实现方式:

特性Vision LLM + Playwright专用 Computer Use API传统 DOM 自动化
视觉理解通用多模态模型专门优化无(依赖选择器)
自主性高(Agent 决策)低(脚本驱动)
元素定位视觉坐标视觉坐标CSS/XPath
复杂页面任意可见界面任意可见界面需要 DOM 访问
成本
维护性无需更新脚本无需更新脚本界面变化需更新

混合方案

实际生产中,我建议混合使用:

  • 已知稳定的界面:用传统 DOM 自动化,快速可靠
  • 未知或变化的界面:用 Computer Use,灵活适应
  • 关键操作:无论哪种方式,都要人工确认

27.9 常见的坑

坑 1:坐标偏移

不同分辨率/缩放下坐标失效。

# 错误:硬编码坐标
await click(890, 62)  # 在其他屏幕上可能偏移

# 正确:使用归一化坐标
normalized = {"x": 0.9, "y": 0.05}
x, y = calibrator.to_screen(normalized["x"], normalized["y"])
await click(x, y)

坑 2:页面加载时机

操作时页面尚未加载完成。

# 错误:点击后立即截图
await click(x, y)
screenshot = await page.screenshot()  # 可能还是旧界面

# 正确:等待页面稳定
await click(x, y)
await asyncio.sleep(0.5)  # 等待动画
await page.wait_for_load_state("networkidle")
screenshot = await page.screenshot()

坑 3:无限重试

错误状态下无限重试消耗大量资源。

# 错误:无退出条件
while not success:
    success = await execute_action()

# 正确:限制重试次数
for attempt in range(3):
    success = await execute_action()
    if success:
        break
    if attempt == 2:
        raise ComputerUseError("Max retries exceeded")

坑 4:敏感信息泄露

截图被发送到 LLM API,可能包含密码等敏感信息。

# 解决方案:敏感区域遮盖
async def safe_screenshot():
    screenshot = await page.screenshot()

    # 检测并遮盖密码输入框
    password_fields = await page.query_selector_all('input[type="password"]')
    for field in password_fields:
        box = await field.bounding_box()
        if box:
            screenshot = cover_area(screenshot, box)

    return screenshot

27.10 回顾

  1. Computer Use 定义:让 Agent 具备视觉理解和界面操作能力,突破 API 边界
  2. 核心循环:感知(截屏)-> 决策(LLM)-> 执行(点击/输入)-> 验证
  3. 坐标校准:使用归一化坐标,处理分辨率和 DPI 差异
  4. 安全防护:危险操作人工确认、OPA 策略限制、域名白名单
  5. 成本意识:每帧视觉调用都有成本,合理控制截屏频率

Shannon Lab(10 分钟上手)

本节帮你在 10 分钟内把本章概念对应到 Shannon 源码。Shannon 目前没有完整的 Computer Use 模块,但相关的工具设计模式可以参考。

必读(1 个文件)

  • config/models.yaml 中的 model_capabilities.multimodal_models:了解哪些模型支持视觉理解

选读深挖(2 个,按兴趣挑)

  • python/llm-service/llm_service/tools/builtin/file_ops.py:参考 dangerous=Truerequires_auth=True 的安全标记设计
  • docs/pattern-usage-guide.md:了解如何在 Shannon 中配置新的工具类型

练习

练习 1:设计安全边界

设计一个 Computer Use 的 OPA 策略,要求:

  • 禁止点击屏幕右上角 5% 区域(通常是关闭/设置按钮)
  • 禁止输入包含 "password" 或 "secret" 的文本
  • 只允许访问指定的 3 个域名

练习 2:故障恢复

设计一个操作失败的检测和恢复流程:

  1. 如何判断"点击没生效"?
  2. 如何区分"页面还在加载"和"操作失败"?
  3. 设计 3 种不同失败场景的恢复策略

练习 3(进阶):成本优化

假设你要用 Computer Use 自动化一个 10 步的表单填写任务,当前每次执行成本 $0.50。设计优化方案,目标是将成本降到 $0.20 以下,同时保持可靠性。


进一步阅读


下一章预告

Computer Use 让 Agent 能操作界面,但写代码是另一个更复杂的场景。

下一章讲 Agentic Coding——让 Agent 理解代码库、编写代码、运行测试、修复 bug。这不是代码补全,而是自主编程。

代码是有结构的:函数调用函数、模块依赖模块。Agent 不仅要会写代码,还要理解代码库的整体架构。

而且,生成的代码必须在沙箱中执行——你不会想让 Agent 在你的生产服务器上 rm -rf / 的。

下一章我们继续。

引用本文 / Cite
Zhang, W. (2026). 第 27 章:Computer Use. In AI Agent 架构:从单体到企业级多智能体. https://waylandz.com/ai-agent-book/第27章-Computer-Use
@incollection{zhang2026aiagent_第27章_Computer_Use,
  author = {Zhang, Wayland},
  title = {第 27 章:Computer Use},
  booktitle = {AI Agent 架构:从单体到企业级多智能体},
  year = {2026},
  url = {https://waylandz.com/ai-agent-book/第27章-Computer-Use}
}