一、先把问题收窄
RAG 最终检索的不是用户上传的文件,而是入库 Pipeline 生产的 Chunk。解析顺序错误、清洗误删正文、分块拆散表头与数据,都会让后续检索建立在错误数据上。
本文只讨论一条链路:
原始文件 → 解析 → 清洗 → 分块 → Embedding → 索引发布
混合检索、Rerank 和 Prompt 编排不在本文展开。目标是把文档稳定地转换成可追踪、可重建、可评测的索引数据。
二、入库架构与数据边界
2.1 总体流程
flowchart TB
Upload["文件上传 / 数据源同步"] --> Preflight["输入预检"]
Preflight --> Router{"解析器路由"}
Router -->|"复杂 PDF / 图片"| MinerU["MinerU"]
Router -->|"Office / 长尾格式回退"| MarkItDown["Microsoft MarkItDown"]
Router -->|"MD / TXT / HTML / Code"| Builtin["内置解析器"]
MinerU --> UDM["统一文档模型 UDM"]
MarkItDown --> UDM
Builtin --> UDM
UDM --> ParseGate{"解析质量门禁"}
ParseGate -->|"通过"| Clean["清洗 Pipeline"]
ParseGate -->|"存在备用路线"| Router
ParseGate -->|"无法修复"| Quarantine["隔离 / 人工处理"]
Clean --> Chunk["结构化分块"]
Chunk --> Batch["Token 动态合批"]
Batch --> Embed["Embedding Gateway"]
Embed --> Validate["向量与索引校验"]
Validate --> Staging["STAGING 索引"]
Staging --> Publish["原子发布"]
Object[("对象存储
原文与阶段产物")]
Meta[("关系数据库
状态、版本、ACL")]
Index[("向量 / 全文索引")]
Upload --> Object
UDM -.-> Object
Clean -.-> Object
Chunk -.-> Object
Preflight -.-> Meta
ParseGate -.-> Meta
Publish --> Meta
Staging --> Index
classDef entry fill:#e8f1ff,stroke:#4c78a8,color:#1f2937;
classDef process fill:#ecf8f1,stroke:#3b8c61,color:#1f2937;
classDef storage fill:#f2ecff,stroke:#7e57c2,color:#1f2937;
classDef warn fill:#fff4df,stroke:#d18b24,color:#1f2937;
class Upload,Preflight entry;
class MinerU,MarkItDown,Builtin,UDM,Clean,Chunk,Batch,Embed,Validate,Staging,Publish process;
class Object,Meta,Index storage;
class Router,ParseGate,Quarantine warn;
2.2 哪些数据是事实源
| 数据 | 存储位置 | 作用 |
|---|---|---|
| 原始文件 | 对象存储 | 审计和重新解析,不可替代 |
| 解析器原始输出 | 对象存储 | 复现解析问题 |
| UDM 与清洗结果 | 对象存储 / Parquet | 重跑清洗和分块 |
| Chunk Manifest | 数据库 / Parquet | 重建向量与全文索引 |
| 文档版本、ACL、状态 | 关系数据库 | 权威业务状态 |
| 向量和倒排索引 | 检索引擎 | 派生数据,可重建 |
不要把唯一一份 Chunk 正文、页码或 ACL 只保存在向量数据库的 Payload 中。
三、输入预检与解析器路由
3.1 输入预检
文件扩展名不可信,解析前至少完成以下检查:
| 检查 | 目的 | 失败处理 |
|---|---|---|
| Magic Bytes、MIME、扩展名一致性 | 识别真实格式 | 拒绝伪造格式 |
| SHA-256 | 创建不可变文档版本 | 哈希失败则停止 |
| 文件大小、页数、解压后大小 | 防止资源耗尽和压缩炸弹 | 超过硬限制直接失败 |
| 损坏、加密、密码保护 | 避免无效重试 | 提示用户修复或提供密码 |
| PDF 文本层和文本密度 | 判断是否需要 OCR | 按页选择解析方式 |
| 宏、脚本和外部资源 | 防止执行不可信内容 | 禁止执行和主动加载 |
所有解析器都应运行在受限容器中,并限制 CPU、内存、临时磁盘、运行时间和网络访问。
3.2 路由流程
flowchart TD
Input["通过预检的文件"] --> Detect["识别真实 MIME 与结构特征"]
Detect --> Text{"确定性文本格式?"}
Text -->|"MD / TXT / HTML / Code"| Builtin["内置解析器"]
Text -->|"否"| MinerCap{"当前 MinerU 支持?"}
MinerCap -->|"支持且需要版面能力"| MinerU["MinerU 解析"]
MinerCap -->|"不支持或无需复杂版面"| MarkCap{"MarkItDown 支持?"}
MarkCap -->|"支持"| MarkItDown["MarkItDown 转 Markdown"]
MarkCap -->|"不支持"| Convert["受控格式转换或拒绝"]
Builtin --> Gate{"质量门禁"}
MinerU --> Gate
MarkItDown --> Gate
Convert --> Gate
Gate -->|"通过"| UDM["输出 UDM"]
Gate -->|"质量差且有备用解析器"| Detect
Gate -->|"无备用路线"| Quarantine["隔离"]
路由依据包括真实 MIME、版面复杂度、解析器能力快照、数据出域策略、历史质量和资源成本。不要把官网支持列表永久硬编码进业务逻辑。
3.3 推荐路由矩阵
MinerU 当前官方 CLI 支持 PDF、图片、DOCX、PPTX 和 XLSX,但不同部署版本与 API 形态的能力可能不同。
| 输入 | 首选 | 回退 | 关键要求 |
|---|---|---|---|
| 有文本层的复杂 PDF | MinerU | MarkItDown 低保真回退 | 保留页码、坐标、表格和阅读顺序 |
| 扫描 PDF、文档图片 | MinerU OCR | 其他 OCR 或人工处理 | 按页 OCR,保留置信度 |
| DOCX / PPTX / XLSX | 当前 MinerU 原生解析 | MarkItDown | 用黄金样本决定优先级 |
| XLS | MarkItDown | 受控 Office 转换 | 依赖对应可选组件 |
| DOC / PPT 等旧格式 | 先受控转换为新格式或 PDF | 提示用户转换 | 不执行宏和嵌入脚本 |
| Markdown / TXT | 内置解析器 | 无 | 保留标题、代码块和源行号 |
| HTML | 内置 DOM 解析器 | MarkItDown | 去除脚本、导航和隐藏节点 |
| CSV / JSON / XML | 内置结构解析器 | MarkItDown | 按记录和字段组织内容 |
| 未识别格式 | MarkItDown 能力探测 | 拒绝并隔离 | 禁止按 TXT 强行读取 |
3.4 三类解析器的边界
MinerU
复杂 PDF 和图片优先使用 MinerU。接入时应保存完整输出包,并记录版本、后端、模型、OCR 语言、表格和公式开关。
机器处理优先读取 content_list.json、content_list_v2.json 或 middle.json,Markdown 主要用于人工预览。不同 MinerU 版本通过独立 Adapter 转换为 UDM,避免清洗和分块代码直接依赖外部 Schema。
混合 PDF 应按页判断:有效文本层直接读取,无文本页启用 OCR,乱码页比较原生文本与 OCR 质量。
Microsoft MarkItDown
MarkItDown 适合将 DOCX、PPTX、XLSX、XLS、HTML、CSV、JSON、XML 等输入转换为 Markdown,再恢复成结构节点。
它通常不提供复杂 PDF 所需的可靠页码和坐标,因此引用精度应降级为章节或转换后行号。服务端只允许处理受控文件或字节流,禁止把用户提供的路径和 URL 直接传入转换器。
内置解析器
- Markdown 使用 AST 保留标题、表格、列表、代码块和源行号
- TXT 做编码检测、换行归一化和行号定位
- HTML 使用 DOM 提取正文结构
- CSV、JSON、XML 按记录和字段组织
- 代码按语言 AST 或语法树保留类、函数和签名
确定性文本不需要经过 OCR 或视觉模型。
3.5 解析成功不等于质量合格
以下情况都应触发回退或隔离:
- 长文档只解析出少量字符
- 双栏文本顺序交叉
- 表格只剩无结构数字
- OCR 乱码或替换字符比例过高
- 结构化文档完全没有标题
- 解析页数与原文差异过大
每份文档最多执行一次明确的备用路线,禁止解析器之间循环切换。
四、统一文档模型与解析质量
4.1 UDM 是解析器防腐层
UDM 不只保存 Markdown,还要保存结构和来源:
| 字段 | 作用 |
|---|---|
document_version_id |
关联不可变文档版本 |
block_id、order |
稳定标识和阅读顺序 |
type |
标题、段落、列表、表格、代码、公式、图片等 |
raw_text |
解析器原始文本,不允许覆盖 |
text |
当前阶段处理后的文本 |
section_path |
所属章节路径 |
page、bbox |
页码和坐标,不存在时必须为空 |
parent_id |
图片与说明、标题与正文等结构关系 |
confidence |
OCR 或解析置信度 |
provenance |
外部解析器节点或源文件行号 |
表格、代码和公式使用独立结构,不强行拍平成段落。
4.2 解析质量门禁
| 指标 | 主要发现的问题 |
|---|---|
| 有效字符数、可打印字符比例 | 空结果、乱码 |
| 替换字符比例 | 编码或 OCR 错误 |
| 页数与页面覆盖率 | 漏页 |
| 标题数量和层级 | 结构丢失 |
| 表格有效率 | 行列识别失败 |
| OCR 低分位置信度 | 集中低质量页面 |
| 重复行比例 | 水印、页眉页脚污染 |
| 阅读顺序评分 | 双栏和复杂版面错序 |
阈值按文档类型配置。小说没有标题并不异常,技术手册没有标题通常需要复核。
五、清洗 Pipeline
5.1 清洗原则
清洗只做三件事:去除确定性噪声、修复解析断裂、补全结构关系。
默认禁止:
- 使用大模型改写原文
- 自动补齐缺失事实
- 合并存在冲突的条款
- 跨文档删除“相似内容”
- 用摘要替代可引用正文
raw_text 永不覆盖,所有删除和修复都要记录 Operator、版本、原因以及变更前后哈希。
5.2 Pipeline 流程
flowchart LR
UDM["UDM"] --> Unicode["字符与换行归一化"]
Unicode --> Repair["断行 / 断词修复"]
Repair --> Margin["页眉页脚与水印识别"]
Margin --> Section["标题树与章节路径"]
Section --> Structure["表格 / 列表 / 代码修复"]
Structure --> Dedup["文档内去重标记"]
Dedup --> Gate{"清洗质量门禁"}
Gate -->|"通过"| Cleaned["Cleaned UDM"]
Gate -->|"删除或改写异常"| Quarantine["隔离 / 抽查"]
Change[("Change Log")]
Unicode -.-> Change
Repair -.-> Change
Margin -.-> Change
Section -.-> Change
Structure -.-> Change
Dedup -.-> Change
5.3 核心 Operator
| Operator | 处理内容 | 安全边界 |
|---|---|---|
| 字符归一化 | Unicode NFC、换行、零宽字符 | 代码和公式不做全角半角替换 |
| 空白归一化 | 连续空格、段落边界 | 不破坏代码缩进和表格 |
| 断行修复 | PDF 视觉行合并 | 结合标点、缩进和坐标 |
| 英文断词修复 | 行尾连字符 | 不修改编号、复合词和代码 |
| 页边噪声识别 | 重复页眉、页脚、水印、页码 | 合同和论文脚注默认保留 |
| 标题树修复 | 章节路径、标题跳级告警 | 不凭空创建缺失标题 |
| 表格修复 | 跨页表头、Caption、Footnote | 无法恢复行列时保留原始产物 |
| 精确去重 | 坐标重叠的重复节点 | 近重复只标记,不直接删除 |
5.4 几个容易误删的场景
页眉页脚
只有同时满足“跨页高频重复”和“长期位于固定页边区域”时才标记为页边噪声。页脚中的合同条款、论文注释和免责声明不能按位置直接删除。
英文连字符
只有连字符位于视觉行尾、下一行以小写字母开始、合并词合理且当前内容不是代码或表格时才修复。
重复内容
跨文档相同正文可以复用 Embedding 结果,但不能删除业务文档。相同内容仍可能拥有不同 ACL、来源和生效时间。
5.5 版本与质量门禁
清洗配置指纹由 Operator 名称、版本、顺序、参数和构建版本共同生成。任何一项变化都产生新产物。
清洗完成后检查:
- 有效正文是否为空
- 删除字符比例是否异常
- Block 类型数量是否突变
- 页边噪声是否覆盖正文区域
- 表格行列是否完整
- 章节路径是否大量跳级
- 乱码、重复和超长段落比例
删除比例超过业务阈值时进入隔离,不直接发布。
六、结构化分块
6.1 先保留结构,再控制 Token
flowchart TB
Cleaned["Cleaned UDM"] --> Tree["构建标题树"]
Tree --> Atomic["生成 Atomic Units
句子 / 列表项 / 表格行 / 函数"]
Atomic --> Type{"内容类型"}
Type -->|"普通正文"| Paragraph["按章节顺序聚合"]
Type -->|"表格"| Table["表头 + 行组 + 脚注"]
Type -->|"FAQ"| FAQ["一问一答"]
Type -->|"代码"| Code["类 / 函数边界"]
Paragraph --> Budget["Token 预算检查"]
Table --> Budget
FAQ --> Budget
Code --> Budget
Budget --> Child["Child Chunk
精确召回"]
Child --> Parent["Parent Chunk
上下文扩展"]
Child --> Link["前后邻接关系"]
固定字符切分会破坏标题、表格和代码边界。推荐三层结构:
- Atomic Unit:句子、列表项、表格行、代码函数等最小语义单元
- Child Chunk:用于 Embedding 和精确召回
- Parent Chunk:命中后用于补充上下文
6.2 Chunk 必备字段
| 字段 | 作用 |
|---|---|
chunk_id、sequence |
稳定标识和文档内顺序 |
parent_chunk_id |
Parent / Child 关系 |
display_text |
上下文和引用使用,接近原文 |
embedding_text |
可附加文档标题和章节路径 |
source_block_ids |
反向定位 UDM |
section_path |
章节语义 |
page_start、page_end |
引用位置 |
prev_chunk_id、next_chunk_id |
邻接扩展 |
token_count、content_hash |
预算控制和增量重建 |
acl_version |
权限索引版本 |
embedding_text 中补充的标题不能作为原文引用,因此必须与 display_text 分开保存。
6.3 初始 Token 基线
以下数值只用于启动,最终由真实评测集决定:
| 内容类型 | 目标 Token | 最大 Token | 重叠方式 |
|---|---|---|---|
| 制度、手册 | 450~700 | 900 | 前后 1~2 句 |
| FAQ | 一组问答 | 600 | 不跨问答 |
| 法律条款 | 一条或一组关联条款 | 800 | 携带章、节 |
| 表格 | 300~600 | 800 | 每块重复必要表头 |
| 代码 | 一个函数或小类 | 800 | 携带路径、类名和签名 |
| Parent Chunk | 1200~2000 | 按生成预算 | 默认不参与向量召回 |
Chunk 太小会丢失完整证据,太大会稀释语义;重叠过大会让 Top K 被相邻副本占满。
6.4 专用分块规则
| 内容 | 规则 |
|---|---|
| 普通正文 | 不跨一级章节;超长段落再按句子拆分 |
| 大表格 | 按行组切分,每块携带 Caption、完整表头和适用脚注 |
| 多级表头 | 展开为完整列路径,例如“华东 / 2026 / 销售额” |
| FAQ | 问题与答案永不分离,问题加入检索文本 |
| 操作步骤 | 优先整体保留;切分后携带任务标题和前置条件 |
| 代码 | 按 AST 的类和函数边界;超长函数才按逻辑块拆分 |
| 图片与图表 | 说明文字、Caption 和图片引用保持关联 |
6.5 增量重建
Chunk ID 由文档版本、分块配置指纹、来源 Block 范围和内容哈希稳定生成。
| 变化 | 处理 |
|---|---|
| 正文和配置完全相同 | 复用 Embedding |
| 正文变化 | 重新 Embedding |
| 位置变化但正文相同 | 复用向量,更新位置和顺序 |
| ACL 变化 | 不重算向量,只更新索引 Payload |
| 分块配置变化 | 生成新 Chunk 和配置指纹 |
6.6 分块验收
重点检查 Token 分布、碎片率、跨章节合并率、表头丢失率、相邻重复率和黄金问题 Recall@K。平均 Chunk 长度不能代表分块质量。
七、Embedding 调度
7.1 调度流程
flowchart LR
Pending["待处理 Chunk"] --> Cache{"向量缓存命中?"}
Cache -->|"是"| Reuse["复用向量值"]
Cache -->|"否"| Queue["有界优先级队列"]
Queue --> Pack["按 Item 数 + Token 数合批"]
Pack --> Limit["RPM / TPM 双维限流"]
Limit --> Semaphore["并发槽"]
Semaphore --> Provider["云端 API / 本地推理服务"]
Provider --> Check{"结果校验"}
Check -->|"通过"| Checkpoint["批次 Checkpoint"]
Check -->|"429 / 5xx"| Backoff["退避并重新计入限额"]
Check -->|"非法单条"| Isolate["二分定位坏 Chunk"]
Check -->|"维度 / NaN 异常"| Stop["停止该配置发布"]
Backoff --> Limit
Isolate --> Queue
Reuse --> Index["STAGING 索引"]
Checkpoint --> Index
7.2 动态合批
一个 Batch 同时满足:
- Item 数不超过
max_batch_items - 总 Token 不超过
max_batch_tokens - 单个 Chunk 不超过
max_input_tokens
固定“每 100 条一批”不可靠。短 FAQ 和长制度 Chunk 的请求大小可能相差几十倍。Token 数应使用目标 Embedding 模型对应的 Tokenizer 预计算。
7.3 并发与速率是两个控制面
Semaphore 只限制同时飞行的请求,不能保证 RPM 和 TPM 不超限,因此发送前必须同时获取:
- 一个请求配额
- 本批 Token 配额
- 一个并发槽
初始并发可根据 RPM、TPM、平均 Batch Token、请求 P95 和服务端硬上限估算,并预留约 20% 抖动空间。运行中根据 429、队列时延和 P95 逐步调整。
任务队列必须有界。不能把数百万个 Chunk 一次性加载进内存或创建等量异步任务。
7.4 云端与本地模型
| 场景 | 调度重点 |
|---|---|
| 云端 API | RPM、TPM、连接并发、Retry-After 和成本 |
| 本地 GPU | 显存、动态合批窗口、模型副本和设备利用率 |
| 在线查询 | 高优先级、低时延、小批次 |
| 文档入库 | 普通优先级、追求吞吐 |
| 全库重建 | 低优先级,只使用剩余资源 |
本地模型由每个推理副本维护有界队列,在短时间窗口内动态合批。不要让多个 Worker 无限制并发调用同一个模型进程。
7.5 错误处理
| 错误 | 处理 |
|---|---|
| 429 | 遵循 Retry-After,降低速率和并发 |
| 网络超时、408、5xx | 有上限指数退避并增加随机抖动 |
| 401、403 | 立即停止队列,修复配置 |
| 请求体过大 | Batch 二分 |
| 单条输入过长 | 返回分块阶段修复,禁止静默截断 |
| 单条输入非法 | 二分定位,其他 Chunk 继续 |
| 数量、维度、NaN、Infinity 异常 | 禁止写入并停止该模型配置发布 |
每次重试都是新请求,必须重新计入 RPM 和 TPM;退避期间释放并发槽。
7.6 配置指纹、缓存与断点续跑
Embedding 配置指纹至少包含:
- Provider、模型 ID 和模型修订版本
- 向量维度、距离度量和归一化方式
- 最大输入 Token
- Document / Query 指令模板
- Tokenizer 和文本预处理版本
缓存键由规范化检索文本和配置指纹生成。缓存只复用向量值,不复用 Chunk ID、ACL、页码和生效时间。
每个 Batch 成功后立即记录 Checkpoint。Worker 崩溃后只扫描未完成 Item,不重算整份文档。
八、索引构建与发布
8.1 状态机
flowchart LR
Uploaded["UPLOADED"] --> Preflight["PREFLIGHT"]
Preflight --> Parsing["PARSING"]
Parsing --> Cleaning["CLEANING"]
Cleaning --> Chunking["CHUNKING"]
Chunking --> Embedding["EMBEDDING"]
Embedding --> Indexing["INDEXING"]
Indexing --> Validating["VALIDATING"]
Validating --> Ready["READY"]
Ready --> Published["PUBLISHED"]
Preflight -.-> Failed["FAILED / QUARANTINED"]
Parsing -.-> Failed
Cleaning -.-> Failed
Chunking -.-> Failed
Embedding -.-> Failed
Indexing -.-> Failed
Validating -.-> Failed
每个阶段记录输入输出哈希、Artifact 地址、配置指纹、耗时、指标、错误码和重试次数。修复后从失败阶段继续。
8.2 阶段级幂等
| 阶段 | 幂等维度 |
|---|---|
| 解析 | 文档版本 + Parser 指纹 |
| 清洗 | 解析产物哈希 + Cleaner 指纹 |
| 分块 | 清洗产物哈希 + Chunker 指纹 |
| Embedding | Chunk 内容哈希 + Embedding 指纹 |
| 索引 | Index Version + Chunk ID |
| 发布 | 预期当前版本 + CAS |
8.3 STAGING 与原子发布
sequenceDiagram
participant W as Ingestion Worker
participant I as STAGING Index
participant V as Validator
participant DB as Metadata DB
participant Q as Query Service
W->>I: 写入新文档版本
W->>V: 提交 Chunk / Vector Manifest
V->>I: 核对数量、维度和抽样召回
V-->>W: 校验通过
W->>DB: CAS 切换 current_version
DB->>DB: content_revision + 1
Q->>DB: 查询权威 current_version 与 ACL
W-->>I: 延迟回收旧版本
发布前新版本不能通过权威版本校验;发布后旧版本不能通过校验,因此一次回答不会混用同一文档的新旧版本。
index_version 表示整代索引结构,通常在模型、维度或 Schema 变化时切换;content_revision 表示当前索引代内的内容和 ACL 修订,用于缓存失效。普通文档更新不需要重建整代索引。
九、最小数据模型
文章不展开完整 DDL,只保留四类核心记录:
| 记录 | 必备字段 | 关键约束 |
|---|---|---|
| 文档版本 | 文档 ID、版本、原文哈希、对象地址、MIME、状态、各阶段指纹 | 文档 ID + 版本唯一 |
| 阶段产物 | 阶段、输入输出哈希、配置指纹、Artifact 地址、质量指标 | 同输入和配置只能有一个有效产物 |
| Chunk Manifest | Chunk ID、顺序、Parent、正文哈希、Token、来源 Block、章节和页码 | 文档版本 + 顺序唯一 |
| Embedding 任务 | Chunk ID、模型指纹、状态、优先级、租约、重试和错误 | Chunk + 模型指纹唯一 |
Worker 通过租约领取任务。进程崩溃后租约过期,其他 Worker 可以继续处理,避免任务永久停留在 RUNNING。
十、可观测性与质量评测
10.1 分层指标
| 层级 | 重点指标 |
|---|---|
| 解析 | 有效字符、漏页、阅读顺序、标题层级、表格有效率、OCR 置信度、回退率 |
| 清洗 | 删除比例、Operator 变更数、噪声保留率、正文误删率、隔离率 |
| 分块 | Token 分布、碎片率、重叠率、表头丢失率、跨章节率、Recall@K |
| Embedding | 队列时延、Batch Item、Batch Token、Tokens/s、缓存命中、429、重试和成本 |
| 发布 | Manifest 差异、校验失败、CAS 冲突、入库到可检索时延 |
每份文档使用统一 Trace 串联预检、解析器路由、清洗 Operator、分块、Embedding Batch、索引校验和发布。普通日志不记录完整敏感正文。
10.2 黄金文档集
黄金集应覆盖:
- 文本型、扫描型和混合型 PDF
- 双栏、跨页表格、脚注和水印
- DOCX 标题与表格
- PPTX 文本框与备注
- XLSX 多工作表与合并单元格
- Markdown 代码块和表格
- 公式、中英混排和长列表
- 损坏、加密、伪造和超限文件
每次 Parser、Cleaner、Chunker 或 Embedding 配置变化,都必须重跑同一批黄金文档和黄金问题。
10.3 变更门禁
flowchart LR
Change["配置或模型变更"] --> Golden["重跑黄金文档"]
Golden --> Compare{"质量、检索、时延、成本达标?"}
Compare -->|"否"| Reject["拒绝发布"]
Compare -->|"是"| Gray["小知识库灰度"]
Gray --> Staging["构建 STAGING"]
Staging --> Observe{"在线指标稳定?"}
Observe -->|"否"| Rollback["回滚"]
Observe -->|"是"| Publish["全量发布"]
十一、落地顺序与验收
11.1 分阶段实施
| 阶段 | 交付内容 | 验收重点 |
|---|---|---|
| 解析闭环 | Preflight、Parser Router、MinerU、MarkItDown、内置解析器、UDM | 能发现静默解析错误 |
| 清洗与分块 | Operator Pipeline、结构化 Chunker、Parent / Child、来源定位 | 清洗可回放,正确证据可独立召回 |
| Embedding 与发布 | 动态合批、双维限流、Checkpoint、STAGING、CAS | 崩溃可续跑,新旧版本不混查 |
| 规模化 | 资源池隔离、多租户配额、灰度和质量看板 | 在线查询不受离线重建影响 |
11.2 上线前必须满足
- 解析器能力来自当前部署快照,质量差时能回退或隔离
- 原文、解析结果、清洗结果和 Chunk 均可追溯
- 清洗不会静默覆盖原文或删除高风险内容
- 表格、FAQ 和代码使用专用分块规则
display_text与embedding_text分离- Batch 同时限制 Item 数、总 Token 和单条 Token
- 并发槽、RPM 和 TPM 同时受控
- 重试、缓存、Checkpoint 和索引写入均幂等
- 新版本只写 STAGING,通过校验后 CAS 发布
- 黄金文档和黄金问题进入变更门禁
十二、总结
生产级 RAG 入库的关键不是堆叠解析器,而是建立一条可验证的数据生产线:
- MinerU、MarkItDown 和内置解析器按能力与质量路由
- UDM 隔离解析器差异并保留来源
- 清洗以可审计 Operator 处理噪声和结构
- 分块以文档结构为先、Token 预算为后
- Embedding 同时控制批量、速率、并发和版本
- 新索引通过 STAGING 校验后原子发布
这条链路稳定后,检索和生成优化才有可信的数据基础。