onesvm-browser-server/docs/overview-integration-20260901.md
chii 983259836d chore: init workspace with onesvm-dev-md + casa-commander
docs: 联网搜索服务架构方案全套(plan-final/design-arch/选型决策/整合导览/MCP文档/部署预设/联调手册)
bench: 5 方案 + 代理 + 站点矩阵本机实测工程(无密钥)
部署目标:primary mgr1 先行测试(待批准后执行)
2026-09-01 15:19:52 +08:00

121 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
type: arch
status: active
created: 2026-09-01
step: P2 / plan-20260901-02
---
# onesvm-browser-server 设计与整合方式总览(入门导览)
> 读者:项目 owner 与后续接手工程师。本文是**梳理与导读**,回答四问——**我们如何整合自部署服务?目前整合哪些?怎么整合的?提供什么样的服务?怎么做并发排队的?**
> 权威关系:决策结论以 `plan-final-20260901.md` 为准,机制细节以 `design-arch-20260901.md` 为准,选型理由见 `decision-candidates-20260901.md`;本文只做组织与串联,数字全部引用自既有文档与 bench 产物(2026-09-01 本机实测)。
## 0. 一段式总览
onesvm-browser-server 是一个**面向智能体消费者的自构建联网搜索服务**:所有消费者(Vlepontas、EAI 等)在统一出口网关注册主体、拿 key,以 MCP(主)或 HTTP(兜底)调用两类意图(`search` / `read`);请求经认证、合规预检后进入**零 Redis 的 SQLite WAL 队列**(60 会话接纳上限),由单写者 scheduler 按能力标签路由给 **Dock 适配器集群**——目前整合了 5+1 个自部署组件(双 SearXNG、Trafilatura、Lightpanda、chrome-headless-shell、mihomo 代理数据面);适配器只产出原始结果,统一由**共享 worker 模版层(整合器)**做体积守卫、正文提纯、安全扫描后封装成 AI 原生信封返回。全栈常驻内存实测 ~380MB,承诺 ≤1GB 渐进扩容。
```mermaid
flowchart LR
C[智能体消费者<br/>Vlepontas / EAI / 注册主体] --> G[统一出口网关 ×N 无状态<br/>MCP 主 POST /mcp + HTTP 兜底 /v1/*<br/>X-Service-Token 认证 · 配额预扣]
G --> POL1[合规·请求侧<br/>SSRF / 域名策略]
POL1 -->|overlay POST /enqueue| S[scheduler 单副本<br/>SQLite WAL 单写者 · ADMIT_MAX=60]
S --> RT{能力路由<br/>region / render 标签}
subgraph DOCK[Dock worker 集群(共享模版层 = 整合器)]
subgraph WA[A 无浏览器]
AA1[适配器: searxng-cn<br/>searxng-global]
AA2[适配器: trafilatura-http]
end
subgraph WB[B 轻渲染]
AB[适配器: lightpanda]
end
subgraph WC[C 保真·按需槽]
AC[适配器: chrome-headless-shell]
end
TPL[共享模版层<br/>RawResult → Size guard → fit markdown<br/>→ 安全扫描/PII redact → 统一信封<br/>词表单源版本化]
WA & WB & WC --> TPL
end
RT --> WA & WB & WC
DOCK -.插拔预留 render=full+headful.-> HD[(有头档·默认不部署)]
WB & WC --> PM[ProxyManager 单副本<br/>mihomo vless 热池 · 域名路由]
AA1 -->|国内域| DI[国内直连]
AA1 -->|境外搜索| PM
TPL -->|Envelope ok/error| C
```
(机制细节拓扑见 design-arch §1;接入时序见 design-arch §3.5。)
## 1. 目前整合了哪些自部署服务
5 个消费组件 + 1 个代理数据面,全部经 2026-09-01 本机 Docker 实测(darwin arm64,cgroup 口径;原始数据 `bench/*/results.json`):
| 组件 | 镜像与版本 pin | 角色 | idle | 单会话峰 | 60 burst 峰 | 出处 |
|---|---|---|---:|---:|---:|---|
| searxng-cn | `searxng/searxng:2026.8.29-d226b78bc`(digest b36af798) | 国内搜索(百度/搜狗/360/必应中国) | 98.9MB | 121.6MB | 170.5MB | S3b-summary §2 |
| trafilatura-http | 自构建 `python:3.12-slim-bookworm` + `trafilatura==2.2.0` | 正文精读(纯 HTTP) | 33.0MB | 35.2MB | 40.6MB | S3b-summary §2 |
| searxng-global | 同 SearXNG 镜像第二实例(Google/Bing/DDG/Brave 等) | 国外搜索(实测 Bing-only,见 D2) | 121.6MB | 149.6MB | 181.3MB | S3c-summary §1 |
| lightpanda | `lightpanda/browser:0.3.7`(digest eae2c7f8) | 默认轻 JS 渲染核 | **3.6MB** | 251.4MB(重 Shopify 页) | 143.4MB | S3c-summary §1 |
| chrome-headless-shell | `chromedp/headless-shell:151.0.7922.109`(digest 2d349b54) | 保真渲染单槽(L2 按需/L3 常驻) | 37.5MB | 394.0MB(同页) | 179.3MB | S3c-summary §1 |
| mihomo(ProxyManager 数据面) | `metacubex/mihomo` v1.19.24 | 代理出口(vless 热池 52 节点实测全活) | 小(未单独采样,估算·待校准) | — | — | proxy-probe.md |
为什么选它们(含排除与预留):见 `decision-candidates-20260901.md` §1–§3。
## 2. 怎么整合的(Dock Protocol)
设计全文:design-arch §3。核心四件套:
1. **适配器契约(五方法)**:`init / health / execute / teardown / capabilities`。`health()` 强制上报 `rss_bytes / startup_ms / slots_free`;`capabilities()` 声明支持的意图、渲染分级(`none|light|full`)、出口需求(`domestic|overseas`)、自身并发上限、是否必须走代理。适配器负责把统一意图翻译成引擎原生调用(SearXNG `format=json`、CDP navigate 等),**只产出 RawResult,原生结构不出适配器**。
2. **共享 worker 模版层(= 整合器,S7 架构审查锁定归属)**:所有适配器共用同一层完成 `RawResult → Size/Type guard → fit markdown → 安全扫描 + PII redact + 注入包裹 → 统一信封`;词表/规则**单源版本化**(`wordlist_version` 入审计),N 个适配器零合规代码,杜绝门闩漂移。
3. **能力路由(标签制)**:`region=domestic` 直连、`region=overseas` 经 ProxyManager、`render=none/light/full` 分流到 A/B/C 类适配器;约 90% 流量(搜索 + 纯 HTTP 读)不进浏览器槽。
4. **降级链**:C 槽满 → B → A → `blocked/upstream`,不静默降数据质量(打 `warnings`);`cloudflare/waf/captcha` 拦截不拿渲染空转,直接 `blocked`(站点矩阵实测纪律,decision-candidates §6)。
### 接入第 6 个方案要做什么(示例:新增 RSSHub 适配器)
1. 部署或接入 RSSHub 实例(自部署 Docker,内网端点),版本 pin 写入 stack;
2. 在 worker 代码里新增 `RsshubAdapter` 实现五方法:`capabilities() = {intents:[search,read], render:none, regions:[domestic,overseas], proxy_required:false, formats:[markdown,links]}`;`execute()` 把 `Search/Read` 意图译为 RSSHub 路由请求,返回 RawResult;
3. 在 scheduler 路由表注册标签(如 `region=domestic, render=none, kind=rss`),按需挂路由规则;
4. **不需要写任何合规/提纯代码**——共享模版层自动生效;只需确认 RawResult 字段映射正确;
5. 跑 bench 三档内存 + 模板断言(参照 `bench/plan.md`),数字回填档位表;超预算则开评审。
## 3. 提供什么样的服务
设计全文:design-arch §2/§3.3;决策摘要:plan-final §1/§3。
- **两类意图**:
- `Search{query, max_results≤20, time_range?, lang?, region}` → 返回 `results[{title,url,content≤800字,score 0–1,engine}]`,不含全文;
- `Read{url, formats=["markdown"], max_chars, extract?, region}` → 返回 fit markdown(实测提纯 420–500 倍:1.44MB Shopify 壳 → 2.9–3.4KB)+ 可选 `extract` 结构化抽取(默认零 LLM 路径:JSON-LD/OG/CSS)。
- `browse`(多步交互)协议预留,默认关闭。
- **region 参数**:`domestic` / `overseas` 由消费者按 MCP 文档**自行选择**(国内直连数据 vs 经代理的外域数据);网关仍按域名路由表强制合规兜底。
- **统一信封**:`{ok, kind, request_id, took_ms, usage{credits,engine,tokens_estimate}, provenance{url,retrieved_at+08:00,adapter,proxy_exit,cached}, error{code,message,retry_after_s?}}`。
- **错误码**(MCP/HTTP 两面对齐):`blocked | denied | timeout | quota | rate_limited | extract_failed | upstream`。
- **双形态**:MCP Server 为主(`POST /mcp`,Streamable HTTP,2026 无状态;2025 兼容腿挂 O9 待决)+ HTTP API 兜底(独立端口 `:8640` + `/bs-api` 前缀,D3 待确认);认证 `X-Service-Token`,禁 Bearer 塞静态 key。
- **能力边界**(20 站实测矩阵):纯 HTTP 够 7 站、须 JS 4 站、当前出口打不过 9 站(Amazon/Medium/Reddit/X/知乎/微博等)——逐场景结论见 `decision-candidates-20260901.md` §6,原始数据 `site-matrix.md`。
## 4. 怎么做并发排队(零 Redis)
设计全文:design-arch §4;实测校准:plan-final §2。
**为什么不要 Redis**:60 深度远低于 SQLite WAL 舒适区;Redis 白占 30–80MB 直接威胁 1GB 预算;NATS Core 不可靠、JetStream 是另一个中间件;PG SKIP LOCKED 需要现成 PG(本集群没有为此单拉)。
**入队路径**:消费者 → gateway(无状态:认证/配额预扣/合规预检)→ overlay 内网 `POST /enqueue` → scheduler(**SQLite 唯一写者**)进程内快通道 + 立即落 WAL → 落盘成功才 ACK 排队位;scheduler 不可达 → 503 + `Retry-After`(fail-closed,gateway 本地不落盘)。
**背压三层**:`ADMIT_MAX=60`(running+queued 合计)→ 超限 429/503 只拒新不杀旧;`CONCURRENT` 浏览器槽 = 1 起步;`HEALTH` 内存阈 60–70%;渲染互斥规则 `shell_active ⇒ lightpanda 停接新任务`(入队侧执行,无需预知页面重量);租约 + reaper + 指数退避(attempts≤2)+ 死信表。
**实测行为锚点**(为什么这样设计):
| 实测现象(2026-09-01) | 对应设计 |
|---|---|
| chrome-headless-shell CONCURRENT=1:60 任务 FIFO 全入队、顺序执行、**0 拒绝 0 OOM**、墙钟 74.0s | 60 是队列深度不是浏览器并发;保真槽单实例排队复用 |
| lightpanda 4 槽:60/60 全过、28.2s(2.13 jobs/s) | 轻渲染多槽并行,承载 JS 流量主力 |
| searxng-cn 裸 60 并发:HTTP 全 200 但断言仅 4/60——百度/搜狗被 CAPTCHA 打灭,必应中国 60/60 | 网关对上游钳 4–8 并发 + 每 host 最小间隔 + 短缓存;**多副本不能分散 CAPTCHA**(反爬按出口 IP 计) |
| trafilatura 60/60、p50 0.115s、burst 仅 40.6MB | 纯 HTTP 读走高并发快通道,不占浏览器槽 |
**负载结论**:60 会话稳态占用率——搜索 ~21%、读取 ~3%、渲染 ~5%(换算见 plan-final §2.5);1GB 可维持 Vlepontas + EAI 日常负载,扩容触发条件与 L3 增量见 D1。
## 5. 延伸阅读
| 想深入了解 | 去读 |
|---|---|
| 决策点与档位表 | `plan-final-20260901.md` §2/§7 |
| 机制细节(队列字段/代理池策略/合规五道) | `design-arch-20260901.md` §4/§5 |
| 为什么选这 5 套、能力边界矩阵 | `decision-candidates-20260901.md` |
| 实测原始数据 | `bench/*/results.json`、`.dsh/artifacts/run-20260901-browser-arch/` |