☰
Docling实战:从PDF到结构化Markdown的文档解析利器
2026/9/26 8:40:43 网站建设 项目流程

做RAG或者大模型微调的朋友,最近肯定被一个叫docling的开源项目刷屏了。这个工具在主流的文档解析圈子里确实有点火,尤其是GitHub上那个IBM的Docling项目,Star涨得很快。干这行最头疼的就是处理 PDF 里复杂的表格、多栏排版、以及那些格式混乱的 Word 文档,传统解析方案在这类场景下翻车率极高。Docling 做的事情很简单也很暴力——直接把 PDF、Word、PPT 等文档精准地转换成结构化 Markdown 或 JSON,让下游的大模型能真正“看懂”文档内容,而不是吃进去一堆乱码和错位的文本流。

这篇文章,我不打算照搬官方文档给你念一遍。我会从实际项目落地的角度,结合我自己的使用体会,把 Docling 的核心原理、环境配置、CLI 用法、Python API 深度调用、以及各种“坑位”一次性和你说清楚。如果你正准备把非结构化文档接入知识库,或者在做文档智能处理相关的工具链,这篇内容会给你省下不少摸索的时间。

1. 项目定位与核心设计思路

1.1 为什么是Docling:它解决了什么痛点

先说说这个项目的出现背景。现在的RAG应用,资料入库这一步看似简单,实际却卡住了一大批人。PDF里每个字都提取出来了,但顺序是乱的;表格被拆成一堆零散的文本框;遇到双栏论文,左栏和右栏的内容混在一起。这些问题听起来不起眼,但直接影响检索质量——你的拆块、嵌入、召回,全部建立在一份“干净”的文本之上。

Docling 的核心定位就是做一个“文档理解”层,而不是简单的文本抽取工具。它不像之前那些开源库停留在轮子阶段,而是直接给你组装好了一整套流水线。几点最打动我的地方:

  • 模块化设计:把文档解析拆解成布局分析、表格识别、阅读顺序归纳等独立模块,每个模块可以单独替换升级,也是它可以持续演进的基础。
  • 高质量输出:不只是给你纯文本,而是输出带层级结构、表格结构、甚至数学公式的 Markdown 和 JSON,对 LLM 理解原文档意图很有帮助。
  • 自包含的模型权重:所有依赖的模型都会在第一次运行时自动从Hugging Face下载,不用折腾复杂的 ONNX 模型部署流程。
  • 不强依赖云 API:整个解析过程可以完全不联网,对数据合规要求高的项目尤其友好。

1.2 核心架构与设计理念拆解

从设计上看,Docling 延续了 IBM 在文档智能方面多年的技术积累,其底座是一个叫Docling Core的包,它定义了一套统一、可扩展的文档表示方式。你可以理解成它内部有一套“标准文档格式”,不管是 PDF 还是 DOCX,最终都会先转成这个统一格式,再做后续处理。

这套“统一文档表示”在设计上很讲究,它区分了物理布局和逻辑结构。比如“这是一个位于页面左上角、占半栏宽度的段落”属于物理布局;“这是一个章标题”属于逻辑结构。Docling 的机制是,先识别物理布局,再用算法推断逻辑结构,最后生成带语义标签的树状内容模型。这一步想象成:它不只是告诉你“这段话在哪”,还告诉你“这段话是干嘛的”。

这么做带来的直接好处是:输出的 Markdown 不是一坨拍平的字符串,而是把 H1/H2/H3 标题层级、列表、引用、表格、公式都保留了下来。数据入库之后,无论你是按标题切片还是按段落切片,都变得非常顺手。

2. 环境准备与快速上手

2.1 环境搭建与依赖安装

新项目到手,第一步永远是装环境。Docling 基于 Python 3.9 以上版本,推荐直接用Python 3.10 或 3.11,太新的版本反而可能存在一些依赖包还没来得及适配的情况。

我建议在虚拟环境里操作,免得污染你其他项目的依赖。命令行里执行:

conda create -n docling python=3.11 -y conda activate docling pip install docling

装完之后验证一下版本,确定核心包和依赖都完整:

docling --version

pip install docling会把主要的依赖都带进来,包括 PyTorch(CPU版)、transformers、torchvision 的 CPU 版本等。这里我特别说明一下:默认安装的是 CPU 版 PyTorch,如果你的机器有 NVIDIA 显卡,并且想用 GPU 加速推理,建议先用官方方式安装 CUDA 版 PyTorch,再安装 docling。否则模型推理速度在那种几百页的大文档上会比较难受。

# 先装CUDA版torch,再装docling pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 pip install docling

依赖装完之后,第一次运行 Docling 时,它会自动下载几个布局分析和表格结构识别的模型文件,体积大概几百 MB,时间取决于网速,耐心等一会儿就行。之后模型会缓存到本地,不用重复下载。

2.2 命令行快速体验:一条命令完成文档转换

CLI 是快速验证效果最直接的方式。准备好一个 PDF 测试文件,执行下面的命令:

docling ./test.pdf --to md --output ./output_dir

执行完之后,在output_dir文件夹里会出现test.md文件。打开看一下,如果原文档是复合排版的 PDF,你会发现输出的 Markdown 已经把段落顺序理顺了,表格也被转成了标准的 Markdown 表格,标题层级基本保持正确。这一步的体验和老牌的解析库完全不是一个级别。

CLI 还提供了一些常用参数,这里我帮你做了个功能对照表:

参数作用说明使用建议
--from指定输入文件格式默认自动检测,一般不用管
--to输出格式,可选md、json、text需要喂给 LLM 用md,需要程序处理用json
--output输出目录路径必填,写清楚避免找半天
--pdf-backend指定 PDF 解析引擎,可选pypdf、pdf2image等扫描版 PDF 建议用pdf2image配合 OCR
--ocr启用 OCR 识别扫描件、拍照件的救命选项
--no-ocr强制关闭 OCR文本型 PDF 可关闭加速处理
--table-structure启用表格结构还原默认开启,遇到表格畸变时可以试着关闭对比
--image-export导出页面图片需要保留版面样式时使用
--device指定推理设备cpu/cuda有 GPU 就填cuda,提速明显

如果只是想快速测试效果,到这一步就够了。但要真正深入使用,比如处理批量文件、自动化入库流程,那必须还得用 Python API。

3. Python API 深度实操解析

3.1 基础调用:DoclingDocument 与 DocumentConverter

Python API 才是 Docling 的灵魂。先看一个最小可用的示例,这里我把每一步都写清楚注释:

from docling.document_converter import DocumentConverter # 创建转换器实例 converter = DocumentConverter() # 传入文件路径或URL,执行转换 result = converter.convert("./test.pdf") # 获取转换后的文档对象 doc = result.document # 导出为 Markdown 文本 md_content = doc.export_to_markdown() # 导出为结构化字典(JSON) json_content = doc.export_to_dict() # 直接打印Markdown print(md_content)

这段代码看着简单,背后发生的事情其实不少。DocumentConverter是调度中心,它会自动选择 PDF 解析引擎,调用布局模型进行版面分析,识别表格结构,最后把结果组合成一个DoclingDocument对象。这个对象内部分层比较清晰,包含texts、tables、pictures等元素,每个元素都有坐标信息、层级信息和所属页面信息。

export_to_dict()导出的 JSON 结构,是处理和检索系统对接时最常用到的。它里面不仅包含了文本内容,还包含了每个元素的边界框坐标(bbox)、置信度(confidence)、页面编号(page_no)等元数据。这意味着下游不管做内容切片,还是做视觉问答,都能拿到足够的辅助信息。在这类任务上,信息越丰富,后面能做的事就越多。

3.2 批量转换与文件夹遍历

实际业务中基本都是批量处理,不可能一个文件一个文件去点。Docling 的 API 也支持批量模式。最直接的办法就是用循环遍历文件夹里的所有文件。但这里我要提醒一句:大文档和高分辨率扫描件都是比较吃内存的,循环处理时建议每次转换完成后主动释放资源。

我在项目里验证过的一个比较稳的批量处理写法是这样:

import time from pathlib import Path from docling.document_converter import DocumentConverter converter = DocumentConverter() data_dir = Path("./raw_pdfs") output_dir = Path("./output_md") output_dir.mkdir(parents=True, exist_ok=True) pdf_files = list(data_dir.glob("*.pdf")) print(f"发现 {len(pdf_files)} 个待处理文件") for idx, pdf_path in enumerate(pdf_files): start = time.time() try: result = converter.convert(pdf_path) doc = result.document output_file = output_dir / f"{pdf_path.stem}.md" output_file.write_text(doc.export_to_markdown(), encoding="utf-8") elapsed = time.time() - start print(f"[{idx+1}/{len(pdf_files)}] 转换完成: {pdf_path.name} 耗时 {elapsed:.2f}s") except Exception as e: print(f"[{idx+1}/{len(pdf_files)}] 转换失败: {pdf_path.name}, 错误: {e}")

这里有几个实战经验可以分享:

  • 单文件转换时间从几秒到几十秒不等,取决于页数和排版复杂程度。批量任务建议加上并发控制或者分批处理,避免长时间占用内存。
  • 如果一批文件里混有损坏的 PDF,转换器会抛异常,捕获异常并继续处理成功文件是比较稳的容错策略。否则一个坏文件会卡死整批任务。
  • 输出文件名最好用stem(不带后缀的文件名),避免和原文件混淆。

3.3 从 DOCX 和 PPT 提取内容

Docling 的能力不只是 PDF,Word 和 PPT 也支持。它的底层逻辑是:DOCX 文件本身已经包含了结构化信息,直接用 python-docx 库读取并转换为 DoclingDocument;PPT 文件内置的文字框和图片位置信息也可以被提取利用。

不过说实话,相对于 PDF 的惊艳表现,DOCX 提取在目前的版本里更多还是做“忠实还原”的活,把原有标题、正文、表格读出来转成 Markdown。对于自带无限复杂格式的 Word 文档,它的表现比 PDF 场景要朴素一些。如果文档本身结构调整严重,比如大量使用文本框、浮动元素、页眉页脚内容奇多,还是要配合人工预处理来提升最终效果。

另外说一下图片格式的输入(如.png、.jpg),Docling 也支持直接传入,配合 OCR 模块可以把图片里的文字和表格识别出来。对于那种“纸质的单据扫描成了图片”的场景,这个功能非常实用。它本质上等于把图像识别 + 版面分析 + 表格识别跑了一遍完整的流水线。

4. 核心原理与高级配置

4.1 PDF解析引擎选型与规则

PDF解析是整个 Docling 技术栈里最关键的环节,因为它遇到的是“没有任何结构信息的一堆绘制指令”。Docling 支持在底层接入不同的解析引擎,针对不同的文档类型用不同的策略。

接触较多的是以下几种:

  • pypdf:纯 Python 实现的解析器,轻量,适合文本型 PDF,也就是那种可以从内嵌字体和文本绘制指令中直接提取文字的文档。遇到扫描版或纯图片型 PDF,它就无能为力了。
  • pdfminer / pdfplumber:对文本布局有更细的解析能力,能拿到每个字符的精确位置。Docling 在内部利用这些坐标信息辅助布局分析,对普通文本 PDF 效果更好。
  • OCR(如 EasyOCR / Tesseract):用视觉模型直接识别图像中的文字。扫描文档在没有数字文本层的情况下,OCR是唯一的通路。

常规建议是:能抽文本层的文档坚决不用 OCR,因为 OCR 适合图片类内容,文本型 PDF 用 OCR 反而会引入识别错误。但对于扫描版 PDF,OCR 又是必须具备的能力。所以我一般在转换前会先用 PyMuPDF 快速判断文档是否有文本层,有就直接解析,没有就启用 OCR。Docling 里可以通过参数控制:

from docling.document_converter import DocumentConverter from docling.datamodel.base_models import InputFormat from docling.datamodel.pipeline_options import PdfPipelineOptions # 针对扫描版PDF启用OCR pipeline_options = PdfPipelineOptions() pipeline_options.do_ocr = True pipeline_options.ocr_options.lang = ["en", "zh"] # 根据你的文档语言调整 converter = DocumentConverter( format_options={ InputFormat.PDF: pipeline_options } )

在实测中,自动判断文本层再决定是否启用 OCR,也算一个实用的小技巧。文本型文档强制 OCR 不仅变慢,还可能把一些特殊符号识别错。

原生界面常见的--ocr开关,在 Python API 中对应的是pipeline_options.do_ocr,可以按文档类型动态设定。对超大批量任务,我给的建议是先抽样判断类型,再分组设置不同的 pipeline。

4.2 表格识别与结构还原

表格是文档解析里公认的大难题。复杂的表格往往包含合并单元格、跨行跨列、多级表头等复杂结构,而且表格经常没有明确的边界线,靠视觉来判断格子范围难度不小。

Docling 内置的表格结构识别模块,核心思路是走“目标检测 + 结构回归”的路线:先用目标检测模型把表格区域框出来,再用深度学习模型识别表格内部的行列、合并单元格和文字内容,最后还原成表格结构。

实际用下来,对常规三线表、列表型数据和带有边框的 Excel 式表格,还原准确率非常高。遇到无框线表格或者非常复杂的嵌套表格,还原结果会有偏差。这时候可以把识别结果和原文档对照一下,必要时手动修正。对于特别敏感的数据,可以把 Docling 导出的 Markdown 表格和源文件做一遍校验。

我整理了一个表格场景识别效果对比:

表格类型识别效果备注
带边框三线表良好常规业务表格基本没问题
无边框视觉对齐表格中等可能需要人工修正
合并单元格复杂表较弱结构还原会出错,需干预
扫描图片表格依赖OCR质量文本清晰度决定最终效果

4.3 OCR融合与图片内容处理

OCR 在 Docling 里的角色不只是拿来做“文字识别”,它还会把识别的文字坐标返回给布局分析模块,帮助判断“这段文字属于标题还是正文”。所以 OCR 和布局分析是协同工作的。开启 OCR 的时机和语言模型的选择,直接关乎解析效果。

语言选择上,如果文档是中英混排,OCR 的语言参数建议设成["en", "zh"]之类的组合,这样识别的准确率会明显好过单一语言。但要注意的是,多语言 OCR 通常会更耗时。如果办件只有英文,那么语言参数只填英文就行。

图片内容处理方面,Docling 会把文档中的图片单独抽取出来,标注尺寸和引用位置。在做 Markdown 输出时,默认情况下图片会另存为文件,并在 Markdown 中用相对路径引用。如果你想把图片一起输出,需要在初始化转换器时配置图片导出选项。

from docling.datamodel.pipeline_options import PdfPipelineOptions pipeline_options = PdfPipelineOptions() pipeline_options.generate_page_images = True pipeline_options.generate_table_images = True

这样设置之后,导出 Markdown 时会将页面或表格的图片一并生成,适合需要保留版面的下游任务。

4.4 文档层级结构与阅读顺序推断

阅读顺序的还原,是 Docling 和“路边社”式 PDF 文本抽取工具拉开差距的关键点。前面我们说过,Docling 可以做物理布局分析,这一步的产出是一堆“块”和“框”。接下来才是它的杀手锏:通过版面分析模型推断这些块之间的逻辑顺序。

做过版面分析的人都知道,这一关最难的其实是“读序”。双栏论文中“左栏从上到下,再读右栏从上到下,但图注、页眉、页脚要跳过”;复杂杂志里“标题、副标题、作者、摘要、正文”的位置关系——这些都是模型需要学习的内容。Docling 依赖的模型在公开的版面数据集上做了充分的预训练,在学术论文、财报、合同等结构化程度较高的文档上,顺序还原成功率很高。

同时,DoclingDocument 还维护了一套树状的层级关系:文档 -> 章节 -> 段落 -> 句子/表格/列表项。这个树状结构在下游做检索切片时非常方便,可以直接按“章节”维度切片,避免把两个不同章节的内容拼成一个语义块。

5. 典型问题排查与性能优化

5.1 转换失败与异常处理的实战经验

我实际跑了几百份文档之后,总结了几个高频问题,和对应的处理建议:

问题现象可能原因解决办法
PDF 转出来是空文本PDF是扫描版,未启用OCR开启OCR,或先用PyMuPDF检查文本层
Markdown表格错乱严重表格无边框或有复杂嵌套手动修正,或切分成小表格再合并
中文字符乱码字体编码问题检查PDF字体子集,尝试OCR方案
转换速度很慢CPU推理 + 高分辨率扫描件换GPU,或对图片做适当压缩预处理
内存占用过高文件页数多且图片多控制并发批次,处理完及时释放变量
模型下载失败/超时Hugging Face连接不稳定提前下载模型到本地缓存目录

贴一个实际处理流程,这是我处理那种“混合型 PDF”(前几页是扫描件,中间是文本,最后还有几张图片)时用的策略:

# 先检查PDF是否包含文本层 import fitz # PyMuPDF doc_check = fitz.open("mixed_file.pdf") text_pages = 0 for page in doc_check: if len(page.get_text().strip()) > 10: text_pages += 1 doc_check.close() # 根据文本层覆盖率决定是否启用OCR text_ratio = text_pages / total_pages if text_ratio < 0.3: # 文本很少,可能是扫描件 pipeline_options.do_ocr = True else: # 以文本为主,关闭OCR加速 pipeline_options.do_ocr = False

5.2 加速技巧与批量策略

CPU 环境下处理 100 页以上的 PDF,时长可能会让人泡杯咖啡回来还没跑完。这里我分享几个实测稳定见效的优化手段:

  • 优先使用 GPU:有 NVIDIA 显卡的话,安装 CUDA 版 PyTorch,然后在转换前设置device="cuda"。布局分析模型推理速度能提高数倍,而表格识别模型提升更明显。
  • 图像预处理:如果扫描件分辨率极高(比如 600 DPI),可以先用 OpenCV 等比压缩到 200~300 DPI 再送去解析。高分辨率对模型识别帮助有限,反而拖慢速度。
  • 关闭不必要模块:如果你的文档是纯文本型 PDF,可以关闭表格识别或图像导出,减少不必要的计算量。
  • 并发但不要无脑开:批量处理时可以用concurrent.futures做多进程,但进程数建议控制在 CPU 核心数以内。过高的并发会导致内存耗尽、进程被系统杀掉。

示例代码片段:

from concurrent.futures import ProcessPoolExecutor, as_completed def convert_one(pdf_path): converter = DocumentConverter() result = converter.convert(pdf_path) return result.document.export_to_markdown() with ProcessPoolExecutor(max_workers=4) as executor: futures = {executor.submit(convert_one, p): p for p in pdf_files} for future in as_completed(futures): output = future.result() # 保存输出

这里我特别提醒一下:DocumentConverter对象在多进程模式下,每个子进程都会单独初始化模型并加载到内存。如果你机器内存只有 8G,开 4 个进程很容易直接 OOM。稳妥推荐先在单进程下跑通一个文件,观察内存占用,再决定并发数。

5.3 输出结果质量控制与校验方法

整条链路转完,输出质量怎么把关,也需要聊聊。我在实践中养成的习惯是:用一套固定的“检查清单”去验证转换结果,而不是靠肉眼一页页翻。

先核对结构层:标题层级是否完整,有没有丢失 H 标签;段落顺序是否和在 PDF 里看到的阅读顺序一致;表格是否闭合,行列数是否一致。然后核对内容层:随机抽查几段文字,看有没有乱码或错字;公式如果是图片形式,确认是否被单独抽取出来。最后做数据校验:对表格型数据,比对原始 PDF 和 Markdown 里数值是否一一对应,这一步在金融报表、合同数据场景下尤其重要。

如果是大规模流水线任务,我一般会在 pipeline 里加一个“后置校验”步骤,把转换结果的 JSON 和 Markdown 统一检查一遍,把可能存疑的文档单独挑出来标注“需要人工复核”,而不是直接混入知识库。对于知识库型应用,宁可让一个存疑文档走人工通道,也不要让错误数据混进去拉低检索质量。

如果你希望拿到更精细的控制,建议多研究DoclingDocument对象里暴露出来的属性和方法。比如元素级置信度字段可以帮你筛选出模型不太确定的内容,再加上坐标信息和层级信息,下游可以做的事就非常多了。

6. 行业应用场景与生态价值

6.1 RAG知识库构建中的关键角色

Docling 当前的流行,很大程度上是被 RAG 应用的爆发给带起来的。做 RAG 的人最痛苦的事情之一就是文档解析。我之前用常见的抽取工具处理 PDF,经常碰到的问题有以下几种:PDF 转出来的段落顺序混乱;表格变成了一行行的零散文本;标题层级缺失。这些问题到了召回环节就是灾难——语义相近的内容因为顺序乱了而检索不到,标题相关的内容因为缺少层级标签没法做 Parent-Child 切片。

用 Docling 做前置解析之后,情况改善比较明显。它输出的 Markdown 天然就是“服务于 LLM”的。标题是标题、表格是表格,LangChain 的MarkdownHeaderTextSplitter可以直接拿来分段,非常契合。我自己的做法是先用 Docling 把整个文档转成 Markdown,再按标题层级做语义切块,保留一层父子关系,最后做向量化入库。这样不光检索准率提升了,生成答案时引用的段落也清晰明确。

6.2 金融、法律与学术文档处理

金融行业的招股书、财报、研报,法律行业的合同文本、判决文书,学术圈的论文 PDF,这些场景对文档结构化要求极高。Docling 在其中的作用可以概括为:把不可读的 PDF 变成可计算的半结构化数据。

举例来说,一份 200 页的上市公司年报,里面有大量财务表格、图表、管理层讨论文本。用 Docling 解析后,表格可以转成 Markdown 表格或 JSON,文字按章节切分,图表保存为独立图片并保留引用位置。后续做财务指标提取、风险因素分析这类任务,解析质量直接决定工作量和准确率。

学术论文解析是另一个典型用例。论文的双栏排版、图注、参考文献格式,过去处理起来非常费劲。Docling 的版面分析模型在这方面做了针对性训练,实测解析 arxiv 论文的效果相当不错,标题、作者、摘要、正文章节能比较准确地切分。

6.3 生态整合与后续扩展方向

Docling 的生态正在快速完善中。IBM 开源团队也一直在迭代核心模型和接口。目前它跟 LangChain、LlamaIndex 的整合已经有人在做,后续接入更多数据处理框架是大概率事件。

社区里已经有人把它接入到数据标注平台、低代码自动化工具、知识图谱构建流程中。前后端上下游的可集成性是一个开源项目最值得一提的地方,Docling 在这方面的优势在于它有规范的 JSON 输出、清晰的 API 接口、以及模型可替换的设计,不是一套写死的黑盒。

有一点我比较期待的方向,是它跟 Agent 类应用的深度结合。未来如果可以让 Agent 通过 Docling 实时读取 PDF、Word,并基于解析结果做问答、摘要或者数据提取,这类结构化文档理解能力会成为 Agent 的工具工具箱里非常实用的一个部分。

对于广大的文档处理工程师来说,现在这个时间点研究和熟悉 Docling,相当于提早掌握了文档智能化的一个重要基础组件。后续无论是自研 RAG 系统,还是做企业级文档中台,这一套技术底座都会发挥长期价值。根据我个人这段折腾下来的感受,Docling 已经是我知识库工具箱里少不了的组件了。最后再分享一个小技巧——如果你手头有一批长期不更新的历史 PDF 档案,先用 Docling 批量转出来的 Markdown 做一次质量抽查,再决定哪些需要用 OCR 方案重新处理,很多陈年数据都能抢救回来。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询