做RAG或者知识库预处理的朋友,这两年应该没少在文档解析上花时间。PDF转文本看着简单,真处理起来全是坑:多栏排版乱序、表格结构丢失、公式变成乱码。docling这个开源工具,目标就是把PDF、Word、PPT这些文档干净利落地转成结构化Markdown和JSON,底层布局模型跑在CPU上就能用。这篇文章从安装配置、核心功能、实测体验到RAG场景的接入,完整走一遍,希望能帮你少踩几个坑。
1. 为什么一堆解析工具里,我最终留下了docling
聊docling之前,先说我之前踩过的那些坑。最早做知识库项目,用的是PyPDF2加正则硬抠文本,单栏纯文字排版尚且能用,一旦遇到双栏论文或者带复杂表格的财报,输出基本就废了。后来换过paddleocr,表格识别效果还行,但部署依赖太重,CPU环境下跑起来也慢,更头疼的是输出格式还得自己拼结构。再后来试过unstructured,接口设计不错,但对学术PDF的支持一直差点意思,遇到公式就抓瞎。
docling是IBM开源的一个文档转换工具,老实说第一次用的时候没抱多大期望。结果跑通一个测试文档之后发现,它是真正把“版面分析”这件事做扎实了的工具。核心思路是这样的:先用一个基于RT-DETR的布局模型把页面里的标题、正文、表格、公式、图片这些区域全部识别出来,再对每个区域做精细解析——表格走TableFormer模型、公式走Texify模型,最后统一输出成带层级结构的Markdown或者JSON。
这种“先版面分析,再内容解析”的两阶段架构,就是docling和普通PDF文本提取工具拉开差距的关键。普通工具是“逐行读字”,docling是“先看版式,再读内容”,处理复杂排版自然更稳。
docling适合谁用?我觉得三类人最需要它:一是做RAG知识库的,需要把各种格式的文档变成干净、结构化、可切分的文本;二是做文档自动化处理流程的,需要把PDF/Word/PPT统一转成Markdown给下游用;三是学术场景的,论文PDF里的双栏排版、数学公式、表格,docling的支持都足够友好。
2. 安装和第一个转换任务:开源工具的“婴儿期”难度
docling的安装属于那种“看起来简单,但有几个暗扣”的类型。它的核心安装命令确实是一行pip,但根据你的场景,有几个额外依赖需要提前想清楚。
2.1 基础安装与国内网络环境的依赖处理
pip install docling注意,docling基于pydantic(目前主流版本是v2),如果你已有的项目里用的是pydantic v1,大概率会有冲突。所以要么在一个全新的虚拟环境里装,要么提前把pydantic升级到v2。我第一次就是直接在老项目里装,结果把pydantic从v1升到v2,整个项目十几个模块报了错,花了一下午才收拾干净。强烈建议用虚拟环境隔离。
另外,docling的OCR能力默认走的是EasyOCR,它依赖PyTorch,第一次跑OCR的时候会从网上下载模型权重。国内网络环境下这个下载经常卡壳,建议提前把模型文件下好,或者配置镜像源。还有一个更省心的方案:如果你对OCR的需求不是特别高,可以先不装PyTorch相关的OCR依赖,docling在纯文本提取场景下也能跑,只是遇到扫描版PDF会输出空白。
2.2 跑通第一个转换:命令行和Python两种方式
docling装好之后,最快体验方式是命令行:
docling https://arxiv.org/pdf/2408.09869 --to md -o ./output这条命令会下载一篇arXiv论文PDF,转成Markdown输出到./output目录。实测下来,单页论文大概需要几秒到十几秒的时间(取决于是否启用OCR和公式识别)。第一次跑会下载布局模型权重,同样建议提前解决网络问题。
Python调用的方式也很直接:
from docling.document_converter import DocumentConverter source = "你的文件路径或者URL" converter = DocumentConverter() result = converter.convert(source) markdown_output = result.document.export_to_markdown() print(markdown_output)就这么几行,一个文件就转完了。支持的输入格式包括PDF、Word(.docx)、PPT(.pptx)、Excel(.xlsx)、图片(.png/.jpg)和HTML。对,你没看错,Excel也在支持列表里,后面我专门测了它的Excel转换效果。
这里有个细节值得说:DocumentConverter默认会做完整的版面分析。如果你只是想把PDF里的纯文本快速抽出来,不想跑模型,可以显式关闭版面分析:
from docling.datamodel.base_models import InputFormat from docling.datamodel.pipeline_options import PdfPipelineOptions pipeline_options = PdfPipelineOptions() pipeline_options.do_ocr = False pipeline_options.do_table_structure = False pipeline_options.do_code = False converter = DocumentConverter(pipeline_options=pipeline_options)关闭之后速度会快很多,适合处理那些格式简单、不需要深度解析的文档。需要说明的是,这些选项耗时数据是基于我自己的实测经验结合社区反馈整理的,不同机器上会有差异,仅供参考。
3. 核心能力拆解:版面分析、表格、公式和OCR的实际表现
docling让我留下来的核心原因,就是它在几个硬骨头能力上真的有东西。下面逐个拆开说。
3.1 版面分析:Layout模型如何识别双栏、标题和图片
版面分析是docling的基石能力。它用的布局模型基于RT-DETR,一个实时目标检测模型,docling团队专门在文档版面数据集上做了训练,能识别标题(Title)、正文(Text)、表格(Table)、公式(Formula)、图片(Figure)、页眉页脚(Header/Footer)、页码(PageNumber)等区域类型。
处理双栏PDF时,普通文本提取工具最大的问题就是左右两栏的文字会混在一起,读起来完全是乱的。docling靠布局模型先框出每一栏的区域,再按照阅读顺序重新排列内容,输出的Markdown自然就是先左栏后右栏的顺序。
我实测了一份双栏论文,左边是正文、右边是图注,docling输出完全正常——左栏读完了才读右栏,一点没串。这一点比我之前用过的所有开源工具都稳。
另一件让我惊艳的是它能把页眉页脚自动剔除掉。之前用pypdf提取论文文本,每页开头都带着期刊名和作者名,后期清洗得写一堆正则。docling直接通过布局模型识别出Header区域并忽略,输出的干净度大幅提升。
3.2 表格:TableFormer模型对复杂表格的还原度
表格是文档解析的重灾区。文字提取工具把表格转成文本流之后,行列关系基本全丢了;普通OCR方案能框出表格区域,但单元格内部的文本还是散的,合并单元格更是无从谈起。
docling的表格识别走的是TableFormer模型,专门做表格结构识别(TSR,Table Structure Recognition),能识别复杂的列合并、行合并场景,并输出HTML格式的表格结构。在转换结果里,表格会以HTML标签的形式嵌入Markdown(见3.4),这样完整保留了行列信息。
我找了份带三线表、带合并单元格的学术论文测了一下,表格结构还原得相当准。用pandas读HTML结果,数据基本上能对齐。当然,如果表格里带着特别复杂的嵌套结构,偶尔也会出错——比如同一行跨了两列的数据被拆到两个单元格里,但这种比例比之前用的工具低太多了。
3.3 公式识别:Texify模型把公式变成LaTeX
公式识别是大多数开源工具的盲区。docling用的是Texify模型,能把公式图片识别成LaTeX代码,直接嵌入Markdown里。
实测下来,对于印刷体的数学公式,比如上下标、分式、根式、求和符号这些,识别精度是够用的。比如下面这个公式:
f(x) = \sum_{n=1}^{\infty} \frac{x^n}{n!}Texify模型能正确识别出LaTeX表达。对于行内公式,docling会用$...$包起来;对于独立成行的块级公式,会用$$...$$包起来,这样下游的Markdown渲染器或者大模型能直接正确解析。
需要提醒的是,公式识别这个功能是默认关闭的,因为跑模型比较慢。如果你处理的文档里带大量公式,需要显式开启do_formula选项,后面第4节会说具体配置。
3.4 输出格式:不仅是一份Markdown
docling的“结构化输出”不止是Markdown这么简单。result.document这个对象在内存里是一个完整的文档树,有层级结构(标题层级、章节顺序)、区块分类(哪些是正文、哪些是表格)、以及表格的结构化表示等。
你可以通过API导出多种格式:
export_to_markdown():带表格HTML和公式LaTeX的Markdown,适合直接喂给大模型export_to_dict()/export_to_json():完整文档树,适合做数据交换和结构化处理export_to_html():HTML格式export_to_document_tree():文档树的可视化,适合调试
JSON格式特别适合做RAG数据源——你可以精确到“某段表格在第几页、它上面是哪个二级标题”这种颗粒度。
3.5 实测Excel转换:比想象中好用
docling的Excel转换能力确实没在官网上重点宣传,但实测效果不错。它会用pandas读取所有sheet表,把每个sheet转换为表格区域,然后以表格列表形式输出到Markdown或JSON中。
这意味着,如果你有一个Excel格式的数据表,docling可以直接把它转换成带表头的Markdown表格,装进RAG知识库的时候,字段语义就保住了。它的转换逻辑会把列名保留在表头,后续切片和检索会更靠谱。
4. 进阶配置:按需开启OCR、公式识别和表格结构
4.1 Pipeline配置全解
docling的文档转换流程叫Pipeline,你可以通过PipelineOptions配置开关。
from docling.datamodel.base_models import InputFormat from docling.document_converter import DocumentConverter from docling.datamodel.pipeline_options import PdfPipelineOptions pipeline_options = PdfPipelineOptions() pipeline_options.do_ocr = True pipeline_options.do_table_structure = True pipeline_options.do_formula = True converter = DocumentConverter(pipeline_options=pipeline_options)几个主要开关的说明:
do_ocr:是否启用OCR识别文字。扫描版PDF必须开启,否则输出空白。默认是Falsedo_table_structure:是否启用表格结构识别。开启后表格会以HTML格式输出,关闭后表格会变成纯文本流,但速度快很多。默认是Falsedo_formula:是否启用公式识别(Texify模型)。默认关闭do_code:是否识别代码块区域。适合处理技术文档do_assembly:是否做内容组装。默认开启,用于把识别结果组装成最终的文档树
还需要注意pdf_backend这个参数,它控制用哪个库解析PDF底层内容,可选值包括pypdf和dlparse_v4。一般保持默认即可,但在特殊PDF上换一个后端可能效果更好。
4.2 OCR引擎选择:EasyOCR之外,还能怎么配
docling的OCR能力默认基于EasyOCR,但EasyOCR对中文的识别精度只能说“能用”,而且模型下载慢、显存占用高。实测发现docling也支持配置OCR引擎,可以在OcrOptions里指定其他引擎。
如果你有GPU,配置PaddleOCR或者Tesseract的体验会更好,尤其是中文材料。不过我在这里不展开说具体配置了,因为版本迭代快,建议以官方文档为准。我自己实际用得比较多的是EasyOCR的默认配置,中文识别率够用,主要是省心。
4.3 加速技巧:用GPU和批处理
在CPU环境下,docling跑一个复杂的PDF(比如带大量表格和公式的论文)可能要一两分钟,GPU能快几倍甚至十几倍。官方文档建议安装支持GPU的PyTorch版本(比如pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121),docling会自动检测并使用GPU。
如果你有一批文档要批量转换,一定要用循环复用同一个DocumentConverter实例。这个实例加载的模型都在内存里,每次重新new一个实例等于重新加载一遍模型权重,耗时可能翻好几倍。以下是我自己在批量场景下用的方式:
from docling.document_converter import DocumentConverter def make_converter(): return DocumentConverter() converter = make_converter() for path in file_list: result = converter.convert(path) text = result.document.export_to_markdown() # 你的后续处理逻辑4.4 混合使用规则
针对不同类型的文档,我建议你采用不同的配置:
| 文档类型 | 建议配置 | 原因 |
|---|---|---|
| 纯文字PDF(书籍/合同) | do_ocr=True | 保证扫描版也能识别 |
| 学术论文PDF | do_table_structure=True, do_formula=True | 保留表格和公式结构 |
| 扫描版文档 | do_ocr=True | 没有OCR就是空白 |
| Word/PPT | 默认配置 | 自带文本层,无需OCR |
| 复杂报表Excel | do_table_structure=True | 保表格行列关系 |
如果你需要高精度表格提取,还可以搭配do_assembly=True,它会根据阅读顺序和层级关系重新组织表格内容。
5. 实战:把docling接入RAG知识库,得到可“喂”给大模型的干净文本
做RAG知识库的人最大的痛点就是文档切分质量。文档解析得越干净,切分就越合理,召回率自然就高。把docling接进来,整个流程会省心很多。下面是我常用的一个处理管线。
5.1 文档层级的清洗与切分
docling输出的Markdown保留了标题层级,天然适合直接喂给切分工具。比如用LangChain或LlamaIndex的MarkdownHeaderTextSplitter,就能根据二级标题、三级标题把长文档切成有语义边界的chunk,而不会硬生生把一个段落拦腰截断。
具体在LlamaIndex里的思路是这样(伪代码示例,版本不同可能有差异):
from docling.document_converter import DocumentConverter from llama_index.core.node_parser import MarkdownNodeParser converter = DocumentConverter() result = converter.convert("你的文件路径") md_content = result.document.export_to_markdown() parser = MarkdownNodeParser() nodes = parser.get_nodes_from_documents([Document(text=md_content)])切出来的node自带层级信息,检索的时候可以按层级过滤,比如只搜二级标题下的内容。
5.2 保留表格的语义:pandas读取JSON导出
对于表格密集型的文档(比如财报、说明书),只有Markdown不够,最好把表格单独拆出来转换成DataFrame。docling的JSON导出里,表格是独立的结构化节点,没有和正文混在一起。这意味着你可以只把表格部分的JSON节点用pandas读成DataFrame,再转入向量库;正文部分照常走文本Embedding。表格和正文用不同的检索策略,在RAG场景下效果会好很多。
5.3 处理扫描版PDF和图片类知识
在知识库场景里,扫描版PDF特别常见。docling开启OCR之后,可以把扫描件里的文字识别出来再进入后续流程。但这里我要给个诚实的提示:OCR有误识别率,如果你对准确率要求极高,建议OCR之后加一道人工抽检环节,或者搭配一个规则清洗层。别指望OCR输出是100%准确的,尤其是中文手写体或者表格里的密集数字。
5.4 一个完整的最小可用链路
我在实际项目里跑通的一个最小链路大致是这样:
- 读取文件列表,逐个调用docling转换
- 导出Markdown文本
- 按标题层级切分成chunk
- 将chunk转为Embedding,存入向量库
- 查询时先检索相关chunk,再拼接Prompt发送给大模型
这套链路跑起来之后,我知识库的召回质量明显提升,核心原因是:切分单元从“平铺的文本流”变成了“带结构的语义块”。
6. 避坑指南:我在这几个地方卡过壳,提前帮你排掉
6.1 Transformer相关依赖导致的安装崩溃
如果你遇到pydantic_core相关报错,基本都是版本冲突问题。建议在一个全新虚拟环境中安装,避免老项目的包版本互相干扰。另外,有些老机器的glibc版本过低会导致某些wheel包安装失败,此时可以尝试用pip install --no-cache-dir docling绕过缓存问题。
6.2 优先级:先跑通小文件,再上大文件
第一次用docling时,我直接丢给它一份几十页的大PDF,结果等了很久没反应,以为卡死了。后来才发现它在默默下载模型权重。所以建议:第一次运行先拿一个小文件跑通全流程,确认权重下载完成、输出正常之后,再处理大规模文档。
6.3 CPU环境下的超时和内存问题
在CPU环境下解释大PDF时,如果文档非常复杂(比如每页都有大量超高分辨率图片),内存占用可能飙得很高,甚至OOM。建议在Pipeline配置中限制图片分辨率:
pipeline_options.images_scale = 2.0表示图片缩放比例,数值越低内存占用越小,但对小字号文字的识别效果会有影响。这个参数需要根据你的文档情况去试。
6.4 复杂PDF的特殊处理
有些PDF的排版极其杂乱(比如多级嵌套表格、跨页表格、特殊字体),docling偶尔也会“翻车”。遇到这种情况,先别急着换工具,试试切换pdf_backend,有时同一个文件换一个解析后端结果完全不同。
另外,扫描版PDF如果清晰度不够,建议先用图像处理工具增强(提高对比度、去除噪点),再喂给docling。OCR的精度和原图质量强相关,这是所有OCR工具的共性。
6.5 不要忽略验证环节
在任何自动化文档解析流程里,一定要有验证环节。docling的输出虽然质量高,但也不是100%完美。建议定期抽样检查关键文档的Markdown输出,确认表格结构没有错乱、公式LaTeX没有语法错误。这些错误在源文档里可能是很小的格式异常,但下游大模型拿到的就是完全不一样的内容。
7. 横向对比:docling vs 其他主流解析方案
这里做一个比较客观的横向对比,帮大家在工具选型时心里有数。
| 工具 | 版面分析 | 表格还原 | 公式识别 | OCR | 输出格式 | 上手难度 |
|---|---|---|---|---|---|---|
| docling | 强 | 强 | 支持 | 支持 | Markdown/JSON/HTML | 低 |
| PyPDF2 + 正则 | 无 | 无 | 无 | 无 | 纯文本 | 低 |
| PaddleOCR | 中 | 中 | 无 | 强 | 文本框/表格 | 高 |
| unstructured | 中 | 中 | 无 | 中 | 文本/JSON | 中 |
| MinerU | 强 | 强 | 支持 | 支持 | Markdown/JSON | 中 |
从这张表能看出来,docling最大的优势是:版面分析、表格还原、公式识别、OCR全都有,且统一输出结构化格式,API也比较简洁。MinerU在某些学术场景下表现也很好,但整体生态和API设计目前docling占优。
选型建议很简单:如果你的内容以学术论文、财报、说明书这类带复杂排版的文档为主,docling是当前开源方案里综合体验最好的选择之一。
8. 一个容易被忽略的小功能:保留Base64图片并嵌入Markdown
最后分享一个小技巧。docling在解析文档时,会默认提取图片并保存到本地目录,同时在Markdown里用相对路径引用。如果你想把Markdown作为单个文件传给下游(比如塞进向量库或发给大模型),图片路径就会断掉。
解决方案很简单:开启export_to_markdown()的图片内嵌选项,让图片以Base64编码直接嵌入Markdown。这个特性在docling 2.x版本中可用,具体API是:
markdown_with_images = result.document.export_to_markdown(image_mode=ImageExportMode.REFERRED) # 需要将图片转换base64嵌入时,使用ImageExportMode.EMBEDDED这样做带来的好处是:单文件自带完整上下文,尤其适合做RAG检索时的输出准备。缺点是文件会变大很多,Base64会把二进制体积增加约33%。我自己的用法是:需要喂大模型的高频文档用内嵌模式,长期存储用外链模式,兼顾效率与存储成本。
还有个配套细节:图片资源提取时可以自定义目录前缀和资源目录。比如:
result = converter.convert(source, resource_dir="assets", image_prefix="assets/")这样项目结构更清晰,其他脚本也好引用。
最后再聊几句实在的。docling这个工具,最打动我的不是某一个单项能力,而是“通盘皆稳”。它不像某些工具那样表格识别超强但公式完全不能看,也不像另一些工具那样文本提取干净但遇到表格直接崩。它会把你丢给它的文档,稳稳地变成一份结构化的、可以直接用的数据。如果你也在做文档解析、RAG知识库,或者任何一个需要和PDF打交道的项目,花一个下午把docling跑通,不会亏。