Meta 代号 Project Hatch 的超级应用项目被曝光后,很多人关心的不是它能不能做成,而是“浏览器”和“电脑操控”这两件事为什么会出现在同一个产品里。前者是超级应用最常见的承载界面,后者代表了 AI 从对话助手走向系统操作助手的关键能力。这篇博客不预测产品成败,而是围绕这两件事拆解技术逻辑:超级应用为什么需要浏览器,AI 操控电脑是怎么做到的,如果你想自己搭一个最小可运行的电脑操控 Agent,应该从哪些模块入手,以及最终落地时会遇到哪些真实工程问题。
整条技术主线可以这样理解:把浏览器当作超级应用的统一入口,把电脑操控当作 AI 的“手和眼睛”,再通过一个 Agent 循环把任务从自然语言转换成一系列可执行、可校验的界面操作。下面先看这个概念层面的关系,再进入具体实现。
1. Project Hatch 为什么把浏览器和电脑操控放在一起
1.1 超级应用的本质是“少装应用,多跑服务”
超级应用并不是一个准确的技术术语,更多是一种产品形态:用户在一个应用里完成社交、支付、生活服务、办公协同等多类任务,而不是为每件事安装独立应用。从工程角度看,超级应用的核心不是功能多,而是“服务前置、任务串联”。用户不需要理解背后的系统边界,只需要在一个入口里按语义发起请求,然后由应用层调度能力。
浏览器之所以适合承载这种形态,是因为它本身就是跨平台、跨厂商、无安装成本的服务入口。在桌面端,浏览器已经稳定支持 HTML5、WebAssembly、扩展系统、开发者工具协议、媒体能力和大量权限 API。这意味着一套 Web 技术栈可以覆盖绝大多数轻量需求。
1.2 浏览器是超级应用最成熟的宿主
把浏览器放进超级应用,不是简单地在应用里套一个浏览器内核,而是把浏览器变成 Agent 的可见操作界面。普通用户看到的还是页面,但技术架构上它承担了三个角色:
- 渲染层:负责呈现 HTML、CSS、富媒体内容,兼容已有 Web 生态。
- 控制层:通过 DevTools Protocol、浏览器扩展、DOM 结构,为 AI Agent 提供可编程接口。
- 安全层:浏览器沙箱可以在不让 Agent 直接触碰操作系统的情况下完成任务,降低权限风险。
所以“超级应用里的浏览器”和普通浏览器区别很大:它默认要暴露更多自动化能力,同时要在安全和可用性之间做平衡。
1.3 电脑操控让 AI 从聊天框走向操作系统
“电脑操控”在 Project Hatch 的语境里,不是简单做一个远程桌面软件,而是让 AI Agent 理解当前屏幕状态,并像人一样操作鼠标、键盘和系统应用。它解决的问题是:当目标应用没有开放 API 或插件时,AI 仍然能通过图形界面完成任务。
这个能力对日常固定流程尤其有价值,例如每天打开一个后台页面、查询数据、截图、生成报表。类似的场景在真实项目中大量存在,但很多自动化脚本只要页面改版一次就全部失效。要解决这个问题,不能只写脚本,而是要让 Agent 具备“看状态、做决策、执行动作、验证结果”的闭环能力。
这里需要强调一点:浏览器内操控和桌面级操控是两种实现深度。浏览器内 Agent 可以读取 DOM、调用页面脚本,定位非常稳定;桌面级 Agent 通常只能通过截屏、OCR、图像匹配和可访问性树来理解界面,难度明显更高。Project Hatch 同时涉及两者,说明它的目标不是做一个网页内的小助手,而是试图统一“Web 入口 + 桌面能力”。
2. AI 操控电脑的核心链路:感知、规划、执行、校验
无论产品叫什么名字,“AI 操控电脑”在技术实现上都可以抽象为四个阶段:感知、规划、执行、校验。理解这条链路,才能理解后续代码模块为什么要这样拆分,以及排错时该查哪一层。
2.1 感知层:从 DOM、可访问性树和屏幕像素里提取状态
感知层解决“Agent 现在看到什么”的问题。浏览器场景中,最稳定的是直接读取 DOM 结构,因为元素有语义、有属性、有层级关系,Agent 可以准确定位搜索框、按钮、表单和文本区域。
桌面场景中,DOM 不存在,常用手段有三种:
- 屏幕截图 + 视觉模型:把整屏截图交给多模态模型,让模型描述界面并输出坐标。
- OCR 提取文本:适合处理 PDF、图片、没有可访问性接口的界面。
- 可访问性树(Accessibility Tree):许多系统提供辅助功能接口,能暴露按钮、输入框、名称和位置。
实际产品通常会组合使用:浏览器用 DOM,桌面用截图 + 可访问性树。不要只依赖一种方式,因为界面会变化,单一感知源很容易失效。
2.2 规划层:把任务翻译成动作序列
规划层的输入是任务描述和当前感知状态,输出是下一步动作。最简单的规划器是“规则 + 状态判断”,适合固定流程;更强大的是多模态大模型,它可以根据截图和 DOM 摘要推理出动作序列。
规划层必须明确动作边界,例如允许的动作集合:
- open_url(url)
- click(selector 或坐标)
- type_text(text)
- press_key(key)
- scroll(direction)
- screenshot(path)
- read_page_text()
把动作集合限制在安全范围内,远比让模型自由执行任意代码要稳妥。这也是超级应用和通用桌面助手之间的重要差异:前者可以通过运行时策略限制 Agent 能碰到的系统资源。
2.3 执行层:点击、输入、滚动这些动作怎么落地
执行层是动作的最终物理实现。浏览器内可以通过 Playwright、Selenium 或 DevTools Protocol 执行高精度操作;桌面级则需要操作系统层面的模拟输入。
在浏览器内,推荐优先使用选择器,而不是坐标。因为坐标会因为窗口大小、DPI、缩放比例和页面布局变化而偏移。只有在没有稳定选择器时才退到图像识别或坐标输入。
在桌面级,坐标又难以避免,因为很多第三方应用没有公开接口。这时候要做好“动作前截图”和“动作后截图”,方便审计和排错。
2.4 校验层:怎么判断任务真的完成了
校验层是整个链路中最容易被忽略的环节。很多 Agent 会陷入“模型认为完成了,但实际上并没有”的假成功状态。
校验方式要分场景:
- 页面出现目标文本或元素。
- URL 变化到预期地址。
- 截图前后差异达到阈值。
- 系统出现预期弹窗或状态标记。
- 目标文件生成且大小合理。
真正的校验不能只看一次动作是否执行成功,还要看业务结果是否达成。例如点击“保存”按钮成功,并不代表文件内容正确。生产级 Agent 必须在关键节点加入独立于模型推理的验证规则。
3. 搭一个最小可运行的浏览器 + 电脑操控 Agent
下面用一个最小示例跑通“感知 -> 规划 -> 执行 -> 校验”循环。这个示例不依赖真实大模型,而是用本地规则引擎模拟规划层,目的是先把工程骨架搭起来。之后再替换成多模态模型时,你只需要替换规划层函数。
3.1 环境准备:Python、Playwright、pyautogui
建议使用 Python 3.10 以上版本。示例依赖两个核心库:
- Playwright:控制真实 Chromium 浏览器,读取 DOM、点击、输入、截图。
- pyautogui:模拟桌面级鼠标键盘操作,用于演示电脑操控边界。
在干净环境里创建虚拟环境并安装依赖:
python -m venv .venv source .venv/bin/activate # Windows 下使用 .venv\Scripts\activate pip install playwright==1.44.0 pyautogui==0.9.54 Pillow==10.3.0 python -m playwright install chromiumplaywright install chromium这一步必须执行,否则运行时会提示找不到浏览器内核。生产环境中,如果代理许可受限,也可以使用系统已安装的 Chromium,并指定 executable_path。
3.2 项目结构:工具、循环、入口分开
建议按工具层、Agent 循环层、入口三部分拆分,方便后续扩展和排错。
project_hatch_demo/ ├── requirements.txt ├── tools.py # 封装浏览器和桌面操作 ├── agent.py # Agent 循环 ├── run_demo.py # 入口 └── demo.html # 本地测试页面这里坚持一个原则:业务代码不要直接调用 pyautogui 或 page.click,而是要经过工具层。工具层统一管理截图路径、日志和异常转换,后续做权限控制和审计也会更容易。
3.3 工具层:把浏览器和桌面操作封装成函数
先创建一个本地测试页面,避免依赖外网环境。页面包含一个输入框、一个按钮和一个结果区域。
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <title>本地 Agent 测试页</title> </head> <body> <input name="keyword" placeholder="请输入搜索词"> <button id="search_btn">搜索</button> <div id="result">等待输入</div> <script> const btn = document.getElementById('search_btn'); btn.addEventListener('click', function () { const val = document.querySelector('input[name=keyword]').value; document.getElementById('result').innerText = '搜索结果:' + val; }); </script> </body> </html>注意:本地 HTML 的 input 是真实输入框,点击按钮后 DOM 会更新结果区域,这给了 Agent 一个可校验的状态。
接着编写 tools.py,把浏览器操作和桌面操作分开封装:
# tools.py from pathlib import Path from playwright.sync_api import sync_playwright import pyautogui class BrowserTool: def __init__(self, headless: bool = False): self._pw = sync_playwright().start() self.browser = self._pw.chromium.launch(headless=headless) self.page = self.browser.new_page() def open_url(self, url: str) -> None: self.page.goto(url, wait_until="domcontentloaded") def read_page_text(self) -> str: return self.page.inner_text("body") def fill_input(self, selector: str, text: str) -> None: self.page.fill(selector, text) def click_selector(self, selector: str) -> None: self.page.click(selector) def screenshot(self, path: str) -> None: Path(path).parent.mkdir(parents=True, exist_ok=True) self.page.screenshot(path=path, full_page=False) def close(self) -> None: self.browser.close() self._pw.stop() class DesktopTool: def screenshot(self, path: str) -> None: Path(path).parent.mkdir(parents=True, exist_ok=True) pyautogui.screenshot().save(path) def screen_size(self): return pyautogui.size()这段代码的关键点是:Agent 循环不直接操作 Playwright 的 API,而是通过 BrowserTool 暴露的方法。这样你可以随时在工具层加入权限校验、日志记录或动作限流,而不用改动上层逻辑。
3.4 循环层:用一个本地 HTML 页面验证感知-规划-执行-校验
编写 agent.py,实现一个简化版 Agent 循环:
# agent.py from tools import BrowserTool, DesktopTool class SimpleAgent: def __init__(self, browser: BrowserTool, desktop: DesktopTool): self.browser = browser self.desktop = desktop def run(self, task: str, max_steps: int = 5) -> None: for step in range(1, max_steps + 1): print(f"[step {step}] 感知当前页面状态") # 1. 感知 page_text = self.browser.read_page_text() # 2. 校验:如果结果区包含任务关键词,说明任务已完成 if task in page_text: print(f"[step {step}] 校验通过,任务完成") self.browser.screenshot(f"logs/final_{step}.png") return # 3. 规划:简化规则,不再依赖模型 if "等待输入" in page_text: print(f"[step {step}] 规划:输入关键词并点击搜索") self.browser.fill_input("input[name=keyword]", task) self.browser.click_selector("#search_btn") else: # 4. 执行层预留分支:这里可以调用桌面级操作 print(f"[step {step}] 当前状态不匹配,截屏保留现场") self.browser.screenshot(f"logs/debug_{step}.png") raise RuntimeError("达到最大步数,仍未完成校验")这个循环虽然简单,但已经具备四层结构。实际使用多模态大模型时,只需要把“规划”那一步替换成模型调用,并把模型的响应规范为固定 JSON 动作,例如:
{"action": "fill_input", "selector": "input[name=keyword]", "text": "Python 异常处理"}3.5 运行结果与扩展为多模态模型
最后是入口文件 run_demo.py:
# run_demo.py from pathlib import Path from tools import BrowserTool, DesktopTool from agent import SimpleAgent if __name__ == "__main__": task = "Python 异常处理" browser = BrowserTool(headless=False) desktop = DesktopTool() agent = SimpleAgent(browser, desktop) try: agent.run(task) finally: browser.close()运行命令:
python run_demo.py预期输出大致如下:
[step 1] 感知当前页面状态 [step 1] 规划:输入关键词并点击搜索 [step 2] 感知当前页面状态 [step 2] 校验通过,任务完成如果这个最小示例运行成功,说明你已经有了一个可扩展的 Agent 骨架。后续要做的工作是替换规划层,例如接入支持视觉输入的多模态模型,让模型根据截图输出动作 JSON,再让执行层去运行。这个模式已经成为当前 AI 操控电脑类产品的主流架构。
4. 工程化落地时最难处理的四个问题
示例能跑通,不代表能上线。真实项目中,电脑操控 Agent 会遇到权限、稳定性、成本和兼容性四类问题。
4.1 权限与安全:系统提示“远程操控”时该怎么处理
在使用 pyautogui、Windows UI Automation 或 macOS Accessibility API 时,系统会弹出辅助功能和屏幕录制权限申请。部分企业即时通讯软件还会提示“电脑上有远程操控”,这是因为系统检测到辅助功能接口被外部程序使用。
这个提示不应该被理解为一个需要绕过的障碍。正确做法是:
- 明确告诉用户 Agent 会读取哪些信息、控制哪些应用。
- 在安装或首次启动时完成授权,并把授权信息记录在配置中。
- 使用独立专用账号运行 Agent,不直接使用管理员账号。
- 保留操作审计日志,记录每次点击、输入和截图。
- 对敏感操作加入人工确认,例如删除文件、发送消息、提交订单。
从安全角度看,有审计日志的 Agent 比没有日志的脚本更容易被接受。生产环境建议把操作日志写到独立的日志平台,而不是只输出到控制台。
4.2 稳定与恢复:窗口漂移、弹窗、网络延迟
UI 自动化最大的敌人不是模型能力,而是界面状态不稳定。窗口大小变化、系统弹窗、输入法状态、网络延迟都会导致动作落空。
应对手段包括:
- 每个关键动作前重新读取状态,不依赖上一次的缓存。
- 对点击操作设置重试次数。
- 为每个动作设置超时,避免页面卡死导致 Agent 无限等待。
- 在每次校验失败时截图保存,保留现场。
- 使用可访问性树时选择稳定属性,比如
name、role、current,而不是索引。
一个常见错误是:Agent 以为页面已经加载完成,就立即点击按钮,结果真实页面还在 loading。生产级实现应该在点击前显式等待元素可操作。
4.3 性能与成本:截图和模型调用频率要控制
如果 Agent 把每步操作都发给视觉大模型,成本和延迟会非常高。一次完整流程可能产生几十张截图、几十次模型调用。优化方向是分场景处理:
- 浏览器内优先使用 DOM 文本,不截图。
- 只有界面疑似变化时才触发截图。
- 桌面场景先做小区域截图,再整屏截图。
- 使用轻量模型判断状态变化,复杂决策才调用高级模型。
可以给模型调用设计一个简单的预算控制:每轮任务最大调用次数、单个动作最大等待时间、截图目录自动清理。这些参数需要在测试环境里反复调整。
4.4 兼容性:浏览器、分辨率、操作系统层面的差异
Playwright 支持 Chromium、Firefox、WebKit,但不同浏览器对权限 API、下载行为、弹窗策略的默认值不同。桌面自动化更是如此:Windows 下可以使用 UI Automation,macOS 下需要辅助功能权限,Linux 下不同发行版的窗口管理器体验差异很大。
在真实项目中不要承诺“一套脚本全平台通用”。建议按平台拆分配置,至少把以下内容外置:
agent: max_steps: 8 screenshot_dir: ./logs timeout_seconds: 15 browser: channel: chromium headless: false viewport: width: 1280 height: 720 user_agent: "" desktop: enabled: false double_click_interval_ms: 200学习环境可以直接在本地运行;生产环境建议使用容器 + 虚拟显示器,例如 Linux 下的 Xvfb,把 Agent 运行在隔离环境中,再通过 VNC 或远程日志观察执行过程。这样即使脚本出错,也不会影响宿主机。
5. 常见问题排查:电脑操控 Agent 不动、乱点、假成功怎么办
下面按“现象 -> 排查顺序 -> 解决方案”的路径整理四个常见问题。
5.1 Agent 一直循环点击但没有效果
可能原因并不是点击函数写错,而是目标元素尚未准备好,或者页面发生了重定向。检查顺序:
- 确认定位元素是否存在。
- 确认元素是否可见、可点击。
- 查看动作前后的截图。
- 检查网络请求或页面 console 日志。
解决方案是在点击前增加wait_for_selector或轮询式等待,并把等待状态打印出来。不要只打印“click success”,因为 Playwright 的 click 成功只代表浏览器接收事件,不代表业务逻辑生效。
5.2 元素定位失败
常见原因包括:
- 页面结构改版。
- 元素在 iframe 内。
- 元素是 shadow DOM。
- 页面用了动态 class 名称。
排查时先打开浏览器 DevTools,确认元素所在的层级,再决定用哪个选择器。如果 class 不稳定,优先使用>