- architecture.md: 新增反检测为核心第一性原理,新增 §3 反检测设计(13 个指纹维度全覆盖) - anti-detection.md: 新增反检测专项文档(14 节,详尽列举检测方式和应对策略) - api.md: POST /pages 新增 profile 参数,新增 GET /profiles 端点 - cli.md: 新增 --profile 全局选项,新增 visionl profiles 命令 - contributing.md: 新增反检测开发规范、检测站点验证要求 - README.md: 更新项目定位和特性描述
20 KiB
VisionL 架构设计
面向 AI 智能体的开源可持久化浏览器 — 架构设计文档
1. 概述
要解决的根本问题
让 LLM 访问各类页面尽可能不被简单的人机验证所拦截。
这是 VisionL 存在的第一性原理,所有设计决策必须围绕这个目标展开。
市面上绝大多数自动化浏览器(Playwright/Puppeteer 裸跑)会在数十个维度上暴露自动化痕迹, 被 Cloudflare、Akamai、DataDome 等反爬服务轻松识别。VisionL 的核心竞争力在于: GUI 浏览器所有能被页面/页面后端检测到的特征,在 CLI 中均有值(可以是模拟的)。
次要目标
- 页面持久化:页面在客户端断连后依然存活,只有显式
kill才能终止 - 智能体优先:CLI 子命令为 LLM 工具调用而设计,输出结构化 JSON
- 本地优先:Daemon 仅监听 localhost,不对外开放
- GUI 就绪:HTTP/WS API 同时服务于 CLI 和未来的 GUI
2. 技术栈
| 层级 | 选择 | 理由 |
|---|---|---|
| 浏览器引擎 | Playwright + Chromium | AI 浏览器自动化的事实标准 |
| 反检测框架 | playwright-extra + puppeteer-extra-plugin-stealth |
自动处理 WebDriver 标记和基础指纹 |
| 指纹补充 | 自研 stealth 模块 | stealth 插件只覆盖约 60% 的指纹,剩余需自行实现 |
| 语言 | TypeScript + Node.js | Playwright 原生语言 |
| 通信协议 | HTTP REST + WebSocket (localhost) | 职责分离,GUI 可复用 |
| 包管理 | npm workspaces (monorepo) | 共享类型 |
| CLI 框架 | commander + chalk | 轻量 |
| HTTP 服务 | 原生 http + ws 库 |
本地 daemon 无需重型框架 |
JSON 转义处理
所有返回给智能体的 JSON 必须通过 JSON.stringify 序列化整个响应对象,
禁止手动拼接 JSON 字符串。页面内容字段中的引号、反斜杠、控制字符均正确处理。
3. 反检测设计(核心)
3.1 指纹覆盖全景
目标:所有能通过 JS API 读取到的浏览器特征,都必须返回真实 GUI 浏览器的值, 不能留下任何自动化痕迹。
以下表格列出页面/后端可检测的维度、Playwright 默认值的问题、以及 VisionL 的应对策略。
3.1.1 Navigator 属性
| 属性 | 裸 Playwright 值 | 问题 | VisionL 策略 |
|---|---|---|---|
navigator.webdriver |
true |
最致命的暴露 | stealth 插件 → false |
navigator.userAgent |
含 "HeadlessChrome" | 直接暴露 | 模拟真实 Chrome UA,可配置 |
navigator.plugins |
空数组 | 真实 Chrome 有 5 个插件 | stealth 插件 → 注入 PDF Viewer 等 |
navigator.languages |
["en-US"] |
需匹配目标地区 | 可配置,默认 ["zh-CN", "en-US"] |
navigator.platform |
随 OS | 无问题但需一致性 | 随系统,但确保与其他指纹一致 |
navigator.hardwareConcurrency |
实际 CPU 核数 | OK | 保持真值 |
navigator.deviceMemory |
实际值 | OK | 保持真值 |
navigator.maxTouchPoints |
0 |
桌面无触摸 | 可配置,桌面默认 0 |
navigator.vendor |
"Google Inc." |
stealth 会修正 | stealth 插件处理 |
navigator.productSub |
"20030107" |
需一致 | stealth 插件处理 |
navigator.connection |
undefined (headless) |
真实 Chrome 有值 | 注入 NetworkInformation 对象 |
navigator.mediaDevices |
存在 | 可能暴露空设备列表 | 模拟至少一个音频设备 |
3.1.2 Chrome 特有属性
| 属性 | 裸 Playwright 值 | 问题 | VisionL 策略 |
|---|---|---|---|
window.chrome |
undefined (headless) |
真实 Chrome 有此对象 | 注入完整 window.chrome 对象 |
chrome.runtime |
N/A | 检测自动化时常用 | 注入 mock runtime |
navigator.brave |
N/A | Brave 检测用,非必须 | 不注入(伪装 Chrome 不是 Brave) |
3.1.3 屏幕与视口
| 属性 | 裸 Playwright 值 | 问题 | VisionL 策略 |
|---|---|---|---|
screen.width/height |
默认 1280x720 | 非标准分辨率 | 可配置,默认 1920x1080 |
screen.availWidth/Height |
同 screen | 任务栏高度需扣除 | 模拟,比 screen 小 40-80px |
screen.colorDepth |
24 |
OK | 24 |
screen.pixelDepth |
24 |
OK | 24 |
window.outerWidth/Height |
与视口相同 | 真实浏览器窗口含边框 | 比视口大(含窗口装饰) |
window.innerWidth/Height |
视口尺寸 | 需与 screen 逻辑一致 | 保证 inner < outer < screen |
window.devicePixelRatio |
1 |
现代设备多为 2 | 可配置,默认 1 或自动检测 |
3.1.4 Canvas 指纹
页面可以在 canvas 上渲染特定图形,获取像素哈希作为指纹。不同 GPU/驱动/OS 的渲染结果 有微小差异。VisionL 需要在 canvas 渲染中加入可控的随机噪声,使每次指纹不同但看起来 像正常设备,从而绕过基于 canvas 哈希的追踪。
| 措施 | 实现 |
|---|---|
| Canvas 2D 噪声 | toDataURL() 和 getImageData() 返回时在像素末尾添加 ±1 随机扰动 |
| WebGL 噪声 | getParameter() 和 readPixels() 添加类似扰动 |
| 一致性 | 同一页面会话内噪声种子固定,跨页面会话刷新 |
3.1.5 WebGL 指纹
| 属性 | 裸 Playwright 值 | VisionL 策略 |
|---|---|---|
UNMASKED_VENDOR_WEBGL |
真实 GPU 厂商 | 可保留真值(多样化),也可统一模拟 |
UNMASKED_RENDERER_WEBGL |
真实 GPU 型号 | 同上 |
| WebGL 渲染噪声 | 无 | 类似 Canvas,在 readPixels 加入微量噪声 |
3.1.6 AudioContext 指纹
页面通过 AudioContext 处理音频信号提取指纹。VisionL 策略:
createOscillator()生成的波形在浮点精度末尾加入随机噪声createAnalyser()的getByteFrequencyData()同样处理- 噪声量级极小(-100dB 级别),不改变音频语义
3.1.7 字体枚举
页面无法直接枚举系统字体列表,但可通过以下方式探测:
- 测量指定字体的文本宽度
document.fontsAPI- Flash(已消亡)
VisionL 默认不做字体列表注入(多数反爬不会测字体),但保持基础常见字体的一致性。
3.1.8 HTTP 请求头
| 头部 | 裸 Playwright 值 | VisionL 策略 |
|---|---|---|
User-Agent |
含 HeadlessChrome | 模拟真实 Chrome UA,可配置 |
Accept-Language |
en-US |
匹配 navigator.languages |
Sec-CH-UA |
不完整 | 补全 "Chromium";v="xxx", "Google Chrome";v="xxx" |
Sec-CH-UA-Platform |
随 OS | 确保一致性 |
Sec-CH-UA-Mobile |
?0 |
?0(桌面) |
Accept |
OK | 保持默认 |
Accept-Encoding |
OK | 保持默认 |
Connection |
keep-alive |
保持默认 |
Upgrade-Insecure-Requests |
1 |
保持默认 |
3.1.9 权限状态
| 权限 | 裸 Playwright 值 | VisionL 策略 |
|---|---|---|
notifications |
prompt |
可配置:prompt/granted/denied |
geolocation |
prompt |
可配置,granted 时提供模拟坐标 |
camera |
prompt |
可配置 |
microphone |
prompt |
可配置 |
midi |
prompt |
保持 prompt |
3.1.10 行为模拟
鼠标移动(v1 基础版,v2 增强):
- 点击前鼠标从当前位置线性移动到目标中心(带随机抖动)
- 移动速度加入随机变化(不恒定)
mousemove事件在移动路径上均匀发射
键盘输入(v1 基础版):
- 每个字符间隔
50-150ms随机 keydown→keypress→keyup完整序列- 中文输入法暂不模拟
滚动:
- 非瞬间跳转,分段滚动
- 每次滚动步长加入随机抖动
3.2 实现方案
daemon/
├── src/
│ ├── stealth/ # 反检测模块
│ │ ├── index.ts # 统一入口,页面创建时注入
│ │ ├── navigator.ts # navigator 属性覆盖
│ │ ├── chrome-runtime.ts # window.chrome 注入
│ │ ├── screen.ts # 屏幕/视口尺寸管理
│ │ ├── canvas-noise.ts # Canvas/WebGL/Audio 噪声
│ │ ├── headers.ts # HTTP 头拦截修正
│ │ ├── permissions.ts # 权限状态管理
│ │ ├── human-input.ts # 鼠标/键盘/滚动行为模拟
│ │ ├── fingerprint-profile.ts # 指纹配置文件结构
│ │ └── profiles/ # 内置指纹模版
│ │ ├── desktop-chrome.ts # 桌面 Chrome 通用模版
│ │ ├── desktop-windows.ts # Windows Chrome
│ │ └── desktop-mac.ts # macOS Chrome
3.3 指纹配置(FingerprintProfile)
// packages/core/src/types/fingerprint.ts
interface FingerprintProfile {
// 浏览器基础
userAgent: string;
platform: string;
languages: string[];
acceptLanguage: string;
// 屏幕
screen: {
width: number;
height: number;
colorDepth: number;
pixelRatio: number;
};
viewport: {
width: number;
height: number;
};
// GPU
webglVendor: string;
webglRenderer: string;
// 时区与位置
timezone: string;
geolocation?: { latitude: number; longitude: number; accuracy: number };
// 权限
permissions: {
notifications: 'prompt' | 'granted' | 'denied';
geolocation: 'prompt' | 'granted' | 'denied';
camera: 'prompt' | 'granted' | 'denied';
microphone: 'prompt' | 'granted' | 'denied';
};
// 行为
behavior: {
mouseMoveDelay: { min: number; max: number }; // ms
keyPressDelay: { min: number; max: number }; // ms
scrollStepDelay: { min: number; max: number }; // ms
};
// Canvas 噪声
canvasNoise: {
enabled: boolean;
strength: number; // 0-1, 噪声强度
};
}
3.4 WebDriver 检测网站验证
v1 目标:通过以下检测站点的自动化识别:
| 检测站点 | 检测方式 | 目标 |
|---|---|---|
| https://bot.sannysoft.com | 综合(navigator + screen + chrome + canvas + webgl + fonts) | 必须全绿 |
| https://fingerprint.com/demo | 综合指纹(最全面) | 降低置信度到非 bot 区间 |
| https://abrahamjuliot.github.io/creepjs/ | 浏览器指纹各维度逐一打分 | 所有维度分数控制在合理范围 |
4. 项目结构
VisionL/
├── docs/
│ ├── development/
│ │ ├── architecture.md # 本文档
│ │ ├── anti-detection.md # 反检测专项文档(检测维度详情、绕过原理)
│ │ ├── api.md # REST + WS 接口文档
│ │ ├── cli.md # CLI 命令参考
│ │ └── contributing.md # 开发规范
│ └── usage/
│ ├── quickstart.md # 快速开始
│ ├── llm-integration.md # 智能体集成指南
│ └── examples.md # 典型场景示例
├── packages/
│ ├── core/ # 共享库:类型定义、HTTP 客户端
│ │ ├── src/
│ │ │ ├── types/
│ │ │ │ ├── page.ts
│ │ │ │ ├── api.ts
│ │ │ │ ├── ws.ts
│ │ │ │ └── fingerprint.ts # 指纹配置类型
│ │ │ ├── client.ts
│ │ │ ├── escape.ts
│ │ │ └── index.ts
│ │ └── package.json
│ ├── daemon/ # 后台进程
│ │ ├── src/
│ │ │ ├── server.ts
│ │ │ ├── routes/
│ │ │ │ ├── pages.ts
│ │ │ │ ├── actions.ts
│ │ │ │ ├── content.ts
│ │ │ │ └── health.ts
│ │ │ ├── browser-manager.ts
│ │ │ ├── page-registry.ts
│ │ │ ├── ws-relay.ts
│ │ │ ├── pidfile.ts
│ │ │ └── stealth/ # 反检测模块
│ │ │ ├── index.ts # 统一注入入口
│ │ │ ├── navigator.ts
│ │ │ ├── chrome-runtime.ts
│ │ │ ├── screen.ts
│ │ │ ├── canvas-noise.ts
│ │ │ ├── headers.ts
│ │ │ ├── permissions.ts
│ │ │ ├── human-input.ts
│ │ │ ├── fingerprint-profile.ts
│ │ │ └── profiles/
│ │ │ ├── desktop-chrome.ts
│ │ │ ├── desktop-windows.ts
│ │ │ └── desktop-mac.ts
│ │ └── package.json
│ └── cli/
│ ├── src/
│ │ ├── index.ts
│ │ ├── commands/
│ │ │ ├── page.ts
│ │ │ ├── action.ts
│ │ │ ├── view.ts
│ │ │ └── daemon.ts
│ │ ├── format.ts
│ │ └── auto-daemon.ts
│ └── package.json
├── package.json
├── tsconfig.json
├── .gitignore
├── README.md
└── LICENSE
5. Daemon 设计
5.1 REST API
| 方法 | 路径 | 说明 | 请求体 | 响应 |
|---|---|---|---|---|
| POST | /pages |
打开新页面 | { url, alias?, profile? } |
{ id, url, alias?, title, status, profileId } |
| GET | /pages |
列出所有页面 | — | [{ id, url, alias?, title, status }] |
| GET | /pages/:id |
页面详情 | — | 同上 |
| DELETE | /pages/:id |
杀死页面 | — | { ok: true } |
| POST | /pages/:id/navigate |
跳转 URL | { url } |
{ url, title } |
| POST | /pages/:id/click |
点击元素 | { selector } |
{ success } |
| POST | /pages/:id/type |
输入文本 | { selector, text } |
{ success } |
| POST | /pages/:id/scroll |
滚动页面 | { deltaY?, toBottom? } |
{ success } |
| POST | /pages/:id/eval |
执行 JS | { code } |
{ result } |
| POST | /pages/:id/wait |
等待条件 | { selector?, ms? } |
{ success } |
| GET | /pages/:id/screenshot |
页面截图 | — | { base64, mime } |
| GET | /pages/:id/text |
页面纯文本 | — | { text } |
| GET | /pages/:id/html |
页面 HTML | — | { html } |
| GET | /profiles |
列出可用的指纹配置 | — | [{ id, name }] |
| GET | /health |
健康检查 | — | { status: "ok" } |
新增:
POST /pages的profile字段指定指纹配置(默认desktop-chrome)。GET /profiles返回所有内置指纹模版。
5.2 WebSocket 事件
同前,另增:
| 事件 | 数据 | 触发时机 |
|---|---|---|
page:detection:warning |
{ id, level, detail } |
页面检测到潜在的自动化特征 |
5.3 页面创建流程(含反检测注入)
visionl page open https://example.com --alias demo --profile desktop-windows
→ POST /pages { url, alias: "demo", profile: "desktop-windows" }
→ browser-manager.createPage(url, fingerprintProfile)
→ 1. 创建 BrowserContext(从 profile 读取 viewport、locale、timezone、geolocation)
→ 2. 创建 Page
→ 3. 注入 stealth 插件(navigator.webdriver 等基础隐藏)
→ 4. 注入自研 stealth 模块:
- 注入 navigator 覆盖脚本(evalOnNewDocument)
- 注入 window.chrome 对象
- 注入 canvas/webgl/audio 噪声脚本
- 注册请求拦截器修正 HTTP 头
- 注入权限状态
→ 5. 导航到目标 URL
→ 6. 注册到 PageRegistry
→ 返回 { id: "p_abc123", ..., profileId: "desktop-windows" }
5.4 行为模拟流程
操作命令(click/type/scroll)不走 Playwright 的 API,而是走自研的 human-input 模块:
visionl click p_abc123 "#login"
→ POST /pages/p_abc123/click { selector: "#login" }
→ action-handler:
→ 1. 获取元素 bounds
→ 2. 计算鼠标路径(当前坐标 → 目标中心 + 抖动)
→ 3. 沿路径逐个发射 mousemove
→ 4. 到达后依次发射 mousedown → mouseup → click
→ 5. (Future) 考虑 ancestor visibility 和 z-index
visionl type p_abc123 "#username" "hello"
→ POST /pages/p_abc123/type { selector: "#username", text: "hello" }
→ action-handler:
→ 1. 聚焦元素(click or focus)
→ 2. 逐字符:keydown → keypress → keyup
→ 3. 每字符间隔随机 50-150ms
→ 4. 完成后可选触发 change/blur 事件
6. CLI 设计(略,同前版本)
CLI 子命令不变。page open 新增 --profile <name> 指定指纹模版。
7. 类型定义(core 包核心类型)
// 新增
interface FingerprintProfile {
id: string; // "desktop-chrome"
name: string; // "桌面 Chrome (通用)"
userAgent: string;
platform: string;
languages: string[];
screen: { width: number; height: number; colorDepth: number; pixelRatio: number };
viewport: { width: number; height: number };
webgl: { vendor: string; renderer: string };
timezone: string;
geolocation?: { latitude: number; longitude: number; accuracy: number };
permissions: FingerprintPermissions;
behavior: FingerprintBehavior;
canvasNoise: { enabled: boolean; strength: number };
}
interface FingerprintPermissions {
notifications: PermissionState;
geolocation: PermissionState;
camera: PermissionState;
microphone: PermissionState;
}
interface FingerprintBehavior {
mouseMoveDelay: { min: number; max: number };
keyPressDelay: { min: number; max: number };
scrollStepDelay: { min: number; max: number };
}
8. 关键设计决策
反检测为首要质量指标
���测、集成测试、手动检测结果共同构成反检测的"质量门"。任何新功能引入不能降低 反检测评分。
指纹模版化
不同网站对不同地区的浏览器有不同的预期。VisionL 提供多套预置指纹模版, 智能体可根据目标网站选择。v1 提供 3 套:
| 模版 ID | 说明 | UA 平台 |
|---|---|---|
desktop-chrome |
桌面 Chrome 通用 | Linux x86_64 |
desktop-windows |
Windows 10 Chrome | Windows NT 10.0 |
desktop-mac |
macOS Chrome | Macintosh Intel |
Canvas 噪声策略
- 同一页面会话(BrowserContext)使用相同的随机种子
- 跨页面会话自动刷新种子
- 噪声强度可配置(0-1),默认 0.3
HTTP 头注入时机
User-Agent和Accept-Language:在创建 BrowserContext 时通过 Playwright API 设置Sec-CH-UA-*系列:通过请求拦截(page.route())修改
其他设计决策(同前)
- v1 不包含会话恢复
- 无身份认证(仅 localhost)
- Page ID + 别名双轨引用
- 每个 daemon 一个 Browser 实例
9. 测试策略
| 层级 | 工具 | 范围 |
|---|---|---|
| 反检测验证 | 脚本 + 人工 | 对 bot.sannysoft.com、fingerprint.com 全绿验证 |
| stealth/navigator | vitest | navigator 各属性值验证 |
| stealth/chrome-runtime | vitest | window.chrome 对象完整性 |
| stealth/canvas-noise | vitest | 噪声输出一致性、强度控制 |
| stealth/headers | vitest + msw | HTTP 头正确性 |
| stealth/human-input | vitest | 鼠标路径计算、键盘延迟分布 |
core 类型 |
ts 类型检查 | 编译期正确性 |
daemon/routes |
vitest + playwright-test | 路由逻辑 |
cli/commands |
vitest + mock | 命令解析 |
| 集成测试 | vitest + 真实 daemon | CLI → daemon → Playwright |
| JSON 转义 | vitest | 特殊字符安全 |
10. 未来规划(v1 范围外)
visionl-gui:桌面 GUI- 会话持久化
- 更多指纹模版(移动端 Chrome、Safari、Edge 等)
- 指纹随机化(每个页面随机微调指纹参数)
- 行为模拟增强(贝塞尔曲线鼠标路径、人类式打字节奏)
- 验证码自动识别(对接打码服务)
- 多用户支持
- 插件系统
- 远程 daemon
- 网络拦截和 Mock API
- Cookie/存储管理 CLI
- 页面录制与回放