再学 Browser Use 的工具使用
昨天我们学习了 Browser Use 是如何利用大模型的结构化输出能力实现工具调用的,通过 AgentOutput 模式定义与动态的 ActionModel 的结合,实现了智能体在执行网页任务时灵活选择和使用不同浏览器工具。
今天我们将继续探讨浏览器操作的具体实现以及如何自定义工具,以扩展 Browser Use 的功能。
工具调用流程
现在我们再次回顾下 Browser Use 智能体循环中的 step() 方法,调用大模型得到下一步动作后,接着通过 multi_act() 方法对每一个动作进行执行:
model_output = await self.get_next_action(input_messages)
result: list[ActionResult] = await self.multi_act(model_output.action)接着通过 controller.act() -> registry.execute_action() 等方法,最后从 registry.actions 数组中找到对应的动作:
action = self.registry.actions[action_name]
return await action.function(params=validated_params, **special_context)这里的 registry.actions 表示 Browser Use 支持的所有工具,那么这个数组是怎么来的呢?我们可以在 Controller 的初始化函数中找到答案:

截图中是 go_to_url 的实现,注意函数上有一个 @self.registry.action 装饰器,这个装饰器的作用就是将这个函数实现添加到 registry.actions 数组中。
内置浏览器动作
Controller 是 Browser Use 工具调用的核心,这个类定义在 browser_use/controller/service.py 文件中,除了上面截图中的 go_to_url 动作,Browser Use 一共内置了 20 个操作浏览器的动作,如 open_tab、scroll_down、extract_content 等,我将其整理成表格如下:
| Action 名称 | 描述(中文) |
|---|---|
| done | 完成任务 - 返回文本,并指明任务是否完成(success=True 表示已完成,否则未完全完成) |
| search_google | 在 Google 中搜索查询,查询应像人类在 Google 搜索时一样具体,不要太模糊或太长 |
| go_to_url | 在当前标签页导航到指定 URL |
| go_back | 后退 |
| wait | 等待指定秒数,默认 3 秒 |
| click_element_by_index | 通过索引点击元素 |
| input_text | 向输入交互元素输入文本 |
| save_pdf | 将当前页面保存为 PDF 文件 |
| switch_tab | 切换标签页 |
| open_tab | 在新标签页打开指定 URL |
| close_tab | 关闭已有标签页 |
| extract_content | 提取页面内容以获取特定信息,例如所有公司名、特定描述、所有关于 xyc 的信息、带结构的公司链接等 |
| get_ax_tree | 获取页面的可访问性树,格式为“role name”,返回指定数量的元素 |
| scroll_down | 页面向下滚动指定像素数,未指定则滚动一页 |
| scroll_up | 页面向上滚动指定像素数,未指定则滚动一页 |
| send_keys | 发送特殊按键字符串,如 Escape、Backspace、Insert、PageDown、Delete、Enter,支持快捷键组合 |
| scroll_to_text | 如果找不到想要交互的内容,则滚动到该文本位置 |
| get_dropdown_options | 获取原生下拉框的所有选项 |
| select_dropdown_option | 通过选项文本为交互元素选择下拉选项 |
| drag_drop | 拖放页面上的元素或坐标,适用于画布绘图、可排序列表、滑块、文件上传和 UI 重排等 |
另外还内置了 6 个操作 Google Sheets 的动作,这些动作仅对 https://docs.google.com 域名生效:
| Action 名称 | 描述(中文) |
|---|---|
| read_sheet_contents | 获取整个工作表的内容 |
| read_cell_contents | 获取一个单元格或单元格范围的内容 |
| update_cell_contents | 更新一个单元格或单元格范围的内容 |
| clear_cell_contents | 清除当前选定的任意单元格 |
| select_cell_or_range | 选择特定的单元格或单元格范围 |
| fallback_input_into_single_selected_cell | 备用方法在(仅一个)当前选定的单元格中输入文本 |
Playwright 介绍
分析上面内置的 20 个浏览器动作源码后你会发现,绝大多数动作都是通过 Playwright 库实现的,比如上面的 go_to_url 动作就是通过 Playwright 的页面对象完成的:
page = await browser_session.get_current_page()
if page:
await page.goto(params.url)
await page.wait_for_load_state()Playwright 本身是一个现代网页应用的端到端测试库,支持多种浏览器和平台,并提供丰富的功能和工具,帮助开发者进行高效的 Web 测试。

它具备如下特性和亮点:
- 跨平台、跨浏览器、跨语言:支持 Chromium、WebKit 和 Firefox 等现代渲染引擎,可在 Windows、Linux 和 macOS 等平台上进行测试,支持 Python、TypeScript、.Net、Java 等主流语言;
- 可靠性、稳定性:它的 自动等待功能(Auto-wait) 无需开发者人为设置超时;专为网页设计的断言(Web-first assertions) 会自动重试直至条件满足;支持配置重试策略,捕获执行轨迹、视频和截图,确保测试的可靠性和稳定性;
- 无需权衡、没有限制:和现代化浏览器架构保持一致,通过在进程外运行测试,摆脱了进程内测试运行器的限制。支持跨多个标签页、多个来源和多个用户的测试场景,并能够创建不同用户的不同上下文。此外,Playwright 产生真实用户无法区分的信任事件,并能够穿透 Shadow DOM 进行帧测试;
- 完全隔离、高效测试:Playwright 为每个测试创建一个浏览器上下文,相当于一个新的浏览器配置文件,实现无开销的完全测试隔离。此外,它允许保存并重用上下文的认证状态,避免了每个测试重复登录,同时保持独立测试的完整隔离;
- 强大的工具和功能:例如 代码生成器 通过记录操作来生成测试代码,以及 Playwright 检查器和追踪查看器等 调试工具 方便开发者诊断问题;
我们在前面安装 Browser Use 的时候,已经安装过 Playwright,其实就两步:
第一步,下载 Playwright 依赖包和命令行工具:
$ pip install playwright第二步,安装 Chromium、Firefox 和 WebKit 的浏览器二进制文件:
$ playwright install注意,每个版本的 Playwright 需要特定版本的浏览器二进制文件才能运行,所以每次更新 Playwright 版本时,记得重新运行 playwright install 命令。
默认情况下,浏览器被下载到如下位置:
- Windows:
C:\Users\<YourUsername>\AppData\Local\ms-playwright - macOS:
/Users/<YourUsername>/Library/Caches/ms-playwright - Linux:
~/.cache/ms-playwright
一切就绪后,就可以和 Browser Use 一样,通过 Playwright 的 API 来操作浏览器了:
import asyncio
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
await page.goto("https://playwright.dev")
print(await page.title())
await browser.close()
asyncio.run(main())具体用法参考 Playwright 的文档:
用户自定义工具
上面提到 Controller 是 Browser Use 工具调用的核心,所有的内置工具都注册在 controller.registry 里面。用户如果要自定义工具,也是通过它来注册的,下面是用户自定义工具的示例:
from browser_use import Controller, ActionResult
controller = Controller()
@controller.action('Ask human for help with a question')
def ask_human(question: str) -> ActionResult:
answer = input(f'{question} > ')
return ActionResult(
extracted_content=f'The human responded with: {answer}',
include_in_memory=True
)可以看到注册一个自定义工具非常简单,只需要在函数上面加一个 @controller.action 装饰器即可,函数入参任意,出参必须是 ActionResult 类型。通过自定义工具,用户可以实现额外的自定义行为、与其他应用的集成、或者像上面例子中那样,与人类进行交互。
然后将这个增强版的 controller 传入 Agent 即可:
agent = Agent(
task='...',
llm=llm,
# 自定义工具
controller=controller,
)关于自定义工具的函数入参,还可以通过 Pydantic 来定义类型、默认值、校验规则、以及详细描述等:
class MyParams(BaseModel):
field1: int
field2: str = 'default value'
field3: Annotated[str, AfterValidator(lambda s: s.lower())] # example: enforce always lowercase
field4: str = Field(default='abc', description='Detailed description for the LLM')
@controller.action('My action', param_model=MyParams)
def my_action(params: MyParams) -> ActionResult:
...另外,自定义工具中还可以使用一些框架提供的参数,这些特殊的参数是由 Controller 注入的,例如 page 或 browser_session 等,这样我们的自定义工具也可以运行 Playwright 代码与浏览器进行交互:
@controller.action('Click element')
def click_element(css_selector: str, page: Page) -> ActionResult:
await page.locator(css_selector).click()
return ActionResult(extracted_content=f"Clicked element {css_selector}")可用的框架提供参数如下:
page: 当前 Playwright 页面;browser_session: 当前浏览器会话;context: 用户自定义的上下文对象;page_extraction_llm: 用于页面内容提取的语言模型实例;available_file_paths: 可用于上传或处理的文件路径列表;has_sensitive_data: 表示操作内容是否包含敏感数据标记,用于避免意外地将敏感数据日志记录到终端。
小结
至此,我们全面学习了 Browser Use 的三大核心功能:任务规划、记忆管理以及工具使用:
- 任务规划:大模型是如何组织提示词,对目标任务进行分析,确定下一步的动作;
- 记忆管理:如何存储和更新智能体的历史操作,以保持上下文的连贯性,提高任务执行的效率;
- 工具使用:通过大模型的格式化输出功能,让智能体灵活地选择工具,通过 Playwright 执行不同的浏览器操作,并支持用户自定义工具,以增强系统的扩展性和适应性。
通过详细剖析相关代码,相信大家对 Browser Use 的架构设计和运作机制有了更深入的理解,在后面的学习中,我将集中于 Browser Use 的实际用法,以及如何通过其强大的浏览器操作能力,去完成更多复杂的自动化任务。

