Skip to content

Browser Design

AceGuru-mjh edited this page Oct 1, 2026 · 4 revisions

浏览器智能体设计裁决

🔧 能力 · 🏠 首页 › Browser-Design

Home Version Kotlin Modules Tools License

Browser-Design typing

📑 本页目录

对标并四点超越 Operit(com.ai.assistance.operit)。 来源:docs/web-browser-automation-final.md、docs/web-browser-chrome.md。

1. 范式对照(2024 旧范式 → 本项目裁决)

维度 2024 旧范式 本项目
元素引用 顺序索引 bid=1,2,3(SPA 局部刷新即失效) 语义哈希 r_<hash>
事件触发 element.click() 合成事件 DOM 定位 → Android dispatchTouchEvent 物理触摸
DOM 传输 每次全量快照 JS 层启发式剪枝 + 字符预算(增量 Diff 为 P2 储备)
人工接管 简单浮窗 状态机驱动的显式握手
截图 全页长图 仅当前视口

四点超越:语义哈希稳定 Ref(抗 SPA 局部刷新)、物理触摸注入(抗 isTrusted 校验)、 JS 层启发式剪枝(省 token)、显式握手人工接管(状态机 + 全局工具锁,零歧义)。

2. 四项创新实现

① 语义哈希 + 降级定位链

ref = "r_" + hash(role + text + domPath + 相对位置)
快照时打 data-apex-hash → 定位用 querySelector('[data-apex-hash="..."]')
DOM 重绘导致 hash 失效时的降级链:
  ① 精确 data-apex-hash
  ② 按快照保存的 role + text 在可视区模糊匹配
  ③ 按相对坐标在父容器内做空间邻近度匹配

暂不做跨 iframe(P2;当前把 iframe 视为整体交互块)。

② 物理触摸桥接

clickElement(ref)
  = JS 取 BoundingRect
  → 换算 WebView 屏幕坐标(叠加浮窗绝对偏移)
  → 构造 MotionEvent(DOWN/UP),DOWN~UP 之间 30~80ms 随机延迟模拟按压
  → webView.dispatchTouchEvent()

为什么不用 el.click():React/Vue 与 Cloudflare/Akamai 会校验 isTrusted 与完整的 touchstart → touchmove → touchend 轨迹。 evaluateJavascript 经 CountDownLatch / suspendCancellableCoroutine 同步化。

③ 剪枝 + 硬上限

  • SNAPSHOT_JS 过滤:display:none / visibility:hidden / offsetParent === null / 不可见非交互无文本节点 / 超深非交互子树;
  • Kotlin 层 DomParser.buildSummary 再按字符预算裁剪折叠;
  • 单次快照元素数 ≤ 50(token 预算保护);
  • 摘要不引 BPE(真 BPE 耗 CPU、增包体),用轻量启发式。

④ 显式握手(重要修正)

Important

原设计的"上下文感知自动探针监控"已被彻底废弃(隐式推断在复杂生产环境不稳定: 误判输入中/已放弃、页面成功标志各异、易误夺控制权)。 改为人类在浮窗点「我已完成操作」按钮触发显式握手,交还 Agent。

  • WAITING_HUMAN 状态锁定所有 Agent 自动化工具(前置守卫 assertAgentControl() 抛 HandoffLockedException / 返回 SYSTEM_LOCKED);
  • completeHandoff() 后自动 snapshot 一次作为隐式上下文回灌 Agent。

3. 状态机与工具接口

HIDDEN → AGENT_DRIVING → WAITING_HUMAN → HANDOFF_COMPLETE

核心工具:browser_navigate(url, new_tab?)、browser_snapshot、browser_click(ref)、 browser_input(ref, text)、browser_scroll(delta_y?)、browser_screenshot(PNG base64 视口)、 browser_show(expand? 默认 true)。

4. 缺口审计落地

P0(6 项全部落地)

# 缺口 做法
1 页面加载等待 onPageFinished + 可选 wait_for 轮询 10s + 15s 超时兜底
2 动作后验证 probePage / PostActionState 对比 URL / 标题 / 可交互元素数
3 JS 弹窗 接管 onJsAlert/Confirm/Prompt 自动 confirm,文本存 lastDialog 注入下次 snapshot
4 渲染进程崩溃 onRenderProcessGone 销毁重建 WebView,置 RECOVERING,返回 true 不 crash 宿主
5 动作空间补全 selectOption / toggle / respondFileChooser + 三个对应工具
11 安全加固 禁 allowFileAccess / allowContentAccess / file-from-URL(防 UXSS 与路径穿越)

P1(3 块)

# 内容
7 RetryPolicy:指数退避 500ms × 2^n、上限 5s、最多 3 次;ElementNotFoundException / TimeoutException / WebViewNotRespondingException 可重试,语义错误(HandoffLockedException)不重试;连续 5 次失败熔断 30s
9 BrowserTracer:内存环形缓冲 100 条(工具/参数/结果/耗时/URL/状态)+ browser_debug_dump(limit)
8 上下文管理轻量版:最近 3 步保留详情,更早压成单行,始终保留 URL 关键帧

未实现(P1/P2 排期)

权限请求、反爬隐身、下载、内存维护、多标签并发上限、Accessibility Tree、网络拦截、任务规划、可编程剪枝。

5. Chrome 层(给人用的浏览器界面)

chrome/           引擎无关 UI 层(BrowserChromeController + SnapshotComposer,不 import 任何 WebView/引擎类型 → 可 @Preview、可 JVM 单测)
   ↓
BrowserEngineGateway        ← 唯一边界契约
   ↓
chrome/bridge/    ApexChromeWiring(真实接线器)、NeonChromeWiring、ChainingClients、
                  DialogRequestRouter、AgentDialogPolicy + 权限记忆
   ↓
TabOperations     六个一行方法
   ↓
BrowserEngine     零行为改动,仅增量接口
  • ChainingClients 链式接管:包一层并转发,保留引擎已有的 onPageFinished 注入 / scheme 白名单 / SSL 拦截 / 渲染进程恢复,只接管 JS 弹窗 / 网页权限 / 地理定位 / 进度标题采集;
  • 快照频率分层:TabSet 低频 resync + Live 高频回调 → SnapshotComposer 合成单一 EngineSnapshot,UI 只消费一个 StateFlow。

人工接管期间人类可做的 10 件事

地址胶囊即进度条 · 多标签(单标签自动隐藏)· 撤销式关闭(4s 宽限期 Snackbar) · 前进/后退/刷新/停止 · 页内查找(findAllAsync + 匹配计数)· 桌面模式(UA 切换 + reload)· JS 弹窗人机双通道 · 网页权限三档(拒绝 / 仅此一次 / 总是允许,按 origin 持久化)· 下载(DownloadShelf,系统 DownloadManager 轮询,回写 engine.lastDownload 保持 Agent 可读)· 溢出菜单。

人机协同语义(核心差异点)

状态 弹窗 权限
WAITING_HUMAN(人在) 弹窗/权限由人裁决 人定;接管横幅常驻「我已完成操作,交还 Agent」
AGENT(无人值守) ALERT 自动确认(不承载选择、无副作用);CONFIRM 默认拒绝;PROMPT 不接管按取消 一律安全拒绝

任何裁决回写 engine.lastDialog,Agent snapshot 注入语义不变。

6. 浮窗安全的三个坑

  1. 不使用 AlertDialog / ModalBottomSheet —— 底层创建 android.app.Dialog 需要宿主窗口 token, overlay 用 app context 无 token → BadTokenException;全部浮层改自绘(ChromeScrimDialog / ChromeBottomSheet);
  2. BackHandler 在浮窗中先探测 LocalOnBackPressedDispatcherOwner;
  3. overlay 窗口加 SOFT_INPUT_ADJUST_RESIZE,WebView 容器 topMargin 由 chrome 头部 onGloballyPositioned 实测高度实时驱动。

7. 验证

项 结果
:app:compileDebugKotlin BUILD SUCCESSFUL(全模块 + Hilt KSP)
单测 56 用例 0 失败:ChromeLogicTest 15 / JsDialogBookkeepingTest 12 / SnapshotComposerTest 7 / AgentDialogPolicyTest 10 / PermissionGateTest 12
DomParserTest 已加"ref 来自语义哈希、不随顺序偏移"意图测试
CI 目标 5 个重型页(淘宝 / X / GitHub / 知乎 / 银行登录)快照 ≤ 4096 tokens

8. 超纲推演(严禁进生产代码)

端侧 VLM「零 DOM 注入」自动化:完全不注入 JS(100% 隐身)、端侧量化 VLM 直接推理 WebView 截图、 输出 {"action":"click","target_visual_desc":"...","coordinates":[540,1200]}。 限制:端侧模型对密集小文本识别率不如直读 DOM 且发热 → 当前坚持"DOM 为主、视觉为辅"双模态。

9. 相关页面

footer

🏠 返回首页 · 📚 文档索引 · ❓ FAQ · 🔧 故障排查 · 🗺️ 路线图 · 🐛 提 Issue

Android Guru Agent · v1.4.4 · Kotlin 2.0.21 · Compose · PRoot · Room

Clone this wiki locally