这是系列文章的第一篇,讲解项目目标、数据分层、解析器选择、环境冻结和决定性样本设计。

公开说明:文中的 IP、用户名、仓库地址、Token、密钥、源文件名、内部哈希和个人目录均已删除或替换。<project-root>、<server-host> 等均为占位符。

系列目录

  1. 解析架构与质量基线:从原始 PDF 到统一解析方案
  2. 块级融合与人工质量验收:解决坏文字层、跨页表格和页面溯源
  3. Chunk、Embedding 与混合检索:构建 PostgreSQL、向量与关键词检索
  4. 服务部署、增量发布与安全运维:REST/MCP、Token、备份与回滚

1. 项目最终规模

这套知识库首版共处理:

项目数量
PDF 文档41
PDF 页面2,999
逻辑表格1,748
页级表格片段2,009
图片对象582
Chunk15,801
Embedding15,801
Embedding 维度2,560

最终系统提供块级来源溯源、表格与图片资产、PostgreSQL 存储、HNSW 向量检索、BM25、RRF 融合、Reranker、REST、MCP、增量发布和可恢复备份。

但这个项目最重要的成果并不是数量,而是建立了一条不会让解析错误静默进入下游的生产线。

2. 为什么不能“PDF 转 Markdown 后直接向量化”

技术 PDF 同时可能包含:

  • 健康的原生文字层;
  • 编码损坏但肉眼显示正常的文字层;
  • 完全扫描页面;
  • 原生文字和扫描图混合页面;
  • 跨页表格;
  • 图片、图表、公式和代码块;
  • 大量标准号、条款号、英文缩写和逻辑节点标识。

解析器即使成功导出 Markdown,也可能已经出现:

  • 标准号被替换成 /;
  • 技术标识整段消失;
  • 扫描页只剩页眉和页码;
  • 跨页表格静默缺一整页;
  • 正文阅读顺序错误;
  • 列表内容存在于中间 JSON,却没有进入最终正文;
  • 图片对象存在,但只有占位符,没有真实图片文件;
  • JSON 可以解析,但某一页正文实际上为空。

因此,“文件生成成功”不是质量标准,“输出看起来像文章”也不是质量标准。

3. 项目的硬约束

项目采用以下原则:

  1. 原始 PDF 永不修改。
  2. 每份来源文件用 SHA-256 固定。
  3. 页面必须保留原始页码映射。
  4. 所有正式文本最终都能追溯到 block 和 bbox。
  5. 自动 QC 通过不等于 OCR 已经人工确认正确。
  6. 上一阶段失败时,禁止进入 Chunk 和 Embedding。
  7. 本地保留完整证据,服务器只保留运行必需资产。
  8. 任何 Token、密码、密钥和 .env 都不得进入 Git。
  9. 已发布 Release 不可修改,只能创建新 Release。
  10. 每次更新必须支持增量复用、原子切换和回滚。

这些规则把系统从一次性脚本提升成了可长期维护的数据生产流程。

4. 总体架构

原始 PDF
文件清单与 SHA-256
MinerU Hybrid High
原生文字与坐标提取
版面、顺序、表格、图片、bbox
文字层健康检测
块级融合
Canonical
结构感知 Chunk
Qwen3 Embedding
Canonical Core
PostgreSQL + pgvector + BM25
RRF + Reranker
REST / MCP

生产端和服务器职责分开:

  • Windows 生产端负责解析、人工 QC、模型运行和 Release 构建;
  • Ubuntu 服务器负责保存精简运行资产、数据库和检索服务。

服务器不是本地 QC 工作区的完整镜像。页面 PNG、解析中间文件和人工校正证据只在本地长期保留。

5. 数据分层

5.1 Source

Source 是来源真值,包含原始 PDF、稳定文档 ID、页数、文件大小和 SHA-256。

来源哈希变化时,应视为新版本文档,不能静默覆盖旧数据。

5.2 Canonical

Canonical 是完成解析、融合和 QC 后的统一文档层,包括:

  • blocks;
  • pages;
  • logical tables;
  • page table fragments;
  • images;
  • 原始页码;
  • bbox 和坐标系;
  • raw、normalized、search 三层文字;
  • 来源与校正记录。

Canonical 一旦被 M6 消费,就作为不可变输入。

5.3 Release

Release 包含某一版本的:

  • Chunk;
  • Embedding;
  • Manifest;
  • SHA-256 清单;
  • 文档计数和输入指纹。

每个 Release 有唯一 ID,发布后不可原地修改。

5.4 Runtime

Runtime 包含 PostgreSQL、检索索引、查询模型、Reranker、REST/MCP 服务和客户端鉴权。

6. 推荐目录结构

本地生产端:

<project-root>/
├── 00-inbox/                 # 原始 PDF,只读
├── 01-sources/               # 来源清单和映射
├── 02-canonical/             # 正式统一文档
├── 03-chunks/                # Chunk Release
├── 04-embeddings/            # Embedding Release
├── 05-bundles/               # 服务器传输包
├── 06-qc/                    # 自动和人工 QC
├── 07-manifests/             # 阶段状态与哈希
├── 08-logs/                  # 日志
├── 09-models/                # 模型缓存
├── 10-app/                   # 脚本、服务和迁移
└── 11-archive/               # 校正包与备份

服务器:

/srv/knowledge/
├── app/
├── config/
├── sources/
├── canonical-core/
├── releases/
├── models/
├── postgres/data/
├── logs/
└── backups/

7. 第一步:清点原始 PDF

解析前为每份 PDF 建立记录:

{
  "document_id": "stable-document-id",
  "source_relative_path": "relative/path/document.pdf",
  "source_sha256": "<sha256>",
  "size_bytes": 12345678,
  "page_count": 120,
  "encrypted": false
}

关键点是从此以后不再使用易变化的文件名作为数据库主身份,而使用稳定 document_id。

Windows 下可以用以下命令复核来源哈希:

Get-FileHash -Algorithm SHA256 -LiteralPath '<pdf-path>'

每次进入新阶段都重新检查原始 PDF 哈希,防止来源在过程中被替换。

8. 解析器评估

前期曾评估传统 PDF 解析和 OCR 方案。实际样本证明,不同解析路线各有明显缺陷:

  • 原生文字路线可能输出大量伪字符;
  • OCR 路线可能整页漏识别正文;
  • 复杂混合页面可能发生阅读顺序错误;
  • 图片对象不一定对应真实导出资产;
  • VLM 可能删除或改写健康文字层中的技术字段。

最终没有对外维护多个解析器路线,而是冻结一套统一结构流程:MinerU 负责版面和视觉资产,系统内部再根据每页文字健康状态决定正文来源。

这并不是让用户选择多个解析器,而是在同一个 Canonical Schema 内保护不同来源的权威边界。

9. 最终 MinerU 配置

正式版本使用 MinerU 3.4.4:

backend = "hybrid-engine"
effort = "high"
parse_method = "auto"
formula_enable = true
table_enable = true
image_analysis = true
concurrency = 1

配置约束:

  • 不为了速度降到 medium;
  • 不自动切换为其他正式解析器;
  • 不调用远程解析 API;
  • 模型、缓存和依赖全部放在独立环境;
  • 精确冻结 Python、MinerU、Torch、CUDA 和依赖版本;
  • 模型和依赖冻结文件都计算 SHA-256。

MinerU 在最终系统中的职责是:

  • layout;
  • reading order;
  • block 类型;
  • bbox;
  • table;
  • image;
  • page mapping;
  • 损坏文字层和扫描页的 OCR 正文。

对于健康原生文字页,MinerU 不得覆盖或删改正文。

10. 决定性样本设计

不要一开始就处理全部页面。Pilot 应覆盖:

  • 健康原生文字页;
  • 编码损坏页;
  • 纯扫描页;
  • 混合版面;
  • 跨页表格;
  • 图片和图表;
  • 公式;
  • 代码与英文标识密集页。

每个样本都记录:

  • 原始 PDF 引用;
  • 原始 PDF SHA-256;
  • 原始页码;
  • 测试输入页码;
  • 每页完整 PNG;
  • MinerU Markdown、JSON、content list 和 middle JSON;
  • 阅读顺序、bbox、表格和图片资产;
  • 输出文件 SHA-256;
  • 转换 Manifest。

11. 跨页测试必须连续

跨页表格不能用非连续页拼成测试 PDF。

假设原始第 7 至 9 页是一张续表。如果只抽取第 7 页和第 9 页,解析器会误以为两页相邻,把它们拼成一张“看似完整”的表,同时静默遗漏第 8 页。

正确规则是:

  • 单页正文可以单页测试;
  • 跨页结构必须包含完整连续范围;
  • 保存测试页到原始页的明确映射;
  • 不允许根据预设行号范围推算页面归属;
  • 每一行的页码必须来自真实页级表格片段。

12. 本阶段门禁

进入块级融合前至少确认:

  • 原始 PDF 哈希不变
  • MinerU 版本和模型未漂移
  • 每个测试页具有原始页码映射
  • 每页 PNG 和结构输出存在
  • 图片对象对应真实文件
  • 表格包含页级 bbox
  • 连续表格没有缺页
  • JSON 严格解析且没有 NaN/Infinity
  • 自动检查没有宣称 OCR 已人工确认正确

第一阶段的结论是:统一解析器不等于统一信任文字来源。MinerU 可以作为统一结构引擎,但正文仍需通过健康检测和块级对齐确定权威来源。

下一篇将详细讲解整个项目最关键的部分:原生文字健康检测、块级融合、跨页表格双向归属、图片资产和人工校正治理。