3.3 自定义动作与扩展


文档摘要

3.3 自定义动作与扩展 3.3 自定义动作与扩展 在 Browser-use 代理网站访问器 的框架设计中,预定义的功能特性固然强大且全面,能够满足绝大多数常见的浏览器自动化需求。然而,技术的魅力在于其无限的可能性,以及用户不断增长的个性化需求。为了赋予 Browser-use 更强大的生命力和更广阔的应用前景,我们特别设计了 自定义动作与扩展 机制。本章节将深入剖析这一核心特性,揭示如何突破框架的固有边界,根据实际场景定制专属的浏览器自动化功能,从而最大化 Browser-use 的效能。 3.3.1 自定义动作的必要性与应用场景 Browser-use 框架内置了丰富的动作类型,例如页面导航、元素点击、文本输入、表单提交、标签页管理等等,这些动作覆盖了 Web 交互的常见操作。

3.3 自定义动作与扩展

3.3 自定义动作与扩展

Browser-use 代理网站访问器 的框架设计中,预定义的功能特性固然强大且全面,能够满足绝大多数常见的浏览器自动化需求。然而,技术的魅力在于其无限的可能性,以及用户不断增长的个性化需求。为了赋予 Browser-use 更强大的生命力和更广阔的应用前景,我们特别设计了 自定义动作与扩展 机制。本章节将深入剖析这一核心特性,揭示如何突破框架的固有边界,根据实际场景定制专属的浏览器自动化功能,从而最大化 Browser-use 的效能。

3.3.1 自定义动作的必要性与应用场景

Browser-use 框架内置了丰富的动作类型,例如页面导航、元素点击、文本输入、表单提交、标签页管理等等,这些动作覆盖了 Web 交互的常见操作。但在实际应用中,仍然存在许多预定义动作无法直接满足的特定需求。例如:

  • 特定网站的特殊操作流程: 某些网站可能存在独特的交互模式或验证机制,标准的点击、输入等动作无法完成特定操作,例如,复杂的拖拽排序、富文本编辑器的内容操作、音视频播放器的控制等等。

  • 数据处理与集成: 用户可能需要将浏览器中抓取的数据进行深度处理,并与外部系统集成,例如,将网页数据实时写入数据库、调用外部 API 进行数据分析、生成自定义报表、发送邮件通知等等。

  • 模拟更高级的用户行为: 除了基本的点击、输入,用户可能需要模拟更精细的用户行为,例如,鼠标悬停触发动态菜单、键盘快捷键操作、模拟用户滚动浏览轨迹等等。

  • 集成第三方库或服务: 为了扩展 Browser-use 的能力,用户可能希望集成各种 Python 第三方库或外部服务,例如,使用图像识别库处理验证码、使用自然语言处理库分析网页文本、调用云服务 API 进行更复杂的数据处理等等。

面对这些多样化且个性化的需求,自定义动作 机制应运而生。它允许用户在 Browser-use 框架内,根据自身业务逻辑和技术栈,灵活地定义和注册全新的浏览器动作。这些自定义动作与内置动作享有同等的地位,可以被大模型智能体调用执行,从而实现更加精细化、智能化的浏览器自动化流程。

应用场景示例:

  • 电商平台商品监控与自动下单: 自定义动作可以实现更精准的商品价格监控,一旦价格低于预设阈值,自动触发下单流程,并集成支付接口完成购买。

  • 社交媒体内容发布与互动: 自定义动作可以模拟用户在社交媒体平台发布内容、评论、点赞等行为,并集成内容审核 API,实现自动化内容营销。

  • 企业内部系统自动化操作: 针对企业内部复杂的 Web 应用系统,自定义动作可以实现特定的业务流程自动化,例如,财务报销系统自动填写单据、CRM 系统自动录入客户信息、OA 系统自动审批流程等等。

  • 网页游戏自动化助手: 在合规的前提下,自定义动作可以辅助玩家进行网页游戏操作,例如,自动打怪、自动采集资源、自动交易物品等等。

3.3.2 自定义动作的核心构成要素

在 Browser-use 框架中,自定义动作的实现主要依赖于以下三个核心要素:

  1. 动作名称 (Action Name): 这是自定义动作的唯一标识符,用于在大模型智能体的动作指令中识别和调用该动作。动作名称需要具有描述性,能够清晰表达动作的功能。例如,"Take Screenshot""Save to Database""Scroll to Bottom" 等。

  2. 参数模型 (Parameter Model): 使用 Pydantic 库定义的参数模型,用于规范自定义动作的输入参数类型和验证规则。参数模型确保了大模型智能体生成的动作指令参数符合预期,避免因参数错误导致的动作执行失败。参数模型定义了动作所需的输入数据结构,例如,截图动作可能需要文件名参数,数据库操作可能需要连接信息和数据内容参数。

  3. 执行函数 (Execution Function): 这是一个异步函数,负责执行自定义动作的具体逻辑。执行函数接收两个关键参数:

    • params: 根据参数模型解析后的参数对象,包含了大模型智能体提供的输入数据。

    • browser_context: Browser-use 框架提供的浏览器上下文对象,用于与浏览器进行交互,执行各种浏览器操作,例如页面操作、元素操作、标签页管理等。

执行函数是自定义动作的核心,用户需要在此函数中编写 Python 代码,利用 Browser-use 提供的浏览器操作 API,以及可能需要的第三方库或外部服务,实现自定义的浏览器自动化逻辑。执行函数需要返回 ActionResult 对象,用于封装动作执行结果,包括提取的内容、错误信息、是否包含在记忆中等。

3.3.3 自定义动作的注册与实现步骤

为了让 Browser-use 框架识别并调用自定义动作,需要进行动作注册。Browser-use 采用了装饰器模式来实现简洁高效的动作注册机制。具体的注册和实现步骤如下:

步骤 1: 定义动作参数模型 (使用 Pydantic)

首先,需要使用 Pydantic 库定义一个继承自 BaseModel 的类,作为自定义动作的参数模型。该模型需要定义动作所需的输入参数及其类型,并可以使用 Field 提供参数描述信息。

from pydantic import BaseModel, Field, Optional class TakeScreenshotAction(BaseModel): """ 截图动作的参数模型 """ filename: str = Field(..., description="保存截图的文件名 (包含路径)") full_page: Optional[bool] = Field(False, description="是否截取完整页面,默认为视窗截图")

步骤 2: 编写动作执行函数 (异步函数)

接下来,需要编写一个异步函数,实现自定义动作的具体执行逻辑。该函数需要接收 params (参数模型对象) 和 browser_context (浏览器上下文对象) 两个参数,并返回 ActionResult 对象。

from browser_use.agent.views import ActionResult from browser_use.browser.browser_context import BrowserContext from browser_use.controller.controller import Controller from playwright.async_api import Page async def take_screenshot_action(params: TakeScreenshotAction, browser_context: BrowserContext) -> ActionResult: """ 执行截图动作的函数 """ page: Page = await browser_context.get_current_page() # 获取当前页面对象 try: await page.screenshot(path=params.filename, full_page=params.full_page) # 执行截图操作 msg = f" 截图已保存到: {params.filename}" return ActionResult(extracted_content=msg, include_in_memory=True) # 返回成功结果 except Exception as e: error_msg = f"❌ 截图失败: {e}" return ActionResult(error=error_msg, include_in_memory=True) # 返回失败结果

步骤 3: 注册自定义动作 (使用装饰器)

最后,需要使用 @agent.controller.registry.action 装饰器将动作执行函数注册到 Browser-use 框架的动作注册表中。装饰器需要指定动作名称 (action_name) 和参数模型 (param_model)。

from browser_use import Agent, Browser # 假设已经创建了 Agent 实例 agent agent = Agent(task="测试自定义截图功能", llm=llm, browser=browser) @agent.controller.registry.action("Take Screenshot", param_model=TakeScreenshotAction) async def take_screenshot(params: TakeScreenshotAction, browser_context: BrowserContext) -> ActionResult: """ 注册自定义截图动作 """ return await take_screenshot_action(params, browser_context) # 调用实际的执行函数

完成以上三个步骤,自定义动作 Take Screenshot 就成功注册到 Browser-use 框架中。大模型智能体在生成动作指令时,就可以识别并调用该动作,用户可以通过自然语言指令,例如 "请截取当前网页并保存为 screenshot.png",来触发该自定义动作。

Graph TD 图示自定义动作注册流程:

3.3.4 自定义动作示例详解:Take Screenshot

为了更深入地理解自定义动作的实现细节,我们以 "Take Screenshot" 动作为例,进行更详细的解析。

1. 参数模型 TakeScreenshotAction:

class TakeScreenshotAction(BaseModel): """ 截图动作的参数模型 """ filename: str = Field(..., description="保存截图的文件名 (包含路径)") full_page: Optional[bool] = Field(False, description="是否截取完整页面,默认为视窗截图")
  • filename: str = Field(..., description="..."): 定义了 filename 参数,类型为字符串 (str),Field(..., description="...") 表示该参数是必需的 (...),并提供了描述信息 "保存截图的文件名 (包含路径)"。当大模型智能体需要调用 Take Screenshot 动作时,必须提供 filename 参数。

  • full_page: Optional[bool] = Field(False, description="..."): 定义了 full_page 参数,类型为可选布尔值 (Optional[bool]),默认值为 False,描述信息为 "是否截取完整页面,默认为视窗截图"。该参数是可选的,如果大模型智能体不提供该参数,则使用默认值 False (视窗截图)。

2. 执行函数 take_screenshot_action:

async def take_screenshot_action(params: TakeScreenshotAction, browser_context: BrowserContext) -> ActionResult: """ 执行截图动作的函数 """ page: Page = await browser_context.get_current_page() # 获取当前页面对象 try: await page.screenshot(path=params.filename, full_page=params.full_page) # 执行截图操作 msg = f" 截图已保存到: {params.filename}" return ActionResult(extracted_content=msg, include_in_memory=True) # 返回成功结果 except Exception as e: error_msg = f"❌ 截图失败: {e}" return ActionResult(error=error_msg, include_in_memory=True) # 返回失败结果
  • page: Page = await browser_context.get_current_page(): 通过 browser_context.get_current_page() 方法获取当前标签页的 Playwright Page 对象。Page 对象提供了丰富的浏览器操作 API,例如 screenshotclickfill 等。

  • await page.screenshot(path=params.filename, full_page=params.full_page): 调用 Playwright Page 对象的 screenshot 方法执行截图操作。path=params.filename 指定截图保存路径,full_page=params.full_page 根据参数模型中的 full_page 参数决定是否截取完整页面。

  • return ActionResult(...): 根据截图操作的成功或失败,返回相应的 ActionResult 对象。成功时,extracted_content 包含成功消息,失败时,error 包含错误信息,include_in_memory=True 表示将结果包含在智能体的记忆中,以便后续步骤可以参考。

3. 动作注册 @agent.controller.registry.action(...):

@agent.controller.registry.action("Take Screenshot", param_model=TakeScreenshotAction) async def take_screenshot(params: TakeScreenshotAction, browser_context: BrowserContext) -> ActionResult: """ 注册自定义截图动作 """ return await take_screenshot_action(params, browser_context) # 调用实际的执行函数
  • @agent.controller.registry.action("Take Screenshot", param_model=TakeScreenshotAction): 使用装饰器注册动作,"Take Screenshot" 是动作名称,TakeScreenshotAction 是参数模型。

  • async def take_screenshot(...): 定义了注册的动作函数,函数名可以自定义,但建议与动作名称相关联,以便于理解。

  • returnawait take_screenshot_action(params, browser_context): 在注册的动作函数中,直接调用了实际的执行函数 take_screenshot_action`,实现了动作的委托执行。这种设计使得注册函数本身保持简洁,主要负责动作的注册和元数据关联,而具体的执行逻辑则封装在独立的执行函数中,提高了代码的可维护性和可读性。

3.3.5 更多自定义动作示例

为了更全面地展示自定义动作的灵活性和实用性,我们再提供几个不同类型的自定义动作示例:

示例 1: Save Page Content to Notion

这个自定义动作演示了如何将当前网页的内容抓取并保存到 Notion 数据库中,展示了 Browser-use 与外部服务集成的能力。

1. 参数模型 SaveToNotionAction:

from pydantic import BaseModel, Field class SaveToNotionAction(BaseModel): """ 保存页面内容到 Notion 的参数模型 """ database_id: str = Field(..., description="Notion 数据库 ID") page_title: str = Field(..., description="Notion 页面标题")

2. 执行函数 save_page_to_notion_action:

from browser_use.agent.views import ActionResult from browser_use.browser.browser_context import BrowserContext from playwright.async_api import Page from notion_client import Client # 假设已安装 notion-client 库 async def save_page_to_notion_action(params: SaveToNotionAction, browser_context: BrowserContext) -> ActionResult: """ 执行保存页面内容到 Notion 的动作函数 """ page: Page = await browser_context.get_current_page() try: page_content = await page.content() # 获取页面 HTML 内容 # 初始化 Notion 客户端 (需要配置 Notion API 密钥) notion = Client(auth=os.environ.get("NOTION_API_KEY")) # 从环境变量获取密钥 # 构建 Notion 页面内容 (这里只是简单示例,可以根据实际需求更精细地处理页面内容) children_blocks = [ { "object": "block", "type": "paragraph", "paragraph": { "rich_text": [ { "type": "text", "text": { "content": page_content[:500] + "..." # 截取部分内容作为示例 } } ] }, } ] # 创建 Notion 页面 notion.pages.create( parent={"database_id": params.database_id}, properties={ "title": {"title": [{"type": "text", "text": {"content": params.page_title}}]}, }, children=children_blocks, ) msg = f" 页面内容已保存到 Notion 数据库: {params.database_id}, 页面标题: {params.page_title}" return ActionResult(extracted_content=msg, include_in_memory=True) except Exception as e: error_msg = f"❌ 保存到 Notion 失败: {e}" return ActionResult(error=error_msg, include_in_memory=True)

3. 动作注册:

@agent.controller.registry.action("Save to Notion", param_model=SaveToNotionAction) async def save_to_notion(params: SaveToNotionAction, browser_context: BrowserContext) -> ActionResult: """ 注册自定义保存到 Notion 动作 """ return await save_page_to_notion_action(params, browser_context)

示例 2: Scroll to Bottom of Page

这个自定义动作演示了如何模拟用户滚动页面到底部的行为,在某些需要加载更多内容或触发懒加载的场景中非常有用。

1. 参数模型 (无需参数):

from pydantic import BaseModel class ScrollToBottomAction(BaseModel): """ 滚动到页面底部动作的参数模型 (无需参数) """ pass # 无需额外参数

2. 执行函数 scroll_to_bottom_action:

from browser_use.agent.views import ActionResult from browser_use.browser.browser_context import BrowserContext from playwright.async_api import Page async def scroll_to_bottom_action(params: ScrollToBottomAction, browser_context: BrowserContext) -> ActionResult: """ 执行滚动到页面底部动作的函数 """ page: Page = await browser_context.get_current_page() try: await page.evaluate("window.scrollTo(0, document.body.scrollHeight)") # 执行 JavaScript 代码滚动到底部 msg = " 页面已滚动到底部" return ActionResult(extracted_content=msg, include_in_memory=True) except Exception as e: error_msg = f"❌ 滚动到底部失败: {e}" return ActionResult(error=error_msg, include_in_memory=True)

3. 动作注册:

@agent.controller.registry.action("Scroll to Bottom", param_model=ScrollToBottomAction) async def scroll_to_bottom(params: ScrollToBottomAction, browser_context: BrowserContext) -> ActionResult: """ 注册自定义滚动到页面底部动作 """ return await scroll_to_bottom_action(params, browser_context)

示例 3: Extract Product Details (Custom Data Extraction Logic)

这个自定义动作展示了如何根据特定网站的结构,编写自定义的数据提取逻辑,从商品详情页抓取商品名称、价格、描述等信息。

1. 参数模型 ExtractProductDetailsAction:

from pydantic import BaseModel, Field class ExtractProductDetailsAction(BaseModel): """ 提取商品详情的参数模型 (无需参数,假设在商品详情页执行) """ pass # 无需额外参数,假设在商品详情页执行

2. 执行函数 extract_product_details_action:

from browser_use.agent.views import ActionResult from browser_use.browser.browser_context import BrowserContext from playwright.async_api import Page async def extract_product_details_action(params: ExtractProductDetailsAction, browser_context: BrowserContext) -> ActionResult: """ 执行提取商品详情的动作函数 (示例网站结构,需根据实际网站调整 CSS 选择器) """ page: Page = await browser_context.get_current_page() try: product_name = await page.locator(".product-title").inner_text() # 使用 CSS 选择器提取商品名称 product_price = await page.locator(".product-price").inner_text() # 使用 CSS 选择器提取商品价格 product_description = await page.locator(".product-description").inner_text() # 使用 CSS 选择器提取商品描述 extracted_data = { "name": product_name, "price": product_price, "description": product_description, } msg = f" 商品详情已提取: {extracted_data}" return ActionResult(extracted_content=msg, include_in_memory=True, data=extracted_data) # 返回提取的数据 except Exception as e: error_msg = f"❌ 提取商品详情失败: {e}" return ActionResult(error=error_msg, include_in_memory=True)

3. 动作注册:

@agent.controller.registry.action("Extract Product Details", param_model=ExtractProductDetailsAction) async def extract_product_details(params: ExtractProductDetailsAction, browser_context: BrowserContext) -> ActionResult: """ 注册自定义提取商品详情动作 """ return await extract_product_details_action(params, browser_context)

这些示例展示了自定义动作的多样性,涵盖了页面操作、外部服务集成、以及自定义数据提取等场景。用户可以根据实际需求,灵活地组合和扩展这些示例,构建更强大的浏览器自动化应用。

3.3.6 自定义动作的错误处理与健壮性

在实际应用中,自定义动作的执行可能会遇到各种不可预测的错误,例如网络问题、网站结构变化、外部服务故障等等。为了提高 Browser-use 代理的稳定性和可靠性,自定义动作的错误处理至关重要。

最佳实践:

  1. 使用 try...except 块捕获异常: 在动作执行函数中使用 try...except 块,捕获可能发生的异常,避免程序崩溃。

  2. 返回 ActionResult 错误信息:except 块中,创建包含错误信息的 ActionResult 对象,并将 error 字段设置为具体的错误描述。这样,Browser-use 框架可以识别动作执行失败,并将错误信息反馈给大模型智能体,以便进行后续的错误处理或重试。

  3. 记录详细的错误日志: 使用 Python 的 logging 模块,在 except 块中记录详细的错误日志,包括异常类型、错误信息、堆栈跟踪等。这有助于开发者在排查问题时快速定位错误原因。

  4. 考虑重试机制: 对于某些可恢复的错误 (例如网络超时、临时服务不可用),可以在动作执行函数中实现简单的重试机制。例如,在 except 块中,等待一段时间后再次尝试执行相同的操作。但需要注意控制重试次数,避免无限循环。

  5. 参数校验与预处理: 在动作执行函数开始时,对参数模型解析后的参数进行校验,确保参数的有效性。可以进行类型检查、范围检查、格式检查等。对于一些需要预处理的参数,例如文件路径、URL 地址等,可以在执行函数中进行规范化处理,提高动作的健壮性。

  6. 资源清理与释放: 如果自定义动作涉及到外部资源的申请和使用 (例如数据库连接、文件句柄等),务必在动作执行函数结束时,在 finally 块中进行资源的清理和释放,避免资源泄露。

错误处理示例 (以 "Save to Notion" 动作为例):

async def save_page_to_notion_action(params: SaveToNotionAction, browser_context: BrowserContext) -> ActionResult: """ 执行保存页面内容到 Notion 的动作函数 (包含错误处理) """ page: Page = await browser_context.get_current_page() try: # ... (获取页面内容、初始化 Notion 客户端等代码) ... # 创建 Notion 页面 (可能抛出异常) notion.pages.create( parent={"database_id": params.database_id}, properties={ "title": {"title": [{"type": "text", "text": {"content": params.page_title}}]}, }, children=children_blocks, ) msg = f" 页面内容已保存到 Notion 数据库: {params.database_id}, 页面标题: {params.page_title}" return ActionResult(extracted_content=msg, include_in_memory=True) except Exception as e: # 捕获所有异常 error_msg = f"❌ 保存到 Notion 失败: {e}" logging.error(f"Save to Notion action failed: {error_msg}", exc_info=True) # 记录详细错误日志 return ActionResult(error=error_msg, include_in_memory=True) finally: # ... (资源清理代码,例如关闭数据库连接,如果需要的话) ... pass # 本例中无需额外资源清理

通过以上错误处理策略,可以显著提高自定义动作的健壮性和可靠性,降低因错误导致的自动化流程中断的风险。

3.3.7 自定义动作的安全性考量

自定义动作机制为 Browser-use 提供了强大的扩展能力,但也引入了潜在的安全风险。由于自定义动作允许用户在框架内执行任意 Python 代码,如果使用不当或缺乏安全意识,可能会导致以下安全问题:

  1. 恶意代码注入: 如果自定义动作的参数来源不可信 (例如直接来自用户输入或外部系统),恶意用户可能通过构造恶意的参数值,注入恶意代码到动作执行函数中,从而执行非预期的操作,甚至危害系统安全。

  2. 敏感信息泄露: 自定义动作的代码可能会意外地泄露敏感信息,例如 API 密钥、数据库密码、用户凭证等。如果这些敏感信息被记录到日志、暴露在错误信息中,或者被恶意用户获取,将造成严重的安全风险。

  3. 资源滥用与拒绝服务: 编写不当的自定义动作可能会消耗大量系统资源 (例如 CPU、内存、网络带宽),甚至导致拒绝服务攻击。例如,无限循环、大量文件读写、频繁的网络请求等。

安全建议:

  1. 参数来源验证与Sanitization: 务必对自定义动作的参数来源进行严格的验证和过滤,确保参数的合法性和安全性。避免直接使用来自不可信来源的参数值,例如用户输入、外部 API 响应等。对于用户提供的输入,需要进行充分的 Sanitization (例如转义特殊字符、限制输入长度等),防止恶意代码注入。

  2. 最小权限原则: 在编写自定义动作的代码时,遵循最小权限原则,只申请必要的权限和资源。避免使用高权限的操作 (例如系统命令执行、文件系统写操作等),除非绝对必要,并进行严格的权限控制。

  3. 敏感信息保护: 不要在自定义动作的代码中硬编码敏感信息 (例如 API 密钥、密码等)。应该使用安全的方式管理敏感信息,例如环境变量、密钥管理服务等。避免将敏感信息记录到日志或错误信息中。

  4. 代码审查与安全审计: 对于重要的自定义动作,建议进行代码审查和安全审计,由安全专家评估代码的安全性,发现潜在的安全漏洞和风险。

  5. 沙箱环境与隔离: 在条件允许的情况下,可以考虑在沙箱环境或隔离的进程中执行自定义动作,限制自定义动作的访问权限和资源使用,降低安全风险的影响范围。

  6. 资源限制与监控: 对自定义动作的资源使用进行限制和监控,例如 CPU 使用率、内存使用量、网络带宽等。一旦发现资源使用异常,及时进行告警和干预,防止资源滥用和拒绝服务攻击。

  7. 安全教育与培训: 加强用户和开发者的安全教育和培训,提高安全意识,使其了解自定义动作的安全风险,并掌握安全编码的最佳实践。

通过综合应用以上安全措施,可以有效地降低自定义动作的安全风险,保障 Browser-use 代理系统的安全稳定运行。

3.3.8 高级自定义与扩展技巧

除了基本的自定义动作注册和实现,Browser-use 还支持一些高级的自定义与扩展技巧,进一步提升框架的灵活性和可定制性:

  1. 动态动作注册: Browser-use 允许在运行时动态注册自定义动作,而不是在代码启动时静态注册。这使得可以根据不同的场景或需求,动态地加载和注册不同的动作集合。例如,可以根据用户的角色权限、当前的任务类型、或者外部配置文件的设定,注册不同的自定义动作。

实现方式:

动态动作注册的核心在于在运行时调用 agent.controller.registry.action 装饰器。可以将动作注册代码放在函数中,根据条件判断是否执行注册。

from browser_use import Agent, Browser from browser_use.agent.views import ActionResult from browser_use.browser.browser_context import BrowserContext from pydantic import BaseModel, Field # 定义一个动态注册的自定义动作 class DynamicActionParams(BaseModel): message: str = Field(..., description="要显示的消息") async def dynamic_action_func(params: DynamicActionParams, browser_context: BrowserContext) -> ActionResult: msg = f"动态动作执行: {params.message}" print(msg) # 实际应用中可以执行更复杂的操作 return ActionResult(extracted_content=msg, include_in_memory=True) def register_dynamic_action(agent_instance: Agent): """ 动态注册自定义动作的函数 """ @agent_instance.controller.registry.action("Dynamic Action", param_model=DynamicActionParams) async def dynamic_action(params: DynamicActionParams, browser_context: BrowserContext) -> ActionResult: return await dynamic_action_func(params, browser_context) # ... (创建 Agent 实例 agent) ... # 在运行时动态注册动作 (例如,根据某个条件) if some_condition: register_dynamic_action(agent) # 现在 "Dynamic Action" 动作就可以被大模型智能体调用了

应用场景:

  • 插件式架构: 将自定义动作封装成独立的插件,根据需要动态加载和卸载插件,扩展 Browser-use 的功能。

  • 权限控制: 根据用户的角色或权限,动态注册不同的动作集合,实现细粒度的权限控制。

  • 任务定制: 根据不同的任务类型,动态注册特定的动作,优化任务执行效率和准确性。

  • 配置驱动: 从配置文件 (例如 JSON, YAML) 中读取动作定义,动态注册动作,实现配置化的动作管理。

  1. 动作组合与编排 (Action Composition & Chaining): 为了构建更复杂的自动化流程,可以将多个已有的动作 (包括内置动作和自定义动作) 组合起来,形成新的复合动作或动作序列。这类似于工作流的概念,可以将简单的动作编排成复杂的任务流程。

实现方式:

可以通过在自定义动作的执行函数中,调用其他已注册的动作来实现动作组合。可以使用 agent.controller.execute_actions 方法来执行一个动作序列。

from browser_use import Agent, Browser from browser_use.agent.views import ActionResult from browser_use.browser.browser_context import BrowserContext from pydantic import BaseModel, Field from typing import List, Dict, Any # 定义一个复合动作,组合了 "Go to URL" 和 "Take Screenshot" 动作 class CompositeActionParams(BaseModel): url: str = Field(..., description="要访问的 URL") screenshot_filename: str = Field(..., description="截图保存文件名") async def composite_action_func(params: CompositeActionParams, browser_context: BrowserContext, agent_instance: Agent) -> ActionResult: # 注意需要传入 agent_instance """ 复合动作执行函数:先访问 URL,然后截图 """ actions = [ {"go_to_url": {"url": params.url}}, # 调用 "go_to_url" 内置动作 {"take_screenshot": {"filename": params.screenshot_filename}} # 调用 "take_screenshot" 自定义动作 (假设已注册) ] results = await agent_instance.controller.execute_actions(actions, browser_context) # 执行动作序列 if any(result.error for result in results): # 检查是否有错误 error_msgs = [result.error for result in results if result.error] return ActionResult(error="\n".join(error_msgs), include_in_memory=True) # 返回错误结果 else: msg = f"复合动作执行完成: 访问 URL '{params.url}', 并截图保存到 '{params.screenshot_filename}'" return ActionResult(extracted_content=msg, include_in_memory=True) # 返回成功结果 # 注册复合动作 @agent.controller.registry.action("Composite Action", param_model=CompositeActionParams) async def composite_action(params: CompositeActionParams, browser_context: BrowserContext) -> ActionResult: global agent # 假设 agent 实例在全局作用域 (或者通过其他方式传递) return await composite_action_func(params, browser_context, agent) # 传递 agent 实例 # ... (创建 Agent 实例 agent 和其他自定义动作 "take_screenshot") ... # 大模型智能体可以调用 "Composite Action" 动作,并提供 URL 和截图文件名参数

应用场景:

  • 复杂任务流程自动化: 将复杂的业务流程拆分成多个简单的动作,然后通过动作组合编排,实现端到端的自动化。

  • 可重用动作模块: 将常用的动作序列封装成复合动作,提高动作的可重用性和代码的模块化程度。

  • 工作流引擎集成: 将 Browser-use 与工作流引擎 (例如 Airflow, Prefect) 集成,利用工作流引擎的可视化编排和任务调度能力,管理和执行复杂的浏览器自动化任务。

  1. 上下文感知动作 (Context-Aware Actions): 为了让自定义动作更智能、更灵活,可以使其具备上下文感知能力,即能够获取和利用当前浏览器状态、Agent 的记忆、以及之前的动作执行结果等上下文信息。

实现方式:

  • 访问 browser_context 对象: browser_context 对象包含了当前浏览器的状态信息,例如当前 URL, 页面 DOM 结构, 可交互元素等。自定义动作可以通过 browser_context 对象获取这些信息,并根据上下文进行不同的操作。

  • 访问 agent.state 对象: agent.state 对象包含了 Agent 的状态信息,例如步骤计数器、连续失败次数、上次动作执行结果等。自定义动作可以利用这些信息进行流程控制或错误处理。

  • 利用 ActionResult.data 字段: 在之前的动作执行结果 ActionResult 中,可以使用 data 字段传递结构化数据 (例如 JSON 对象)。后续的自定义动作可以从记忆中获取之前的 ActionResult,并解析 data 字段,获取上下文信息。

from browser_use import Agent, Browser from browser_use.agent.views import ActionResult from browser_use.browser.browser_context import BrowserContext from pydantic import BaseModel, Field # 定义一个上下文感知动作,根据页面标题判断执行不同操作 class ContextAwareActionParams(BaseModel): expected_title_prefix: str = Field(..., description="期望的页面标题前缀") async def context_aware_action_func(params: ContextAwareActionParams, browser_context: BrowserContext) -> ActionResult: """ 上下文感知动作执行函数:根据页面标题前缀判断执行不同操作 """ page = await browser_context.get_current_page() current_title = await page.title() if current_title.startswith(params.expected_title_prefix): msg = f"页面标题匹配,执行操作 A: {current_title}" # ... (执行操作 A 的代码) ... else: msg = f"页面标题不匹配,执行操作 B: {current_title}" # ... (执行操作 B 的代码) ... return ActionResult(extracted_content=msg, include_in_memory=True) # 注册上下文感知动作 @agent.controller.registry.action("Context Aware Action", param_model=ContextAwareActionParams) async def context_aware_action(params: ContextAwareActionParams, browser_context: BrowserContext) -> ActionResult: return await context_aware_action_func(params, browser_context) # ... (创建 Agent 实例 agent) ... # 大模型智能体可以调用 "Context Aware Action" 动作,并提供期望的页面标题前缀

应用场景:

  • 条件分支逻辑: 根据当前页面状态、用户会话状态等上下文信息,动态决定执行不同的动作分支,实现更智能的自动化流程。

  • 状态机驱动: 将浏览器自动化流程建模为状态机,根据当前状态和事件 (例如页面加载完成、元素出现等) 触发不同的动作,实现更复杂的交互逻辑。

  • 自适应策略: 根据之前的动作执行结果 (例如成功或失败、提取的数据内容),动态调整后续的动作策略,提高自动化流程的鲁棒性和效率。

  1. 自定义动作库与插件化: 为了更好地组织、管理和复用自定义动作,可以将自定义动作封装成独立的库或插件。这样可以提高代码的可维护性、可扩展性,并方便在不同的 Browser-use 项目中共享和复用自定义动作。

实现方式:

  • 模块化组织: 将相关的自定义动作放在同一个 Python 模块 (例如一个 .py 文件) 中。

  • 包管理: 将自定义动作模块打包成 Python 包,可以使用 pip 等工具进行安装和管理。

  • 插件加载机制: 开发插件加载机制,在 Browser-use 启动时,自动扫描指定的插件目录,加载并注册插件中的自定义动作。可以使用 Python 的 importlib 模块实现动态模块加载。

应用场景:

  • 行业特定动作库: 针对不同的行业或应用领域 (例如电商、金融、社交媒体),开发行业特定的自定义动作库,提供更专业的自动化解决方案。

  • 第三方动作插件: 允许第三方开发者开发和发布自定义动作插件,扩展 Browser-use 的功能生态系统。

  • 企业内部动作平台: 企业内部可以构建自定义动作平台,集中管理和维护常用的自定义动作,方便员工在不同的自动化项目中复用。

通过这些高级自定义与扩展技巧,Browser-use 不仅仅是一个预定义功能的框架,更是一个高度可定制、可扩展的平台,能够满足各种复杂和个性化的浏览器自动化需求,真正实现 "Make websites accessible to AI agents" 的愿景。

本章节详细介绍了 Browser-use 框架的自定义动作与扩展机制,从必要性、核心构成、注册步骤、示例详解,到错误处理、安全性考量和高级技巧,力求全面深入地解析这一重要特性。掌握自定义动作与扩展,将能够充分释放 Browser-use 的潜力,构建更加强大、智能、灵活的浏览器自动化应用。


发布者: 作者: 转发
评论区 (0)
U