作品 02 / 搜索与正文读取基础设施

SearchX.

一个 Provider-aware WebSearch 服务与一条带显式策略防护的 WebFetch 管线:两个 Go 应用可独立部署,并明确呈现失败、缓存与降级行为。

为什么做它。

搜索可靠性远不只是发出一个 HTTP 请求,然后看到 200 就算成功。

不同 Provider 的查询语法、翻页状态、浏览器依赖、容量、CAPTCHA 行为与结果结构并不相同。正文读取还有另一组风险:SSRF、重定向、JavaScript 空壳页面、提取质量与格式转换。

SearchX 把这些复杂度收敛在两个原子服务里。WebSearch 返回排序后的链接与 opaque cursor;WebFetch 对公网 URL 施加显式策略,再把它转换为 canonical document。二者可以独立演进和部署,不必耦合成一个巨大的抓取进程。

实现架构。

外部网关根据契约把请求交给对应服务;每个服务独立拥有策略、编排、Adapter 与降级路径。

SearchX 架构:API 网关将请求分别路由到 WebSearch 与 WebFetch。公开 WebSearch 请求严格按 Provider 顺序执行,每个 Adapter 先租用一个 Profile,再规范化结果并加密 cursor。WebFetch 在 HTTP 路径校验并固定公网目标;降级到 Chromium 后只复查最终 URL,不固定 DNS,也不拦截子资源请求。两个服务共享 Go Runtime 与 Docker、Kubernetes 交付层。
两个可独立部署的服务只共享运行基础,不共享业务管线。

WebSearch 链路。

请求只规范化一次,随后只交给能够兑现声明语义的 Provider。

  1. 01契约入口

    Gin 校验请求、timeout、region、路由顺序、filters、高级 query options 与可选 opaque cursor。

  2. 02搜索计划

    能力感知编译器把受支持的操作符映射到 Brave 或 DuckDuckGo,并在执行前移除不兼容 Provider。

  3. 03缓存保护

    fresh 内存缓存与 singleflight 合并重复工作;实时搜索失败时,stale cache 作为明确标记的降级结果。

  4. 04有序 Provider 链

    公开请求严格按顺序执行 Provider Adapter,每个 Adapter 租用一个 Profile;首个有效结果胜出,可重试失败则进入下一个 Provider。

  5. 05Provider Adapter

    Baidu、Bing、Brave 与 DuckDuckGo Adapter 各自负责 transport、浏览器状态、parser 与类型化失败分类。

  6. 06稳定输出

    URL 先规范化,再执行域名规则和去重;AES-GCM 将 Provider continuation 加密到与原请求绑定的 cursor 中。

WebFetch 链路。

正文读取是一条具有可替换 seam 的显式管线,每个阶段都有明确的质量判断。

  1. 01安全目标

    URL Policy 只接受 HTTP(S),拒绝凭据和危险端口,解析全部地址、屏蔽私网和保留地址,并固定已批准的 DNS 结果。

  2. 02站点策略

    按最长域名后缀和路径前缀选择可选站点策略;GenericStrategy 保留默认行为。

  3. 03HTTP 优先

    在分配浏览器资源前,先由有 body、redirect 与 timeout 上限的 HTTP Reader 读取。

  4. 04提取与评估

    MIME 检测选择 HTML 或纯文本提取器;Quality Evaluator 区分有效正文、JS 空壳、过短页面、登录墙与 CAPTCHA。

  5. 05浏览器降级

    满足条件的失败或需要渲染的页面进入有并发槽限制的 Chromium Adapter,随后再次走同一提取与质量链路;该分支会复查最终 URL,但不会固定 DNS 或拦截子资源请求。

  6. 06Canonical Output

    正文以与展示格式无关的形态缓存,再转换为 Markdown 或 text,并按 Unicode code point 截断。

技术栈。

技术栈刻意保持克制:以标准 Go 并发为主,只在浏览器自动化、正文提取与交付位置使用专门 Adapter。

Runtime

Go 1.26

context、goroutine、有界 channel、singleflight、类型化领域错误,以及方便确定性测试的依赖注入。

HTTP 与契约

Gin + OpenAPI

Gin 1.12 HTTP Adapter、严格 YAML、CORS、请求级 timeout、health/readiness 路由与版本化 API schema。

浏览器与解析

chromedp + goquery

Chrome DevTools Protocol 自动化、Provider parser、Readeck Readability、HTML-to-Markdown、MIME 检测与纯文本提取。

安全与状态

SSRF Policy + AES-GCM

HTTP Reader 路径使用 DNS/IP 规则与目标固定;搜索翻页使用加密、过期、与请求绑定的 opaque cursor。

交付

Docker + Kubernetes

WebSearch 与 WebFetch 使用独立 image 和 manifest,共享 Runtime helper,支持环境变量/YAML 覆盖并接入 API 网关。

验证

Test · race · vet · build

单元与集成 fixture、Provider parser、cursor 与 SSRF 测试、Go benchmark、race detection、vet,以及可复现的 curl、Python、Go 示例。

已经实现。

  • Baidu、Bing、Brave、DuckDuckGo 有序执行,以及类型化失败处理、单 Profile 租约、容量状态、quarantine 与顺序 fallback。
  • 能力感知的高级搜索、include/exclude domain 强制校验、URL 规范化、去重与加密 continuation cursor。
  • fresh/stale 内存缓存、重复请求合并、实时并发上限、队列上限与请求级 diagnostics。
  • HTTP 路径带 SSRF 防线的单 URL fetch、受限 redirect/body、HTML/纯文本提取、质量门禁与 Chromium fallback。
  • Markdown/text 转换、OpenAPI 契约、API 网关示例、本地 Demo、Docker image、Kubernetes manifest 与共享 logging/timeout helper。

诚实边界。

SearchX 是 retrieval infrastructure,不是 answer engine。

  • WebSearch 返回 Provider 排序后的链接;它不会读取结果正文、调用 LLM、合成答案,也没有 semantic rerank 阶段。
  • 容量感知的 auto router 可供内部调用,但公开 HTTP 请求会物化 Provider 列表并严格顺序降级;不会并行查询或聚合多个 Provider。
  • WebFetch 一次读取一个公网 URL;PDF、Office、图片、OCR、批量、登录页面、付费墙与 CAPTCHA 求解不在当前契约内。
  • HTTP Reader 会固定已校验的 DNS 目标并检查重定向;Chromium fallback 当前只复查最终 URL,不固定 DNS 或拦截子资源,因此两条路径的 SSRF 保证并不相同。
  • cache 与浏览器 Profile 按 Pod 本地保存;WebSearch 多副本需要共享 cursor secret,但两个服务都不依赖共享数据库。

查看 WebSearch module ↗
查看 WebFetch module ↗