GPT-5.4 Computer Use 实战:3 步让 AI 操控浏览器帮你干活 🖥️

上周五 OpenAI 发布 GPT-5.4 的时候,我盯着 Computer Use 的 demo 看了整整半小时------AI 自己打开浏览器、点按钮、填表单、截图验证结果,全程不需要人干预。

说实话,之前 Claude 的 Computer Use 我就体验过,但那个延迟和准确率劝退了不少人。这次 GPT-5.4 直接把 OSWorld 基准测试干到 75%,超过人类的 72.4%。我当天晚上就开始折腾 API,踩了不少坑,今天把完整的接入流程和代码分享出来。

先说结论

特性 GPT-5.4 Computer Use Claude Computer Use
OSWorld 准确率 75.0% 22.0%
上下文窗口 1M tokens 200K tokens
响应速度 较快(结构化动作) 较慢(截图循环多)
API 价格 $2.50/M 输入 $3/M 输入
适用场景 浏览器自动化/桌面操控 通用桌面操控

简单说:GPT-5.4 的 Computer Use 目前是最能打的方案,尤其适合浏览器自动化场景。

什么是 Computer Use?

Computer Use 不是传统意义上的 Selenium/Playwright 自动化。传统方案你需要写选择器、处理各种异常,一旦页面改版就全废了。

GPT-5.4 的 Computer Use 完全不同------它看截图,然后告诉你该点哪里、该输入什么。就像一个远程协助的真人,只不过反应速度比真人快几十倍。

工作流程是这样的:

markdown 复制代码
你发任务 → 模型看截图 → 返回操作指令(点击/输入/滚动)
    ↑                                    ↓
    └──── 执行操作,再截一张图 ←──────────┘

这个循环一直转,直到任务完成。

第 1 步:环境准备

安装依赖

bash 复制代码
pip install openai playwright
playwright install chromium

配置 API Key

bash 复制代码
export OPENAI_API_KEY="sk-proj-xxxxx"

如果你在国内,直接调 OpenAI 官方 API 延迟会比较高,可以用兼容 OpenAI 协议的中转服务,改个 base_url 就行:

python 复制代码
from openai import OpenAI

# 方式一:直连 OpenAI(需要网络条件)
client = OpenAI()

# 方式二:用 ofox.ai 的聚合接口,国内直连低延迟
client = OpenAI(
    base_url="https://api.ofox.ai/v1",
    api_key="你的 ofox key"
)

启动隔离浏览器

这一步很关键------一定要用隔离环境。Computer Use 会操控你的浏览器,如果用日常浏览器,AI 一不小心就把你的 GitHub 仓库删了(别问我怎么知道的)。

python 复制代码
from playwright.async_api import async_playwright
import asyncio

async def launch_browser():
    pw = await async_playwright().start()
    browser = await pw.chromium.launch(
        headless=False,  # 设 True 跑生产,False 方便调试
        args=[
            "--disable-extensions",
            "--no-first-run",
            "--disable-default-apps",
        ]
    )
    context = await browser.new_context(
        viewport={"width": 1440, "height": 900}  # 推荐分辨率
    )
    page = await context.new_page()
    return pw, browser, page

为什么推荐 1440x900?因为 OpenAI 官方文档明确说这个分辨率下模型的点击准确率最高。

第 2 步:核心代码------截图-操作循环

这是完整的 Computer Use 调用代码:

python 复制代码
import base64
import asyncio
from openai import OpenAI
from playwright.async_api import async_playwright

client = OpenAI()  # 或指向你的中转服务

async def take_screenshot(page) -> str:
    """截图并转 base64"""
    screenshot_bytes = await page.screenshot()
    return base64.b64encode(screenshot_bytes).decode("utf-8")

async def execute_action(page, action):
    """执行模型返回的操作指令"""
    action_type = action.get("type")

    if action_type == "click":
        x, y = action["x"], action["y"]
        button = action.get("button", "left")
        await page.mouse.click(x, y, button=button)
        print(f"  🖱️ 点击 ({x}, {y})")

    elif action_type == "type":
        text = action["text"]
        await page.keyboard.type(text, delay=50)
        print(f"  ⌨️ 输入: {text[:30]}...")

    elif action_type == "keypress":
        keys = action["keys"]
        for key in keys:
            await page.keyboard.press(key)
        print(f"  ⌨️ 按键: {keys}")

    elif action_type == "scroll":
        x = action.get("x", 0)
        y = action.get("y", 0)
        await page.mouse.wheel(x, y)
        print(f"  📜 滚动 ({x}, {y})")

    elif action_type == "drag":
        start = action["start"]
        end = action["end"]
        await page.mouse.move(start["x"], start["y"])
        await page.mouse.down()
        await page.mouse.move(end["x"], end["y"])
        await page.mouse.up()
        print(f"  🔀 拖拽 ({start['x']},{start['y']}) → ({end['x']},{end['y']})")

    elif action_type == "wait":
        ms = action.get("ms", 1000)
        await asyncio.sleep(ms / 1000)
        print(f"  ⏳ 等待 {ms}ms")

    elif action_type == "screenshot":
        print("  📸 模型请求截图")

async def computer_use_loop(page, task: str, max_turns: int = 20):
    """Computer Use 主循环"""

    # 第一步:截图 + 发送任务
    screenshot_b64 = await take_screenshot(page)

    response = client.responses.create(
        model="gpt-5.4",
        tools=[{"type": "computer"}],
        input=[
            {
                "role": "user",
                "content": task
            }
        ],
        # 附带初始截图
        truncation="auto"
    )

    for turn in range(max_turns):
        # 检查是否有 computer_call
        computer_calls = [
            item for item in response.output
            if item.type == "computer_call"
        ]

        if not computer_calls:
            # 没有操作指令了,任务可能完成
            text_outputs = [
                item for item in response.output
                if hasattr(item, "content")
            ]
            if text_outputs:
                print(f"\n✅ 任务完成!模型回复:")
                for t in text_outputs:
                    print(t.content)
            break

        # 执行所有操作
        for call in computer_calls:
            print(f"\n[Turn {turn + 1}] 执行操作批次:")
            for action in call.actions:
                await execute_action(page, action)
                await asyncio.sleep(0.3)  # 操作间隔,模拟真人

            # 执行完截图,发回给模型
            await asyncio.sleep(1)  # 等页面渲染
            screenshot_b64 = await take_screenshot(page)

            response = client.responses.create(
                model="gpt-5.4",
                previous_response_id=response.id,
                input=[{
                    "type": "computer_call_output",
                    "call_id": call.call_id,
                    "output": {
                        "type": "computer_screenshot",
                        "image_url": f"data:image/png;base64,{screenshot_b64}",
                        "detail": "original"  # 保持原始分辨率
                    }
                }]
            )
    else:
        print("⚠️ 达到最大轮次限制")

# 使用示例
async def main():
    pw, browser, page = await launch_browser()

    await page.goto("https://www.google.com")
    await asyncio.sleep(2)

    await computer_use_loop(
        page,
        "搜索 'Python FastAPI tutorial 2026',打开第一个结果,总结页面内容"
    )

    await browser.close()
    await pw.stop()

asyncio.run(main())

第 3 步:实际跑起来看效果

我用上面的代码跑了几个实际场景:

场景 1:自动填写表单

python 复制代码
await computer_use_loop(
    page,
    "打开 https://httpbin.org/forms/post,填写表单:Customer 填 'Zhang San',Size 选 Medium,Topping 选 Bacon,点击提交"
)

模型一共用了 4 轮截图循环就搞定了:截图→定位输入框→逐个填写→点提交。全程大概 15 秒。

场景 2:抓取动态加载的数据

之前用 Selenium 写爬虫,最烦的就是等 AJAX 加载完成。Computer Use 天然解决这个问题------它看截图判断页面是否加载完,不用写一堆 WebDriverWait

python 复制代码
await computer_use_loop(
    page,
    "打开 GitHub Trending 页面,找到今天 Star 最多的 Python 项目,告诉我项目名和 Star 数"
)

场景 3:跨页面工作流

python 复制代码
await computer_use_loop(
    page,
    """
    1. 打开 GitHub,搜索 'fastapi'
    2. 进入 tiangolo/fastapi 仓库
    3. 查看最新的 Release 版本号
    4. 回到搜索结果,查看第二个结果的 Star 数
    5. 对比两个项目,告诉我哪个更活跃
    """
)

这种多步骤跨页面的任务,传统自动化写起来巨麻烦,Computer Use 就是一段自然语言描述。

踩坑记录

坑 1:分辨率很重要

一开始我用 1920x1080,模型经常点歪,后来换成 1440x900 好了很多。OpenAI 文档里说可以缩放截图,但一定要重新映射坐标

python 复制代码
# 如果你缩放了截图,坐标也要按比例调整
scale_x = original_width / screenshot_width
scale_y = original_height / screenshot_height
actual_x = action["x"] * scale_x
actual_y = action["y"] * scale_y

坑 2:detail 参数别省

发送截图的时候,detail 一定要设成 "original",不然模型看到的是压缩后的模糊图,点击位置会偏。虽然 "original" 会多消耗 token,但省这点钱不值得。

坑 3:操作间隔不能太快

每个操作之间至少加 300ms 延迟。不是因为模型需要,而是浏览器渲染需要时间。点击一个按钮后页面可能要弹窗、跳转、加载数据,太快截图会截到中间状态,模型就懵了。

坑 4:安全隔离是认真的

千万不要在你的日常浏览器里跑 Computer Use。用一个干净的 Playwright 浏览器实例,或者更稳妥------用 Docker 跑个隔离环境:

dockerfile 复制代码
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y xvfb x11vnc firefox xdotool
ENV DISPLAY=:99
CMD Xvfb :99 -screen 0 1440x900x24 & x11vnc -display :99 -nopw -forever &
EXPOSE 5900

然后 VNC 连进去观察 AI 在干嘛,眼见为实。

坑 5:费用控制

Computer Use 每轮都要发截图(按 image_url 计费),一个复杂任务跑 15-20 轮,token 消耗蹭蹭涨。建议:

  • 简单任务设 max_turns=10
  • 截图前缩放到合理尺寸(但不能太小)
  • previous_response_id 利用缓存,缓存命中的输入 token 只要 $0.25/M,比原价省 90%

GPT-5.4 三个版本怎么选?

版本 价格 (输入/输出) 适用场景
GPT-5.4 <math xmlns="http://www.w3.org/1998/Math/MathML"> 2.50 / 2.50 / </math>2.50/15 日常 Computer Use,性价比最高
GPT-5.4 Thinking 同上 + 推理token 复杂决策、多步规划
GPT-5.4 Pro <math xmlns="http://www.w3.org/1998/Math/MathML"> 30 / 30 / </math>30/180 极端复杂任务,一般用不上

我的建议是先用标准版跑,90% 的场景够用了。只有那种需要"想一想再做"的复杂工作流,才需要 Thinking 版。

小结

GPT-5.4 的 Computer Use 确实是一个质变------从"AI 只能聊天"到"AI 能帮你操作电脑"。虽然现在还有一些限制(延迟、费用、偶尔点歪),但已经能覆盖很多实际场景了:表单填写、数据抓取、跨应用工作流。

我现在已经把一些重复性的浏览器操作都用 Computer Use 自动化了,真的省了不少时间。如果你也想尝试,建议先从简单的单页面任务开始,熟悉了截图-操作的循环模式,再逐步上复杂场景。

完整代码我放在 Gist 上了,有问题评论区见 👇

相关推荐
进击的尘埃2 小时前
Service Worker 离线缓存这事,没你想的那么简单
javascript
进击的尘埃2 小时前
HTTP/3 的多路复用和 QUIC 到底能让页面快多少?聊聊连接迁移和 0-RTT
javascript
Maxkim3 小时前
前端工程化落地指南:pnpm workspace + Monorepo 核心用法与实践
前端·javascript·架构
祈安_3 小时前
Java实现循环队列、栈实现队列、队列实现栈
java·数据结构·算法
皮皮林55115 小时前
拒绝写重复代码,试试这套开源的 SpringBoot 组件,效率翻倍~
java·spring boot
小兵张健15 小时前
开源 playwright-pool 会话池来了
前端·javascript·github
codingWhat19 小时前
介绍一个手势识别库——AlloyFinger
前端·javascript·vue.js
Lee川19 小时前
深度拆解:基于面向对象思维的“就地编辑”组件全模块解析
javascript·架构
进击的尘埃19 小时前
Web Worker 与 OffscreenCanvas:把主线程从重活里解放出来
javascript