# onesvm-browser-server 面向智能体的**自构建联网搜索服务**:消费者拿一把 `X-Service-Token`,用 MCP(主)或 HTTP(兜底)调用 `search` / `read`。国内直连,国外走自有代理池,query **不经过** Tavily / Jina 等境外 SaaS。 现网入口:`http://192.168.1.51:8640`(MCP `POST /mcp`,HTTP `POST /v1/search` `/v1/read`)。 | 你是谁 | 先读 | |---|---| | 消费方(Vlepontas / EAI) | [`docs/mcp-usage-20260901.md`](docs/mcp-usage-20260901.md) → [`docs/integration-vlepontas-20260901.md`](docs/integration-vlepontas-20260901.md) | | 接手开发 | [`docs/dev-handoff-20260902.md`](docs/dev-handoff-20260902.md)(本文下面是设计与选型摘要) | | 改架构 / 拍板 | [`docs/plan-final-20260901.md`](docs/plan-final-20260901.md)(决策权威)→ [`docs/design-arch-20260901.md`](docs/design-arch-20260901.md)(机制权威) | --- ## 1. 要解决什么问题 智能体需要「上网查公开页」。买境外 SaaS 会把 query 送出境,且按次计费;自建浏览器集群又容易把整机内存和出口 IP 打爆。本仓的约束是: - **境内闭环**:搜索与精读默认不经境外托管 API。 - **内存纪律**:常驻业务峰 ≤1GB(L2);60 = 队列深度,不是 60 个浏览器。 - **零 Redis**:SQLite WAL 单写者排队。 - **诚实能力**:公开网页大约九成;登录墙 / 强 WAF / Google 搜索不承诺。住宅 IP 是另一条带成本声明的通道,本服务不做。 人交「事件怎么活、怎么死、多快死」;实现按 [`onesvm-dev-md/base/engineering-standards.md`](../onesvm-dev-md/base/engineering-standards.md) 事件表,缺格不补默认值开工。 --- ## 2. 设计科学(为什么长这样) ### 2.1 统一出口,双形态同一内核 所有消费者注册主体、拿可吊销 key。MCP 与 HTTP 共用 **Auth → Policy → Queue → Engine**。错误码两面对齐。静态服务密钥只走 `X-Service-Token`,禁止塞进 `Authorization: Bearer`。 ### 2.2 分层内核,而不是「一个大浏览器」 流量大约 90% 是搜索 + 纯 HTTP 精读,不该进 Chromium。 | 层 | 适配器 | 何时用 | |---|---|---| | A 无浏览器 | SearXNG-CN / SearXNG-Global / Trafilatura | 搜索发现、静态正文 | | B 轻渲染 | Lightpanda | HTTP 抽空、需要一点 JS | | C 保真 | chrome-headless-shell(按需槽,默认 0 副本) | 轻核不够时 | | 预留 | Camoufox / 有头档 | 强对抗 + 住宅 IP,不在 1GB 预算内 | 降级链:C 满 → B → A → `blocked`/`upstream`。Cloudflare / WAF / 验证页**不拿渲染空转**,直接 `blocked`。 ### 2.3 出口与身份分开记账 - **出口**:国内域直连;境外经 ProxyManager + mihomo vless 热池。决定「Google 过不过」的是 IP 信誉,不是 UA 字符串。 - **身份(P0/P1,2026-09-02 落地)**:每生产节点 8 套 Chrome 136 模版(与 Trafilatura `curl_cffi` `impersonate=chrome136` 自洽);一等 Cookie 养在本节点 SQLite。罐按 **模版 × http|cdp × 出口 × eTLD+1** 隔离,节点内共享、不按消费者拆。登录态 Cookie 名直接丢弃。403/验证页整域丢罐。Cookie **不进 MCP、不进 jobs.payload**。 Go 侧 `httpx` 仍是 Go TLS,UA 写诚实的 `onesvm-browser-server-httpx/1.0`,禁止再伪装 Chrome(TLS/UA 必须自洽)。 ### 2.4 合规双向保险 请求侧在网关:SSRF、仅 80/443、域名策略、普通 key 遵守 robots。响应侧在 worker 模版层:体积/类型白名单、词表、PII 脱敏、注入包裹。命中即 `denied` 并审计,不假装成功。 --- ## 3. 选用方案(实测后入选,不是目录堆砌) 2026-09-01 本机 Docker 评分(内存 30% / 质量 25% / 成功率 20% / 延迟 15% / 运维 10%)。全文:[`docs/decision-candidates-20260901.md`](docs/decision-candidates-20260901.md)。 | 方案 | 分 | 角色 | 为什么留 | |---|---:|---|---| | Trafilatura-HTTP | 96.8 | 默认精读 | 60/60、p50 ~60ms、正文干净;现网已加 curl_cffi | | Lightpanda | 91.0 | 默认 JS | idle 3.6MB;CF/Amazon 仍过不了 | | chrome-headless-shell | 85.5 | 保真按需 | 单槽 FIFO 零拒绝;重页 ~400MB | | SearXNG-CN | 71.5 | 国内搜索 | 政策词准;突发时百度/搜狗 CAPTCHA,靠排队钳 4–8 | | SearXNG-Global | 62.0 | 国外搜索 | 实例稳,但数据中心 IP 下 **仅 Bing**;产品不承诺多源 | **明确排除**:playwright-distributed(Redis)、Browserless(4GB 档)、Jina 云(query 出境)、Firecrawl 自托管(与 shell+模版层重叠且更重)。 **用户已拍板**:D1 先 L0→L2(≤1GB);D2 接受 Bing-only 起步;D5 不做 Camoufox;Amazon 本站非本服务刚需。 现网能力以 [`docs/mcp-usage-20260901.md`](docs/mcp-usage-20260901.md) §4 为准(2026-09-02 mgr1 复测),不要把 09-01 bench 的「BBC 稳取 / Amazon 一律不行」抄进消费方文档。 --- ## 4. 仓库地图 ``` server/ Go 单二进制,-role=gateway|scheduler|proxymanager cmd/browser-server/ 入口 internal/contract/ 信封与 Job(Session 字段 json:"-") internal/gateway/ MCP + /v1 + Auth + 策略预检 internal/scheduler/ 队列、路由、模版层整合器、junk 过滤、Cookie 绑定 internal/dock/ 五适配器(SearXNG×2、Trafilatura、Lightpanda、shell) internal/fingerprint/ 每节点 Chrome 136 模版 internal/session/ Cookie 罐(Sanitize / TTL / reap) internal/store/ SQLite(jobs、keys、fp_*、session_cookies) internal/proxymanager/ 订阅 / 探活 / 域名路由 internal/policy/ SSRF / robots / 域名 internal/safetyscan/ 响应侧词表与包裹 stacks/ Swarm stack + SearXNG 配置 + Trafilatura 镜像 scripts/ smoke-local.sh、deploy-mgr1.sh(默认 dry-run) bench/ 选型期实测(无密钥) docs/ 决策 / 机制 / MCP / 接手 ``` 源文件硬上限 **600 行**(`make wc`)。禁止万能 `util` 包。 --- ## 5. 本机怎么跑 ```bash make test # go test(合入前加 -race:cd server && go test -race ./...) make vet make smoke # compose + stub 引擎,12 步断言 make image # onesvm/browser-server:dev(默认 linux/amd64) make image-trafilatura # onesvm/trafilatura-http:dev ``` 生产节点通常拉不到 Docker Hub。镜像必须在可联网机器构建/拉取,再 `docker save | ssh … docker load`,stack 用 `--resolve-image never`。**同 tag 覆盖后必须 `docker service update --force`**,否则任务还跑旧层。 mgr1 部署属 🟡:只在用户明确「确认执行」后跑 `bash scripts/deploy-mgr1.sh --apply`。密钥在 gitignore 的 `deploy.env`,不入 git。 --- ## 6. 文档索引 完整表见 [`docs/README.md`](docs/README.md)。冲突时: 1. [`docs/plan-final-20260901.md`](docs/plan-final-20260901.md) — 决策 2. [`docs/design-arch-20260901.md`](docs/design-arch-20260901.md) — 机制 3. 代码 — 现网行为(文档会过期,以代码与 §4 现网复测为准)