ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

CAMEL Hybrid Browser Toolkit 页面快照机制:PageSnapshot 的设计原理与 Agent 实战

CAMEL Hybrid Browser Toolkit 页面快照机制:PageSnapshot 的设计原理与 Agent 实战 CAMEL Hybrid Browser Toolkit 页面快照机制PageSnapshot 的设计原理与 Agent 实战【免费下载链接】camel CAMEL: The first and the best multi-agent framework. Finding the Scaling Law of Agents. https://www.camel-ai.org项目地址: https://gitcode.com/GitHub_Trending/ca/camel本文围绕 CAMEL 仓库中camel.toolkits.hybrid_browser_toolkit.snapshot模块的核心类PageSnapshot深入讲解其YAML 结构化页面快照 增量 diff的设计原理、capture 完整流程、ref 引用体系与优先级检测逻辑并结合browser_session.py、agent.py与hybrid_browser_toolkit.py的源码调用链说明如何在 CAMEL 多智能体框架中用它驱动浏览器 Agent 自主感知页面并执行任务。一、为什么浏览器 Agent 需要页面快照浏览器 Agent 的核心挑战在于大语言模型无法直接看见网页渲染结果。无论是让 Agent 点击按钮、填写表单还是分析页面内容它都需要一种比 HTML 原始源码更精炼、比截图更省 token 的页面表示。CAMEL 的 Hybrid Browser Toolkit 给出的答案是PageSnapshot——一个将当前页面 DOM 中的可交互元素提取为结构化文本YAML 风格的工具类。从 snapshot.py 的类注释可以看到它的定位Utility for capturing YAML-like page snapshots and diff-only variants.即它一方面生成YAML 风格的完整快照另一方面还能生成仅包含差异diff-only的增量版本。这两者构成了浏览器 Agent 感知页面的核心数据源也是 agent.py 中快照 → LLM 规划 → 执行动作 → 再次快照闭环的基础。PageSnapshot 在仓库中的位置PageSnapshot位于camel/toolkits/hybrid_browser_toolkit_py/snapshot.pyAPI 文档路径为camel.toolkits.hybrid_browser_toolkit.snapshot是纯 Python 实现不依赖 TypeScript 端配合同目录下的 unified_analyzer.js负责在页面内提取 DOM 结构化信息工作。它被 browser_session.py 中的BrowserSession持有self.snapshot PageSnapshot(page)并通过get_snapshot()对外暴露。二、PageSnapshot 的类结构与初始化2.1 构造函数def __init__(self, page: Page):构造函数接收一个 Playwright 的Page实例from playwright.async_api import Page在TYPE_CHECKING下导入仅用于类型标注。初始化时它会设置以下关键状态见 snapshot.py属性类型说明pagePagePlaywright 页面实例所有快照抓取都基于它snapshot_dataOptional[str]最近一次完整快照非 diff缓存供 diff 比较使用_last_urlOptional[str]最近一次抓取时的页面 URLlast_infoDict[str, List[int] \| bool]记录最近一次抓取的元信息含is_diff是否为 diff 结果与priorities页面中包含的优先级级别默认[1, 2, 3]dom_timeoutintDOM 稳定等待超时取自ConfigLoader.get_dom_content_loaded_timeout()其中dom_timeout来源于 config_loader.py 中的BrowserConfig.get_dom_content_loaded_timeout()默认值为 5000msDEFAULT_DOM_CONTENT_LOADED_TIMEOUT 5000可通过环境变量HYBRID_BROWSER_DOM_CONTENT_LOADED_TIMEOUT覆盖。这说明快照抓取前会先等待 DOM 稳定避免抓到未渲染完成的半成品页面。2.2 公开方法一览按照文档与源码PageSnapshot对外暴露的核心入口是capture()内部辅助方法包括方法类型作用capture(force_refresh, diff_only, viewport_limit)公开 async 方法抓取当前页面快照或与上次快照比较生成 diff_format_snapshot(text)静态方法将原始快照文本包装成 YAML 代码块_compute_diff(old, new)静态方法用difflib.unified_diff计算两次快照的差异_detect_priorities(snapshot_yaml)实例方法检测快照中包含的元素优先级级别1/2/3_get_snapshot_direct(viewport_limit)内部 async 方法执行快照提取 JS带重试返回原始分析结果三、capture()一次完整快照抓取的生命周期capture()是PageSnapshot的核心方法snapshot.py签名与参数如下async def capture( self, *, force_refresh: bool False, diff_only: bool False, viewport_limit: bool False, ) - str:三个关键字参数的作用force_refresh默认False是否强制刷新完整快照。历史实现中当 URL 未变化时会跳过重新生成但这会导致 Agent 无法感知未发生导航但 DOM 已更新的场景典型如 SPA 应用、Wordle 这类动态游戏页面。源码中的注释明确说明早退逻辑已被移除现在每次都抓取全新 DOM如果抓取结果与上次逐字节相同则在比较步骤后直接返回否则调用方即使在 URL 未变化时也能拿到更新后的快照。diff_only默认False为True时不返回完整快照而是返回与上一次快照的结构化 diff。viewport_limit默认False是否将快照范围限制在当前视口viewport内。对应 hybrid_browser_toolkit.py 中 When True, only return snapshot results 的说明。3.1 执行流程拆解capture()的完整生命周期如下等待 DOM 稳定调用self.page.wait_for_load_state(domcontentloaded, timeoutself.dom_timeout)确保页面 DOM 已加载完成超时由dom_timeout控制。执行快照提取 JS调用_get_snapshot_direct(viewport_limitviewport_limit)在页面上下文中执行unified_analyzer.js提取结构化信息。若返回结果是包含snapshotText键的字典unified analyzer result则提取该字段否则直接使用原返回值。格式化通过_format_snapshot(snapshot_text or empty)将原始文本包装为 YAML 风格输出空结果时输出empty占位。计算 diff可选若diff_onlyTrue且已有缓存的snapshot_data则调用_compute_diff(self.snapshot_data, formatted)生成增量结果。更新缓存将_last_url与snapshot_data注意缓存的是完整快照而非 diff更新为当前结果。检测优先级对格式化文本调用_detect_priorities()并写入last_info供上层 Agent 判断页面类型。异常兜底任何异常都会被捕获并记录日志返回Error: Could not capture page snapshot {exc}错误串保证 Agent 不会因快照失败而崩溃。3.2 快照提取的导航竞态重试机制_get_snapshot_direct()中有一段值得注意的容错逻辑snapshot.py快照 JS 从Path(__file__).parent / unified_analyzer.js读取并缓存在类级缓存_snapshot_js_cache中避免每次抓取都重新读文件。Playwright 在调度 JS 与执行 JS 之间发生页面导航时会抛出Execution context was destroyed或包含Most likely because of a navigation的错误。此时实现会最多重试 3 次每次重试前先等待下一次domcontentloaded事件再重新执行evaluate。对于非导航类的其他异常则立即中止并返回None不做无谓重试。这段逻辑保证了在用户快速点击链接、页面跳转频繁的真实场景下快照抓取依然稳健。四、快照格式YAML 风格与 ref 引用体系4.1 _format_snapshot 输出格式staticmethod def _format_snapshot(text: str) - str: return \n.join([- Page Snapshot, yaml, text, ])即输出格式为- Page Snapshot yaml 快照内容快照内容本身由 unified_analyzer.js 在页面内生成典型的可交互元素行格式为来自 [hybrid_browser_toolkit.py](https://link.gitcode.com/i/ed5634587e1c8ebafba2ec45d036727c) 的文档示例link Sign In [ref1]textbox Username [ref2]每一行代表页面中的一个可交互元素包含角色role、可读名称name和唯一引用 ID [refN]。ref 是整个 Hybrid Browser Toolkit 操作体系的关键browser_click、browser_type、browser_select 等工具都通过 ref 定位目标元素因此快照既是 Agent 的眼睛也是动作执行的坐标系统。 ### 4.2 与 TypeScript 实现的对应 仓库中还存在 TypeScript 版本的 [snapshot-parser.ts](https://link.gitcode.com/i/7eae86650ea0404d473f5747433fe518) 与 [browser-session.ts](https://link.gitcode.com/i/a78b1ae1033186d4feb00d55993791b1)Python 版的 PageSnapshot 是与之平行、面向 Python 调用方hybrid_browser_toolkit_py的实现。两者共享同一套ref 引用 YAML 结构化快照的交互协议设计。 ## 五、增量感知_compute_diff 与 diff-only 模式 ### 5.1 实现原理 _compute_diff() 使用 Python 标准库 difflib 计算两次快照的统一差异[snapshot.py](https://link.gitcode.com/i/cd029373953e5e1423aba71fdbb70bf9#L221-L249) python diff list( difflib.unified_diff( old.splitlines(False), new.splitlines(False), fromfileprev, tofilecurr, lineterm, ) ) if not diff: return - Page Snapshot (no structural changes) return \n.join([- Page Snapshot (diff), diff, *diff, ])输出有两种形态有变化时返回- Page Snapshot (diff)包裹的diff代码块包含prev/curr两个文件的统一差异无变化时返回- Page Snapshot (no structural changes)表示页面结构未发生改变。5.2 在 Agent 闭环中的价值diff-only 模式的价值在于token 效率与变化聚焦。在 agent.py 的solve_task主循环中diff_snapshot await self._session.get_snapshot( force_refreshActionExecutor.should_update_snapshot(action), diff_onlyTrue, )Agent 每执行一个动作后只向 LLM 返回页面相对上一个状态变了什么而不是每次都灌入整页快照。同时Agent 通过判断返回串是否以- Page Snapshot (no structural changes)开头来决定是否需要更新完整快照缓存full_snapshot实现动作执行 → 增量观察 → 必要时全量刷新的自适应感知。5.3 与 should_update_snapshot 的配合actions.py 中的ActionExecutor.should_update_snapshot(action)用于判断某类动作执行后是否需要强制刷新快照例如点击、输入等可能改变页面结构的动作。force_refresh与diff_only的组合让快照抓取既有增量效率又不会漏掉结构性变化。六、优先级检测_detect_priorities 的规则_detect_priorities()负责从快照文本中检测页面包含的元素优先级级别返回值是升序排列的列表如[1, 2, 3]。判定规则snapshot.py优先级判定条件元素示例1行内小写后包含input、button、select、textarea、checkbox、radio、link之一输入框、按钮、下拉框、链接等可交互元素2行内包含label标签元素3其余所有[ref...]行一般文本/静态元素具体实现是遍历快照的每一行跳过不含[ref的行将包含交互关键字的行归为优先级 1、标签归为优先级 2、其余归为优先级 3若整页都没有[ref行则兜底返回[3]。last_info[priorities]会被 agent.py 记录如Initial snapshot priorities%s供上层 Agent 判断当前页面是否可交互例如全是静态内容的页面与带大量表单的页面Agent 采取的策略应不同。七、在 HybridBrowserToolkit 中的完整调用链PageSnapshot处于整条浏览器 Agent 链路的中间层。从 hybrid_browser_toolkit.py 可以看到工具清单中暴露了browser_get_page_snapshot其实现第 1424 行起会先调用_get_unified_analysis()获取页面分析数据再格式化输出。整体调用关系为HybridBrowserToolkit.browser_get_page_snapshot() │ ▼ BrowserSession.get_snapshot(force_refresh, diff_only, viewport_limit) │ ▼ PageSnapshot.capture(...) ──► unified_analyzer.js页面内执行 │ ├── _format_snapshot() → 完整 YAML 快照 ├── _compute_diff() → diff-only 增量 └── _detect_priorities() → last_info[priorities]同时在高层 Agent 闭环agent.py 的solve_task中PageSnapshot支撑了初始全量快照 → LLM 生成 plan → 执行动作 → diff 快照 → 判断是否全量刷新的迭代循环直至任务完成或达到max_steps默认 15 步。八、测试与验证仓库测试文件 test_hybrid_browser_toolkit.py 中通过 mock WebSocket 返回了快照格式的样例- Page snapshot yaml test content这与 _format_snapshot 的输出结构一致验证了快照以 fenced YAML 代码块形式返回给调用方这一协议约定。相关工具行为测试同样断言 browser_get_page_snapshot 等工具会随动作结果返回快照字段如 open_browser、visit_page、click 等返回体中的 snapshot 键。 ## 九、关键配置速查 与 PageSnapshot 直接相关的配置集中在 [config_loader.py](https://link.gitcode.com/i/95f8810242bf883f5b18c78731dbb6a7) 的 BrowserConfig 中均支持环境变量覆盖 | 配置项 | 默认值 | 环境变量 | 影响 | | --- | --- | --- | --- | | dom_content_loaded_timeout | 5000ms | HYBRID_BROWSER_DOM_CONTENT_LOADED_TIMEOUT | capture() 中等待 domcontentloaded 的超时 | | navigation_timeout | 10000ms | HYBRID_BROWSER_NAVIGATION_TIMEOUT | 页面导航超时goto | | network_idle_timeout | 5000ms | HYBRID_BROWSER_NETWORK_IDLE_TIMEOUT | 导航后等待网络空闲的超时 | | page_stability_timeout | 1500ms | HYBRID_BROWSER_PAGE_STABILITY_TIMEOUT | 页面稳定性等待 | | screenshot_timeout | 15000ms | HYBRID_BROWSER_SCREENSHOT_TIMEOUT | 截图超时 | 这些参数在 HybridBrowserToolkit.__init__ 中也可直接以关键字参数传入如 dom_content_loaded_timeout未传入时回落到环境变量或默认值。 ## 十、小结 PageSnapshot 是 CAMEL Hybrid Browser Toolkit 中连接浏览器 DOM与LLM 认知的桥梁 - **结构化感知**将复杂 DOM 提取为带 ref 引用的 YAML 风格文本让 LLM 以极低 token 成本理解页面 - **增量效率**diff_only 模式 _compute_diff 让 Agent 只需关注页面变化配合 force_refresh 和 should_update_snapshot 实现高效的自适应感知 - **稳健性**DOM 稳定等待、导航竞态重试3 次、异常兜底保证真实网页环境下的可用性 - **信息回传**last_infois_diff、priorities为上层 Agent 提供页面类型与变化状态的元数据。 对于希望基于 CAMEL 构建浏览器自动化 Agent 的开发者深入理解 PageSnapshot 的上述机制是掌握快照协议、定制 Agent 感知策略、诊断Agent 看不到页面变化类问题的最佳起点。相关代码可继续在 [snapshot.py](https://link.gitcode.com/i/cd029373953e5e1423aba71fdbb70bf9)、[browser_session.py](https://link.gitcode.com/i/f27aa4c4f5965ffa8647aa7a14372e77) 与 [agent.py](https://link.gitcode.com/i/31b3424b0bc2e0226b7b5af07d286119) 中深入研读。【免费下载链接】camel CAMEL: The first and the best multi-agent framework. Finding the Scaling Law of Agents. https://www.camel-ai.org项目地址: https://gitcode.com/GitHub_Trending/ca/camel创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表