本篇定义"自动启停浏览器 + 会话/Profile 管理 + 可插拔传输驱动"的运行时。 对应传统 RPA 的 Robot 运行时,但把"浏览器如何被驱动"抽象成可热切换的传输契约。
flowchart TD
subgraph IDENTITY["身份层 · Identity Profile(长期,可信累积)"]
P1["profile=mac-m4-chrome-stable<br/>seed=identity-A<br/>cookies/localStorage 持久化<br/>一致性指纹 + 行为参数"]
end
subgraph SESSION["会话层 · Session(一次运行的浏览器实例)"]
S1["绑定一个 Identity + 一个传输档位(T0–T3)<br/>+ 可选代理出口<br/>= 一个 Chrome 进程"]
end
subgraph PAGE["页面层 · Page / Tab"]
PG1["标签页,AX-tree ref 定位<br/>行为合成在此作用"]
end
P1 --> S1 --> PG1
- 一身份一进程:一个逻辑身份 = 一个持久化 Profile = 一个 Chrome 进程(借鉴 mochi "多 session = 多进程",避免跨身份指纹串味)。
- 会话绑定档位与出口:档位(T1/T2/T3)与代理出口在会话创建时确定,运行中可因被拦而升档(触发换会话)。
- Page 用 AX-tree ref:Agent/解释器都用稳定整型 ref,不手写选择器。
stateDiagram-v2
[*] --> Idle
Idle --> Launching: 收到会话请求
Launching --> Warming: 进程起+注入指纹/脚本(top-of-frame)
Warming --> Ready: 一致性自检通过
Warming --> LaunchFailed: 启动/自检失败
Ready --> Busy: 执行动作
Busy --> Ready: 动作完成
Busy --> Recovering: 崩溃/断连/无响应
Recovering --> Ready: 从持久化状态重建(cookies/URL/进度)
Recovering --> Failed: 重试超限
Ready --> Draining: 空闲超时/被回收
Draining --> Parked: 保存状态→进程可复用/挂起
Parked --> Ready: 命中复用
Parked --> Idle: 达 TTL→关闭进程
LaunchFailed --> Idle
Failed --> Idle
设计要点:
- 自动启动:会话请求触发按需启动;启动即注入一致性指纹脚本(
addScriptToEvaluateOnNewDocument或Fetch.fulfillRequest注入,top-of-frame,避免源属性泄漏)。 - 一致性自检:启动后跑一次内部探针(类 mochi Probe-Manifest),核对指纹面自洽、无
navigator.webdriver、无HeadlessChrome痕迹;不过则不投入使用。 - 自动停止 / 回收:空闲超时 → Draining → 保存状态 → Parked(可复用或挂起)→ 达 TTL 关闭。避免"用完不关"的资源泄漏,也避免"每次全新会话"的可疑感。
- 崩溃恢复:Recovering 从持久化的 cookies/当前 URL/回放进度检查点重建会话并续跑(对应 SC5)。
- 检查点(checkpoint):回放解释器在关键节点落进度检查点,崩溃后可从最近检查点续跑而非从头。
flowchart LR
REQ["会话请求(身份?/档位?/域)"] --> SCHED["池调度器"]
SCHED -->|命中空闲同身份| REUSE["复用 Parked 会话(暖启动)"]
SCHED -->|需新身份/并发| NEW["新建会话(冷启动)"]
subgraph POOLS["资源池"]
IDLEPOOL["Parked 会话池(LRU + TTL)"]
PROFILES["Identity Profile 库(Vault 管理)"]
PROXIES["代理/出口池(T3, 住宅优先)"]
end
REUSE --> IDLEPOOL
NEW --> PROFILES
NEW --> PROXIES
SCHED --> LIMITS["并发/速率护栏(按域)"]
- 暖启动复用:优先复用同身份 Parked 会话,降低启动开销、也让身份"连续在线"更像真人。
- 并发与速率护栏:按域限制并发会话数与请求速率(责任使用 + 降低风控触发)。
- 身份轮换(T3):高频长跑时从 Profile 库轮换身份+住宅出口,防止单身份声誉累积(与 03 §7 呼应)。
- 本地优先:默认不启用代理(本机住宅 IP 最一致);仅在策略要求或声誉风险时启用 T3 代理池。
上层(回放解释器 / Actor)只依赖统一契约,不感知底层是 patchright 还是裸 CDP。驱动作为受控子进程经 gRPC over UDS 挂到控制面。
classDiagram
class BrowserNode {
<<gRPC 接口>>
+Capabilities() Caps
+LaunchSession(IdentitySpec, Tier, ProxySpec) SessionHandle
+Navigate(session, url, waitPolicy)
+Snapshot(session) AXTree+Screenshot
+Resolve(session, LocatorBundle) ElementRef
+HumanClick(session, ref, behaviorParams)
+HumanType(session, ref, textOrSecretRef, behaviorParams)
+HumanScroll(session, target, behaviorParams)
+Extract(session, schema) StructuredData
+Fetch(session, request) Response
+Assert(session, Assertion) bool
+SaveState(session) StatePath
+CloseSession(session)
+SelfCheck(session) CoherenceReport
}
class DriverHTTP_T0
class DriverPW_T1
class DriverCDP_T2
class DriverCDPPlus_T3
BrowserNode <|.. DriverHTTP_T0
BrowserNode <|.. DriverPW_T1
BrowserNode <|.. DriverCDP_T2
BrowserNode <|.. DriverCDPPlus_T3
契约设计原则:
- 只暴露拟人原语:没有裸
click/type,只有HumanClick/HumanType/HumanScroll(行为合成内建,借鉴 mochi 无page.click的做法)——从 API 层面杜绝"机器人式瞬移点击"。 Capabilities()声明能力:如 T0 不支持 JS 执行/复杂交互;解释器据此决定可否降档。- 机密以
secretRef传递:驱动向 Vault 解引用,明文不过 gRPC 边界(I-5)。 Fetch走浏览器自身:需要旁路请求已知 XHR 时也经 Chromium 发出,保持 JA4/H2 一致(03 §4)。SelfCheck返回一致性报告:供池在 Warming 阶段判定是否投用。
| 驱动 | 运行时 | 关键实现 | 许可 |
|---|---|---|---|
driver-http (T0) |
任意 | curl_cffi / bogdanfinn tls-client:Chrome 形状 TLS+H2;无浏览器进程 | MIT/BSD |
driver-pw (T1) |
Node 或 Python | Patchright,channel=chrome 驱动真实 Chrome;humanization 层 |
Apache-2.0 |
driver-cdp (T2) |
Python(参考 nodriver)/ 未来 Bun(mochi) / 自研 Go | --remote-debugging-pipe 裸 CDP、无 Runtime.enable、无 TCP 端口;一致性注入 + OS 级输入 |
nodriver=AGPL-3.0;mochi=MIT |
driver-cdp+ (T3) |
同 T2 | T2 + 代理编排 + 可选 patched 二进制(camoufox/Cloak)+ CAPTCHA 升级钩子 | 视组件 |
为什么核心 Go、驱动可异种语言:Go 做控制面(守护、并发、单二进制)最省心;而"过第③层"的最强实现现在在 Python(nodriver)/Bun(mochi)。用 gRPC 子进程隔离,既拿到最强隐身,又不牺牲核心的工程性(I-1 的价值)。语言选择完全藏在
BrowserNode契约之后,可随生态演进替换。
sequenceDiagram
autonumber
participant INTP as 回放解释器/Actor
participant POOL as 池调度器
participant VAULT as Vault
participant DRV as Transport Driver
participant CH as 系统 Chrome
INTP->>POOL: 申请会话(域, 身份?, 期望档?)
POOL->>POOL: 选档(记忆/探针) + 选身份Profile
POOL->>VAULT: 取身份画像 + 代理出口(如T3)
VAULT-->>POOL: (profile,seed) + proxy
POOL->>DRV: LaunchSession(identity, tier, proxy)
DRV->>CH: 起进程(pipe 模式/channel=chrome, headful)
DRV->>CH: 注入一致性指纹脚本(top-of-frame)
DRV->>DRV: SelfCheck 一致性 + 地理校验
alt 自检通过
DRV-->>POOL: SessionHandle(Ready)
POOL-->>INTP: 会话就绪
else 自检失败/地理矛盾
DRV-->>POOL: 拒绝(GeoMismatch/CoherenceFail)
POOL->>POOL: 换身份/换出口 重试
end
- 档位定义、指纹一致性、行为合成细节 → 03
- 会话/身份/代理由谁治理、Vault 存储模型 → 05
- 解释器如何调用这些原语跑技能 → 02
- 驱动契约如何映射到 Agent 可见的 MCP 原语 → 06
- 浏览器自动启动/停止/回收,空闲不泄漏、非全新会话(SC5)。
- 崩溃可从检查点/持久化状态恢复续跑(SC5)。
- Profile→Session→Page 三层模型,一身份一进程。
-
BrowserNode统一契约,只暴露拟人原语,档位可热切换(I-1/I-2)。 - 会话启动含一致性自检 + 地理校验,不带矛盾上场(I-3)。
- 机密以 secretRef 传递,明文不过驱动边界(I-5)。