从网页抓取到可引用知识:xHalo Crawl 与 Corpus 项目架构复盘

如果只看功能列表,xhalo-crawl 和 xHalo Corpus 很容易被理解成两个相邻但不同的项目:前者负责抓网页、搜索、浏览器渲染和 PDF,后者负责诗歌数据、语义搜索和 RAG。

但复盘到现阶段,它们更适合被理解成同一条数据生命线的前后两段:

Crawl 负责把“不可信、会变化、来源复杂的外部内容”变成受约束的采集结果;Corpus 负责把“值得长期保留的内容”变成有稳定身份、Rights、Provenance、Release 与 Citation 的可复用知识。

这两者之间的区别非常重要。

网页抓取结果可以过期,可以重新抓取,可以因为 Provider、时间、动态渲染而变化;Canonical Corpus 则不能随着某个 URL 今天返回什么内容就一起漂移。正因为如此,xHalo 没有把 Crawl 做成“直接往向量库里塞网页”的管线,也没有把 Corpus 做成“一个更大的爬虫数据库”。中间增加了 Copy-on-Ingest、Rights、Trust、Stable ID、Provenance、QA 和 Immutable Release 等治理层。

截至 2026 年 8 月下旬,这条架构已经完成了大部分关键地基:Crawl 的主要 REST、Search、PDF、Browser Run、OCR 与 Studio 已进入生产;Corpus 的 Poetry 生产读平面已启用,活动 Release 包含 349,506 个作品,Public API 与 Semantic Search 已开放,管理员认证的 Browser Intake 也已启用。

但最值得注意的是:自动 Crawl → Corpus handoff、corpus.submit Production allowlist 和自动 Publication 仍然保持关闭。

这不是“还差一个开关”,而是整个项目目前最重要的一条边界。

一、为什么需要把 Crawl 与 Corpus 放在一起复盘

xHalo 的知识能力最初并不是从一个完整“Corpus Platform”设计开始的。

更早的时候,数据问题主要以独立领域存在:Bible 有 Bible Data 和 RAG,Buddhist 有自己的数据加工与向量化,News 有采集和归档,Blog 有 Markdown 内容,Crawl 则解决“怎样从网页拿到可用内容”。随着 Poetry、文学、剧本、心理学等后续知识域进入规划,一个重复的问题越来越明显:

  • 每个数据域都重新写 Source Adapter;
  • 每个项目都自己处理 ID、去重、Rights、Provenance;
  • RAG Chunk 规则各自发展;
  • Embedding、Vectorize 导入与缓存重复建设;
  • 原始数据、规范化数据、发布数据之间没有统一边界;
  • Crawl 抓到的网页内容无法安全地直接变成长期知识资产。

于是 Corpus 的意义逐渐清楚:它不是“另一个内容 API”,而是 xHalo 的 Canonical Corpus Compiler + Knowledge Release Plane。

同一时期,Crawl 也从简单的 fetch 服务逐步发展成统一采集能力:不仅有 Direct Fetch,还加入 Browser Run、Search、PDF、OCR、Provider Router、预算、熔断、SSRF、安全限制和 Studio。

这样,两个项目自然形成了一条链:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
External Source
↓
Crawl / Search / Browser / PDF
↓
Raw + Normalized Result
↓
Governed Intake
↓
Canonical Corpus
↓
Immutable Release
↓
D1 / Vectorize / Pages
↓
Reader / RAG / Agent / TTS

但现阶段真正成熟的地方,恰恰在于没有把这条链变成“抓完自动发布”。


二、现阶段生产状态:两个项目已经走到不同成熟阶段

在讨论架构前,需要先区分“设计目标”和“真实已上线状态”。

xhalo-crawl 当前生产状态

截至 2026-08-15 的机器状态与 Final Closure 记录,Crawl 的主要能力可以简化为:

能力 当前状态
/v1/fetch Production verified
/v1/render Production verified
/v1/extract Disabled
/v1/crawl Production deployed
/v1/search Production deployed
/v1/pdf/inspect Production verified
/v1/pdf/parse Production deployed
Jobs / Usage Production deployed
Crawl Studio Production verified
Direct Fetch Enabled
Browser Run Enabled
Serper / Brave / SearXNG / xHalo RAG Search Enabled
Local OCR Enabled
Stagehand Disabled
Crawl4AI Disabled
Scrapling Disabled
crawl.* MCP Production candidate,未进入 Production Active Manifest

这里最容易产生误判的一点是:Production deployed 不等于 Production verified。

Search、Jobs/Usage、某些异步和复杂路径虽然已经部署,但仍缺少完整的 authenticated real-data Production round trip。原因不是服务没有上线,而是生产 Developer API Key 的创建路径本身要求真实用户会话,之前的自动化审查没有通过“临时绕过认证”的方式制造测试入口。

因此 Crawl 当前已经是一个真实生产服务,但仍处在“能力已上线、生产证据继续补全”的工程阶段。

Corpus 当前生产状态

Corpus 的状态则更集中:

  • Production Corpus API:corpus.xhalo.co;
  • Public API:开启;
  • Semantic Search:开启;
  • Corpus Write:关闭;
  • Production D1:xhalo-corpus-poetry-index;
  • Production Vectorize:xhalo-corpus-poetry-bgem3;
  • Poetry Data:poetrydb.xhalo.co;
  • Reader:poetry.xhalo.co;
  • 活动 Release:poetry-2026-08-12-r2;
  • Work Count:349,506;
  • Embedding:BGE-M3,1024 维;
  • Browser Intake:Production enabled;
  • Crawl Intake:关闭;
  • corpus.submit Production Allowlist:关闭;
  • Publication:关闭。

也就是说 Corpus 已经同时具备两种状态:

  1. 读平面已经是真实生产系统;
  2. 写入与发布平面仍然保持严格 Gate。

这种“读成熟、写保守”的状态,我认为是目前非常合理的阶段选择。


三、总体架构:Acquisition Plane 与 Canonical Knowledge Plane

如果只保留最重要的边界,Crawl 与 Corpus 可以被拆成两个平面。

3.1 Acquisition Plane:Crawl 的任务是获得“可处理的外部证据”

Crawl 面对的是互联网本身的不确定性:

  • HTML 随时变化;
  • JS 页面需要浏览器;
  • 搜索结果来自多个 Provider;
  • PDF 可能是文本、扫描件、加密文件或恶意结构;
  • URL 可能跳转到内网、Metadata Endpoint 或危险目标;
  • Provider 的价格、限额和延迟并不相同;
  • 抓回来的网页内容本身也可能包含 Prompt Injection。

因此 Crawl 的正确输出不是“知识”,而是:

1
2
3
4
5
6
7
8
9
10
Acquisition Result
├ raw payload / object reference
├ normalized representation
├ source URL / canonical URL
├ provider
├ fetch time
├ raw hash
├ normalized hash
├ metadata / provenance
└ bounded execution evidence

这些对象是 可审计的采集结果,但并不是长期 Canonical Truth。

3.2 Canonical Knowledge Plane:Corpus 的任务是决定“什么能够成为知识资产”

Corpus 面对的问题完全不同:

  • 同一个作品来自多个来源时,它们是不是同一个 Work?
  • 原作是公版,但现代译本或注释是否可以发布?
  • 一个作品的稳定 ID 应该如何保持不漂移?
  • 内容修订后,ID、hash 与 Citation 分别怎么变化?
  • 哪些数据是 Canonical,哪些只是检索投影?
  • Embedding 是否可以重建?
  • FTS、Vectorize 与静态正文之间谁是事实源?
  • 发布新数据后如何原子切换?
  • 如何回滚到旧 Release 而不破坏引用?

所以 Corpus 的输出不是“抓取结果”,而是:

1
2
3
4
5
6
7
8
9
10
Canonical Corpus
├ stable public IDs
├ content tree
├ rights decisions
├ provenance events
├ QA results
├ dedup candidates
├ immutable release manifest
├ citation projection
└ rebuildable derived indexes

这就是两个项目的本质区别。


四、xhalo-crawl:已经从 Fetch Worker 发展为 Acquisition Runtime

4.1 Provider Router 是 Crawl 的核心,而不是 Provider 数量

Crawl 早期最直观的能力是“抓一个 URL”。但当 Browser Run、Stagehand、Crawl4AI、Scrapling、Search、PDF、OCR 都出现之后,真正需要解决的问题变成:谁来决定该使用什么方式获取内容?

当前设计选择让 Server-side Provider Router 做决定,而客户端只表达 Intent,例如:

  • 是否允许浏览器;
  • 是否允许异步;
  • 最大页面数;
  • 最大深度;
  • 成本上限;
  • 是否需要结构化结果;
  • 风险容忍度。

Router 再综合:

  • Domain Policy;
  • Cache;
  • Provider 成功率;
  • P95 延迟;
  • Cost;
  • Circuit Breaker;
  • 页面是否 JS-heavy;
  • Caller Scope;
  • Remaining Budget;
  • Approval State。

这是一个很重要的架构选择,因为它避免了客户端逐渐绑定具体 Provider。

如果未来 Browser Run 换成新的实现、Search Provider 调价、某个 Provider 故障,业务端不需要理解这些细节。

4.2 Crawl 的安全层比“抓取功能”更重要

从 Final Closure 的代码和测试看,Crawl 已经形成了一组比较扎实的采集安全约束:

  • localhost / RFC1918 / link-local / IPv6 private / metadata endpoint 禁止访问;
  • 每一次 redirect 都重新解析 DNS 并重新执行 SSRF Guard;
  • 禁止非 HTTP(S) scheme 和非允许端口;
  • 限制 raw bytes、decompressed bytes、redirects、pages、depth、execution time 和 result size;
  • fetched content 一律标记为 untrusted data;
  • 网页正文不能修改 Tool Permission、Budget、Scope 或触发额外未授权操作;
  • Interactive / write actions 默认关闭;
  • Scrapling 被定义成 approval-gated fallback,而不是绕过 CAPTCHA/WAF/paywall 的工具。

更值得肯定的是,Final Closure 没有只停留在“源代码看起来安全”,而是真正补了 adversarial PDF binary、SSRF redirect、浏览器 CORS 和 /ready binding 验证。

4.3 Browser 和 Search 的成本控制已经从估算走向运行时约束

Browser Run 并不是直接调用后再统计,而是由 CRAWL_BUDGET_COORDINATOR 在执行前进行 reservation,再根据真实使用量 settlement。

Search 也经历了一次比较典型的修正:早期存在硬编码价格和未真正调用的 seed 路径,后来改成 Admin 管理的 versioned pricing ledger,并加入 Provider deadline、rolling failure rate / P95 与 circuit breaker。

这说明 Crawl 的成本模型正在从“开发时知道大概多少钱”转向“Runtime 本身知道这次请求是否应该执行”。

4.4 PDF / OCR 的工程价值高于表面功能

PDF 是 Crawl 中最容易被低估的一部分。

现实 PDF 可能包含:

  • CJK / RTL;
  • 表格;
  • 大图;
  • image-only scan;
  • malformed xref;
  • object explosion;
  • embedded JavaScript;
  • embedded file;
  • encryption;
  • compression bomb;
  • huge declared image dimensions。

Final Closure 之后,项目已经把这些真实二进制 fixture 固化到 CI,而不是只用几个正常 PDF 做 demo。

同时,Oracle ARM 上的 OCR 也加入了实际并发限制:因为 OCR Worker 与生产 Auth / PostgreSQL 共用 VPS,项目选择使用 Semaphore(1) 把第二个并发 OCR 直接以 503 拒绝,而不是让多个 Tesseract / Ghostscript 进程同时压满主机。

这个取舍并不“漂亮”,但很符合现阶段资源现实。


五、xHalo Corpus:核心不是向量库,而是 Canonical Compiler

Corpus 项目里最值得保留的设计,是从一开始就没有把 Vectorize 当作知识库本身。

5.1 Canonical Corpus 才是正文事实源

Corpus Pipeline 明确规定:

Canonical Corpus is the only body-text source of truth.

这条原则会直接影响后续所有存储层:

  • Pages Release 保存可发布的正文 read model;
  • D1 负责索引、FTS 和轻量元数据;
  • Vectorize 保存 Embedding;
  • R2 保存 Intake 原始对象;
  • Embedding Cache 只是构建加速;
  • Reader 与 RAG 最终都要回到 Release 中 hydrate 正文。

因此,D1 或 Vectorize 损坏时,理论上应该能够从 Canonical Release 重建,而不是反过来从向量索引“恢复知识”。

5.2 Stable ID 与 Content Hash 被刻意区分

这也是一个容易做错的地方。

如果直接用内容 hash 作为公开 ID,那么文本每次修订都会创建一个新的“作品”;如果只用标题和作者,又会遇到同名、异体、不同 Edition、不同翻译等问题。

Corpus 选择保留:

  • stable public ID;
  • aliases;
  • Work / Edition / structural scope;
  • content hash;
  • source locator;
  • provenance event。

内容发生变化时可以更新 hash,但公共身份并不必然变化。

这为后续 Citation、Reader URL、跨版本兼容和用户收藏提供了稳定基础。

5.3 去重不等于自动合并

Poetry Processing 同时生成:

  • exact-content duplicate;
  • bibliographic same-work candidate。

但不同来源的 Work / Edition 自动 merge 数保持为 0。

这一点看似保守,实际上是 Corpus 可信度的关键。标题相同、作者相同、正文相近,都不足以让机器直接宣布“这是同一个作品版本”。

系统负责发现候选,人或后续更严格的治理规则负责确认关系。

5.4 Rights 是构建流程的一部分,不是发布前的说明文字

Corpus 把 Rights 拆成多个组件:

  • original work;
  • edition;
  • source terms;
  • translation / annotation 等可能存在的派生权利。

未知或 quarantine 的内容不能进入正式 Release。

PoetryDB 的 3,162 条记录就是一个很好的例子:代码能够获取和规范化数据,并不代表数据内容的授权已经明确,因此这些记录被留在 Rights Quarantine,而不是因为“数据已经抓到了”就一起发布。

这会增加运营成本,但比事后清理已经发布的数据可靠得多。


六、Pages + D1 + Vectorize:为什么要采用三层读平面

Corpus 当前生产架构并不是“所有内容塞进 D1”。

后来的一次优化把 Corpus API 改成 index-only D1 + Pages hydration:

1
2
3
4
5
6
7
8
9
Query
↓
D1 FTS / Vectorize
↓ IDs / scores
Pages immutable release
↓ hydrate canonical body
Corpus API
↓
Reader / RAG / Tool

这套结构的优点很明显。

Pages Data

适合:

  • 大量不可变正文;
  • 静态分片;
  • CDN 缓存;
  • Release 版本化;
  • 文件 hash 校验;
  • 低运行成本。

D1

只保留:

  • Work index;
  • FTS5;
  • metadata;
  • Citation JSON;
  • release/version linkage。

D1 不再承担全部正文,因此数据库更轻。

Vectorize

负责:

  • BGE-M3 1024 维向量;
  • language family / release metadata;
  • semantic recall。

搜索再通过 Work ID 返回 Pages hydrate 正文。

这种三层结构比单一数据库复杂,但与 Corpus 的“所有派生层可重建”原则一致。


七、Crawl → Corpus:真正关键的是 Copy-on-Ingest

两者整合中最重要的设计不是一个 API 名称,而是 Copy-on-Ingest。

假设 Crawl 抓取:

1
https://example.com/article

当天得到正文 A。

如果 Corpus 只保存 URL,那么一个月后 Reader 或 RAG 再访问这个 URL,可能得到正文 B,甚至页面已经不存在。

这样 Corpus 的 Citation 就失去了稳定性。

所以设计变成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Crawl Result
├ temporary raw object
├ temporary normalized object
├ raw SHA-256
└ normalized SHA-256

↓ explicit Add to Corpus

Corpus Snapshot
├ content-addressed immutable raw
├ content-addressed immutable normalized
├ source URL
├ fetch time
├ provider
├ job/result ID
├ robots state
├ rights declaration
├ trust declaration
└ manifest

这意味着 Corpus 保存的是“当时经过确认要摄取的那个版本”,而不是一个未来会变化的引用。

7.1 当前 Production 边界

这里必须强调现实状态:

  • Browser / Admin Intake:Production 已开启;
  • Crawl Intake:Production 关闭;
  • corpus.submit Allowlist:关闭;
  • Publication:关闭。

所以当前系统并不是:

1
Crawl → 自动进入 Corpus → 自动向量化 → 自动发布

而是:

1
2
3
4
5
6
7
External / Admin source
↓
Authenticated Intake
↓
Processing / review / candidate
↓
[Publication Gate still closed]

而 Crawl handoff 则已经有完整源代码契约和 Preview 前置设计,但尚未成为 Production 自动通路。

我认为这是现阶段正确的状态。


八、与其他 xHalo 模块的依赖关系

Crawl 与 Corpus 自身并不负责所有横向平台能力。

xhalo-auth

负责:

  • User Identity;
  • Session;
  • Corpus session bridge;
  • Entitlement。

Corpus Browser Intake 在 8 月 13 日开启后,浏览器并不是直接拿着 Intake secret 请求 Worker,而是:

1
2
3
4
5
6
7
8
9
admin.xhalo.co
↓
api-admin.xhalo.co
↓ validate admin session
private Service Binding
↓
Corpus Intake
↓ independently validate forwarded session
xhalo-auth

这比在前端暴露 Intake Origin 或 Internal Secret 更合理。

xhalo-admin

负责:

  • Developer API Key;
  • Crawl 管理;
  • Crawl Usage / Settings;
  • Corpus Intake Console;
  • Platform Admin BFF;
  • 需要人工确认的管理操作。

因此 Crawl 与 Corpus 都没有再建设第二套 Admin。

xhalo-ai-workflow

负责:

  • Tool Registry;
  • Agent / Workflow;
  • MCP Export;
  • Model Cost;
  • Context / Tool Policy。

它可以调用 Crawl 和 Corpus,但不应该拥有它们的 D1、R2 或 Canonical Data。

xhalo-tts / Reader / Story 等消费者

它们通过 Corpus API 或已发布 Tool 读取知识,不直接依赖构建 Pipeline 的内部格式。

这种关系意味着平台真正共享的是 Contract,而不是数据库。


九、分阶段实施过程:为什么这两套系统没有一次性“做大而全”

回看实施过程,可以把大量 PR 和 Phase 压缩成八个架构里程碑。

阶段 A:Crawl Foundation

最初先固定边界:

  • Crawl 只负责 acquisition / normalization;
  • Provider Router 在 Server;
  • SSRF Guard;
  • Job / Result;
  • Defuddle normalization;
  • 不建设第二套 Auth / Admin / MCP。

这个阶段的价值是防止 Crawl 从第一天就变成“浏览器自动化万能工具”。

阶段 B:Preview 与生产切换

之后补上:

  • D1 / R2 / Queue;
  • Browser Budget Coordinator;
  • Developer API;
  • Preview / Production 资源隔离;
  • Release Safety;
  • 2026-08-05 Phase 12 Production Cutover。

Crawl 到这里才真正成为生产服务。

阶段 C:Search / PDF / OCR / Studio

后续扩展包括:

  • Search Gateway;
  • Serper / Brave / SearXNG / xHalo RAG;
  • Auto / Web / Knowledge / Hybrid modes;
  • realtime / cost-sensitive / research profiles;
  • Provider Deadline;
  • Circuit Breaker;
  • Pricing Ledger;
  • PDF Inspect / Parse;
  • Selective OCR;
  • Crawl Studio。

这个阶段把 Crawl 从“抓 URL”扩展成完整 Web Context Service。

阶段 D:Corpus Canonical Foundation

Corpus 从一开始先解决结构问题:

  • canonical entity;
  • content tree;
  • stable ID registry;
  • aliases;
  • source profile;
  • rights;
  • provenance;
  • QA;
  • Intake state machine。

而不是先做 UI 或向量库。

阶段 E:Poetry Processing 与 Local RAG

Poetry 成为第一个 reference domain:

  • Chinese Poetry;
  • Gutenberg;
  • Standard Ebooks;
  • Wikisource;
  • parse / normalize;
  • dedup candidate;
  • Poetry chunk profile;
  • 本地 LM Studio / BGE-M3;
  • embedding cache;
  • Vectorize NDJSON;
  • Retrieval Benchmark。

这一步证明 Canonical Contract 可以承载真实内容域。

阶段 F:Immutable Release 与生产读平面

接下来建立:

  • immutable releases/<version>;
  • manifest;
  • shard;
  • lookup / browse / authors;
  • latest pointer;
  • integrity check;
  • rollback;
  • D1 FTS;
  • Vectorize;
  • Corpus API;
  • Reader。

最终 Production Poetry Release 达到 349,506 Works。

阶段 G:Governed Intake

Intake Worker、R2、Queue、Workflow、Auth Bridge 和 Admin Console 逐步进入生产。

8 月 13 日,Production Browser Intake 正式打开,但其它写入边界继续保持:

1
2
3
4
Browser Intake      ON
Crawl Handoff OFF
corpus.submit OFF
Publication OFF

这个状态说明系统已经允许“把新东西送进处理系统”,但还没有允许“送进去就成为正式知识”。

阶段 H:Quality Closure / Final Closure

Crawl 后期大量工作已经不是开发新功能,而是重新验证已经存在的能力:

  • 修 IDOR;
  • 修 Studio CORS;
  • 补 Search Provider deadline / circuit breaker;
  • 修 Pricing Ledger;
  • 补 PDF 二进制安全 fixture;
  • 限制 OCR 并发;
  • 加 Retention Cleanup;
  • 对齐 OpenAPI / SDK;
  • 真正实现 /ready;
  • 建 current-state.json 与文档一致性检查。

这是一个很明显的阶段变化:项目开始从“功能建设期”进入“证据与治理期”。


十、这两个项目目前做得最好的部分

10.1 没有把 Crawl Result 当成 Canonical Data

这是整体最重要的正确决策。

Crawl 是 acquisition,Corpus 是 canonicalization。两个概念没有混在一起。

10.2 Copy-on-Ingest 解决了网页会变化的问题

Corpus 吸收的是一个经过 hash 固定的 Snapshot,而不是一个未来可能返回不同内容的 URL。

这使 Citation、RAG Evidence 和 Release 才真正稳定。

10.3 Corpus 的 Derived Layer 可重建

Pages 正文、D1 Index 和 Vectorize 各司其职。D1 / Vectorize 不成为正文的唯一事实源。

这降低了数据库锁定和长期迁移风险。

10.4 Rights / Provenance / QA 进入构建管线

这些不是 README 里的原则,而是决定 Candidate 是否可发布的真实 Gate。

10.5 Crawl 的成本治理已经进入 Runtime

Browser reservation / settlement、Search pricing ledger、deadline 和 circuit breaker 都比单纯记录 usage 更成熟。

10.6 Security Review 开始依赖真实失败案例

Studio CORS 是一个很典型的例子:之前 curl / Node 测试都没暴露浏览器跨域问题,真正浏览器验收才发现整个 Studio 从实际点击路径看并不可用。

这种 bug 很有价值,因为它推动测试从“API 返回 200”变成“用户真的能用”。

10.7 Immutable Release + Pointer Activation 很适合长期知识库

Release 本身不覆盖,Activation 只移动 pointer;Rollback 也只指回一个已经存在、完整性通过的 Release。

比直接更新“当前数据库内容”更容易审计和回滚。


十一、还需要加强的部分

11.1 Crawl 仍存在 Production Evidence Gap

目前多个能力是 production_deployed,但不是 production_verified。

尤其:

  • Search real result content;
  • async Crawl budget path;
  • Jobs / Usage authenticated path;
  • Hybrid / Research / Auto 某些模式的真实生产表现。

这意味着下一阶段不应该继续优先增加 Search Provider,而应该获得真实生产调用样本。

11.2 Crawl 的 Live Feature Flag 事实仍然过于依赖 deploy-time override

这是一个非常值得重视的风险。

仓库中的 wrangler.jsonc 仍然把大量 CRAWL_*_ENABLED 默认设为 false,真实 Production 则通过 deploy-time --var override 开启。

这样做的初衷是 fail closed,但副作用是:

一次不带完整 override 的普通 wrangler deploy,有可能把已经上线的能力重新关闭。

Final Closure 已经意识到这个问题,并在部署前从 live version 重建完整变量列表,但长期看这仍然不是最理想的 Deployment Truth 模型。

更好的方向是让 live capability state 有机器可验证、可生成部署参数的单一事实源,而不是依赖操作员记住“不能 bare deploy”。

11.3 Provider Router 的“架构宽度”目前大于真实可用宽度

设计上有:

1
2
3
4
5
Direct
Browser Run
Stagehand
Crawl4AI
Scrapling

但 Production 真实启用的是 Direct + Browser Run,Stagehand 当前明确 disabled,Crawl4AI / Scrapling 也关闭。

因此现阶段更准确的说法不是“五 Provider 自动路由已经成熟”,而是:

Provider Router 的抽象已经成熟,但真正稳定的 Production Provider 集合仍然较窄。

这并不是坏事,只需要文档和产品预期保持一致。

11.4 Stagehand 不应该为了“架构完整”被强行修复

真实诊断已经把早期“CDP WebSocket 问题”进一步缩小到自定义 Model Client completion-tracking 路径。

如果 Direct + Browser Run + Search 已经覆盖绝大部分需求,那么是否继续投入 Stagehand,应该由真实任务缺口决定,而不是因为架构图上预留了这个 Provider。

11.5 Corpus 的自动化写平面仍然没有闭环

当前 Browser Intake 已经 Production enabled,但:

  • Crawl handoff 关闭;
  • corpus.submit 关闭;
  • Publication 关闭。

这意味着 Corpus 还没有形成完整的“外部发现 → 自动候选 → 审核 → 发布”运营闭环。

这应该是下一阶段最值得推进的一条链,但仍然不应该直接跳到自动 publish。

11.6 Poetry 的成功还不能证明所有 Corpus Domain 都已验证

Corpus Contract 的目标是复用于:

  • Fiction;
  • Drama;
  • Screenplay;
  • Psychology;
  • Private Corpus。

但当前真正经过 349,506 Works 规模验证的是 Poetry。

长篇小说、章节树、脚本角色、心理学著作的引用单位、Rights 粒度、Chunk Profile 和 Edition 关系都可能不同。

所以 Corpus Platform 的下一项关键验证,不应该只是“再导入更多诗”,而是选择一个结构差异明显的第二 Domain。

11.7 Rights / Duplicate Review 的人工成本会随规模迅速增加

当前“zero automatic merge”是正确的安全边界,但随着数据源增加,人工 review candidate 数量可能成为瓶颈。

后续应该提高的是 Review tooling 和 evidence quality,而不是简单放宽自动 merge。

11.8 Corpus 状态文档已经出现一次真实 Drift

这是本次复盘发现的一个具体例子。

docs/CURRENT_STATE.md 的 prose 仍写着截至 8 月 12 日 Browser Intake 关闭,而 8 月 13 日的 docs/current-state.json 与真实提交已经把:

1
2
production_browser_intake = true
AUTH_SESSION_ENABLED = true

正式打开。

也就是说项目已经有机器状态源,但人读状态页仍可能落后。

这和 Crawl 后期花大量精力解决的 Documentation State Governance 是同一类问题。

下一步应该让 prose summary 尽量由 machine state 生成,而不是维护两份手写真相。


十二、成本与性能复盘

这两个项目有一个共同特点:并没有把“全部 Cloudflare 服务都用上”当成架构目标,而是在不同阶段把负载放到更适合的层。

Crawl

  • 普通网页优先 Direct Fetch;
  • JS-heavy 才进入 Browser;
  • Browser 有 included-only / budget gate;
  • Search 有 Provider Cost Profile;
  • OCR 放在已有 Oracle ARM 上,并限制并发;
  • R2 用于临时对象和内容寻址缓存;
  • D1 保存 job、usage、pricing、audit,而不是大正文。

Corpus

  • 大规模不可变正文放 Pages Data;
  • D1 变成 index-only;
  • Vectorize 只负责 semantic retrieval;
  • Embedding 用本地 LM Studio / BGE-M3 构建;
  • SQLite cache 复用 unchanged text 的 vector;
  • Release embedding 以 immutable batch + SHA checkpoint 方式可恢复上传。

这套架构的共同逻辑其实是:

把昂贵、动态的事情尽量限制在 ingestion/build 阶段,把生产读取变成廉价、缓存友好、可预测的路径。

这是 Corpus 当前能够承载 349,506 Works 而不必把所有正文塞进运行时数据库的重要原因。


十三、下一阶段建议:重点不是继续“加功能”,而是闭合四条链

P0:统一 Runtime Truth

首先解决:

1
2
3
4
5
6
Source config
Live Cloudflare state
current-state.json
CURRENT_STATE.md
Admin UI
Release scripts

之间的事实一致性。

尤其 Crawl 的 deploy-time feature flags,应从机器状态安全生成 Deploy Manifest,降低 bare deploy 误关闭能力的风险。

P1:建立安全的 Production Verification Principal

当前很多 Production Evidence 缺口都卡在“没有一个安全、短期、可审计的真实测试身份”。

应该设计一个真正的:

1
2
3
4
5
6
7
production-smoke principal
├ least privilege
├ short-lived
├ explicit scopes
├ no user data access by default
├ auditable
└ revocable

而不是要求每次用真实个人 Developer API Key,或为了测试临时关闭生产 Auth。

P2:推进 Crawl → Corpus Preview 自动 Handoff

已经有 Source Contract,下一步应该验证:

1
2
3
4
5
6
7
8
9
10
11
Crawl Result
↓
request digest
↓
approval binding
↓
copy-on-ingest
↓
Corpus Intake job
↓
idempotent replay

重点测试:

  • approval expiry;
  • duplicate request;
  • hash mismatch;
  • changed URL;
  • revoked actor;
  • rights rejection;
  • concurrent handoff;
  • rollback。

P3:Publication 继续作为独立 Gate

即使 Crawl Handoff 可以自动触发 Intake,也不要直接把:

1
processed → published

变成同一步。

正确链路更接近:

1
2
3
4
5
6
7
intake
→ processed
→ candidate
→ rights / QA / dedup review
→ release build
→ release verification
→ explicit activation

P4:用第二个 Domain 验证 Corpus Generalization

建议选择和 Poetry 差异明显的一个领域,例如:

  • 长篇 Fiction;或
  • Drama / Screenplay。

验证:

  • 章节层级;
  • 长文本 chunk;
  • Edition / translation;
  • Character / Scene 结构;
  • Citation;
  • Rights component;
  • Reader hydration;
  • RAG retrieval。

这比继续扩大 Poetry 数量更能证明 Corpus Platform 的通用性。

P5:统一 Crawl / Corpus Trace

最终一条知识可以回答:

1
2
3
4
5
6
7
8
这个 Corpus Work
来自哪个 Source?
是哪次 Crawl / Upload?
经过哪个 Adapter?
用了什么 Rights Decision?
生成哪个 Release?
对应哪些 Vectorize Chunks?
最终被哪个 RAG Run 引用了?

这才是一个真正可审计的知识平台。


十四、总结:真正的产物不是爬虫,也不是向量库

回看 Crawl 和 Corpus 的建设过程,最容易被外部观察到的能力其实都不是最重要的:

  • Browser Run;
  • Search;
  • PDF;
  • OCR;
  • Vectorize;
  • BGE-M3;
  • Reader;
  • RAG。

这些都只是系统组件。

真正决定这两个项目长期价值的,是下面三条边界:

第一条:Crawl 不拥有知识真相

它提供的是一次受约束、可审计的外部 acquisition result。

第二条:Corpus 不信任“已经抓到了”

只有经过 Stable ID、Rights、Provenance、QA、Release 和 Citation 的内容,才进入长期知识平面。

第三条:自动化不能绕过 Publication Authority

即使未来 AI Workflow、Agent、Crawl 能自动发现和摄取大量资料,最终“什么成为 xHalo 的正式知识资产”仍然应该经过独立、可追踪、可回滚的发布门。

因此现阶段最准确的架构描述不是:

xHalo 已经有一个很强的爬虫和一个大型 RAG 库。

而是:

xHalo 正在形成一条从外部世界到 Canonical Knowledge 的受治理数据管线:Crawl 负责 acquisition,Corpus 负责 canonicalization,AI Workflow 负责 orchestration,而最终 Publication 仍然保持独立权限。

这条边界如果能够继续保持,未来无论加入文学、剧本、心理学、哲学、News、Map 还是用户私有资料,都可以复用同一条知识治理逻辑,而不必再次退回“抓数据 → 切 Chunk → 塞向量库”的临时方案。