设计:从 300 节点截断到可见优先的可观测快照)
qwen-code 与 Cua Driver 的浏览器语义状态semantic_v2设计从 300 节点截断到可见优先的可观测快照【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code本技术指南以packages/cua-driver/docs/browser-semantic-state-plan.md为骨架结合packages/cua-driver/rust/crates/cua-driver-core中已落地的源码实现完整剖析 Cua Driver 如何让get_browser_state在大应用页面成百上千的隐藏、离屏、陈旧节点中依然返回当前视图里真正重要的页面内容与可操作控件。读完本文你将掌握语义快照的架构分层可读内容与可操作 ref 分离、可见性分级与排序预算、scope_ref/query/continuation三种受控读取机制、帧与 Shadow DOM 组合的安全模型以及该方案在 macOS / Windows / Linux X11 / Wayland 上的跨平台验收路径。1. 背景get_browser_state在 v1 时代的四个结构性缺陷原方案文档browser-semantic-state-plan.md明确指出了旧收集器cua-driver-core/src/browser/engine.rs中的DOM.getDocument遍历在pierced DOM 文档序 宽泛的标签/属性交互规则 收集后截断到 300 个 ref这一链路下的四个问题隐藏或保留的应用子树会吃光整个 ref 预算——大型 SPA 中大量display:none、虚拟化列表外、历史保留的节点排在可见控件之前可见内容对离屏内容没有任何优先级——文档序决定了输出顺序而文档序与用户当前在看什么无关静态页面文本完全缺失——旧响应只包含可操作的 ref没有标题、段落等可读内容Agent 无法读页面截断只回报一个布尔值——调用方既不知道缺了多少也不知道缺的是什么、如何补取。源码中可印证 v1 的硬上限packages/cua-driver/rust/crates/cua-driver-core/src/browser/engine.rs中仍保留着pub const MAX_REFS_PER_SNAPSHOT: usize 300;即文档所说truncates the result to 300 refs after collection。单纯调高上限只会放大输出体积却保留排序错误这一根本缺陷——这正是semantic_v2要解决的问题。方案目标在精确浏览器绑定之后Agent 应能通过浏览器工具直接读取并操作网页内容原生 AXAccessibility与 PXPixel仅保留给浏览器 chrome、权限弹窗、下载、文件选择器和显式回退场景。2. 必须保留的既有保障semantic_v2是增量演进方案明确列出实现过程中不得破坏的既有契约原生pid与window_id仍然是绑定锚点浏览器 target、tab、快照、ref 仍是会话级能力每次变更操作都要重新证明浏览器代次generation、frame 身份、document 身份和后端节点存活get_browser_state保持只读浏览器引擎支持时页面操作保持后台安全background-safe出现歧义状态时产生结构化拒绝structured refusal而不是猜测。源码侧对应的实现事实是BrowserEngine的变更前再验证链revalidate_for_mutation在每次输入或导航前重新证明进程指纹 → 原生归属/边界 → endpoint 归属 → CDP target 类型/窗口整条链路frame_session_for_mutation额外重新证明 ref 的 frame/document 身份frame id loader idOOPIF 还需目标下已附加的 child target见 engine.rs。凡无法证明身份的 frame 内容一律从快照中省略——never guessed绝不猜测。3. 五大设计原则3.1 先观察、后行动Observe before actingget_browser_state只产生确定性的状态与能力不运行模型、不选择动作、不修改页面、不修复失败的工作流。调用方的正确循环是观察状态 → 选取当前 ref → 调用类型化动作 → 再次观察状态。3.2 内容与动作分离Separate content from actions可读的页面内容与可操作的元素是两套数据语义大纲semantic outline标题、文本、landmark、表单状态、对话框、滚动上下文ref 映射ref map只包含声明了某种浏览器动作的元素静态文本可以携带一个不透明的只读标识符用于范围限定但绝不能被browser_click或browser_type接受。3.3 先排序、后限流Rank before limiting收集器先分类并排序节点再施加输出预算。默认排序层级当前激活的 modal、dialog、聚焦元素及其语义上下文当前视口viewport内的可操作元素当前视口内的可读内容视口附近near viewport的可操作元素视口附近的可读内容其余已布局内容通过 continuation 或 scope 请求时。每一层内部保留文档序。3.4 页面可见性 ≠ 桌面可见性Page visibility is not desktop visibility浏览器布局可见性描述的是页面内容是否渲染在 tab 视口内或附近与原生浏览器窗口是否位于前台、是否被其他窗口遮挡、是否在可见桌面之外完全无关。这一区分保留了完整的后台浏览器动作能力background browser actions。3.5 策略高于传输细节Keep policy above transport details驱动可以缓存协议连接和单次快照内使用的数据但不得缓存自然语言动作计划或重放旧的选择器。工作流重复与自我修复属于调用方 Agent 的职责Cua Driver 每次变更操作仍要求一个当前的 capability。4. 快照架构多路协议输入与语义节点模型4.1 每个 tab 并发收集的输入来源用途Frame treeframe 拓扑、loader 身份、父子关系Accessibility tree角色、名称、值、状态、可读文本、忽略节点的剪枝Pierced DOM后端节点 ID、标签、属性、作者 Shadow root、同进程 frame 文档Layout snapshot计算可见性、边界、视口关系、绘制顺序paint orderLayout metrics视口尺寸、滚动偏移、设备缩放实现上每个唯一 CDP 会话在快照期间只建一个 DOM 索引同进程 frame 共享该会话索引跨进程 frameOOPIF走既有的、经过 capability 测试的子会话通道。这避免了每个 frame 重复的完整 DOM 读取——源码中semantic.rs的build_dom_index正是对整棵 pierced 树单次遍历建立DomIndexbackend node id → 标签/属性/文档序/CSS 隐藏标记/父节点/所属 frame随后从该索引切片出各 frame 子树。4.2SemanticNode内部模型frame_ref backend_node_id? role name? value? states parent children document_order visibility action_kinds源码实现与之一一对应semantic.rs中的SemanticNode携带ax_id、parent_ax_id、child_ax_ids、backend_node_id、role、name、value、statesBTreeMapString, Value、frame: FrameRef、visibility: BrowserVisibility、actions: VecBrowserActionKind与document_order。visibility是封闭枚举in_viewport near_viewport offscreen css_hidden no_layout page_occluded unknownstore.rs中的BrowserVisibility枚举与文档完全一致InViewport / NearViewport / Offscreen / CssHidden / NoLayout / PageOccluded / Unknown并在注释中重申Browser-layout visibility. This is independent from native desktop foreground or occlusion state.page_occluded采取保守策略若绘制顺序证据不完整则降级为unknown并保留该节点。绝不从原生窗口遮挡推断 CSS 或页面遮挡。4.3 无障碍优先的语义提取Accessibility-first semantics语义大纲以无障碍树为主来源因为它天然包含角色、名称、值、状态与可读文本。处理规则移除 ignored 与冗余的结构节点但保留有用祖先仅当父节点已携带相同 accessible name 时才折叠重复的静态文本有界 DOM 补充部分自定义控件不会以可操作的 AX 节点出现因此对具有明确交互证据的元素做有界补充原生交互标签受支持的交互 ARIA 角色显式事件监听器或处理器可编辑内容具有非零布局边界的 pointer cursor。补充必须拒绝aria-hidden、hidden、display:none、visibility:hidden、零透明度以及继承的 pointer-cursor 噪声。源码侧semantic.rs定义了SEMANTIC_COMPUTED_STYLES常量精确抓取display、visibility、opacity、pointer-events、cursor、position、z-index、overflow-x、overflow-y九项计算样式用于隐藏判定。4.4 帧与 Shadow 组合Frame and shadow composition保留既有帧安全模型每个可操作条目记录FrameRef与 document 身份同进程 iframe 条目需要 frame-tree 身份跨进程 iframeOOPIF条目需要包含的 child target 与被证明的身份作者 Shadow root 组合进宿主 frame用户代理user-agentShadow root 保持排除无法证明的 frame 内容以原因 数量的形式省略。engine.rs顶部注释对此有翔实描述快照组合使用pierce: true将 Shadow DOM 组合进主 frame 遍历并跳过 user-agent shadow roots同进程 iframe 经contentDocument遍历、ref 携带来自Page.getFrameTree的 child frame 身份OOPIF 仅在Target.setAutoAttachcapability 测试成功后经会话作用域的Target.attachedToTarget事件访问。semantic.rs的build_dom_index遍历逻辑同样显式跳过shadowRootType user-agent的 shadow root并沿contentDocument递归携带子 frame id。4.5 有界协议回退Bounded protocol fallback大页面可能让无界的DOM.getDocument失败。回退策略分五步先请求完整 pierced 树仅对已知的 depth 或 serialization 失败用逐级变浅的深度重试用有界的DOM.describeNode调用补充缺失分支强制执行 time、node、frame、hydration-call 预算无法证明完整树时如实报告部分覆盖。瞬时传输失败仍然属于错误不得被当作能力缺口或部分成功处理。5. 公共契约Public Contract5.1 版本化快照请求新增带版本号的快照请求不破坏既有客户端{ session: research-1, target_id: bt-..., tab_id: tab-..., snapshot_format: semantic_v2 }迁移期间既有响应以dom_refs_v1形式保留skill 与测试 harness 先在semantic_v2上运行之后才将其设为默认旧格式只通过正常弃用流程移除。源码事实tools.rs中快照工具的参数 schema 定义了snapshot_format枚举[dom_refs_v1, semantic_v2]其中dom_refs_v1仍是兼容默认值同时scope_ref、query、continuation三个参数只有在snapshot_format semantic_v2时才被允许否则工具直接报错scope_ref, query, and continuation require snapshot_formatsemantic_v2。5.2 默认响应结构{ status: ok, mode: snapshot, snapshot: { id: p42, format: semantic_v2, complete: false, scope: viewport, omitted: { css_hidden: 410, offscreen: 82, unprovable_frame: 0 }, continuation: opaque-capability-or-null }, page: { url: https://fixture.invalid/inbox, title: Inbox, focused_ref: p42:8 }, outline: ...compact semantic tree..., refs: [] }要点outline是供模型消费的紧凑文本refs保持结构化 JSON用于确定性动作路由响应不得暴露原始 CDP target ID、后端节点 ID、object ID 或选择器。5.3 可操作 ref每个 ref 暴露足够的公开信息以选择类型化动作{ ref: p42:8, role: button, name: Reply, states: { disabled: false }, actions: [click], frame: main, visibility: in_viewport }内部存储保留既有的后端节点与帧证据。变更工具在请求的动作不在actions中时拒绝该 ref。源码侧store.rs的BrowserActionKind定义了五类已声明的动作Click / Type / Upload / Pointer / Scroll并序列化为click、type、upload、pointer、scrollsemantic.rs的to_ref_entry仅在节点持有backend_node_id时才将SemanticNode转为可操作RefEntryactions与visibility随条目保存。5.4 三种受控只读观察机制按优先级支持三种 scope 机制scope_ref检查以当前语义 ref 或可操作 ref 为根的子树query返回 role、accessible-name 与可见文本匹配附带祖先上下文continuation从同一实时快照代次中查看下一个排序分段。所有 scope token 都是不透明、会话绑定、tab 绑定、代次绑定的。不将 XPath 或 CSS 作为首要 Agent 契约专家专用 selector 字段留待 capability 路径被接受后再评估。源码侧semantic.rs的SemanticPage通过next_offset: Optionusize表达 continuation 能力page()方法以offset budget切片候选集候选按(query_score 逆序, rank, document_order)三级排序。5.5 截断与预算的替代方案用单个truncated布尔值替换为收集是否完整complete省略了哪些可见性层级按省略原因计数omitted实际应用的节点预算与输出预算存在更多已验证状态时的不透明 continuation 能力。首版实现中预算为配置常量公开数值化覆盖需待性能与滥用边界被摸清后才开放。源码事实semantic.rs定义DEFAULT_SEMANTIC_NODE_BUDGET: usize 300、NEAR_VIEWPORT_MARGIN: f64 1_000.0视口外 1000px 内视为 near viewport、MAX_SEMANTIC_TEXT_CHARS: usize 1_000以及OmissionCountscss_hidden / offscreen / page_occluded / no_layout / unknown / budget / unprovable_frame——与文档中的省略计数一一对应。6. 代码变更清单落地情况对照方案规划了五处代码变更以下逐一说明仓库中的对应实现engine.rs将协议收集与语义组合分离收集 frame、AX、DOM、layout、viewport 状态语义节点排序先于输出限流仅为已声明动作种类铸造 ref保持 OOPIF 包含与清理返回覆盖与省略诊断。文件中保留了 v1 的MAX_REFS_PER_SNAPSHOT常量并在模块头注释中完整记录了 v2 快照组合的帧安全模型。store.rs存储快照格式与代次为RefEntry增加动作种类存储不透明 continuation 与 scope 能力静态语义节点保持在可操作 ref 映射之外导航、重连、更新快照、会话结束与 target 替换时使所有派生能力失效。tools.rs为快照模式新增snapshot_format、scope_ref、query、continuation返回语义大纲、结构化 refs 与覆盖诊断bind 模式保持不变保持 MCP 只读注解准确语义快照从不执行 setup。浏览器传输层为 AX 与 layout 快照新增类型化协议响应模型如build_layout_index解析 layout snapshot 的 strings/documents/nodes/layout 结构已知 depth/serialization 失败与传输失败分开归类并发调用取消安全在不含页面文本的前提下发出 timing 与 count 指标。Skill 与文档packages/cua-driver/rust/Skills/cua-driver/BROWSER.md已切换到semantic_v2——例如其 curl 示例session:browser-run-1,snapshot_format:semantic_v2并教授快照 → 选择当前 ref → 动作 → 重新快照循环、受控读取与 continuation页面内容在绑定后应留在浏览器工具上get_window_state保留给浏览器 chrome 与原生回退用户参考文档待 schema 验收后再补充。7. 测试策略从确定性夹具到跨平台 E2E7.1 共享确定性夹具扩展仓库内 web harness加入一个大型应用夹具必须包含活动视图之前超过 300 个隐藏或保留的控件虚拟化列表与选中详情视图可见标题、消息正文、可编辑回复框与发送按钮覆盖其下控件的 modal 遮罩嵌套作者 Shadow DOM同进程与跨进程 iframe动态重渲染与导航控件不同区域中的重复名称可通过 continuation 或 scope 到达的离屏控件。只使用夹具数据源码、日志、截图或产物中不得出现客户域名、账户名、邮件文本、个人资料路径或浏览器历史。7.2 单元测试覆盖为以下行为新增测试AX 角色/名称/状态/静态文本规范化CSS 与布局可见性分类排序稳定性与文档序平局动作种类分配隐藏节点排除DOM 补充去重帧与 Shadow 组合有界深度回退与部分覆盖报告输出预算与 continuation 失效query 与 scope 歧义导航、重渲染、重连、新快照后的陈旧 ref。仓库中已有对应测试文件packages/cua-driver/rust/crates/cua-driver-core/src/browser/v2_tests.rssemantic_v2 专项测试与packages/cua-driver/rust/crates/cua-driver/tests/standalone_browser_behavior_test.rs独立浏览器行为测试。7.3 浏览器 E2E 行同一套源码构建的 Rust 测试行在每个受支持的浏览器与平台上运行场景前台姿态后台姿态必需证据读取可见详情文本yesyes语义大纲包含夹具文本点击可见动作yesyes夹具日志恰好变更一次向可见编辑器输入yesyes精确送达的文本且无输入泄漏隐藏节点压力yesyes可见控件在预算下存活作用域内重名动作yesyes仅作用域区域变化Modal 页面遮挡yesyes被覆盖控件省略或标记为 occludedContinuationyesyes离屏控件变得可寻址重渲染陈旧性yesyes旧 ref 被拒绝、新 ref 成功帧与 Shadow 动作yesyes精确包含的 frame 发生变更后台行在浏览器原生被遮挡、且焦点/光标/泄漏哨兵sentinels激活的情况下运行页面视口保持不变使两种姿态下的浏览器布局可见性可比。7.4 平台门槛macOS当前主机或受认可 VM本地源码安装浏览器同意按既有流程已授予Windows交互式 GitHub-hosted runner 或 Azure RDP 桌面绝不能是 session 0Linux X11带标准浏览器 harness 的交互式桌面Linux Wayland受认可合成器 精确浏览器绑定不支持的合成器身份保持为结构化拒绝。语义收集器运行在原生平台层之上因此跨操作系统应产生等价的页面结果平台差异仅限于绑定、endpoint 证明、同意流程与原生哨兵。8. 交付阶段Phases与门槛阶段内容门槛Phase 0复现与度量加入隐藏节点压力夹具证明当前收集器省略可见内容记录协议时间、节点数、响应字节、输出行数新增失败测试且不为迁就现状而修改期望夹具在源码构建上确定性复现缺陷Phase 1语义大纲AX 语义模型可读内容与可操作 ref 分离返回v1 收集器保留动作种类检查无需原生 AX 即可获得可见详情文本与编辑器状态Phase 2布局与排序接入 layout snapshot 与视口指标可见性分类可见优先排序与覆盖诊断保守页面遮挡处理隐藏节点压力不再挤占可见状态Phase 3作用域与延续新增scope_ref、语义 query、不透明 continuation每个能力绑定到当前会话/target/tab/代次拒绝陈旧与歧义作用域重名与离屏内容无需原始选择器或无限响应即可寻址Phase 4帧与规模加固按协议会话共享 DOM 索引有界深度回退与 hydration验证同进程/跨进程帧与 shadow root设定 time/node/frame/memory/response 预算大型多帧夹具在预算内完成预算耗尽时如实报告部分覆盖Phase 5跨平台验收更新 skill 与协议 schema 测试在 macOS/Windows/X11/受认可 Wayland 上运行前后台 harness 行发布矩阵摘要、trace 与仅含夹具的视频验证日志与产物不含非夹具会话的页面文本所有受支持行通过或产生文档化的结构化拒绝旧快照格式保持兼容Phase 6默认迁移semantic_v2成为 skill 默认监控大小、延迟、拒绝、陈旧 ref 指标文档化旧格式弃用窗口v1 仅在已接受客户端与 harness 迁移后移除一个发布周期内无未解决的兼容性或隐私回归9. 完成定义Definition of Done项目完成的标准共八条源码构建的 Cua Driver 可精确绑定到浏览器 tab并在不借助原生 AX 检查的情况下读取大型应用视图当超过 300 个隐藏或保留节点位于前方时可见文本与动作依然可用静态内容与可操作 ref 分离变更工具强制执行已声明的动作种类scope 与 continuation 是会话绑定能力且陈旧行为有测试覆盖帧、Shadow、导航、重渲染、重连测试保持精确的变更契约macOS / Windows / X11 / 受认可 Wayland 上所有已宣告浏览器路线的前后台 E2E 行全部通过skill、协议 schema、支持参考、CI 矩阵与发布说明描述所交付的行为仓库扫描与产物审查未发现客户标识符、账户内容、本地 profile 路径、endpoint token 或原始浏览器 ID。10. 明确的非目标Non-GoalsCua Driver 内部不进行模型推理不提供自然语言的browser_act或browser_extract工具不自动重放或自愈旧动作计划不将 XPath、CSS 选择器、后端节点 ID 或 CDP target ID 作为首要公共契约不把原生窗口可见性当作页面元素可见性不把任意静态文本变得可点击当协议或预算限制产生部分快照时不宣称状态完整。11. 总结semantic_v2的核心贡献是把get_browser_state从一个按文档序截断的可操作 ref 列表升级为一个可见优先、内容/动作分离、可受控分页、如实报告覆盖度的确定性语义快照。它在保留dom_refs_v1兼容默认的同时通过无障碍树、pierced DOM 与布局证据的三源合并解决了大应用中隐藏节点挤占预算、静态文本缺失、截断不可观测三大痛点并以帧身份证明、Shadow DOM 组合与不透明能力令牌守住安全边界。方案自 browser-semantic-state-plan.md 提出后已在 semantic.rs、store.rs、tools.rs 中落地skill 侧BROWSER.md与测试侧v2_tests.rs均已切到新格式剩余工作聚焦于跨平台前后台验收与默认迁移。若你需要在真实浏览器上复现这套流程可按 BROWSER.md 中的命令以snapshot_formatsemantic_v2发起快照再依次尝试scope_ref、query与continuation即可观察到先观察、后行动、再观察的完整循环。【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考