Agent 核心循环 — ReAct 模式在浏览器中的落地
学习目标
本章要解决什么问题:
- Browser Use 的 Agent 核心循环如何组织浏览器环境的特殊反馈(DOM、截图、页面状态)
- 如何在循环中集成规划、循环检测和失败恢复
- 如何设计和调优循环参数(最大步骤、失败次数、超时)
前置知识
- Agent 核心循环设计 — ReAct 模式、Session/Turn 模型、Doom Loop 检测
下文假设你已理解 Agent 核心循环的通用原理,直接聚焦 Browser Use 的具体实现。
项目实践
三步循环结构
Browser Use 的 Agent.step() 将每次循环分为三个明确的阶段:
Phase 1 — _prepare_context():
- 调用
get_browser_state_summary(include_screenshot=True)获取当前页面状态 - 检查新下载的文件,更新
available_file_paths - 根据当前 URL 更新动作模型(页面过滤动作)
- 调用
_message_manager.prepare_step_state()准备消息状态 - 可选的消息压缩(
maybe_compact_messages()) - 注入各类 nudge:预算警告、重规划提示、循环检测提示
Phase 2 — _get_next_action():
- 从 Message Manager 获取完整消息列表
- 调用
llm.ainvoke(messages, output_format=AgentOutput)获取结构化输出 - 内置重试:如果 LLM 返回空动作,发送澄清消息并重试一次
- 支持超时控制(每模型独立 timeout,默认 75-90s)
Phase 3 — _execute_actions() + _post_process():
- 解析 LLM 输出中的
action列表 - 通过事件总线分发每个动作到对应的 Watchdog 处理
- 收集动作结果(
ActionResult列表) - 检查下载更新、更新计划状态、记录行为序列(用于循环检测)
- 如果动作出错,递增
consecutive_failures计数器
循环终止条件:
- LLM 调用
done动作(任务完成) - 达到
max_steps(步骤预算耗尽) - 连续失败次数超过
max_failures(默认 5 次) - 外部中断(
register_should_stop_callback返回 True)
LLM 输出结构
Browser Use 使用 Pydantic 模型约束 LLM 输出格式:
AgentOutput { current_state: { thinking: str # 思维链 evaluation_previous_goal: str # 上一步评估 memory: str # 短期记忆 next_goal: str # 下一步目标 } action: list[ActionModel] # 要执行的动作列表}在 flash_mode 下,current_state 中的规划字段被移除(低能力模型不需要输出计划)。
失败恢复机制
Browser Use 实现了两层失败恢复:
动作级恢复:
- 单步失败时,错误消息作为
ActionResult(error=...)注入下一轮上下文 - LLM 看到错误后可以调整策略
- 连续 N 次失败后,强制终止 Agent
LLM 级恢复:
- 当主 LLM 遇到速率限制或服务端错误(401/429/5xx)时
- 自动切换到
fallback_llm(如果配置了的话) - 一旦切换,整个运行剩余部分都使用 fallback
问题与规避
Agent 在复杂页面陷入操作循环
问题:Agent 可能在页面上反复执行相似操作(如反复滚动但找不到目标元素)。
对策:loop_detector 在后台追踪两个维度的异常:
- 动作重复:滑动窗口内相同动作名(排除 wait/done/go_back)的重复率
- 页面停滞:连续多步后 DOM 指纹(文本内容哈希 + 元素计数)无变化
当检测到循环时,自动注入逐步升级的 nudge 消息:
- 第一轮:“你可能在重复操作,尝试改变策略”
- 第二轮:“建议输出 plan_update 重新规划”
- 最终轮:如果仍未改善,触发终止
多步任务中途失败导致前功尽弃
问题:Agent 执行 20 步后失败,之前的发现全部丢失。
对策:
- 文件系统持久化:Agent 有自己的临时目录(
/tmp/browser_use_agent_{id}_{timestamp}/) todo.md文件:Agent 可以记录任务进度- 中间文件:Agent 在提取数据时可以保存到文件系统
- 失败时的最终结果会包含之前累积的所有发现
超时配置不当导致不必要的失败
问题:使用 Groq 时默认的 90s 超时太长(Groq 通常 30s 内完成),而 Gemini 3 Pro 思考模式下 75s 不够。
对策:Browser Use 内置了模型特定的超时规则,开箱即用:
| 模型族 | 超时 |
|---|---|
| Gemini(非 3-pro) | 75s |
| Gemini 3-pro | 90s |
| Groq | 30s |
| Claude / O3 / DeepSeek | 90s |
设计取舍
同步循环 vs 异步事件驱动
| 方案 | 优势 | 代价 |
|---|---|---|
| 同步循环(当前) | 简单直观、易于调试 | 单步阻塞整个 Agent |
| 异步事件驱动 | 可以并发处理多个任务 | 状态管理复杂、调试困难 |
Browser Use 选择同步循环是因为:浏览器操作通常是顺序依赖的(先导航再点击再输入),并发收益有限。
规划集成:强制 vs 可选
enable_planning=True(默认):Agent 在探索后创建计划,支持动态更新flash_mode=True:规划字段从输出 schema 中移除,纯 ReAct- 设计权衡:规划增加 Token 成本,但对复杂多步任务有显著收益
Flash Mode 的取舍
Flash Mode 是一种能力自适应设计:当使用低能力模型时,精简输出 schema(移除 planning 字段),减少 Token 消耗和推理复杂度。代价是 Agent 失去了规划和结构化思考的能力,更适合简单的单步任务。