跳转到内容

工具调用协议 — LLM 决策到浏览器操作的映射

学习目标

  • 理解 Browser Use 如何将 LLM 的 JSON 输出映射为浏览器动作
  • 掌握动态 discriminated union Pydantic 模型的生成机制
  • 了解页面感知工具过滤和坐标点击的实现

前置知识

下文假设你已理解工具调用的通用原理,直接聚焦 Browser Use 的具体实现。


项目实践

动态 Discriminated Union 模型生成

Browser Use 的 Registry.create_action_model() 在运行时动态生成包含所有注册动作的联合 Pydantic 模型:

# 伪代码示意
ActionModel = Annotated[
Union[
Annotated[ClickElementAction, Field("click_element")],
Annotated[TypeTextAction, Field("type_text")],
Annotated[NavigateAction, Field("navigate")],
Annotated[ScrollAction, Field("scroll")],
# ... 更多动作
],
Field(discriminator=True)
]

关键设计

  • 每个动作对应一个 Pydantic 模型,包含参数定义
  • 使用 Pydantic v2 的 discriminator 字段实现快速反序列化
  • 当注册新工具(通过 @tools.action() 装饰器)后,重新调用 create_action_model() 生成新模型
  • Agent 的 AgentOutput 类型使用 type_with_custom_actions() 工厂方法,将动态 ActionModel 嵌入输出 schema

内置动作集合

Browser Use 提供 15+ 内置浏览器动作:

动作参数说明
click_elementindex 或 coordinate点击交互元素
type_textindex, text向输入框输入文本
navigateurl, new_tab导航到 URL
scrolldirection, amount滚动页面
go_back浏览器后退
extractquery从页面提取信息
screenshot截取当前页面
switch_tabtarget_id切换到标签页
close_tab关闭当前标签页
search_googlequeryGoogle 搜索
send_keyskeys发送键盘快捷键
upload_fileindex, paths上传文件
get_dropdown_optionsindex获取下拉选项
select_dropdown_optionindex, value选择下拉选项

页面过滤动作

根据当前页面 URL 动态调整可用动作:

# 在 Registry 中注册 URL 级过滤
registry.register_action(
name="click_buy_button",
description="点击购买按钮",
url_filter=lambda url: "cart" in url or "checkout" in url
)

Agent 在每次 turn 前调用 registry.get_prompt_description(url) 获取当前页面可用的动作描述,注入到上下文。这减少了发送给 LLM 的 schema 大小,并避免了在不适用的页面上出现不相关的动作。

坐标点击

对支持视觉的模型(Claude Sonnet/Opus、Gemini 3 Pro、Browser Use 自研模型),工具返回元素的像素坐标 (x, y) 而非仅索引:

# 在 Agent 初始化时自动检测
model_name = getattr(llm, 'model', '').lower()
supports_coordinate_clicking = any(
pattern in model_name for pattern in [
'claude-sonnet-4', 'claude-opus-4', 'gemini-3-pro', 'browser-use/'
]
)
if supports_coordinate_clicking:
tools.set_coordinate_clicking(True)

坐标点击的优势是不受 DOM 动态变化的影响——LLM 直接在截图上定位点击位置。

动作超时保护

每个动作有独立的超时限制:

  • 默认:180s(_ACTION_TIMEOUT_FALLBACK_S
  • 环境变量:BROWSER_USE_ACTION_TIMEOUT_S 覆盖
  • 超时后返回 ActionResult(error="timeout") 而非挂起

问题与规避

工具 schema 过大消耗 Token

问题:当注册了大量自定义工具时,所有工具的 JSON Schema 会显著增加 prompt 大小。

对策

  • 使用页面过滤:只发送当前页面可用的工具
  • 将常用工具保持精简的参数定义
  • 对不常用工具使用 exclude_actions 参数临时禁用

动态 DOM 导致元素索引失效

问题:Agent 获取 DOM 快照后,页面可能动态变化,导致之前分配的索引 [5] 指向不同的元素。

对策

  • 每次 step 重新获取 DOM 快照,索引仅在单步内有效
  • 坐标点击进一步降低了索引失效的风险(基于截图而非 DOM)
  • 动作执行时通过 CDP 重新验证元素存在性

LLM 输出格式错误

问题:LLM 可能返回不符合 discriminated union schema 的 JSON。

对策

  • Pydantic 校验失败时,捕获 ValidationError 并返回错误消息
  • 错误消息包含期望的 schema 格式,引导 LLM 修正
  • 对于空动作输出,自动注入安全 noop(done with success=False

设计取舍

元素索引 vs 坐标点击

方案优势代价
元素索引不依赖视觉、所有模型通用DOM 动态变化时失效
坐标点击抗 DOM 变化、更贴近人类操作需要视觉模型、对截图质量敏感

Browser Use 两者兼有:对视觉模型启用坐标点击,对纯文本模型回退到索引。

动态模型 vs 静态模型

方案优势代价
动态 discriminated union工具热插拔、运行时扩展类型检查器支持弱
静态 Union 类型类型安全、IDE 提示好修改工具需改代码

Browser Use 选择动态模型是为了支持用户通过 @tools.action() 装饰器在运行时注册自定义工具。


参考来源