1. 概述
在Browser-use框架中,核心任务是使大模型能够像人类一样操作浏览器。本文深入探讨大模型如何实际控制浏览器,重点解析从模型输出到浏览器动作执行的完整流程。
上一篇(公众号首发)-Browser-use AI自动化框架深度解析(二):提示词构造机制
2. 系统架构与数据流
Browser-use采用标准的Agent-Environment交互范式,以闭环反馈机制实现大模型与浏览器的交互:
┌────────────┐ 状态提示词 ┌───────────┐
│ │ ───────────────> │ │
│ 浏览器环境 │ │ 大模型 │
│ │ <─────────────── │ │
└────────────┘ 结构化动作 └───────────┘
2.1 核心交互流程
- 状态获取:框架捕获当前浏览器状态,包括DOM结构、可交互元素和页面元数据
- 状态表示:将状态转换为结构化提示词注入大模型上下文
- 决策生成:大模型分析状态并生成结构化的动作计划
- 动作执行:框架解析动作计划并在浏览器中执行相应操作
- 结果反馈:执行结果和新状态反馈回大模型,进入下一轮迭代
这种基于状态-动作-反馈的迭代模式支持大模型进行多步骤任务规划和执行。
3. 大模型输出设计
大模型需要生成特定格式的JSON结构以实现对浏览器的控制,主要通过工具调用(Tool Calling)机制实现。
3.1 结构化输出示例
{"current_state": {"evaluation_previous_goal": "成功打开了百度首页","memory": "我正在执行搜索四川十大景点的任务。已完成第1步:打开百度首页。","next_goal": "在搜索框中输入'四川十大景点'"},"action": [{"input_text": {"index": 5,"text": "四川十大景点"}},{"click_element": {"index": 6}}]
}
3.2 输出结构解析
-
current_state
:任务状态信息evaluation_previous_goal
:上一步骤完成状态的评估memory
:工作记忆,存储任务关键信息next_goal
:规划的下一步目标
-
action
:动作序列- 支持单步多动作执行
- 每个动作以键值对形式表示,键为动作名称,值为参数对象
这种设计不仅规范了输出格式,还通过 memory 字段为大模型提供了上下文记忆能力,从而支持复杂任务的分解与执行。
3.3 Pydantic模型定义
Browser-use使用Pydantic模型定义输出结构,确保类型安全和参数验证:
def _setup_action_models(self):class CurrentState(BaseModel):evaluation_previous_goal: str = Field(..., description="评估上一步目标的完成情况")memory: str = Field(..., description="记录重要信息,用于跟踪进度")next_goal: str = Field(..., description="下一步要完成的具体目标")class AgentOutput(BaseModel):current_state: CurrentState = Field(..., description="当前状态评估和下一步计划")action: List[Dict[str, Dict[str, Any]]] = Field(..., description="要执行的动作列表")self.CurrentState = CurrentStateself.AgentOutput = AgentOutput
这些模型不仅用于验证输出合规性,还作为函数调用的JSON Schema,指导大模型生成规范化输出。
4. 工具调用机制
4.1 多模型适配策略
Browser-use支持多种工具调用方式,以适配不同的模型能力边界:
def _set_tool_calling_method(self) -> Optional[ToolCallingMethod]:"""Set tool calling method based on model and provided setting"""if self.settings.tool_calling_method == 'auto':if 'gpt-' in self.model_name or 'claude-3' in self.model_name:return 'function_calling'elif 'Qwen' in self.model_name or 'deepseek' in self.model_name:return 'raw'else:return Nonereturn self.settings.tool_calling_method
4.2 调用方式分类
-
原始模式 (
raw
)- 适用于不支持原生工具调用的模型
- 从文本输出中解析JSON结构
- 实现方式:
output = self.llm.invoke(input_messages) output.content = self._remove_think_tags(str(output.content)) try:parsed_json = extract_json_from_model_output(output.content)parsed = self.AgentOutput(**parsed_json) except (ValueError, ValidationError) as e:raise ValueError('Could not parse response.')
-
函数调用 (
function_calling
)- 适用于支持工具调用的现代模型(OpenAI/Anthropic)
- 利用模型原生工具调用接口
- 实现方式:
structured_llm = self.llm.with_structured_output(self.AgentOutput, include_raw=True, method=self.tool_calling_method ) response: dict[str, Any] = await structured_llm.ainvoke(input_messages) parsed: AgentOutput | None = response['parsed']
-
结构化输出 (
None
)- 使用LangChain的结构化输出机制
- 提供类型安全和验证
- 兼容各种模型
5. 动作注册与执行系统
动作系统是Browser-use的核心组件,负责将大模型的意图转换为具体的浏览器操作。
5.1 动作注册机制
Browser-use使用装饰器模式实现动作注册:
class Controller(Generic[Context]):def __init__(self):self.registry = Registry()@self.registry.action('Go to URL', param_model=GoToUrlAction)async def go_to_url(params: GoToUrlAction, browser: BrowserContext):url = params.urlawait browser.goto(url)msg = f'🌐 Navigated to {url}'logger.info(msg)return ActionResult(extracted_content=msg, include_in_memory=True)@self.registry.action('Click on element', param_model=ClickElementAction)async def click_element(params: ClickElementAction, browser: BrowserContext):state = await browser.get_state()element_node = state.element_tree.find_by_index(params.index)if not element_node:msg = f'❌ Could not find element with index {params.index}'logger.warning(msg)return ActionResult(error=msg, include_in_memory=True)await browser.click(element_node.xpath)msg = f'🖱️ Clicked on element [{params.index}] {element_node.text}'logger.info(msg)return ActionResult(extracted_content=msg, include_in_memory=True)
动作注册时需指定三个关键要素:
- 动作名称:用于在大模型输出中识别动作
- 参数模型:定义参数类型和验证规则
- 实现函数:执行具体浏览器操作的异步函数
这些模型用于验证模型输出并生成函数调用的JSON模式,帮助大模型理解预期输出格式。
5.2 内置动作类型
Browser-use预定义了多种浏览器动作类型:
类别 | 动作 | 功能 |
---|---|---|
导航类 | go_to_url |
导航到指定URL |
back |
返回上一页 | |
forward |
前进到下一页 | |
refresh |
刷新当前页面 | |
交互类 | click_element |
点击页面元素 |
input_text |
输入文本 | |
select_option |
选择下拉选项 | |
scroll |
滚动页面 | |
标签页管理 | open_tab |
打开新标签页 |
switch_tab |
切换标签页 | |
close_tab |
关闭当前标签页 | |
内容提取 | extract_content |
提取页面内容 |
任务控制 | done |
标记任务完成 |
5.3 动作执行流程
动作执行由execute_actions
方法实现,该方法处理参数解析、动作调度和错误处理:
async def execute_actions(self,actions: List[Dict[str, Dict[str, Any]]],browser_context: BrowserContext,agent_output: Optional[Any] = None,llm: Optional[BaseChatModel] = None,sensitive_data: Optional[Dict[str, str]] = None
) -> List[ActionResult]:"""Execute a list of actions on the browser"""results = []for action in actions:# 1. 解析动作类型和参数action_type = list(action.keys())[0]action_params = list(action.values())[0]# 2. 处理敏感数据action_params = self._process_sensitive_data(action_params, sensitive_data)# 3. 查找动作处理函数try:action_handler = self.registry.get_action(action_type)# 4. 执行动作result = await action_handler(browser_context=browser_context,**action_params)# 5. 记录结果results.append(result)except Exception as e:# 6. 处理错误error_traceback = traceback.format_exc()results.append(ActionResult(error=error_traceback, include_in_memory=True))return results
执行流程中的关键步骤:
- 解析动作类型和参数
- 处理敏感数据(如密码等)
- 从注册表中查找对应的动作处理函数
- 执行动作并获取结果
- 记录执行结果,处理可能出现的异常
6. 迭代执行与状态管理
Browser-use通过_run_iteration
方法实现Agent的单步迭代执行,包含完整的状态捕获、动作生成和执行环节:
async def _run_iteration(self) -> Tuple[bool, bool]:"""Run one iteration of the agent loop"""# 1. 获取当前浏览器状态state = await self.browser_context.get_state()# 2. 创建步骤信息step_info = AgentStepInfo(step_number=self.state.n_steps,consecutive_failures=self.state.consecutive_failures,)# 3. 将状态添加到消息管理器self._message_manager.add_state_message(state=state,result=self.state.last_result,step_info=step_info,use_vision=self.settings.use_vision,)# 4. 运行规划器(如果启用)if self.settings.planner_llm and self.state.n_steps % self.settings.planner_interval == 0:plan = await self._run_planner()self._message_manager.add_plan(plan, position=-1)# 5. 获取消息历史input_messages = self._message_manager.get_messages()# 6. 获取下一个动作action_output = await self.get_next_action(input_messages)# 7. 保存状态和输出self.state.last_state = stateself._message_manager.add_model_output(action_output)# 8. 检测是否完成任务done = any(list(a.keys())[0] == 'done' for a in action_output.action)if done:return True, False# 9. 执行动作results = await self.controller.execute_actions(actions=action_output.action,browser_context=self.browser_context,agent_output=action_output,llm=self.settings.page_extraction_llm or self.llm,sensitive_data=self.sensitive_data)# 10. 处理结果self.state.last_result = results# 11. 检查结果是否包含错误any_error = any(r.error for r in results)return False, any_error
这种迭代执行模式实现了完整的感知-决策-执行闭环,使大模型能够基于当前状态调整策略,处理动态变化的网页环境。
7. 元素选择与跟踪机制
7.1 基于索引的元素选择
Browser-use通过索引机制简化元素选择,大模型根据提示词中的元素索引选择交互对象:
Interactive elements from top layer of the current page inside the viewport:
[0]<input type="text" placeholder="搜索关键词">搜索</input>
[1]<button>搜索</button>
[2]<a href="https://example.com">链接文本</a>
大模型通过指定索引实现元素选择:
{"click_element": {"index": 1}
}
7.2 智能元素跟踪
为应对动态网页中元素位置的变化,Browser-use实现了元素跟踪机制:
async def _update_action_indices(self,historical_element: Optional[DOMHistoryElement],action: ActionModel,current_state: BrowserState,
) -> Optional[ActionModel]:"""更新动作索引以匹配当前页面状态。如果找不到元素,返回None。"""if not historical_element or not current_state.element_tree:return action# 在当前元素树中查找历史元素current_element = HistoryTreeProcessor.find_history_element_in_tree(historical_element, current_state.element_tree)if not current_element or current_element.highlight_index is None:return None# 如果索引变化了,更新动作索引old_index = action.get_index()if old_index != current_element.highlight_index:action.set_index(current_element.highlight_index)logger.info(f'元素在DOM中移动,索引从{old_index}更新为{current_element.highlight_index}')return action
元素跟踪的核心逻辑:
- 保存历史元素的关键属性(XPath、属性、文本等)
- 在新状态中查找匹配度最高的元素
- 自动更新动作索引以适应元素位置变化
- 处理元素消失的情况并提供错误反馈
这一机制使Browser-use具备适应动态网页的能力,提高任务执行的稳定性。
8. 可扩展性与自定义动作
8.1 自定义动作注册
Browser-use提供了简洁的API用于扩展自定义动作:
from browser_use import Agent, Browser, ActionRegistry
from pydantic import BaseModel, Field
from browser_use.agent.views import ActionResult# 定义动作参数模型
class TakeScreenshotAction(BaseModel):filename: str = Field(..., description="保存截图的文件名")# 创建Agent实例
browser = Browser()
agent = Agent(task="测试截图功能", llm=llm, browser=browser)# 注册自定义动作
@agent.controller.registry.action("Take screenshot", param_model=TakeScreenshotAction)
async def take_screenshot(params: TakeScreenshotAction, browser_context):# 获取页面对象page = await browser_context.get_current_page()# 执行截图await page.screenshot(path=params.filename)# 返回结果msg = f"📸 Screenshot saved to {params.filename}"return ActionResult(extracted_content=msg, include_in_memory=True)
自定义动作需要三个关键组件:
- 参数模型:定义输入参数及验证规则
- 动作名称:注册动作时指定的识别标识
- 执行函数:实现具体操作逻辑的异步函数
8.2 后端适配层
Browser-use设计了模块化的后端适配层,支持多种浏览器自动化技术:
- Playwright:默认后端,支持多种浏览器
- Selenium:传统的浏览器自动化工具
- Chrome DevTools Protocol (CDP):直接与Chrome通信
- 自定义后端:通过实现接口扩展其他自动化技术
选择后端的示例:
from browser_use import Browser, BrowserConfig, PlaywrightBackendconfig = BrowserConfig(browser_type="firefox")
browser = Browser(config=config, backend=PlaywrightBackend())
agent = Agent(task="搜索四川的10大景点", llm=llm, browser=browser)
这种可扩展的后端架构使Browser-use能够适配不同的浏览器环境和自动化需求。
技术实现案例
搜索引擎交互
完整的搜索任务执行流程展示:我需要搜索四川的10大景点
初始状态
Current url: about:blank
Available tabs:
- Tab 1 (active): about:blankInteractive elements from top layer of the current page inside the viewport:
(no elements found)
我需要搜索四川的10大景点
初始动作(导航到搜索引擎)
{"current_state": {"evaluation_previous_goal": "我刚开始任务,还没有执行任何目标","memory": "我需要搜索四川的10大景点","next_goal": "导航到百度搜索引擎"},"action": [{"go_to_url": {"url": "https://www.baidu.com"}}]
}
执行结果
Action result: 🌐 Navigated to https://www.baidu.com
更新状态
Current url: https://www.baidu.com
Available tabs:
- Tab 1 (active): https://www.baidu.comInteractive elements from top layer of the current page inside the viewport:
[0]<input type="text" placeholder="百度一下">百度一下</input>
[1]<button>百度一下</button>
...
搜索动作
{"current_state": {"evaluation_previous_goal": "成功导航到百度搜索引擎","memory": "我正在搜索四川的10大景点,已成功打开百度首页","next_goal": "在搜索框中输入'四川十大景点'"},"action": [{"input_text": {"index": 0,"text": "四川十大景点"}},{"click_element": {"index": 1}}]
}
执行结果
Action result: ⌨️ Input text "四川十大景点" into index 0
Action result: 🖱️ Clicked on element [1] 百度一下
这个循环持续进行,直到满足完成条件或达到最大步骤限制。
总结
Browser-use通过结构化输出和工具调用机制,使大模型能够灵活控制浏览器。其核心组件包括工具调用机制、动作注册系统、执行引擎和状态反馈机制。这种设计使AI能够执行从简单信息收集到复杂多步骤交互的Web任务。理解这些控制机制,开发者可以更有效地利用Browser-use构建强大的浏览器自动化应用。
想了解更多技术实现细节和源码解析,欢迎关注我的微信公众号【松哥ai自动化】。每周我都会带来一篇深度技术文章,从源码角度剖析各种实用工具的实现原理。
下一篇我们将深入分析Browser-use是如何进行数据处理的!