当 AI Agent 学会"边跑边修"

2026 年,AI Agent 的浏览器操控赛道已经卷成了红海——Browser Use、Agent-E、WebVoyager 各显神通。但一个来自 browser-use 团队的开源项目,用不到 600 行 Python 代码杀出重围:Browser Harness

截至 2026 年 8 月,这个项目在 GitHub 上已斩获 17,100+ Star,成为浏览器 Agent 领域增长最快的项目之一。它的核心理念只有一句话:把 LLM 直接连到 Chrome 的 CDP 端口,缺什么函数让 AI 自己写。

这不是又一个"封装 Playwright"的中间层框架。Browser Harness 的设计哲学是极简主义——没有选择器引擎,没有页面模型,没有预定义的工作流。它只提供一组最小化的 CDP 辅助函数,剩下的交给 LLM 在运行时动态生成。

更惊人的是它的自修复能力:当 Agent 遇到框架没有覆盖的操作时,它不会报错退出,而是自己编写一个新的 helper 函数,保存到本地工作区,下次直接复用。框架越用越强,这就是"自修复"的含义。

与 Playwright/Puppeteer 的本质区别

很多人会问:这不就是 Playwright 的 Python 封装吗?答案是否定的。

Playwright 和 Puppeteer 是传统自动化框架。它们的设计目标是"人类编写脚本控制浏览器",提供了丰富的选择器引擎(CSS、XPath、text)、页面模型、等待机制和断言库。你需要预先知道要点击什么元素、填写什么表单、等待什么条件。

Browser Harness 是 AI 原生框架。它假设控制浏览器的不是人类脚本,而是 LLM。因此它: - 不依赖选择器,而是通过 CDP 直接操作坐标和 DOM - 不提供高级等待机制,而是让 LLM 自己判断何时页面就绪 - 不预定义工作流,而是让 LLM 根据当前页面状态决定下一步 - 不报错退出,而是让 LLM 动态生成缺失的辅助函数

这种设计让 Browser Harness 能够处理从未见过的网页结构。传统自动化脚本遇到新的 DOM 结构就会失败,但 Browser Harness 的 Agent 会"看懂"页面,然后编写新的代码来完成任务。

核心架构:592 行代码的组织方式

Browser Harness 的代码库极其精简,核心只有 5 个文件:

src/browser_harness/
├── __init__.py      # 37 行,包初始化
├── _ipc.py          # 201 行,Unix Socket/TCP 进程间通信
├── helpers.py       # 564 行,核心 CDP 辅助函数
├── daemon.py        # 850 行,后台守护进程管理
├── run.py           # 407 行,CLI 入口和 REPL
└── admin.py         # 1191 行,安装、更新、诊断工具

总计约 3,250 行代码(不是 592 行,592 行是早期版本的代码量)。但即使扩展到 3,000+ 行,这个代码量仍然只有 Playwright 的 1/50。

关键模块解析

helpers.py 是整个框架的灵魂。它只提供 20 多个基础函数:

# 导航和页面信息
goto_url(url)              # 导航到 URL
page_info()                # 获取当前页面信息(URL、标题、尺寸、滚动位置)
wait_for_load()            # 等待页面加载完成

# 元素交互
click_at_xy(x, y)          # 点击坐标
type_text(text)            # 输入文本
fill_input(selector, text) # 填充表单字段

# JavaScript 执行
js(expression)             # 执行 JavaScript 并返回结果

# CDP 原始访问
cdp(method, **params)      # 直接调用 Chrome DevTools Protocol

# 截图和录制
capture_screenshot(path)   # 截图
start_recording(name)      # 开始录制操作
stop_recording()           # 停止录制

这些函数通过 Unix Socket(或 Windows TCP)与后台 daemon 进程通信。daemon 维护着与 Chrome CDP 端口的 WebSocket 连接。

daemon.py 负责: - 自动发现运行中的 Chrome 实例 - 启动后台守护进程 - 管理 CDP 连接池 - 处理多标签页切换 - 支持云端浏览器(Browser Use Cloud)

run.py 是 CLI 入口。它启动一个 REPL(Read-Eval-Print Loop),让 LLM 可以通过 heredoc 方式执行 Python 代码:

browser-harness <<'PY'
goto_url("https://example.com")
print(page_info())
PY

这种设计让 LLM 可以像调用函数一样控制浏览器,而不需要理解底层的 CDP 协议细节。

自修复机制:AI 如何动态生成缺失函数

Browser Harness 最核心的创新是自修复(Self-Healing)机制。传统框架遇到不支持的操作时会抛出异常,而 Browser Harness 让 LLM 自己写代码解决问题。

工作流程

1. Agent 收到任务:下载 X(Twitter) 上最新的 20 个视频
2. Agent 调用 goto_url("https://x.com/profile")
3. Agent 调用 page_info() 获取页面信息
4. Agent 需要滚动页面加载更多帖子,但框架没有 scroll_to_bottom() 函数
5. Agent 自己编写:
   def scroll_to_bottom(times=10):
       for _ in range(times):
           js("window.scrollTo(0, document.body.scrollHeight)")
           time.sleep(2)
6. 保存到 agent-workspace/agent_helpers.py
7. 下次任务直接复用

这种机制的关键在于 agent_helpers.py 文件。它位于 Agent 的工作区,不在框架源码目录中。Agent 可以自由修改这个文件,添加任何需要的辅助函数。

代码示例

# agent-workspace/agent_helpers.py
# Agent 自动生成的辅助函数

def scroll_to_bottom(times=10):
    """滚动到页面底部,加载更多内容"""
    for _ in range(times):
        js("window.scrollTo(0, document.body.scrollHeight)")
        time.sleep(2)

def extract_video_urls():
    """提取页面中所有视频链接"""
    return js("""
        Array.from(document.querySelectorAll('video source'))
            .map(el => el.src)
            .filter(src => src)
    """)

def download_file(url, filename):
    """下载文件到本地"""
    import urllib.request
    urllib.request.urlretrieve(url, filename)

当 Agent 执行任务时,这些自定义函数会被自动加载。框架通过 from agent_helpers import * 将它们注入到 REPL 环境中。

为什么这很重要

传统自动化框架的扩展需要: 1. 理解框架的插件机制 2. 遵循严格的 API 规范 3. 发布到包管理器 4. 等待用户安装

Browser Harness 的自修复机制让扩展变得即时且个性化: - Agent 根据当前任务需求生成代码 - 代码保存在本地,立即可用 - 不需要发布或安装 - 每个用户的 Agent 会根据自己的使用模式进化

这就是"框架越用越强"的含义。你的 Agent 处理过的任务越多,它积累的辅助函数就越丰富,未来处理类似任务的效率就越高。

技术实现细节

Chrome DevTools Protocol (CDP)

Browser Harness 的核心通信协议是 CDP。CDP 是 Chrome 浏览器提供的调试接口,允许外部程序控制浏览器的几乎所有行为。

# helpers.py 中的 cdp() 函数
def cdp(method, session_id=None, **params):
    """直接调用 CDP 方法"""
    return _send({
        "method": method,
        "params": params,
        "session_id": session_id
    }).get("result", {})

# 使用示例
cdp("Page.navigate", url="https://example.com")
cdp("Input.dispatchMouseEvent", type="mousePressed", x=100, y=200)
cdp("Runtime.evaluate", expression="document.title")

CDP 的优势在于: - 无需选择器:直接通过坐标点击,绕过复杂的 CSS/XPath 选择器 - 跨域支持:CDP 在浏览器底层工作,不受同源策略限制 - 完整控制:可以访问网络请求、DOM、JavaScript 运行时、性能数据等

进程间通信 (IPC)

Browser Harness 使用 Unix Socket(POSIX)或 TCP(Windows)实现 CLI 与 daemon 之间的通信。

# _ipc.py 中的核心逻辑
def connect(name, timeout=1.0):
    """连接到 daemon"""
    if not IS_WINDOWS:
        s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        s.connect(str(_sock_path(name)))
        return s, None
    # Windows 使用 TCP
    port, token = _read_port_file(name)
    s = socket.create_connection(("127.0.0.1", port))
    return s, token

def request(c, token, req):
    """发送请求并接收响应"""
    if token:
        req = {**req, "token": token}
    c.sendall((json.dumps(req) + "\n").encode())
    data = b""
    while not data.endswith(b"\n"):
        chunk = c.recv(1 << 16)
        if not chunk:
            break
        data += chunk
    return json.loads(data or b"{}")

这种设计的优势: - 低延迟:Unix Socket 比 HTTP 快得多 - 安全性:Unix Socket 通过文件权限控制访问 - 简单性:不需要 HTTP 服务器、路由、序列化等复杂逻辑

自动发现 Chrome 实例

daemon.py 会自动扫描系统中运行中的 Chrome 实例:

# daemon.py 中的浏览器发现逻辑
_MAC_PROFILES = (
    "Library/Application Support/Google/Chrome",
    "Library/Application Support/Google/Chrome Canary",
    "Library/Application Support/Arc/User Data",
    # ... 更多浏览器
)

_LINUX_PROFILES = (
    ".config/google-chrome",
    ".config/chromium",
    ".config/microsoft-edge",
    # ... 更多浏览器
)

def supported_browser_running():
    """检测是否有支持的浏览器在运行"""
    return any(browser_running_for_profile(base) for base in PROFILES)

它通过检查 SingletonLock 文件和 DevToolsActivePort 文件来判断浏览器是否在运行,以及是否启用了远程调试。

与其他浏览器 Agent 对比

特性 Browser Harness Browser Use Agent-E WebVoyager
代码量 3,250 行 15,000+ 行 20,000+ 行 10,000+ 行
设计哲学 极简主义 功能完整 企业级 研究导向
自修复 ✅ 核心特性
CDP 直接访问
选择器引擎 ❌ 坐标优先
云端浏览器
录制功能
学习曲线

Browser Harness 的核心优势是极简 + 自修复。它不试图提供所有功能,而是让 LLM 根据需求动态生成代码。这种设计让它能够处理从未见过的场景,而其他框架需要预先编写适配器。

实战案例:自动化完成复杂网页任务

案例 1:下载 X(Twitter) 视频

# 任务:下载 X 上最新的 20 个视频

browser-harness <<'PY'
# 1. 导航到 X 个人主页
goto_url("https://x.com/username/media")
wait_for_load()

# 2. 滚动加载更多帖子
scroll_to_bottom(20)  # Agent 自动生成的函数

# 3. 提取视频 URL
videos = extract_video_urls()  # Agent 自动生成的函数

# 4. 下载视频
for i, url in enumerate(videos[:20]):
    download_file(url, f"video_{i+1}.mp4")
    print(f"Downloaded {i+1}/20")
PY

案例 2:填写复杂表单

# 任务:自动填写注册表单

browser-harness <<'PY'
goto_url("https://example.com/register")
wait_for_load()

# 获取页面信息
info = page_info()
print(f"Page: {info['title']}")

# 使用 Accessibility Tree 找到表单元素
tree = cdp("Accessibility.getFullAXTree")["nodes"]
# 过滤出输入框
inputs = [n for n in tree if n.get("role") == "textbox"]

# 填写表单
for input_node in inputs:
    # 获取坐标
    box = cdp("DOM.getBoxModel", backendNodeId=input_node["backendDOMNodeId"])
    x = sum(box["model"]["content"][0::2]) / 4
    y = sum(box["model"]["content"][1::2]) / 4

    # 点击并输入
    click_at_xy(x, y)
    type_text("test@example.com")
PY

案例 3:抓取动态加载的内容

# 任务:抓取无限滚动的商品列表

browser-harness <<'PY'
goto_url("https://example.com/products")
wait_for_load()

products = []
last_height = 0

# 滚动直到没有新内容
for _ in range(50):
    # 获取当前产品
    new_products = js("""
        Array.from(document.querySelectorAll('.product-card'))
            .map(card => ({
                name: card.querySelector('.name').textContent,
                price: card.querySelector('.price').textContent
            }))
    """)

    # 检查是否有新内容
    if len(new_products) == len(products):
        break

    products = new_products

    # 滚动
    js("window.scrollTo(0, document.body.scrollHeight)")
    time.sleep(2)

print(f"Found {len(products)} products")
PY

局限性和适用场景

局限性

  1. 依赖 Chrome:只支持 Chrome/Chromium 系浏览器,不支持 Firefox/Safari
  2. 需要手动启用远程调试:首次使用需要在 chrome://inspect 中勾选"允许远程调试"
  3. 坐标点击不稳定:页面布局变化会导致坐标失效(但 LLM 可以自适应)
  4. 不适合大规模爬虫:单实例设计,不适合并发抓取数千个页面
  5. 需要 LLM 支持:没有 LLM 就无法发挥自修复能力

适用场景

个人自动化任务:下载视频、填写表单、抓取数据 ✅ 测试和调试:快速验证网页功能 ✅ 复杂交互流程:需要动态决策的多步骤任务 ✅ 已登录会话:利用 Chrome 的登录状态访问需要认证的网站 ✅ Bot 保护网站:使用真实浏览器绕过反爬虫机制

大规模数据抓取:使用 Scrapy + Playwright 更合适 ❌ 跨浏览器测试:使用 Playwright 的多浏览器支持 ❌ 简单的 HTTP 请求:使用 requests/httpx 更高效

安装和快速上手

安装

# 使用 uv 安装(推荐)
uv tool install --python 3.12 browser-harness

# 或使用 pip
pip install browser-harness

首次配置

  1. 打开 Chrome,访问 chrome://inspect/#remote-debugging
  2. 勾选"允许远程调试此浏览器实例"
  3. 测试连接:
browser-harness <<'PY'
print(page_info())
PY

如果看到当前页面的信息(URL、标题、尺寸),说明连接成功。

与 Claude Code 集成

# 安装 browser-harness
uv tool install --python 3.12 browser-harness

# 注册为 skill
mkdir -p ~/.codex/skills/browser-harness
browser-harness skill > ~/.codex/skills/browser-harness/SKILL.md

然后在 Claude Code 中,Agent 会自动使用 browser-harness 处理所有浏览器任务。

总结评价

Browser Harness 代表了 AI Agent 工具设计的一个重要趋势:从复杂框架走向极简主义

它的核心洞察是:与其试图预定义所有可能的浏览器操作,不如提供最小化的基础函数,让 LLM 根据具体任务动态生成代码。这种设计不仅减少了代码量,还提高了灵活性——Agent 可以处理从未见过的场景。

优点: - ✅ 代码极简,易于理解和定制 - ✅ 自修复机制让框架越用越强 - ✅ CDP 直接访问,性能优秀 - ✅ 支持云端浏览器,可扩展到大规模任务 - ✅ 录制功能方便调试和回溯

缺点: - ❌ 依赖 Chrome,不支持其他浏览器 - ❌ 首次配置需要手动启用远程调试 - ❌ 坐标点击在布局变化时不稳定 - ❌ 不适合大规模并发任务

推荐指数:⭐⭐⭐⭐⭐(5/5)

对于需要自动化浏览器任务的开发者,Browser Harness 是目前最优雅的选择。它的极简设计和自修复能力让它能够适应各种复杂场景,而 3,000+ 行的代码量意味着你可以轻松理解它的每一行实现。

如果你正在构建 AI Agent,或者需要自动化复杂的网页任务,Browser Harness 值得一试。它可能会改变你对浏览器自动化的认知——最好的框架不是功能最多的,而是让 AI 能够自己解决问题的


参考链接: - GitHub: browser-use/browser-harness - 文档: SKILL.md - 安装指南: install.md - Browser Use Cloud: cloud.browser-use.com

FAQ

1. Browser Harness 和 Playwright 有什么区别?

Browser Harness 是 AI 原生框架,设计目标是让 LLM 控制浏览器,不提供选择器引擎和高级等待机制,而是通过 CDP 直接操作坐标和 DOM。Playwright 是传统自动化框架,为人类编写脚本设计,提供丰富的选择器和等待机制。Browser Harness 的核心优势是自修复能力——遇到不支持的操作时,LLM 会自己编写代码。

2. Browser Harness 支持哪些浏览器?

目前只支持 Chrome/Chromium 系浏览器,包括 Google Chrome、Chrome Canary、Microsoft Edge、Brave、Arc 等。不支持 Firefox 和 Safari,因为 Browser Harness 依赖 Chrome DevTools Protocol (CDP)。

3. 如何启用 Chrome 的远程调试?

打开 Chrome,访问 chrome://inspect/#remote-debugging,勾选"允许远程调试此浏览器实例"。macOS 用户可能需要在系统设置中授予终端 Accessibility 权限。

4. Browser Harness 适合大规模爬虫吗?

不适合。Browser Harness 是单实例设计,主要面向个人自动化任务。如果需要并发抓取数千个页面,建议使用 Scrapy + Playwright 或 Browser Use Cloud 的云端浏览器功能。

5. 自修复机制是如何工作的?

当 Agent 遇到框架没有覆盖的操作时,它会自己编写一个新的 Python 函数,保存到 agent-workspace/agent_helpers.py 文件中。下次执行任务时,这个函数会被自动加载。这样框架就"学会"了新的能力,越用越强。