关注最新技术的发展和应用落地,聚焦性能优化与架构设计,欢迎关注!
一、文档解析
文档解析技术的本质在于将格式各异、版式多样、元素多种的文档数据,包括段落、表格、标题、公式、多列、图片等文档区块,转化为阅读顺序正确的字符串信息。高质量的文档解析能够从各种复杂格式的非结构化数据中提取出高精准度的信息,对 RAG 系统最终的效果起决定性的作用。
1.文档解析的目标
解析不只是“把文件变成字符串”,它需要尽量保留:
文本内容。 标题层级。 段落、列表、代码块和表格边界。 页码和版面位置。 图片标题、表格标题和脚注关系。 文档来源、版本、更新时间与访问权限。
推荐将各种格式转换成统一文档模型,再做 Chunking。Docling 的 DocumentConverter 支持 PDF、Markdown、HTML、DOCX、XLSX、PPTX、CSV 和图片等格式,并输出统一的 DoclingDocument。
from docling.document_converter import DocumentConverterconverter = DocumentConverter()result = converter.convert(”docs/manual.pdf”)document = result.documentprint(document.export_to_markdown())
解析器输出必须带状态。失败、部分成功和完全成功不能混为一谈。
2. PDF 解析
PDF 是视觉排版格式,不天然包含可靠的阅读顺序。常见问题包括:
双栏内容顺序错乱。 页眉、页脚和页码混入正文。 扫描 PDF 没有文本层。 表格被拆成无意义的单词序列。 连字符换行造成单词断裂。 脚注插入正文中间。 图片中的文字需要 OCR。
(1)先区分 PDF 类型
不要对所有 PDF 无条件 OCR,OCR 会增加延迟,并可能把本来正确的文本变成错误结果。
(2)需要保留的定位信息
每个 Chunk 至少保留:
source_uridocument_idpage_numbersection_path原始文档版本或内容哈希
如果需要在 PDF 中高亮引用,还应保存 bounding box 或解析器提供的 provenance。
(3)PDF 质量检查
索引前抽样检查:
页面是否缺失。 字符是否乱码。 标题层级是否基本正确。 阅读顺序是否正确。 表格行列是否对应。 OCR 置信度是否过低。 页码与 Chunk 定位是否匹配。
解析失败的页面应进入隔离队列,不应悄悄索引空文本。
3.Markdown 解析
Markdown 自带标题、列表、表格和代码块结构,应该使用 Markdown AST 或结构化解析器,而不是只按换行切割。
应保留:
# 到 ###### 的标题路径。列表的父子关系。 fenced code block 的语言标记。 表格表头。 链接目标和图片说明。 Front Matter 中的标题、日期、标签和版本。
例如下面的内容:
# 支付服务## 重试规则失败请求最多重试 3 次。
正文 Chunk 应带上 支付服务 > 重试规则,否则“最多重试 3 次”失去语义范围。
4. HTML 解析
网页解析的目标是正文,而不是完整 DOM 文本。
通常需要删除:
script、style、导航栏和页脚。Cookie 提示和广告。 重复菜单。 隐藏元素。
通常需要保留:
页面标题和标题层级。 正文、列表、代码块和表格。 canonical URL。 发布与更新时间。 链接的绝对 URL。 文档语言。
同一网页可能在多个 URL 出现,应优先使用 canonical URL 和内容哈希去重。
对于 JavaScript 动态页面,普通 HTTP 下载可能只有空壳,需要使用浏览器渲染或站点 API。但登录态、robots 规则、版权和访问权限必须由采集层处理。
5.表格与结构化文档
(1)表格
表格不能简单按字符长度切割。每个表格 Chunk 必须保留表头,否则单独一行数值无法解释。
适用策略:
小表格整体保存。 大表格按连续行分块,每块重复表头。 超宽表格按业务相关列分组,但保留主键列。 表格标题、单位、脚注和来源作为 Metadata。 合并单元格需要展开或显式记录层级关系。
Docling HybridChunker 支持表格跨块时重复表头。
(2)CSV、JSON 和数据库记录
结构化数据应先保留 Schema:
字段名。 字段含义。 类型和单位。 主键与时间字段。 数据来源和更新时间。
一行数据库记录未必适合直接转换成自然语言。对于实时库存、订单状态等数据,通常更适合运行时调用数据库或 API,而不是离线 RAG。
(3)Office 文档
DOCX:保留标题、段落、列表、表格和批注边界。 XLSX:保留工作表名、表头、单元格单位和公式结果来源。 PPTX:保留页码、标题、正文以及演讲者备注;不要把视觉上无关的文本框强行合并。
6.文档清洗
清洗应尽量保守。错误清洗会永久破坏证据。
常见操作:
Unicode 规范化。 统一换行符和多余空白。 删除重复页眉和页脚。 修复明确的断行和连字符。 去除空段落。 识别重复页面和重复文档。 保留代码缩进、表格边界和标题层级。
不要轻易执行:
删除所有标点。 删除所有短行。 全局删除数字。 自动改写原文。 把多个表格压成连续文本。
清洗前后都应保存内容哈希、解析器版本和清洗规则版本,以便重建索引。
7. 元数据提取
推荐的 Chunk Metadata:
{”chunk_id”: ”稳定且唯一的标识”,”document_id”: ”文档稳定标识”,”parent_chunk_id”: null,”source_uri”: ”原始文件或页面地址”,”title”: ”文档标题”,”section_path”: ”一级标题 > 二级标题”,”page_number”: 12,”content_type”: ”paragraph”,”language”: ”zh-CN”,”tenant_id”: ”tenant-a”,”visibility”: ”internal”,”source_version”: ”git:8f31c2a”,”content_hash”: ”sha256:...”,”parser_version”: ”docling-x.y.z”,”indexed_at”: ”ISO-8601 时间”}
Metadata 有四个用途:
权限与租户过滤。 时间、产品、语言等业务过滤。 生成 Citation。 更新、删除和索引重建。
权限字段不能只存在于原系统。进入检索索引时也必须带上可执行的权限信息,并在查询时强制过滤。
二、Chunking
1.Chunk是什么
Chunk 就是“数据块”或“内容片段”,是 Chunking(分块)之后得到的单个单元。
好的 chunk 应满足:语义相对完整、大小适中、保留来源和标题等元数据。块太小会缺乏上下文,块太大会降低检索精度并浪费上下文预算。
(1)一个 chunk 通常包含
正文内容 文档名称 标题或章节 页码或位置 唯一 ID 时间、标签、权限等元数据
(2)与 Token 的区别
Token:模型处理文字的最小计量单位之一。 Chunk:人为或程序组织出来的语义片段,由多个 Token 构成。 Document:完整文档,由多个 Chunk 构成。
Document├── Chunk 1│ └── 多个 Token├── Chunk 2│ └── 多个 Token└── Chunk 3└── 多个 Token
简单说:Token 是模型“读取文字”的单位,Chunk 是系统“管理和检索内容”的单位。
2.分块策略
合理的分块能够确保检索到的片段与用户查询信息高度匹配,避免信息冗余或丢失。 分块有助于提升生成内容的连贯性,精心设计的独立语义片段可以降低模型对上下文的依赖,从而增强生成的逻辑性与一致性。 分块策略的选择还会影响系统的响应速度与效率,模型能够更快、更准确地处理和生成内容。
分块策略最大的挑战在于确定分块的大小。如果片段过大,可能导致向量无法精确捕捉内容的特定细节并且计算成本增加;若片段过小,则可能丢失上下文信息,导致句子碎片化和语义不连贯。较小的块适用于需要细粒度分析的任务,例如情感分析,能够精确捕捉特定短语或句子的细节。更大的块则更为合适需要保留更广泛上下文的场景,例如文档摘要或主题检测。因此,块大小的确定必须在计算效率和上下文信息之间取得平衡。
(1)固定长度分块
最基本的方法是将文档按固定大小进行分块,通常作为分块策略的基准线使用。比如按照100、200字符进行分块。
该种方式一般不会进行使用,因为不考虑内容上下文,可能在句子或段落中断内容,导致无意义的文本块。生产中通常先按结构切,再用 Token 上限处理过长块。
(2)重叠分块(Chunk Overlap)
通过滑动窗口技术切分文本块,使新文本块与前一个块的内容部分重叠,从而保留块边界处的重要上下文信息,增强系统的语义相关性。虽然这种方法增加了存储需求和冗余信息,但它有效避免了在块之间丢失关键语义或句法结构。
优点
需要深入理解语义并保持上下文完整性的文档,如法律文档、技术手册或科研论文;
提升分块内容的连贯性,以提高分析质量。
缺点
计算复杂度增加,处理效率降低;
冗余信息的存储和管理成为负担。
使用原则:
固定长度分块通常需要适量 Overlap。 按标题或自然段落分块不一定需要固定 Overlap。 表格重复表头属于结构上下文,不等同于普通文本 Overlap。 检索后必须按 document_id + span去重或合并相邻块。
不要默认 50% Overlap。大量重复通常会降低上下文有效信息密度。
(3)递归分块
通过预定义的文本分隔符(如换行符\n\n、\n ,句号、逗号、感叹号、空格等)迭代地将文本分解为更小的块,以实现段大小的均匀性和语义完整性。此过程中,文本首先按较大的逻辑单元分割(如段落 \n\n),然后逐步递归到较小单元(如句子 \n 和单词),确保在分块大小限制内保留最强的语义片段。
这种方法适用于需要逐层分析的文本文档或需要分解成长片段、长段落的长文档,如研究报告、法律文档等。不过仍有可能在块边界处模糊语义,容易将完整的语义单元切分开。
(4)文档特定分块
根据文档的格式(如 Markdown、或编程语言如 Python 等)进行定制化分割的技术。此方法依据文档的特定格式和结构规则,例如 Markdown 的标题、列表项,或 Python 代码中的函数和类定义等,来确定分块边界。通过这种方式,确保分块能够准确反映文档的格式特点,优化保留这些语义完整的单元,提升后续的处理和分析效果。
(5)语义分块
语义分块通常先把文本拆成句子或小单元,然后计算相邻单元 Embedding 相似度,在主题变化明显的位置切分。
优点:
可以发现没有标题的主题边界。 对访谈、会议记录和长篇叙述有帮助。
缺点:
索引成本高,处理效率降低。 阈值依赖语料和模型。 结果可能不稳定。 容易破坏表格、代码和正式条款结构。
推荐把语义分块作为实验策略,不要默认替代文档结构。对结构化文档,标题和段落边界通常更可靠。
(6)混合分块
混合分块是一种结合多种分块方法的技术,通过综合利用不同分块技术的优势,提高分块的精准性和效率。例如,在初始阶段使用固定长度分块快速整理大量文档,而在后续阶段使用语义分块进行更精细的分类和主题提取。根据实际业务场景,设计多种分块策略的混合,能够灵活适应各种需求,提供更强大的分块方案。
实现起来复杂度高,难度大
3.Chunk Metadata
Chunk Metadata 除了文档级字段,还应记录:
chunk_indexsection_pathpage_numberstart_line/end_line或版面位置content_typetoken_countprevious_chunk_id/next_chunk_idparent_chunk_id
parent_chunk_id 支持 Parent-Child Retrieval:用较小的 Child Chunk 做精确召回,再把较完整的 Parent Section 交给模型。它通常比一开始就把所有 Chunk 做得很大更可控。
4.推荐的结构优先策略
先识别标题、段落、表格、列表和代码块↓保留不能拆的结构单元↓合并相邻过短单元↓对过长单元按句子/Token 再切分↓附加标题路径、页码和父子关系
Docling HybridChunker 就采用结构分块后再按 tokenizer 调整大小的思路。
夜雨聆风