Browser Use Agent 深度解析:从技术原理到 Harness Engineering 的范式革命
约 50 分钟阅读2 次阅读

Let我先搜索一下最新的相关资料。
让我继续搜索更多关于 Harness Engineering 和 browser-use 的深度技术资料。
让我再搜索一些补充资料,然后开始撰写文章。
好的,资料已经收集充分,下面开始撰写完整的技术文章。
Browser Use Agent 深度解析:从技术原理到 Harness Engineering 的范式革命
引言:从脚本自动化到智能体驱动
多年来,开发者使用 Selenium、Puppeteer、Playwright 等工具自动化浏览器操作。这些工具功能强大,但本质上是"脆性"的——我们编写依赖特定 CSS 选择器、XPath 或元素 ID 的脚本,一旦网站 UI 发生变化,脚本就会崩溃,维护成本极高。
2024 年末至 2025 年初,一种全新的范式开始崛起:让大语言模型(LLM)直接"看懂"并"操控"浏览器。Browser Use 正是这一浪潮中最具代表性的开源项目之一。它由 Magnus Müller 和 Gregor Žunić 创建,是一个基于 Python 的开源库,通过将 LLM 的推理能力与 Playwright 的浏览器控制能力相结合,让 AI Agent 能够像人类一样浏览网页、点击按钮、填写表单、提取数据。
与此同时,2025 年下半年,OpenAI 在其内部 Codex 项目中提出了一个影响深远的工程理念——Harness Engineering(驾驭工程)。这一理念的核心观点是:在 AI Agent 时代,工程师的核心工作不再是编写代码,而是设计环境、明确意图、构建反馈回路,使 Agent 能够可靠地工作。
本文将深入剖析 Browser Use Agent 的技术架构、核心原理和实现细节,并结合 Harness Engineering 的最新理念,探讨如何在生产环境中构建可靠的浏览器自动化智能体系统。
第一部分:Browser Use Agent 技术架构全解
1.1 整体架构概览
Browser Use 的架构可以用一条清晰的数据流管线来描述:
用户输入任务
→ LLM 处理与推理
→ DOM 提取 + 视觉分析
→ 动作规划
→ Playwright 执行
→ 状态更新
→ 反馈回路(循环直到任务完成)
这条管线的每一个环节都经过精心设计,形成了一个闭环的 Agent Loop(智能体循环)。整个系统由三大核心组件构成:
- LLM 集成层(大脑)
- 浏览器控制引擎(手脚)
- 视觉理解系统(眼睛)
1.2 LLM 集成层:Agent 的大脑
LLM 集成层是 Browser Use 的决策中枢。它负责:
- 接收用户的自然语言任务描述
- 理解当前网页的状态(DOM 结构 + 截图)
- 推理下一步应该执行什么动作
- 判断任务是否已经完成
Browser Use 支持多种 LLM 后端,包括:
| 提供商 | 模型示例 | 适用场景 |
|---|---|---|
| Browser Use 官方 | ChatBrowserUse | 最高精度 + 最快速度 + 最低 Token 成本 |
| OpenAI | GPT-4o / GPT-4.1-mini | 复杂推理与导航 |
| Anthropic | Claude Sonnet 4 | 高质量推理 |
| Gemini 2.0 Flash | 视觉密集型任务 | |
| 本地部署 | Ollama (Llama 3.1) | 隐私敏感场景,零 API 成本 |
一个最简单的 Agent 创建方式如下:
from browser_use import Agent, ChatBrowserUse
from dotenv import load_dotenv
import asyncio
load_dotenv()
async def main():
llm = ChatBrowserUse()
agent = Agent(
task="Find the number 1 post on Show HN",
llm=llm
)
await agent.run()
if __name__ == "__main__":
asyncio.run(main())
这段代码背后发生的事情远比表面复杂。agent.run() 启动了一个迭代循环,每一轮循环中:
- 系统提取当前页面的 DOM 状态和截图
- 将状态信息与任务描述一起发送给 LLM
- LLM 返回一个或多个动作指令(如 click、type、navigate)
- Playwright 执行这些动作
- 系统观察执行结果,更新状态,进入下一轮
1.3 浏览器控制引擎:Playwright 与 CDP
Browser Use 底层使用 Playwright 作为浏览器自动化框架,通过 Chrome DevTools Protocol (CDP) 与 Chromium 浏览器通信。相比传统的 HTTP 驱动方式,CDP 基于 WebSocket 的双向通信具有更低的延迟和更丰富的控制能力。
Browser 对象的配置非常灵活:
from browser_use import Browser
browser = Browser(
headless=False, # 是否无头模式
window_size={'width': 1920, 'height': 1080},
highlight_elements=True, # 高亮交互元素(辅助 AI 视觉识别)
paint_order_filtering=True, # 过滤被遮挡的元素,优化 DOM 树
minimum_wait_page_load_time=0.25, # 页面加载最小等待时间
wait_for_network_idle_page_load_time=0.5,
wait_between_actions=0.5, # 动作间等待时间
)
关键的浏览器能力包括:
- 多标签页管理:Agent 可以打开、切换、关闭多个标签页
- 域名限制:通过
allowed_domains和prohibited_domains控制 Agent 的访问范围 - 代理支持:内置 ProxySettings,支持认证代理
- 云端浏览器:通过
use_cloud=True一键接入 Browser Use Cloud,自动绕过验证码和反爬检测 - 视频录制:支持录制 Agent 操作过程,便于调试和审计
1.4 视觉理解系统:DOM + Vision 的混合方案
这是 Browser Use 最具创新性的设计之一。传统自动化工具只依赖 DOM 结构来定位元素,但 DOM 信息往往不完整——动态渲染的内容、Canvas 元素、复杂的 CSS 布局都可能导致 DOM 分析失效。
Browser Use 采用了 DOM + Vision 的混合分析策略:
- DOM 提取:解析页面的 HTML 结构,识别可交互元素(按钮、链接、输入框等),为每个元素分配索引编号
- 视觉分析:对页面进行截图,利用 LLM 的多模态能力(如 GPT-4o 的视觉理解)分析截图内容
- 元素高亮:在截图上高亮标注可交互元素,帮助 LLM 更准确地理解页面布局
Agent 的视觉模式有三种配置:
agent = Agent(
task="...",
llm=llm,
use_vision="auto", # "auto" | True | False
vision_detail_level="auto" # "low" | "high" | "auto"
)
"auto"(默认):包含截图工具,但仅在 LLM 主动请求时使用视觉True:每一步都包含截图False:完全禁用视觉,仅依赖 DOM
这种混合方案的优势在于:即使一个按钮没有明确的 id 或 class,Agent 也能通过视觉识别找到它——就像人类用户一样。
1.5 Agent Loop:核心控制循环
Agent 的核心是一个迭代控制循环,其伪代码如下:
while not done and steps < max_steps:
# 1. 获取当前页面状态
state = extract_dom() + take_screenshot()
# 2. 组装上下文,调用 LLM
response = llm.call(system_prompt + state + task + history)
# 3. 解析 LLM 返回的动作
actions = parse_actions(response)
# 4. 执行动作(最多 max_actions_per_step 个)
for action in actions:
result = playwright.execute(action)
if page_changed:
break # 页面变化后停止执行剩余动作
# 5. 更新历史记录
history.append(state, actions, result)
# 6. 检查是否完成
if response.is_done:
done = True
几个关键的设计决策:
max_actions_per_step(默认 3):每一步 LLM 最多可以输出 3 个动作。例如填写表单时,Agent 可以一次性输出"填写用户名 → 填写密码 → 点击登录"三个动作,减少 LLM 调用次数max_failures(默认 3):连续失败 3 次后停止,避免无限循环use_thinking(默认 True):允许 Agent 在输出动作前进行显式推理(类似 Chain-of-Thought)flash_mode:快速模式,跳过评估和推理步骤,仅使用记忆,适合简单任务
1.6 工具系统(Tools)
Browser Use 提供了一套丰富的内置工具,同时支持开发者自定义扩展:
内置工具分类:
- 导航控制:
search、navigate、go_back、wait - 页面交互:
click、input、scroll、find_text、send_keys、upload_file - 标签管理:
switch、close - 内容提取:
extract(使用 LLM 从页面提取结构化数据) - 视觉分析:
screenshot - 表单控制:
dropdown_options、select_dropdown - 文件操作:
write_file、read_file、replace_file - JavaScript 执行:
evaluate(执行自定义 JS 代码) - 任务完成:
done
自定义工具的注册非常简洁:
from browser_use import Tools, Agent, ActionResult, BrowserSession
tools = Tools()
@tools.action(description='Save extracted data to database')
async def save_to_db(data: dict, browser_session: BrowserSession) -> ActionResult:
# 你的数据库写入逻辑
db.insert(data)
return ActionResult(extracted_content=f"Saved {len(data)} records")
@tools.action(description='Get 2FA code from authenticator')
async def get_2fa_code() -> ActionResult:
code = authenticator.get_current_code()
return ActionResult(extracted_content=f"2FA code: {code}")
agent = Agent(
task="Login to the dashboard and export monthly report",
llm=llm,
tools=tools
)
注意 browser_session: BrowserSession 这个参数名必须精确匹配——Agent 通过参数名注入依赖,使用错误的名称会导致工具静默失败。
1.7 Agent 输出与历史记录
agent.run() 返回一个 AgentHistoryList 对象,包含完整的执行历史:
history = await agent.run()
# 基本信息
history.urls() # 访问过的 URL 列表
history.action_names() # 执行过的动作名称
history.extracted_content() # 提取的内容列表
history.errors() # 错误列表
# 分析方法
history.final_result() # 最终结果
history.is_done() # 是否完成
history.is_successful() # 是否成功
history.model_thoughts() # Agent 的推理过程
history.number_of_steps() # 总步数
history.total_duration_seconds() # 总耗时
# 结构化输出
history.structured_output # 当使用 output_model_schema 时
这套历史记录系统为调试、审计和优化提供了完整的可观测性基础。
第二部分:Harness Engineering——Agent 时代的工程范式
2.1 什么是 Harness Engineering?
2025 年 8 月,OpenAI 的 Codex 团队启动了一项激进的实验:构建一款软件产品,其中没有一行代码是人工编写的。五个月后,这个代码仓库达到了约一百万行代码,由仅三名工程师(后扩展到七名)通过指导 Codex Agent 完成。约 1,500 个 Pull Request 被打开与合并,平均每位工程师每天处理 3.5 个 PR。
在这个过程中,他们提出了 Harness Engineering 的概念:
当软件工程团队的主要工作不再是编写代码,而是设计环境、明确意图和构建反馈回路,从而使 AI Agent 能够可靠地工作时——这就是 Harness Engineering。
用一个比喻来理解:LLM 是引擎,Harness(驾驭系统)是整辆车——底盘、变速箱、方向盘、刹车、燃油系统和电子设备,将原始动力转化为可控、可靠的运动。没有人会买一台裸露的引擎。
2.2 Harness 的三层架构
+--------------------------------------------------+
| Layer 3: 编排层 (Orchestration) |
| 工作流逻辑、Agent 协调、路由 |
+--------------------------------------------------+
| Layer 2: 运行时环境 (Runtime Environment) |
| 工具、记忆、护栏、I/O 处理 |
+--------------------------------------------------+
| Layer 1: 模型接口 (Model Interface) |
| API 调用、Prompt 组装、响应解析 |
+--------------------------------------------------+
- Layer 1(模型接口):如何调用模型——Prompt 模板、参数配置、响应解析、API 错误处理
- Layer 2(运行时环境):模型周围的一切——工具定义、记忆存储、输入验证、输出护栏、上下文窗口管理
- Layer 3(编排层):多次调用如何协调——Agent 循环、任务分解、条件分支、人工审批门、并行执行
2025 年大多数团队只构建了 Layer 1。而在 2026 年能够交付可靠 AI 产品的团队,三层都经过了精心工程化。
2.3 Harness Engineering 的七大核心组件
组件一:工具选择与集成
工具赋予模型超越文本生成的能力:网页搜索、代码执行、数据库查询、API 调用、文件操作。
关键设计决策:
- 暴露哪些工具(多不一定好——工具泛滥会让模型困惑)
- 如何描述工具(Schema 设计直接影响工具调用准确率)
- 沙箱与权限(模型实际能做什么 vs 它认为自己能做什么)
- 超时与降级行为(工具调用失败时怎么办)
最佳实践:从 3-5 个定义清晰的工具开始,每个工具有明确的、不重叠的用途。仅在有证据表明模型需要时才添加新工具。
组件二:记忆系统
LLM 是无状态的,每次调用都从零开始。记忆系统创造了连续性的效果。
| 记忆类型 | 范围 | 实现方式 | 用途 |
|---|---|---|---|
| 对话记忆 | 单次会话 | 消息历史缓冲 | 聊天应用 |
| 工作记忆 | 单个任务 | 草稿本/KV 存储 | 多步推理 |
| 情景记忆 | 跨会话 | 向量数据库 + 摘要 | 用户偏好、历史交互 |
| 语义记忆 | 全局 | 知识库/RAG | 领域知识、文档 |
| 程序记忆 | 全局 | 工具定义 + 示例 | 已学习的工作流 |
关键问题不是"要不要加记忆",而是"什么应该被记住、记多久、如何检索"。
组件三:护栏与验证
护栏是 LLM 输出与生产后果之间的安全网,在三个阶段运作:
输入护栏:
- 内容过滤(阻止 Prompt 注入、PII 泄露)
- Schema 验证
- 速率限制和成本控制
输出护栏:
- 格式验证(JSON Schema、类型检查)
- 事实性验证(与源文档交叉引用)
- 安全分类器(毒性、偏见、幻觉检测)
- 业务逻辑检查
执行护栏:
- 工具调用审批(破坏性操作需人工确认)
- 资源限制(最大迭代次数、最大 Token 数、单次请求最大成本)
- 死锁检测(Agent 陷入循环)
组件四:重试与错误恢复
请求
|
v
[尝试 1: 主模型]
|-- 成功 --> 验证 --> 返回
|-- 失败 --> [尝试 2: 重新组织 Prompt]
|-- 成功 --> 验证 --> 返回
|-- 失败 --> [尝试 3: 降级模型]
|-- 成功 --> 验证 --> 返回
|-- 失败 --> [升级到人工处理]
重试策略的层次:
- 简单重试——相同 Prompt,相同模型(处理瞬时 API 错误)
- 重组重试——根据错误修改 Prompt
- 模型降级——切换到备用模型
- 分解重试——将失败的任务拆分为更小的子任务
- 人工升级——N 次失败后路由到人工操作员
组件五:上下文管理
随着上下文窗口扩展到 100 万+ Token,挑战不再是容量,而是策展。将所有内容塞入上下文会降低性能,策略性的上下文组装才能提升效果。
- 相关性排序:使用 Embedding 为每个查询浮现最相关的文档
- 时效性加权:优先使用最新信息
- 压缩:摘要旧的上下文以保留含义同时减少 Token
- 分块:将大文档拆分为语义有意义的段落
- 优先区域:将最关键的信息放在上下文的开头和结尾(模型对这些位置的注意力更高)
组件六:可观测性与追踪
你无法改进你无法衡量的东西。需要追踪的指标:
- 每个组件的延迟(模型调用、工具执行、检索、验证)
- 每次请求的 Token 使用量和成本
- 按任务类型的成功/失败率
- 护栏触发频率
- 用户满意度信号
- 漂移检测(输出质量随时间退化)
组件七:Prompt 模板与版本控制
在 Harness Engineering 中,Prompt 作为代码管理,而非临时字符串:
- 存储在版本控制的模板文件中
- 使用变量进行动态上下文注入
- 用生产流量 A/B 测试 Prompt 变体
- 追踪 Prompt 性能指标
- 将 Prompt 逻辑与应用逻辑分离
2.4 OpenAI 的实践经验:给 Agent 一张地图,而非一本千页说明书
OpenAI Codex 团队在实践中学到的最重要教训之一:
上下文是稀缺资源。一个巨大的指令文件会挤掉任务、代码和相关文档——Agent 要么会错过关键约束条件,要么开始针对错误的约束条件进行优化。
他们最初尝试将所有指导信息放入一个巨大的 AGENTS.md 文件,结果失败了。文件变得陈旧,Agent 无法判断哪些信息仍然有效。
最终方案是将 AGENTS.md 视为目录(约 100 行),指向更深层次的结构化知识源:
AGENTS.md (约 100 行,作为地图)
├── docs/design/ # 设计文档(含验证状态)
├── docs/architecture/ # 架构文档(域和包分层的顶层地图)
├── docs/quality/ # 质量文档(每个领域和层的评分)
├── docs/plans/ # 执行计划(进度和决策日志)
└── docs/principles/ # 核心理念(Agent 优先的操作原则)
这实现了渐进式披露:Agent 从一个小而稳定的切入点开始,被指导下一步该去哪里查看,而不是一开始就被淹没。
2.5 通过不变量强制执行质量,而非微观管理
OpenAI 团队围绕一个严格的架构模型构建应用,每个业务域划分为固定的层:
Types → Config → Repo → Service → Runtime → UI
依赖方向经过严格验证,仅允许有限的边。这些约束通过自定义 Linter(由 Codex 自己生成)和结构测试机械地强制执行。
关键洞察:在以人为本的工作流中,这些规则可能让人感到迂腐。但有了 Agent,它们就成了倍增器——一旦编码,就能立即应用于所有地方。
他们还建立了"垃圾回收"机制:定期运行后台 Codex 任务,扫描偏差、更新质量等级、发起有针对性的重构 PR。技术债务就像高息贷款——持续小额偿还,远好过让债务累积后痛苦地一次性解决。
第三部分:将 Harness Engineering 应用于 Browser Use Agent
3.1 Browser Use 中的 Harness 体现
回过头来看 Browser Use 的架构,它实际上已经内置了 Harness Engineering 的许多核心理念:
| Harness 组件 | Browser Use 中的实现 |
|---|---|
| 工具系统 | 内置 20+ 工具 + 自定义 @tools.action 扩展 |
| 护栏 | allowed_domains、prohibited_domains、max_steps、max_failures |
| 记忆 | AgentHistoryList、max_history_items 控制记忆窗口 |
| 重试 | max_failures + final_response_after_failure |
| 可观测性 | 完整的执行历史、截图记录、视频录制、HAR 追踪 |
| 上下文管理 | page_extraction_llm(可用小模型提取页面内容)、DOM 过滤 |
| 编排 | Agent Loop + 多动作步骤 + thinking 模式 |
3.2 构建生产级 Browser Use Agent 的 Harness 架构
以下是一个将 Harness Engineering 理念完整应用于 Browser Use Agent 的生产架构设计:
import asyncio
import logging
from browser_use import Agent, Browser, Tools, ActionResult, ChatBrowserUse
from pydantic import BaseModel
# ============================================
# Layer 1: 模型接口 - 配置与降级策略
# ============================================
# 主模型
primary_llm = ChatBrowserUse()
# 降级模型(当主模型失败时)
from browser_use import ChatOpenAI
fallback_llm = ChatOpenAI(model="gpt-4.1-mini")
# 页面提取专用小模型(降低成本)
extraction_llm = ChatOpenAI(model="gpt-4.1-mini")
# ============================================
# Layer 2: 运行时环境 - 工具、护栏、验证
# ============================================
# 结构化输出 Schema(输出护栏)
class ResearchResult(BaseModel):
title: str
url: str
summary: str
confidence: float
# 自定义工具
tools = Tools(exclude_actions=['evaluate']) # 移除 JS 执行(安全护栏)
@tools.action(
description='Save research results to database',
allowed_domains=['*.example.com'] # 域名限制护栏
)
async def save_results(results: list[dict]) -> ActionResult:
# 输出验证
validated = [ResearchResult(**r) for r in results]
# 持久化逻辑
return ActionResult(
extracted_content=f"Saved {len(validated)} results",
long_term_memory="Results have been saved, no need to save again"
)
@tools.action(description='Ask human for confirmation before proceeding')
async def human_confirmation(question: str) -> ActionResult:
answer = input(f"[Agent asks]: {question} (y/n) > ")
return ActionResult(extracted_content=f"Human responded: {answer}")
# 浏览器配置(执行护栏)
browser = Browser(
headless=True,
window_size={'width': 1920, 'height': 1080},
allowed_domains=['*.google.com', '*.github.com'], # 域名白名单
prohibited_domains=['*.gambling-site.net'], # 域名黑名单
highlight_elements=True,
paint_order_filtering=True,
record_video_dir='./recordings', # 可观测性:录制操作视频
minimum_wait_page_load_time=0.5,
wait_for_network_idle_page_load_time=1.0,
)
# ============================================
# Layer 3: 编排层 - 重试、降级、反馈回路
# ============================================
async def run_with_harness(task: str, max_retries: int = 3):
"""带完整 Harness 的 Agent 执行函数"""
for attempt in range(max_retries):
try:
# 选择模型(首次用主模型,重试用降级模型)
llm = primary_llm if attempt == 0 else fallback_llm
agent = Agent(
task=task,
llm=llm,
browser=browser,
tools=tools,
page_extraction_llm=extraction_llm,
use_vision="auto",
max_actions_per_step=3,
max_failures=3,
use_thinking=True,
output_model_schema=ResearchResult,
save_conversation_path=f'./logs/conversation_{attempt}.json',
generate_gif=True,
)
history = await agent.run(max_steps=50)
# ========== 执行后验证(输出护栏) ==========
if history.is_done() and history.is_successful():
result = history.structured_output
# 业务逻辑验证
if result and result.confidence >= 0.7:
logging.info(f"Task completed successfully on attempt {attempt + 1}")
logging.info(f"Steps: {history.number_of_steps()}, "
f"Duration: {history.total_duration_seconds():.1f}s")
return result
else:
logging.warning(f"Low confidence result ({result.confidence}), retrying...")
continue
# 任务未完成但未报错——可能是 max_steps 耗尽
if not history.is_done():
logging.warning(f"Agent did not finish within max_steps on attempt {attempt + 1}")
# 分析失败原因,调整下一轮策略
thoughts = history.model_thoughts()
logging.debug(f"Last thoughts: {thoughts[-3:] if thoughts else 'None'}")
continue
except Exception as e:
logging.error(f"Attempt {attempt + 1} failed with error: {e}")
if attempt == max_retries - 1:
# 最终降级:人工升级
logging.critical("All retries exhausted. Escalating to human operator.")
raise
await asyncio.sleep(2 ** attempt) # 指数退避
return None
# ============================================
# 入口
# ============================================
async def main():
result = await run_with_harness(
task="Go to GitHub trending repositories, find the top 3 Python projects "
"from this week, extract their name, URL, and description."
)
if result:
print(f"Result: {result}")
if __name__ == "__main__":
asyncio.run(main())
这段代码展示了一个完整的三层 Harness 架构:
- Layer 1 配置了主模型与降级模型,以及专用的页面提取小模型以降低成本
- Layer 2 定义了工具(含安全限制)、结构化输出 Schema、浏览器安全配置
- Layer 3 实现了带指数退避的重试循环、模型降级策略、输出质量验证和人工升级机制
3.3 上下文管理:给 Agent 一张地图
Browser Use 中的上下文管理是一个容易被忽视但极其关键的环节。每一步 Agent 循环都需要将以下信息塞入 LLM 的上下文窗口:
系统 Prompt(角色定义 + 工具描述)
+ 任务描述
+ 当前页面 DOM(可能非常大)
+ 截图(如果启用视觉)
+ 历史记录(之前的动作和结果)
+ 自定义指令
当页面 DOM 很大、历史步骤很多时,上下文窗口会迅速膨胀。Browser Use 提供了几个关键的上下文管理机制:
agent = Agent(
task="...",
llm=llm,
# 上下文压缩:用小模型提取页面关键内容,而非传递完整 DOM
page_extraction_llm=ChatOpenAI(model="gpt-4.1-mini"),
# 历史窗口:仅保留最近 N 步的完整历史
# 更早的历史会被压缩为摘要
max_history_items=20,
# DOM 过滤:paint_order_filtering 移除被遮挡的元素
# 减少 DOM 噪声
browser=Browser(paint_order_filtering=True),
# 视觉细节级别:low 模式使用更少的 Token
vision_detail_level="low",
)
这与 OpenAI Codex 团队的"地图而非说明书"理念完全一致——不要把所有信息一股脑塞给 Agent,而是提供一个精简的、分层的信息结构,让 Agent 按需深入。
3.4 记忆系统的深度设计
Browser Use 的记忆系统分为三个层次:
短期记忆:步骤历史
每一步的动作和结果都记录在 AgentHistoryList 中。这是 Agent 的"工作记忆",让它知道自己做过什么、看到过什么。
中期记忆:长期记忆注入
通过自定义工具的 ActionResult,可以向 Agent 注入持久化的记忆:
@tools.action(description='Login to the system')
async def login(username: str, password: str) -> ActionResult:
# ... 登录逻辑 ...
return ActionResult(
extracted_content="Login successful",
# 这条信息会被持久化到 Agent 的记忆中
# 在后续所有步骤中都可见
long_term_memory="Already logged in as admin. No need to login again."
)
跨会话记忆:对话持久化
通过 save_conversation_path 保存完整的对话历史,可以在后续会话中加载:
agent = Agent(
task="Continue the research from yesterday",
llm=llm,
save_conversation_path='./sessions/research_session.json',
)
在 Harness Engineering 的框架下,记忆系统的设计原则是:
- 选择性记忆——不是所有信息都值得记住,过多的记忆会稀释关键信息
- 结构化存储——使用明确的类型(事实、偏好、约束)而非原始文本
- 衰减机制——旧的、不再相关的记忆应该被淡化或移除
- 检索优先——记忆的价值不在于存储,而在于能否在正确的时刻被检索出来
3.5 护栏的多层防御
在生产环境中,Browser Use Agent 的护栏需要从多个维度构建:
┌─────────────────────────────────────────────────┐
│ 第一层:输入护栏 │
│ - 任务描述的内容过滤(防止 Prompt 注入) │
│ - 敏感信息脱敏(PII 检测与替换) │
│ - 任务复杂度评估(过于复杂的任务拒绝或拆分) │
├─────────────────────────────────────────────────┤
│ 第二层:执行护栏 │
│ - 域名白名单/黑名单 │
│ - 工具权限控制(禁用危险工具如 evaluate) │
│ - 最大步数限制(max_steps) │
│ - 最大失败次数(max_failures) │
│ - 单步最大动作数(max_actions_per_step) │
│ - 页面加载超时 │
│ - 成本预算(Token 消耗上限) │
├─────────────────────────────────────────────────┤
│ 第三层:输出护栏 │
│ - 结构化输出验证(output_model_schema) │
│ - 业务逻辑检查(如置信度阈值) │
│ - 敏感数据过滤(防止 Agent 泄露密码等) │
│ - 人工审批门(关键操作前请求确认) │
└─────────────────────────────────────────────────┘
一个实际的多层护栏实现:
from browser_use import Agent, Browser, Tools, ActionResult
# 执行护栏:浏览器级别
browser = Browser(
allowed_domains=['*.target-site.com'],
prohibited_domains=['*.social-media.com', '*.payment.com'],
headless=True,
)
# 工具护栏:禁用危险操作
tools = Tools(
exclude_actions=[
'evaluate', # 禁止执行任意 JavaScript
'upload_file', # 禁止上传文件
'write_file', # 禁止写入本地文件
]
)
# 输出护栏:结构化验证
from pydantic import BaseModel, validator
class SafeOutput(BaseModel):
data: str
source_url: str
@validator('data')
def no_sensitive_info(cls, v):
import re
# 检测并拒绝包含信用卡号的输出
if re.search(r'\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b', v):
raise ValueError("Output contains potential credit card number")
return v
# 人工审批护栏
@tools.action(description='Submit form with important data')
async def submit_form(data: dict) -> ActionResult:
print(f"\n⚠️ Agent wants to submit: {data}")
approval = input("Approve? (yes/no) > ")
if approval.lower() != 'yes':
return ActionResult(extracted_content="Human rejected the submission. Try a different approach.")
# ... 执行提交 ...
return ActionResult(extracted_content="Form submitted successfully")
第四部分:高级模式与最佳实践
4.1 多 Agent 协作
Browser Use 支持多个 Agent 共享同一个浏览器实例,实现协作式任务处理:
from browser_use import Agent, Browser
browser = Browser()
# Agent 1:负责搜索和收集信息
researcher = Agent(
task="Search for the latest AI research papers on arxiv about browser agents",
llm=llm,
browser=browser,
)
# Agent 2:负责分析和总结
analyst = Agent(
task="Analyze the papers found in the browser tabs and create a summary",
llm=llm,
browser=browser, # 共享同一个浏览器
)
# 顺序执行
research_history = await researcher.run()
analysis_history = await analyst.run()
在 Harness Engineering 的编排层中,多 Agent 协作可以进一步扩展为:
async def orchestrated_research(topic: str):
browser = Browser()
# 阶段 1:并行搜索(多个 Agent 搜索不同来源)
agents = [
Agent(task=f"Search {source} for: {topic}", llm=llm, browser=browser)
for source in ["Google Scholar", "arXiv", "GitHub"]
]
# 注意:Browser Use 的浏览器实例是单线程的
# 并行需要多个浏览器实例
results = []
for agent in agents:
history = await agent.run()
results.append(history.extracted_content())
# 阶段 2:综合分析
synthesizer = Agent(
task=f"Based on these findings, create a comprehensive summary:\n{results}",
llm=llm,
browser=browser,
)
return await synthesizer.run()
4.2 敏感操作处理
处理登录、支付等敏感操作时,Browser Use 提供了安全的凭证注入机制:
import os
# 方式一:通过 sensitive_data 参数注入(不会出现在日志中)
agent = Agent(
task="Login to the admin dashboard at https://admin.example.com",
llm=llm,
sensitive_data={
'ADMIN_USERNAME': os.getenv('ADMIN_USERNAME'),
'ADMIN_PASSWORD': os.getenv('ADMIN_PASSWORD'),
'TOTP_SECRET': os.getenv('TOTP_SECRET'),
},
)
# 方式二:通过自定义工具注入 2FA 代码
import pyotp
@tools.action(description='Get current 2FA code')
async def get_2fa() -> ActionResult:
totp = pyotp.TOTP(os.getenv('TOTP_SECRET'))
return ActionResult(extracted_content=f"Current 2FA code: {totp.now()}")
sensitive_data 中的值会被替换为占位符(如 x])出现在 Agent 的上下文中,Agent 知道在需要时使用这些占位符,但实际值不会被发送到 LLM——这是一个关键的安全设计。
4.3 连接已有浏览器会话
在某些场景下,你可能需要 Agent 接管一个已经登录的浏览器会话,而不是从零开始:
from browser_use import Browser
# 方式一:连接到已运行的 Chrome 实例(通过 CDP)
# 先启动 Chrome:chrome --remote-debugging-port=9222
browser = Browser(
cdp_url="ws://localhost:9222/devtools/browser/..."
)
# 方式二:使用持久化的用户数据目录(保留 Cookie 和登录状态)
browser = Browser(
user_data_dir='./chrome_profile',
keep_alive=True, # 任务结束后不关闭浏览器
)
# 方式三:使用 Browser Use Cloud(自动处理验证码和反爬)
browser = Browser(use_cloud=True)
4.4 性能优化策略
在生产环境中,Browser Use Agent 的性能优化需要从多个维度入手:
Token 成本优化
agent = Agent(
task="...",
llm=llm,
# 1. 使用小模型提取页面内容(大幅降低主模型的输入 Token)
page_extraction_llm=ChatOpenAI(model="gpt-4.1-mini"),
# 2. 降低视觉细节级别
vision_detail_level="low",
# 3. 限制历史记忆窗口
max_history_items=10,
# 4. 启用 flash 模式(跳过评估和推理)
flash_mode=True, # 适合简单、重复性任务
# 5. 增加单步动作数(减少 LLM 调用次数)
max_actions_per_step=5,
)
执行速度优化
browser = Browser(
headless=True, # 无头模式更快
minimum_wait_page_load_time=0.1, # 减少等待时间
wait_for_network_idle_page_load_time=0.3,
wait_between_actions=0.2, # 减少动作间隔
)
成本与质量的权衡矩阵
| 场景 | 推荐配置 | 预估成本/任务 |
|---|---|---|
| 简单数据提取 | flash_mode + gpt-4.1-mini + no vision | $0.01-0.05 |
| 复杂表单填写 | thinking + gpt-4o + auto vision | $0.10-0.50 |
| 多页面研究 | thinking + ChatBrowserUse + auto vision | $0.20-1.00 |
| 关键业务流程 | thinking + ChatBrowserUse + high vision + human approval | $0.50-2.00 |
4.5 调试与可观测性
Browser Use 提供了丰富的调试工具:
import logging
# 启用详细日志
logging.basicConfig(level=logging.DEBUG)
agent = Agent(
task="...",
llm=llm,
# 保存完整对话历史(含 LLM 输入输出)
save_conversation_path='./debug/conversation.json',
# 生成操作 GIF 动画
generate_gif=True,
# 录制操作视频
browser=Browser(record_video_dir='./debug/videos'),
)
history = await agent.run()
# 执行后分析
print(f"总步数: {history.number_of_steps()}")
print(f"总耗时: {history.total_duration_seconds():.1f}s")
print(f"访问的 URL: {history.urls()}")
print(f"执行的动作: {history.action_names()}")
print(f"错误: {history.errors()}")
print(f"Agent 思考过程: {history.model_thoughts()}")
在 Harness Engineering 的可观测性框架下,还应该追踪:
# 自定义指标收集
class AgentMetrics:
def __init__(self):
self.runs = []
async def track_run(self, task: str, agent: Agent):
import time
start = time.time()
history = await agent.run()
duration = time.time() - start
metrics = {
'task': task,
'success': history.is_successful(),
'steps': history.number_of_steps(),
'duration_seconds': duration,
'errors': len(history.errors()),
'urls_visited': len(history.urls()),
'actions_executed': len(history.action_names()),
# Token 使用量需要从 LLM 回调中获取
}
self.runs.append(metrics)
# 发送到监控系统
# datadog.send_metrics(metrics)
# prometheus.observe(metrics)
return history
第五部分:Browser Use Agent 的技术挑战与前沿探索
5.1 当前面临的核心挑战
挑战一:反爬与验证码
现代网站越来越多地部署反自动化措施——CAPTCHA、设备指纹、行为分析、IP 信誉评分。Browser Use 通过以下方式应对:
- Browser Use Cloud:官方云端浏览器服务,内置验证码绕过和反检测能力
- 代理支持:通过
ProxySettings配置代理 IP 轮换 - 持久化会话:使用
user_data_dir保持真实的浏览器指纹 - 人工介入:当遇到无法自动处理的验证码时,通过自定义工具请求人工协助
@tools.action(description='Solve CAPTCHA that the agent cannot handle')
async def solve_captcha() -> ActionResult:
input("Please solve the CAPTCHA in the browser window, then press Enter...")
return ActionResult(extracted_content="CAPTCHA solved by human")
挑战二:动态内容与 SPA
单页应用(SPA)的动态渲染给 DOM 提取带来了挑战。页面内容可能在初始加载后通过 JavaScript 异步更新,Agent 在 DOM 提取时可能看到不完整的页面。
Browser Use 的应对策略:
browser = Browser(
# 等待网络空闲,确保异步请求完成
wait_for_network_idle_page_load_time=2.0,
# 额外的页面加载等待
minimum_wait_page_load_time=1.0,
)
# 或者在 Agent 层面使用 wait 动作
# Agent 可以主动调用 wait 工具等待特定条件
挑战三:幻觉与错误累积
LLM 可能"幻觉"出不存在的页面元素,或者误解页面内容。在多步任务中,一个早期的错误可能像滚雪球一样累积,导致后续所有步骤都偏离正确路径。
Harness Engineering 的应对策略:
- 检查点验证:在关键步骤后插入验证逻辑
- 状态断言:定期检查 Agent 是否仍在正确的页面/状态
- 回滚机制:检测到偏差时回退到上一个已知正确的状态
- 多路径探索:对关键决策点尝试多种方案
@tools.action(description='Verify current page matches expected state')
async def verify_state(expected_url_pattern: str, expected_content: str,
browser_session) -> ActionResult:
page = browser_session.current_page
current_url = page.url
if expected_url_pattern not in current_url:
return ActionResult(
extracted_content=f"WARNING: Expected URL containing '{expected_url_pattern}' "
f"but got '{current_url}'. Navigation may have gone wrong.",
long_term_memory=f"State verification failed. Current URL: {current_url}"
)
content = await page.content()
if expected_content.lower() not in content.lower():
return ActionResult(
extracted_content=f"WARNING: Expected content '{expected_content}' not found on page."
)
return ActionResult(extracted_content="State verification passed.")
挑战四:成本控制
每一步 Agent 循环都需要调用 LLM,加上截图的 Token 开销,复杂任务的成本可能快速攀升。
成本控制的分层策略:
预算控制层
├── 任务级预算:每个任务设置最大 Token/成本上限
├── 步骤级优化:flash_mode、减少视觉使用、压缩历史
├── 模型级策略:简单步骤用小模型,关键决策用大模型
└── 架构级设计:缓存常见页面的 DOM 结构,避免重复提取
5.2 Browser Use 与竞品对比
2025 年的浏览器 Agent 赛道已经相当拥挤,以下是主要竞品的对比:
| 特性 | Browser Use | Playwright MCP | Stagehand | LaVague |
|---|---|---|---|---|
| 开源 | ✅ MIT | ✅ Apache 2.0 | ✅ MIT | ✅ Apache 2.0 |
| 语言 | Python | TypeScript | TypeScript | Python |
| LLM 支持 | 多模型 | 依赖 MCP 客户端 | OpenAI/Anthropic | 多模型 |
| 视觉理解 | ✅ 混合模式 | ❌ 纯 DOM | ✅ 视觉优先 | ✅ |
| 自定义工具 | ✅ 装饰器 API | ❌ | 有限 | ✅ |
| 云端浏览器 | ✅ 官方云 | ❌ | ❌ | ❌ |
| GitHub Stars | 60k+ | N/A | 15k+ | 5k+ |
| 生产就绪度 | 高 | 中 | 中 | 中 |
Browser Use 的核心优势在于:
- 最大的社区和生态(60k+ Stars)
- DOM + Vision 混合分析的成熟实现
- 灵活的工具扩展系统
- 官方云端浏览器服务(解决反爬问题)
- 完善的可观测性工具链
5.3 前沿探索:Agent 的自我进化
Harness Engineering 的终极愿景不仅是让 Agent 可靠地执行任务,还包括让 Agent 能够自我改进。OpenAI Codex 团队的实践揭示了一个有趣的模式:
Agent 可以为自己编写工具、测试和文档。
在 Browser Use 的语境下,这意味着:
# 未来可能的自进化模式
# 1. Agent 从失败中学习,自动生成新的工具
@tools.action(description='Create a new reusable tool from learned pattern')
async def create_tool(tool_name: str, tool_code: str, description: str) -> ActionResult:
# Agent 识别到重复的操作模式后
# 自动将其封装为可复用的工具
# 保存到工具库中供后续任务使用
pass
# 2. Agent 自动优化 Prompt
# 基于历史成功/失败记录,调整系统 Prompt 中的指导信息
# 3. Agent 自动生成测试用例
# 对关键业务流程生成回归测试,确保网站变化时及时发现
这与 Harness Engineering 中"垃圾回收"的理念一脉相承——Agent 不仅执行任务,还持续维护和优化自身的运行环境。
第六部分:实战案例——构建一个生产级的竞品监控系统
让我们将前面所有的理论知识整合到一个完整的实战案例中:构建一个自动化的竞品价格监控系统。
6.1 需求描述
- 每天自动访问 3 个竞品网站
- 提取指定产品的价格、库存状态和促销信息
- 将数据存储到数据库
- 价格变动超过 5% 时发送告警
- 需要处理登录、反爬、动态加载等复杂场景
6.2 完整实现
import asyncio
import json
import logging
from datetime import datetime
from typing import Optional
from pydantic import BaseModel, Field
from browser_use import Agent, Browser, Tools, ActionResult, ChatBrowserUse
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# ============================================
# 数据模型(输出护栏)
# ============================================
class ProductPrice(BaseModel):
product_name: str
price: float = Field(ge=0)
currency: str = Field(default="USD")
in_stock: bool
promotion: Optional[str] = None
source_url: str
extracted_at: str = Field(default_factory=lambda: datetime.now().isoformat())
class CompetitorReport(BaseModel):
competitor: str
products: list[ProductPrice]
extraction_success: bool
error_message: Optional[str] = None
# ============================================
# 工具定义
# ============================================
tools = Tools(
exclude_actions=['evaluate', 'upload_file'] # 安全护栏
)
# 模拟数据库
price_history_db: list[dict] = []
@tools.action(description='Save product price to database and check for significant changes')
async def save_price(product_name: str, price: float, currency: str,
in_stock: bool, source_url: str,
promotion: str = None) -> ActionResult:
record = ProductPrice(
product_name=product_name,
price=price,
currency=currency,
in_stock=in_stock,
promotion=promotion,
source_url=source_url,
)
# 检查价格变动
previous = [r for r in price_history_db
if r['product_name'] == product_name and r['source_url'] == source_url]
alert_msg = ""
if previous:
last_price = previous[-1]['price']
change_pct = abs(price - last_price) / last_price * 100
if change_pct >= 5:
alert_msg = (f" ALERT: Price changed by {change_pct:.1f}% "
f"(was {last_price} {currency}, now {price} {currency})")
logger.warning(f"Price alert for {product_name}: {alert_msg}")
# 在生产环境中,这里会发送 Slack/Email 通知
price_history_db.append(record.model_dump())
return ActionResult(
extracted_content=f"Saved: {product_name} @ {price} {currency}.{alert_msg}",
long_term_memory=f"Price for {product_name} has been saved. Do not save it again."
)
@tools.action(description='Report extraction failure for a competitor')
async def report_failure(competitor: str, error: str) -> ActionResult:
logger.error(f"Extraction failed for {competitor}: {error}")
return ActionResult(
extracted_content=f"Failure reported for {competitor}: {error}"
)
# ============================================
# Harness 编排层
# ============================================
class CompetitorMonitor:
def __init__(self):
self.llm = ChatBrowserUse()
self.browser = Browser(
headless=True,
window_size={'width': 1920, 'height': 1080},
highlight_elements=True,
paint_order_filtering=True,
minimum_wait_page_load_time=1.0,
wait_for_network_idle_page_load_time=2.0,
)
async def monitor_competitor(self, competitor_name: str, url: str,
products: list[str]) -> CompetitorReport:
"""监控单个竞品网站,带完整的重试和降级策略"""
max_retries = 3
for attempt in range(max_retries):
try:
product_list = ", ".join(products)
task = (
f"Go to {url} and find the following products: {product_list}. "
f"For each product, extract the current price, currency, "
f"whether it's in stock, and any active promotions. "
f"Use the save_price tool to save each product's data. "
f"If a product cannot be found, skip it and continue with the next one."
)
agent = Agent(
task=task,
llm=self.llm,
browser=self.browser,
tools=tools,
use_vision="auto",
use_thinking=True,
max_actions_per_step=3,
max_failures=3,
save_conversation_path=(
f'./logs/{competitor_name}_{datetime.now().strftime("%Y%m%d_%H%M")}'
f'_attempt{attempt}.json'
),
generate_gif=True,
)
history = await agent.run(max_steps=40)
if history.is_done():
# 从数据库中提取本次运行保存的记录
saved_products = [
ProductPrice(**r) for r in price_history_db
if r['source_url'].startswith(url.split('/')[2]) # 匹配域名
]
logger.info(
f"[{competitor_name}] Completed: {len(saved_products)} products, "
f"{history.number_of_steps()} steps, "
f"{history.total_duration_seconds():.1f}s"
)
return CompetitorReport(
competitor=competitor_name,
products=saved_products,
extraction_success=True,
)
# Agent 未完成——可能是步数耗尽
logger.warning(
f"[{competitor_name}] Agent did not finish on attempt {attempt + 1}. "
f"Last thoughts: {history.model_thoughts()[-1] if history.model_thoughts() else 'N/A'}"
)
except Exception as e:
logger.error(f"[{competitor_name}] Attempt {attempt + 1} failed: {e}")
if attempt < max_retries - 1:
await asyncio.sleep(2 ** attempt) # 指数退避:1s, 2s, 4s
# 所有重试耗尽
return CompetitorReport(
competitor=competitor_name,
products=[],
extraction_success=False,
error_message=f"All {max_retries} attempts failed",
)
async def run_daily_monitoring(self, competitors: list[dict]) -> list[CompetitorReport]:
"""每日监控入口:顺序执行所有竞品监控"""
reports = []
for comp in competitors:
logger.info(f"Starting monitoring for: {comp['name']}")
report = await self.monitor_competitor(
competitor_name=comp['name'],
url=comp['url'],
products=comp['products'],
)
reports.append(report)
# 竞品之间间隔,避免触发反爬
await asyncio.sleep(5)
# 生成汇总报告
success_count = sum(1 for r in reports if r.extraction_success)
total_products = sum(len(r.products) for r in reports)
logger.info(
f"\n{'='*50}\n"
f"Daily Monitoring Summary\n"
f"Competitors monitored: {len(reports)}\n"
f"Successful: {success_count}/{len(reports)}\n"
f"Total products tracked: {total_products}\n"
f"{'='*50}"
)
return reports
# ============================================
# 入口
# ============================================
async def main():
competitors = [
{
"name": "Competitor A",
"url": "https://www.competitor-a.com/products",
"products": ["Widget Pro", "Widget Lite", "Widget Enterprise"],
},
{
"name": "Competitor B",
"url": "https://www.competitor-b.com/pricing",
"products": ["Basic Plan", "Pro Plan", "Enterprise Plan"],
},
{
"name": "Competitor C",
"url": "https://www.competitor-c.com/store",
"products": ["Starter Kit", "Professional Kit"],
},
]
monitor = CompetitorMonitor()
reports = await monitor.run_daily_monitoring(competitors)
# 持久化报告
with open(f'./reports/daily_{datetime.now().strftime("%Y%m%d")}.json', 'w') as f:
json.dump([r.model_dump() for r in reports], f, indent=2, default=str)
if __name__ == "__main__":
asyncio.run(main())
6.3 架构复盘
这个竞品监控系统完整体现了 Harness Engineering 的三层架构:
| 层级 | 实现 | 作用 |
|---|---|---|
| Layer 1 模型接口 | ChatBrowserUse() + 结构化 task prompt | 驱动 Agent 的推理与决策 |
| Layer 2 运行时环境 | Tools(含 save_price、report_failure)、ProductPrice Schema 验证、exclude_actions 安全限制 | 约束 Agent 的行为边界 |
| Layer 3 编排层 | CompetitorMonitor 类、重试循环、指数退避、汇总报告 | 协调多任务执行与异常恢复 |
同时覆盖了 Harness 的七大组件:
- 工具选择——精选
save_price和report_failure,禁用evaluate和upload_file - 记忆——
long_term_memory防止重复保存,save_conversation_path持久化对话 - 护栏——Pydantic Schema 验证、价格非负约束、工具黑名单
- 重试——3 次重试 + 指数退避 + 错误日志
- 上下文管理——
use_vision="auto"按需使用视觉,use_thinking=True启用推理 - 可观测性——完整日志、GIF 录制、对话保存、汇总报告
- Prompt 管理——结构化的 task 描述,明确指定提取字段和工具使用方式
第七部分:展望——Browser Agent 的未来
7.1 从工具到基础设施
2025 年的 Browser Use 仍然主要被当作一个"工具"来使用——开发者编写脚本,调用 Agent,获取结果。但随着 Harness Engineering 理念的普及,Browser Agent 正在向"基础设施"演进。
未来的 Browser Agent 平台可能具备以下特征:
- 声明式任务定义:开发者只需描述"我要什么",而非"怎么做"。类似于 Kubernetes 的声明式 API,你定义期望状态,系统自动规划执行路径。
# 未来可能的声明式任务定义
task:
name: "daily-price-check"
schedule: "0 9 * * *"
targets:
- url: "https://competitor.com/pricing"
extract:
- field: "price"
selector_hint: "main pricing table"
type: float
- field: "plan_name"
type: string
output:
format: "json"
destination: "s3://my-bucket/prices/"
guardrails:
max_cost_per_run: "$0.50"
max_duration: "5m"
allowed_domains: ["competitor.com"]
-
自愈能力:当网站 UI 变化导致提取失败时,Agent 自动适应新的页面结构,无需人工更新脚本。这是传统 Selenium 脚本永远无法实现的能力。
-
联邦式执行:任务自动分发到全球各地的浏览器节点执行,绕过地理限制,提高可靠性。
7.2 Agent-Native 软件架构
OpenAI Codex 团队的实践揭示了一个更深层的趋势:软件架构本身正在为 Agent 而重新设计。
传统架构为人类开发者优化——代码组织方式、命名约定、文档风格都是为了让人类更容易理解和修改。Agent-Native 架构则增加了一个新的维度:让 Agent 也能高效地理解和操作代码。
这意味着:
- 更严格的类型系统——类型不仅帮助人类,更帮助 Agent 理解代码的意图和约束
- 更细粒度的模块化——小而独立的模块比大而复杂的模块更容易被 Agent 理解和修改
- 机器可读的架构文档——不仅有人类可读的 README,还有结构化的架构描述文件
- 自动化的不变量检查——通过 Linter、类型检查器和结构测试,机械地强制执行架构约束
7.3 Harness Engineer 的角色定义
随着 Agent 承担越来越多的执行工作,工程师的角色正在发生根本性转变。OpenAI 团队将这个新角色称为 Harness Engineer,其核心职责包括:
- 环境设计师:设计 Agent 的运行环境——工具、权限、约束、反馈机制
- 意图翻译者:将模糊的业务需求翻译为 Agent 可以理解和执行的精确规范
- 质量守护者:设计验证机制,确保 Agent 的输出满足质量标准
- 系统架构师:设计多 Agent 协作的编排逻辑,处理故障恢复和降级策略
- 反馈回路工程师:构建从执行结果到 Agent 改进的闭环反馈系统
这不是"提示工程"的升级版。Harness Engineering 涵盖了从系统架构到运维监控的完整工程实践,它要求工程师同时具备软件工程的严谨性和对 LLM 行为特性的深刻理解。
7.4 开放问题
尽管 Browser Use Agent 和 Harness Engineering 代表了当前的最佳实践,仍有许多开放问题等待解决:
-
可靠性的天花板在哪里? 当前最好的 Browser Agent 在复杂任务上的成功率大约在 70-90%。对于关键业务流程,这个数字是否足够?如何在不牺牲灵活性的前提下进一步提高可靠性?
-
成本曲线何时交叉? 目前 Browser Agent 的单次任务成本(2.00)在某些场景下高于传统脚本。随着模型成本持续下降,何时会达到全面替代的经济拐点?
-
安全边界如何定义? 让 AI Agent 自主浏览互联网并执行操作,安全风险如何量化和管控?特别是在涉及支付、个人数据和法律合规的场景中。
-
Agent 的可解释性? 当 Agent 做出意外决策时,我们能否追溯其推理过程并理解"为什么"?当前的
model_thoughts()提供了部分可见性,但远未达到完全可解释的程度。 -
多 Agent 协作的涌现行为? 当多个 Agent 在同一个浏览器或同一个网站上协作时,是否会出现意料之外的涌现行为?如何预防和检测?
结语
Browser Use Agent 代表了浏览器自动化从"脚本驱动"到"智能体驱动"的范式转换。它不再要求开发者精确指定每一个 CSS 选择器和操作步骤,而是让 AI 像人类一样理解页面、规划路径、执行操作。
但正如 OpenAI Codex 团队的实践所揭示的,原始的 LLM 能力只是引擎。要将这台引擎变成一辆可靠的汽车,需要 Harness Engineering——精心设计的工具系统、多层护栏、智能记忆、弹性重试、全面可观测性和严谨的编排逻辑。
对于今天的开发者而言,最务实的建议是:
- 从简单任务开始,用 Browser Use 的默认配置快速验证可行性
- 逐步添加 Harness 组件——先加护栏和重试,再加可观测性和记忆
- 将 Prompt 和工具定义视为代码,纳入版本控制和 Code Review
- 为 Agent 设计环境,而非为环境编写 Agent——投资于清晰的架构约束和自动化验证,而非越来越复杂的 Prompt
- 保持人类在回路中——至少在关键决策点,保留人工审批的能力
浏览器 Agent 的时代才刚刚开始。我们正站在一个从"编写自动化脚本"到"设计智能体运行环境"的转折点上。掌握 Harness Engineering 的团队,将在这场转型中占据先机。
参考资料:
- Browser Use 官方文档:https://docs.browser-use.com
- Browser Use GitHub 仓库:https://github.com/browser-use/browser-use
- OpenAI Codex: Building Software with No Human-Written Code (2025)
- Harness Engineering: The Emerging Discipline of Making AI Agents Work Reliably
- Anthropic Computer Use, Google Project Mariner 等相关项目文档