这是系列文章的第一篇,讲解项目目标、数据分层、解析器选择、环境冻结和决定性样本设计。
公开说明:文中的 IP、用户名、仓库地址、Token、密钥、源文件名、内部哈希和个人目录均已删除或替换。
<project-root>、<server-host>等均为占位符。
系列目录
- 解析架构与质量基线:从原始 PDF 到统一解析方案
- 块级融合与人工质量验收:解决坏文字层、跨页表格和页面溯源
- Chunk、Embedding 与混合检索:构建 PostgreSQL、向量与关键词检索
- 服务部署、增量发布与安全运维:REST/MCP、Token、备份与回滚
1. 项目最终规模
这套知识库首版共处理:
| 项目 | 数量 |
|---|---|
| PDF 文档 | 41 |
| PDF 页面 | 2,999 |
| 逻辑表格 | 1,748 |
| 页级表格片段 | 2,009 |
| 图片对象 | 582 |
| Chunk | 15,801 |
| Embedding | 15,801 |
| Embedding 维度 | 2,560 |
最终系统提供块级来源溯源、表格与图片资产、PostgreSQL 存储、HNSW 向量检索、BM25、RRF 融合、Reranker、REST、MCP、增量发布和可恢复备份。
但这个项目最重要的成果并不是数量,而是建立了一条不会让解析错误静默进入下游的生产线。
2. 为什么不能“PDF 转 Markdown 后直接向量化”
技术 PDF 同时可能包含:
- 健康的原生文字层;
- 编码损坏但肉眼显示正常的文字层;
- 完全扫描页面;
- 原生文字和扫描图混合页面;
- 跨页表格;
- 图片、图表、公式和代码块;
- 大量标准号、条款号、英文缩写和逻辑节点标识。
解析器即使成功导出 Markdown,也可能已经出现:
- 标准号被替换成
/; - 技术标识整段消失;
- 扫描页只剩页眉和页码;
- 跨页表格静默缺一整页;
- 正文阅读顺序错误;
- 列表内容存在于中间 JSON,却没有进入最终正文;
- 图片对象存在,但只有占位符,没有真实图片文件;
- JSON 可以解析,但某一页正文实际上为空。
因此,“文件生成成功”不是质量标准,“输出看起来像文章”也不是质量标准。
3. 项目的硬约束
项目采用以下原则:
- 原始 PDF 永不修改。
- 每份来源文件用 SHA-256 固定。
- 页面必须保留原始页码映射。
- 所有正式文本最终都能追溯到 block 和 bbox。
- 自动 QC 通过不等于 OCR 已经人工确认正确。
- 上一阶段失败时,禁止进入 Chunk 和 Embedding。
- 本地保留完整证据,服务器只保留运行必需资产。
- 任何 Token、密码、密钥和
.env都不得进入 Git。 - 已发布 Release 不可修改,只能创建新 Release。
- 每次更新必须支持增量复用、原子切换和回滚。
这些规则把系统从一次性脚本提升成了可长期维护的数据生产流程。
4. 总体架构
生产端和服务器职责分开:
- 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 可以作为统一结构引擎,但正文仍需通过健康检测和块级对齐确定权威来源。
下一篇将详细讲解整个项目最关键的部分:原生文字健康检测、块级融合、跨页表格双向归属、图片资产和人工校正治理。
创建可增量发布的私有知识库(一):解析架构与质量基线
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法