带着脚镣跳舞 - Browser Use智能体行为模式分析

admin 2025年6月25日16:37:59评论3 views字数 7838阅读26分7秒阅读模式

设计哲学:在混沌中建立秩序

网页的世界本质上是混沌的、多变的。对于一个AI代理而言,直接面对这份复杂性无异于在迷雾中航行。browser-use 的核心设计哲学,正是在这种混沌的Web环境中,为AI代理建立一套结构化、可预测且健壮的推理与行动框架

它并非试图让AI“完全自由”地理解和操作网页,而是通过以下四大支柱,在人类的意图与机器的执行之间,架起一座坚实的桥梁:

  1. 抽象与简化 (Abstraction & Simplification): 将原始、复杂的DOM转化为对模型友好的、带有明确交互标记(bid)的结构化信息,屏蔽无关细节。
  2. 工具化行动 (Tool-based Actions): 限制代理的行动空间,将其约束在一套定义明确、功能稳定的“工具集”内(如clicktype),避免了不可控的代码生成。
  3. 结构化推理 (Structured Reasoning): 强制代理在行动前必须进行“思考”(thought),并以标准化的格式(JSON)输出决策,使其行为不仅可执行,更可解释。
  4. 健壮性设计 (Robust Design): 承认网页操作的脆弱性,通过多层回退(Fallback)机制确保每一个行动都尽最大可能被成功执行。

本文将围绕这一核心哲学,深入剖析 browser-use 代理的感知、思考与行动的全过程。

观察:从网页到结构化感知的转化

代理的第一步是“观察”,即将混沌的网页转化为自身能够理解的结构化数据。这一过程完美体现了“抽象与简化”的设计哲学。

1. 前端注入:DOM的“翻译官” (dom/buildDomTree.js)

browser-use 并非直接处理原始HTML,而是通过Playwright的 page.evaluate_handle() 方法,向当前页面注入一段核心的JavaScript脚本。这个脚本扮演了“翻译官”的角色:

  • 智能识别与标记:它递归地扫描整个DOM树,依据标签名(如 <a><button>)和ARIA角色,精准识别出所有可交互的元素。最关键的是,它会为这些元素动态添加一个唯一的 data-browser-use-id 属性,也就是我们熟知的 bid。这个bid成为了后续AI与具体元素进行沟通的唯一标识。
  • 结构化信息提取:脚本不仅进行标记,还提取了元素的 aria-label、文本内容、placeholder 等关键属性,最终将这些信息整合成一个结构化的JSON对象返回给Python后端。

2. 后端缓存:连接AI决策与浏览器元素的“地址簿”

当Python后端从前端接收到包含bid标记的JSON数据后,Session对象会立即执行一个至关重要的动作:构建或更新元素缓存 (element_cache)。

我们可以把element_cache理解为一个动态更新的“地址簿”。它的作用是:

  • 键(Key): AI在思考时使用的抽象ID,即bid(例如 "12")。
  • 值(Value): 浏览器执行时需要的具体“地址”,即一个Playwright Locator对象。Locator是Playwright库中用于定位和操作元素的强大工具。

构建过程:在每一次“观察”循环中,这个“地址簿”都会被清空并重建。dom/service.py会遍历从前端获取的所有带bid的元素信息,并为每一个bid创建一个对应的Locator,然后存入element_cache字典中。

# 简化示例:构建 bid 到 Locator 的映射# self.element_cache 是一个字典# "12" 是从JS收到的 bid# self.page.locator(...) 是 Playwright 的元素定位器self.element_cache["12"] = self.page.locator('[]')

这个缓存机制是连接AI抽象决策(“我要点击bid为12的元素”)与浏览器具体执行(“找到data-browser-use-id为12的元素并点击它”)的核心枢纽。正因为有了这个实时更新的“地址簿”,代理才能在动态变化的网页上准确地执行LLM的指令。

思考:基于规则与上下文的决策

代理的“思考”阶段是其智能的核心,它体现了“工具化行动”“结构化推理”的哲学。代理的思考并非天马行空,而是被一套严谨的规则和丰富的上下文所引导。

代理的“宪法”:系统提示词 (system_prompt.md)

每次与LLM交互,browser-use 都会发送一段不变的系统提示词,这构成了代理行为的“宪法”:

  • 工具箱定义:明确列出所有可用的工具,如 click(bid, ...)type(bid, ...)。这为LLM提供了一个封闭且确定的行动集合,从根本上保证了行为的可预测性和安全性。
  • 结构化输出指令:强制要求LLM的回答必须是一个包含 thought(思考过程)和 action(行动指令)的JSON对象。thought 字段让我们可以洞察其决策逻辑,而 action 字段则保证了机器可以稳定解析并执行。

任务的“上下文”:动态提示词

在“宪法”的框架下,动态信息被填充进来,为LLM提供决策所需的一切情境:

  • 用户总目标 (Objective):确保代理在多步操作后依然“不忘初心”。
  • 行动历史 (Memory):将过往的“思考-行动-结果”序列传入,形成短期记忆,使代理能从过去的成功与失败中学习。
  • 当前页面状态:将“观察”阶段获取的简化DOM和截图作为输入,让代理基于最新的环境信息进行决策。

行动:追求确定性的健壮执行

“行动”阶段充分展示了“健壮性设计”的哲学。由于网页的脆弱性,任何操作都可能失败。browser-use 并非天真地假设每次点击都会成功,而是在 browser_use/browser/session.py 中构建了一套强大的、追求确定性的执行逻辑。

以 Session.click 为例,其执行流程堪称典范:

  1. 标准尝试:首先,通过 element_cache 找到元素的 Locator,并执行Playwright标准的 locator.click()。此方法会自动等待元素变得可见且可操作,应对了大部分场景。
  2. 强制回退:如果标准点击因元素被遮挡等原因失败,系统会尝试 locator.click(force=True)。此方法会忽略部分可操作性检查,增加了成功的概率。
  3. JavaScript回退:如果强制点击依然失败,系统将采用最后的“杀手锏”——locator.dispatch_event('click')。这会直接在浏览器中执行JavaScript来触发点击事件,能够绕过许多复杂的前端框架限制。

这种“标准尝试 -> 超时重试 -> 多种回退策略”的层层保障,使得代理的每一步行动都极为可靠,极大地提升了自动化任务的整体成功率。

工具箱(Toolbox)深度解析:从代码到实例

以下是 browser-use 代理的完整工具集。需要强调的是,下文中每个“典型使用场景”里的JSON示例,都是AI代理在接收到一个完整的、包含系统提示词、用户目标、当前页面状态和历史记录的提示词后,所生成的最终决策输出。其中的 thought 字段,正是其内部决策逻辑的体现。

1. click(bid, description)

  • 用途: 点击由bid标识的元素。这是最核心的交互动作。
  • 代码实现细节 (Session.click):
    • 通过 element_cache 将 bid 转换为 Playwright Locator
    • 调用 locator.click(timeout=...),并辅以 force=True 和 dispatch_event('click') 作为回退机制。
  • 典型使用场景:

    {  "thought": "我已经填写完所有信息,现在需要点击'提交'按钮 (bid=45) 来完成表单提交。",  "action": {    "name": "click",    "args": {"bid": "45", "description": "点击提交按钮"}  }}

2. type(bid, text, description)

  • 用途: 在由bid标识的输入框中输入文本。
  • 代码实现细节 (Session.type):
    • 同样通过 element_cache 找到 Locator
    • 主要调用 locator.fill(text),此方法会先清空输入框再填入新内容,高效且稳定。在某些需要模拟真实输入的场景,也可能使用 locator.type(text)
  • 典型使用场景:

    {  "thought": "页面上有一个标签为'搜索'的输入框 (bid=12),我需要在这里输入用户的查询内容'AI最新的发展'。",  "action": {    "name": "type",    "args": {"bid": "12", "text": "AI最新的发展", "description": "在搜索框中输入查询"}  }}

3. scroll(direction, description)

  • 用途: 滚动页面以浏览更多内容。
  • 代码实现细节 (Session.scroll):
    • 这是一个页面级操作,不针对特定bid
    • 通过调用 self.page.mouse.wheel(delta_x, delta_y) 模拟鼠标滚轮滚动。delta_y的正负值决定了向上还是向下滚动。
    • 对于滚动到底部/顶部,可能会直接执行JS:self.page.evaluate("window.scrollTo(...)")
  • 典型使用场景:

    {  "thought": "当前屏幕上没有看到'下一步'按钮,我需要向下滚动页面 (direction='down') 来寻找更多的内容。",  "action": {    "name": "scroll",    "args": {"direction": "down", "description": "向下滚动页面查看更多选项"}  }}

4. select_option(bid, value, description)

  • 用途: 在<select>下拉菜单中选择一个指定的选项。
  • 代码实现细节 (Session.select_option):
    • 找到bid对应的<select>元素的Locator
    • 调用Playwright的 locator.select_option(value=...)value通常是选项的value属性值或可见文本。
  • 典型使用场景:

    {  "thought": "我需要选择配送国家。我看到了一个国家选择的下拉框 (bid=33),我将选择值为'USA'的选项。",  "action": {    "name": "select_option",    "args": {"bid": "33", "value": "USA", "description": "选择美国作为配送国家"}  }}

5. navigate(url, description)

  • 用途: 导航到新的网址。
  • 代码实现细节 (Session.navigate):
    • 核心是调用 self.page.goto(url)。此方法会自动等待页面加载完成(load事件触发)后才返回。
  • 典型使用场景:

    {  "thought": "任务的第一步是访问Hacker News网站。我将直接导航至'https://news.ycombinator.com'。",  "action": {    "name": "navigate",    "args": {"url": "https://news.ycombinator.com", "description": "访问Hacker News首页"}  }}

6. 标签页管理 (open_new_tabswitch_tabclose_tab)

  • 用途: 管理多个浏览器标签页。
  • 代码实现细节 (Browser类):
    • open_new_tab: 调用 self.browser_context.new_page() 创建新页面,并为其包裹一个新的 Session 对象。
    • switch_tab: 调用 page.bring_to_front() 将指定索引的标签页激活。
    • close_tab: 调用 page.close() 关闭当前标签页。
  • 典型使用场景:

    {  "thought": "我需要在一个新的标签页中打开这个链接(bid=50),以便不离开当前页面。",  "action": {    "name": "open_new_tab",    "args": {"url": "https://example.com/details", "description": "在新标签页中打开详情"}  }}

7. ask_user(question)

  • 用途: 当代理遇到无法解决的困难时(如复杂的验证码),向用户请求帮助。
  • 代码实现细节:
    • 这并非一个浏览器操作,而是一个中断信号。它会暂停代理的执行,并将question的内容输出给用户。
  • 典型使用场景:

    {  "thought": "我遇到了一个复杂的图形验证码,我无法识别。我需要向用户询问验证码的内容。",  "action": {    "name": "ask_user",    "args": {"question": "请帮我输入图片中的验证码字符。"}  }}

8. done(result)

  • 用途: 标志着任务的成功完成,并返回最终结果。
  • 代码实现细节:
    • 这是一个终止信号,它会使 agent.run() 的主循环退出,并将 result 作为最终返回值。
  • 典型使用场景:

    {  "thought": "我已经成功将商品加入购物车并跳转到了确认页面。任务已经完成,我将返回'成功加入购物车'作为结果。",  "action": {    "name": "done",    "args": {"result": "成功加入购物车"}  }}

完整的提示词示例:一个具体的场景

为了更直观地理解,让我们构建一个完整的、发送给大语言模型的提示词。

场景: 代理已经完成了在GitHub上搜索“browser-use”的操作,现在正处于搜索结果页面。它的下一步任务是点击第一个搜索结果。

发送给模型的完整提示词将由以下部分组成:

SYSTEM MESSAGE (系统提示词)

你是一个AI网页浏览助手,你的任务是帮助用户完成网页操作。你会收到一个简化版的网页DOM,其中所有可交互的元素都有一个唯一的 "bid" 属性。请根据用户的目标,分析当前的页面状态和历史记录,然后从以下可用工具中选择一个来执行。# 可用工具:- `click(bid, description)`: 点击指定bid的元素。- `type(bid, text, description)`: 在指定bid的元素里输入文本。- `scroll(direction, description)`: 向下或向上滚动页面。- `done(result)`: 当你认为任务已经完成时调用,并附上最终结果。- ... (其他工具)# 规则:1.  仔细思考,一步一步来。2.  在你的 `thought` 字段中解释你为什么选择这个行动。3.  你的输出必须是严格的JSON格式,包含 `thought` 和 `action` 两个键。# 输出格式:{  "thought": "你的思考过程...",  "action": {    "name": "你的工具名称...",    "args": {      "参数1": "值1",      "参数2": "值2"    }  }}

USER MESSAGE (用户消息) 的构建分析

用户消息并非一个单一的文本块,而是由多个结构化部分组合而成,为LLM提供决策所需的所有上下文。

第一部分: 最终目标 (Objective)

这部分始终保持不变,作为代理所有行动的“指北针”。

# 最终目标在GitHub上搜索 "browser-use" 仓库,并点击进入第一个搜索结果。

第二部分: 行动历史 (Memory)

这部分记录了代理从任务开始到当前的所有“思考-行动-结果”循环,是代理的短期记忆。

# 历史记录- **思考**: 我需要先访问 GitHub,然后在搜索框里输入 "browser-use" 并执行搜索。- **行动**: `navigate(url="https://github.com")`- **结果**: 成功导航到 GitHub。- **思考**: 我现在在 GitHub 首页,我需要找到搜索框并输入 "browser-use"。- **行动**: `type(bid="5", text="browser-use")`- **结果**: 成功在搜索框中输入文本。- **思考**: 我已经输入了搜索词,现在需要点击搜索按钮或者按回车键来执行搜索。- **行动**: `click(bid="6")`- **结果**: 点击成功,页面已跳转到搜索结果。

第三部分: 当前页面状态 (Current State)

这是代理的“眼睛”,包含最新的简化DOM和页面截图。

# 当前页面状态 (简化DOM)这是GitHub搜索 "browser-use" 的结果页面。<div role="group">  <a bid="25" href="/browser-use/browser-use" text="browser-use/browser-use">    <span>Make websites accessible for AI agents.</span>  </a>  <p>Stars: 8.5k</p></div><div role="group">  <a bid="26" href="/other/repo" text="other/repo">    <span>Some other repository.</span>  </a>  <p>Stars: 1.2k</p></div>... (其他搜索结果)# 截图[这里会附上一张当前浏览器页面的截图,以供多模态模型参考]

模型的预期决策:

在接收到由以上三部分组合而成的完整用户消息后,LLM会分析所有信息:

  • 它知道最终目标是点击第一个结果。
  • 它看到历史记录表明搜索已经完成。
  • 它分析当前页面DOM,发现第一个结果是一个 <a> 标签,文本是 browser-use/browser-use,并且它的 bid 是 "25"。

因此,它会生成如下的决策JSON:

{  "thought": "我已经成功搜索了'browser-use'。根据页面内容,第一个搜索结果是'browser-use/browser-use',它的bid是25。我的目标是点击第一个结果,所以我现在应该点击这个链接。",  "action": {    "name": "click",    "args": {      "bid": "25",      "description": "点击第一个搜索结果 'browser-use/browser-use'"    }  }}

这个例子完整地展示了代理如何利用其“宪法”和丰富的“上下文”来进行一次精准的、有理有据的决策。

结论

browser-use 的成功,并非源于让AI拥有无尽的自由,恰恰相反,它源于一套在混沌中建立秩序的深刻设计哲学。通过抽象简化环境、工具化行动、结构化推理和健壮化执行,它为AI代理戴上了一副既能精准感知世界、又能稳健采取行动的“镣铐”。正是这副“镣铐”,让代理的舞蹈步步为营,最终在复杂的网络舞台上完成了精准而优美的演出。

对于所有致力于构建AI原生应用的开发者来说,browser-use 所体现的设计思想,无疑提供了宝贵的参考与启示。

原文始发于微信公众号(先进攻防):带着脚镣跳舞 - Browser Use智能体行为模式分析

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年6月25日16:37:59
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   带着脚镣跳舞 - Browser Use智能体行为模式分析http://cn-sec.com/archives/4199398.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息