做知识库抽取这几年,PDF解析一直是我花了最多时间调教的一环。早先用的方案说白了都是“文字搬运工”:把PDF里的字符抠出来,按坐标拼回段落,图片和表格只能另做处理。最让我没法忍受的是PDF里那些带跨行、跨页的表格,抽出来的结果要么全部挤成一坨,要么多列变一列,交给下游做RAG也好、做结构化存储也好,效果都一言难尽。直到我接触并系统用上Docling之后,才发现把文档“读对”和“读出来”是两件完全不同的事。
Docling是IBM开源的一个文档转换工具,它做的不是简单的文本抽取,而是把PDF、Word、PPT、Excel甚至图片中的版面结构——标题、段落、表格、图片、公式、阅读顺序——整体解析出来,输出成结构化的Markdown或JSON。简单说,它比传统解析工具多做了两件事:一是识别版面结构,二是还原阅读顺序。这个能力对做RAG知识库、文档结构化管理、批量转换这类场景来说,价值非常大。
这篇文章我会从核心机制、安装实操、输出格式取舍、踩坑记录、工具选型五个方面展开。不管你是做文档解析、知识库构建,还是纯想把一批PDF批量转成Markdown,里面都有可以直接参考的东西。
1. 为什么我最终把Docling放进了文档解析管线
先说说之前工具链的痛点,不然你体会不到Docling解决了什么真问题。我早先用的是PyMuPDF加自研规则:先用fitz把页面里的文本块取出来,然后根据坐标算出块与块之间是同一段还是换段,表格则基本靠正则硬猜边界。这个方案对一些版式规整的期刊论文勉强够用,但遇到营销手册、政府公告、带双栏的学术文献,就会频繁出问题。最常见的是栏目错乱,左栏右栏的文本混在同一段里;其次是表格列腿分叉,表头跟单元格对不上,抽出来之后根本没法回填到数据库里。
后来我意识到,文档解析这个事不能用“抠文字”的思路,得用“看版式”的思路。这就需要一个模型先识别页面里哪些区域是标题、哪些是正文、哪些是表格、哪些是图片,然后再按区域去解析内容。Docling的底层干的就是这样一件事:先用一个布局分析模型对页面做区域分割,再用表格结构模型把表格的行列关系还原出来,最后按特定阅读顺序把文本组装起来。
正因为Docling从设计之初就自带这个“先看版式再抠文字”的管线,我才决定把它放进正式的解析流程里。它对比传统解析工具的差别,可以这样理解:老办法是把一页纸当成一堆随便摆放的文字块,靠坐标猜关系;Docling是先把一页纸当成一个包含标题、段落、图片、表格的版面,再让模型把每个元素的边界和层级关系弄清楚。后面做知识库上传的时候,这段结构化信息能省掉你一大半的清洗工作。
另外要提一点,Docling的输出不只有Markdown一种形态。它内部维护了一个叫DoclingDocument的对象模型,里面记录了页面尺寸、文本元素类型、表格单元格坐标、图片位置这些信息。你既可以把完整结构导出成JSON,也可以只导出成干净的Markdown,这就给下游系统留了很大的弹性。如果你做RAG,可以直接把JSON里的层级信息喂给分割策略;如果想发布成文档,Markdown就足够了。
2. Docling核心机制:布局分析、表格识别与OCR三段式
这一节看名字可能有点偏理论,但你理解了它的工作原理之后,遇到具体问题就不容易慌,因为你知道问题出在管线里的哪一环。
2.1 布局分析:它怎么知道标题、正文和表格的位置
Docling在解析PDF时,首先会对每个页面做一次布局分析,这一步用的是基于深度学习的版面分割模型,模型训练时依托的是DocLayNet数据集——IBM开源的文档布局标注集。这个模型会把页面里每一个视觉区块打上标签,大致包括标题、正文、图片、表格、公式、页眉、页脚、列表项等类型,并给出每个区块的边界框坐标。
这一步的价值在于,文本块不再是孤立的坐标点,而是有了语义角色。比如页眉页脚如果能被识别出来,你就可以在后续流程里选择跳过;再比如公式区块被单独识别出来后,你就不至于把公式符号混在正文里抽出来。对一篇双栏论文来说,布局模型还承担了一个隐含任务:决定阅读顺序。先读左上栏还是先读右上栏,并不是简单按y坐标排序,而是要理解栏目的物理边界。
实际操作中,布局分析的准确率基本决定了整条管线的上限。Docling使用的是深度学习模型而非传统规则,所以它对之前靠规则无法处理的异形版面也要稳定得多。但模型也不是万能的,后面我会专门提到一些它容易栽跟头的场景。
2.2 表格识别:TableFormer和规则方法的本质差异
表格是整个文档解析里最麻烦的部分,因为表格的信息不仅存在文字里,还存在于行列的二维关系中。传统工具处理表格,大都是把单元格文字提出来,然后根据水平线和垂直线去猜测列边界。可现实中的表格经常不带完整的线框——比如用底纹分隔行、用缩进表示层级,或者单元格合并、跨行跨列,这些都会让线框派工具当场“瘫痪”。
Docling里的表格结构识别走的是另一条路。它用的是Transformer结构的模型,Google的TableFormer也经常在这个语境里被提到。这类模型的输入是表格区域里的视觉特征和文字特征,输出是每个单元格的行号、列号,以及跨行跨列信息。换句话说,模型是把整个表格当成一幅图像和一个文本矩阵看,而不是死板地追踪表格线。
我在实测里感受最深的是,对于带跨行合并的“总分总”类表格,Docling的还原效果比PyMuPDF加规则高出一大截。Markdown输出时它会自动生成对应的行span和列span,结构基本和原PDF一致。
2.3 OCR不是必须,但多数中文扫描件绕不开
Docling对文本型PDF可以直接从自带的文本层读内容,不需要OCR。但如果PDF本身是扫描件——没有文本层,只有图片——你就必须让OCR介入。Docling把OCR作为管线中的一个可选后端来设计。你可以配置ocr开关,也可以用不同的OCR引擎来跑文字识别。
在这条管线里,OCR识别的文字会被当成“页面上某区块内的文本”放回布局模型给出的框里,所以即使整页是扫描图,只要布局分析能分出标题和正文的区域,OCR结果依然能保持版式结构。这一点非常关键,因为很多独立的OCR工具只输出“文字流”,不会保留标题、正文、表格的分层关系。
就我个人经验来说,中文扫描版PDF在Docling里需要把OCR模式打开,而且要选对后端。关于不同OCR后端的差异,我在第五节的踩坑部分会展开讲。
3. 从安装到跑通第一个文档:CLI和Python API实操
谈到工具,上手门槛往往是第一道坎。Docling的安装不算复杂,Python环境准备好,一条pip命令就能往里拉,但模型下载和初次推理往往会卡住新手,这里把整个流程完整走一遍。
3.1 环境准备和初次模型下载
Docling是基于Python的库,建议单独建一个虚拟环境,避免和项目里其他包产生依赖冲突。安装命令很直接:
pip install docling装好之后,首次调用解析时会自动从线上拉取模型权重,包括布局分析模型、表格结构模型,以及你选择的OCR引擎模型。这几个模型加起来有好几百MB,第一次跑会明显感觉卡了很久,那不是程序死了,而是在下载模型。
为了不让后续解析频繁等待,我建议第一次先用一个小文件跑一遍,让模型全部落地到本地缓存,之后再批量处理就顺了。如果你用GPU,Docling会自动走CUDA加速,CPU也能跑,但速度会慢不少,这个后面说。
3.2 命令行模式:一条命令完成转换
Docling自带命令行工具,装好包之后可以直接在终端里跑。最简单的用法是把单个PDF转成Markdown:
docling input.pdf默认情况下,输出文件会和源文件在同一目录下,生成一个同名Markdown文件。如果你想指定输出目录,可以加-o参数:
docling input.pdf -o ./output_dir命令行对批量转换也很友好,可以一次传入多个文件:
docling file1.pdf file2.docx file3.pptx --to md -o ./output_dir这里注意,Docling不止能处理PDF,Word、PPT、Excel、图片这些格式它也能读。我日常用得最多的是PDF,但偶尔会把Word报告直接丢给它转Markdown,体验很顺。命令行里加--to参数可以指定输出格式,除了md,还支持json和html。
3.3 Python API:把解析能力嵌进你自己的流程
如果你的需求不是一次性的转换,而是要对接自己的系统,用Python API会更灵活。核心用法其实就两行:
from docling.document_converter import DocumentConverter converter = DocumentConverter() result = converter.convert("input.pdf") doc = result.documentconvert返回的结果里,.document就是一个DoclingDocument对象。接下来你可以按需导出:
# 导出为Markdown文本 md_text = doc.export_to_markdown() # 导出为完整结构的JSON json_data = doc.export_to_dict()如果你在做一个批量处理程序,我习惯的做法是逐文件convert,然后立刻把Markdown和JSON都落盘,后面要用哪种都方便。还需要说明的是,convert方法支持传入本地路径,也支持传入HTTP链接,我试过直接解析线上PDF链接,效果一样。
另外,和LangChain的集成也是现成的,LangChain里有个DoclingLoader,直接加载DoclingDocument并切分成Document块。如果你做RAG,这一篇接一篇串起来很省事。
4. 输出Markdown和JSON的取舍:给下游喂什么数据最合适
Docling的输出能力很强,但“输出强”不等于“用得对”。很多人在这一步会踩坑:把Markdown当万能格式到处喂,或者把所有解析结果都存JSON,结果下游处理起来反而变慢。这一节聊聊两种格式的真实差异,以及我的取舍逻辑。
4.1 Markdown的定位:给人和大模型看
从Docling导出的Markdown和传统PDF抽取工具给出的Markdown有个明显区别:表格不再是碎掉的文本,而是真正的Markdown表格语法;标题层级会被还原成#级别;图片会以占位符或引用形式保留;列表也保持嵌套关系。这相当于把视觉版面变成了语义层次。
如果你做RAG,直接把这种Markdown喂给分割器,效果会很好。因为语义层级已经天然存在,标题和正文不会揉在一起,表格也能作为整块内容进入向量库。实测下来,召回时对“某个表格里的数值”这类问题,回答准确率明显比文本流方案高。
4.2 JSON的价值:给系统和数据库用
如果你要做的不是问答,而是把文档结构化后入库,那么JSON才是更完整的形态。export_to_dict()导出的JSON会包含页面信息、文本元素、表格单元格的坐标和行列归属,甚至每个区块的边界框。这些信息足够你还原出一份接近原版式的数据结构。
比如你要把解析后的文档录入知识管理数据库,JSON里的表格行列信息可以直接映射成数据库表;而Markdown里的表格就做不到这么细,你还得额外写一个解析Markdown表格的模块。
我的建议是:面向人阅读、面向大模型生成,用Markdown;面向系统存储、面向程序消费,用JSON。项目里最稳的做法是两种都导出,因为体积都不大,但下游可选择的空间就大了。
4.3 批量处理时怎么组织输出,避免文件名冲突
批量处理时有个小麻烦:Docling输出的文件名默认和源文件保持一致,但如果你同时处理a.pdf和a.docx,Mercy覆盖风险就来了。我现在的做法是输出目录里按源文件扩展名再分一层,或者在代码里拼一个带原格式前缀的新文件名:
out_path = output_dir / f"{stem}.md"另一个经验是,批量转换前先把文件按类型分好批次,PDF一批、Word一批、图片一批。这样做最大的好处是,如果某类文件触发了Bug,你可以精准定位,而不是整批全部失败。
5. 实战中反复踩到的坑,以及绕坑方案
任何工具都有脾气,Docling也不例外。我把它用在生产管线之后,前后踩过不少坑,挑几个有代表性的列出来,给后来者省点时间。
5.1 扫描版PDF默认不跑OCR,抽出来是空文本
最容易迷惑人的坑就在这里。Docling对“有文本层的PDF”默认不开启OCR,它直接读文本层数据。但如果PDF是扫描版,文本层压根不存在,你又不主动开OCR,它就只会返回图片区块信息,Markdown里整页基本是空的。
解决办法是在PipelineOptions里把OCR打开。在Python API里可以这么做:
from docling.document_converter import DocumentConverter, PipelineOptions options = PipelineOptions(ocr=True) converter = DocumentConverter() result = converter.convert("scan.pdf", options=options)如果是命令行,也有对应的参数控制OCR开关。这里提醒一下:OCR打开之后,运行时间会明显变长,没有GPU的话,一本几百页的扫描书会跑到你怀疑人生。
5.2 中文PDF的OCR识别率不稳
Docling默认接入的OCR后端对中文的支持不能说不好,但肯定不如专门的国产OCR引擎。我拿一批中文扫描版PDF做测试,部分字会识别错,尤其是繁体、异体字以及表格里的窄体字。建议是,如果你的扫描件是中文,可以考虑切换OCR后端,或者在Docling出结果后,再用一个专门的中文OCR跑一遍关键字段做校验。
如果你接受二段式处理,还有一个思路:先用Docling做版面分析和表格结构识别,再把每个区块裁出来交给更专业的中文OCR识别。这种方案比整体跑Docling慢,但准确率上限更高。
5.3 表格复杂到一定程度,结构识别会翻车
Docling的表格识别虽然比传统工具强,但它不是无敌的。遇到合并单元格特别多的“大乱表”,或者表格里套着小表格,输出结果偶尔会出现行列错位。更常见的场景是表格里只有一个单元格跨了多行,表头被自动拆成了重复列。
这类问题没有银弹。我现在的处理策略是:表格识别结束后,自动统计一下每个表格的单元格数量和行列跨度,如果发现异常——比如单行跨度超过5列——就把这个表格标记出来,走人工复核。Docling输出的JSON里带了坐标和行列信息,这个校验逻辑写起来不算难。
5.4 阅读顺序对双栏、页眉页脚依然有失灵案例
Docling对阅读顺序的处理已经在向“按版面视觉流”靠拢了,但双栏论文偶尔还是会乱序。特别是在左边栏底部和右边栏顶部有插图、公式栏插入的情况下,模型容易把左右两栏的内容按z字形混合起来读,导致段落断裂。
解决思路是,对这类论文我通常在做完Docling解析后,先看一下输出的段落顺序是否正确,如果发现乱序,就用它JSON里的坐标数据做一次重排。坐标虽然不能完全代表语义顺序,但配合区块类型,能解决大多数乱序问题。
另外,页眉页脚有时候会混进正文。Docling的布局模型虽然能把页眉页脚识别成独立区块,但转换成Markdown时,这些区块有时仍会保留。如果你想彻底干净,需要在导出后做一层后处理,去掉页眉区域对应的文本行。没有现成参数能一键过滤,是我比较遗憾的地方。
6. 和其他工具对比后,Docling适合什么场景
最后聊一下工具选型。市面上的文档解析方案不少,每个都有一批忠实用户,但侧重点完全不一样。我只挑几个有代表性的做比较,方便你判断Docling在哪类场景里是更优解。
6.1 常见替代方案优缺点对照
| 工具 | 核心手段 | 优势 | 短板 |
|---|---|---|---|
| PyMuPDF | 规则+坐标提取 | 快、轻量、可控性强 | 版面结构理解弱,表格基本靠猜 |
| PaddleOCR / PP-Structure | OCR+版面分析 | 中文识别强,表格还原不错 | 部署较重,管线复杂度高 |
| Unstructured | 分区提取,面向RAG | 上手快,各种格式都接 | 复杂表格和多栏处理一般 |
| Marker | 深度学习转Markdown | 输出干净,适合直接喂LLM | 自托管队列和模型更新问题较多 |
| Docling | 深度学习版面+表格识别 | 结构化强,JSON信息完整,多格式统一 | 速度不算顶级,全流程定制门槛有 |
这张表不是想论证Docling“全行业第一”,而是想说明每个方案的取舍点。PyMuPDF胜在轻和快,适合对结构要求不高的场景;PaddleOCR胜在中文识别精度,适合扫描版中文文档;Docling胜在版式结构信息丰富,尤其适合需要精确保留表格关系、做结构化入库或者喂RAG的场景。
6.2 我现在的建议用法和场景判断
如果你准备做RAG知识库,Docling是我目前比较推荐的起点。原因有三个:一是它能把表格作为整体结构送给向量化模型,减少了“表格被撕碎”导致的召回偏差;二是输出的JSON里有坐标和语义角色,方便你在分割策略里按标题层级做切片;三是它对Word、PPT、PDF一视同仁,能统一你公司内部的文档处理管道。
如果只是每天几十个PDF需要快速转Markdown做简单问答,那用轻量工具完全够,不需要动用深度学习管线。判断标准就是一句话:你的下游是否需要“版面结构”这个信息。需要,就上Docling;不需要,就选更轻的方案。
另外补充一点,Docling的模型更新迭代挺快的,建议定期升级版本。我遇到过某个旧版本对特定版面解析效果特别差的情况,升级之后直接缓解,这类问题优先级很高。
以我用了大半年的体感来说,Docling已经成为我文档解析流程里一个固定环节。它不是没有毛病——速度一般、复杂版面偶尔会错、页眉页脚过滤缺失——但在“输出结构化信息”这个核心指标上,它确实给项目带来了质的改变。如果你的工作也卡在“PDF抽出来结构稀烂”这个坎上,值得花一个下午把Docling跑通,再对照它输出的JSON看一页PDF,你就明白我说的“先看版式再抠文字”到底好在哪了。