基于Docling结合多模态大模型的的PDF转Markdown
项目地址:https://github.com/EvannZhongg/Docling2md.git
项目背景
基于我当前使用 LLM 构建知识图谱的处理的是一系列复杂的PDF文档,这些PDF包含图像、表格、文本等混合信息,结构复杂、不规则,无法直接使用。因此,需要一个高效、可扩展的结构化预处理流程来为后续实体提取、图谱生成等任务提供清洗后的输入,同时流程需要兼具准确和部署的方便。
例如 MinerU
和 Textin
,它们转换的效果都非常好;但 MinerU
部署不太方便集成到项目中显得笨重, Textin
是商用软件价格不美丽;于是近期发现了 Docling
的开源模型,同时python中也可以直接安装 Docling
的依赖包避免下载模型,于是尝试了一下感觉效果还不错符合我的预期。
尤其是在对表格进行处理时,Docling
是将表格转化为管道表格结构,而 MinerU
和 Textin
都是将表格转换为 HTML 格式;相比 HTML 格式,管道表格在传递给大模型时能够节省更多的token,减轻了大模型的负担。
本项目基于 Docling
框架,对 PDF 文件进行结构解析,结合多种大模型能力,实现了文档的多模态理解与 Markdown / JSON 格式结构化输出,为知识图谱构建奠定基础。
实现的思想与目标
项目的核心目标是提高PDF中信息保留的完整程度方便后续将纯文本信息输入给大模型构建知识图谱,并解决以下几个关键问题:
- PDF转Markdown:通过Docling将PDF内容转化为Markdown,尤其是提取表格和图片,并在Markdown中保持其结构。
- 复杂表格图像的处理与修复:通过视觉大模型处理PDF中的表格图片,修复异常或模糊的表格结构。
- 异常文本分词的修复:直接使用
Docling
的OCR有时会出现文本识别异常,对于长文本中的异常无空格情况,通过大模型进行自动分词修复,保证文本可读性。 - 对图片的描述与理解: 对识别出的图像(非表格)调用视觉大模型进行内容描述,生成自然语言图像摘要,并写入 Markdown 与结构 JSON。
流程示意:
graph TD A[PDF Document] --> B[DocumentConverter] B --> C[Structured Document] C --> D[Element Iteration] D --> E[Text Processing] D --> F[Table Processing] D --> G[Image Processing] E --> H[LLM Classification] F --> I[Table Structure Analysis] G --> J[VLM Captioning] H --> K[Markdown Output] I --> K J --> K K --> L[Markdown File] K --> M[JSON Metadata] K --> N[Extracted Images]
项目流程与技术细节
1. 表格结构识别与修复
- 使用 Docling 自动检测表格区域,导出
DataFrame
。 - 若存在列名重复或列数异常,启用视觉大模型模型对表格截图分块修复,生成标准 Markdown 管道表格(pipe table)。
- 分块方式:按行高切图,并拼接小块确保高度。
- 所有修复表格记录修复来源,存入 JSON 中以备审计与训练数据回溯。
表格异常处理的流程结合了 按固定行高切块 和 基于最低高度与宽度的分块合并 两种方法。
按固定行高切块
在函数 split_table_image_rows
中,表格图像被按照固定的行高(默认为 400 像素)进行裁切。
1 | def split_table_image_rows(pil_img: Image.Image, row_height: int = 400) -> list: |
根据您上传的代码文件内容,表格异常处理的流程结合了按固定行高切块和基于最低高度与宽度的分块合并两种方法。以下是具体的实现细节和举例说明:
- 输入: 表格图像
pil_img
和一个可配置的row_height
(默认值为 400 像素)。 - 逻辑:
- 按照从上到下的顺序,每隔
row_height
像素裁切一次。 - 如果剩余的高度不足
row_height
,则取到最后的边界。
- 按照从上到下的顺序,每隔
- 输出: 返回一个包含多个裁切后图像片段的列表。
这种方式确保了表格图像能够被分割成多个子图像,每个子图像的高度不超过 row_height
。
基于最低高度与宽度的分块合并
在函数 merge_small_chunks
中,对裁切后的图像片段进一步处理,确保每个片段的高度和宽度满足最低要求(因为视觉大模型在上传图片时有最小像素要求,需要长宽大于 10 像素,为避免切块过小,这里默认高度为 300 像素,宽度为 20 像素)。
1 | def merge_small_chunks(chunks: list, min_height: int = 300, min_width: int = 20) -> list: |
- 输入: 裁切后的图像片段列表
chunks
,以及最低高度min_height
(默认 300 像素)和最低宽度min_width
(默认 20 像素)。 - 逻辑:
- 遍历所有片段:
- 如果某个片段的高度或宽度小于最低要求,则将其与下一个片段拼接,直到满足最低尺寸要求。
- 如果某个片段已经满足最低要求,则直接加入结果列表。
- 对于最后一个临时块,如果其高度仍低于最低要求,则创建一个新的图像块,填充到最低高度。
- 遍历所有片段:
- 输出: 返回一个经过合并后的图像片段列表。
3. 综合处理流程
在主流程中,表格异常的处理逻辑如下:
1 | if not table_df.columns.is_unique or table_df.shape[1] < 2: |
流程说明:
- 检测表格异常:
- 如果表格的列名不唯一 (
table_df.columns.is_unique
) 或者列数少于 2 (table_df.shape[1] < 2
),认为表格结构异常,这些异常通常是 OCR 模型本身的不足导致的表格生成失败。
- 如果表格的列名不唯一 (
- 按固定行高切块:
- 使用
split_table_image_rows
将表格图像按固定行高(默认 400 像素)切分为多个片段。
- 使用
- 合并小块:
- 使用
merge_small_chunks
合并高度或宽度不足的片段,确保每个片段的高度至少为 300 像素,宽度至少为 20 像素。
- 使用
- 并发调用大模型:
- 对每个合并后的片段并发调用
ask_table_from_image
函数,将图像转换为 Markdown 表格。
- 对每个合并后的片段并发调用
- 拼接结果:
- 将所有片段的 Markdown 表格拼接起来:
- 第一个片段保留表头和分割线。
- 其余片段仅保留数据行。
- 将所有片段的 Markdown 表格拼接起来:
- 保存结果:
- 将修复后的表格以 Markdown 格式保存,并记录相关信息到 JSON 文件中。
举例说明
假设我们有一个PDF文件,其中包含一个异常的表格图像。该表格的高度为 1208 像素,宽度为 900 像素,代码会按照以下步骤处理该表格图像:
在函数 split_table_image_rows
中,表格图像会被按固定行高(默认为 400 像素)进行裁切。
- 表格高度为 1208 像素,固定行高为 400 像素。
- 裁切的片段范围如下:
- 第一块:
top=0
,bottom=400
→ 高度为 400 像素。 - 第二块:
top=400
,bottom=800
→ 高度为 400 像素。 - 第三块:
top=800
,bottom=1200
→ 高度为 400 像素。 - 第四块:
top=1200
,bottom=1208
→ 高度为 8 像素。
- 第一块:
最终会生成 4 个片段,其中前 3 个片段的高度为 400 像素,最后一个片段的高度为 8 像素。
在函数 merge_small_chunks
中,会对裁切后的片段进行检查,确保每个片段的高度和宽度满足最低要求(默认高度为 300 像素,宽度为 20 像素)。
- 第一块:高度为 400 像素,宽度为 900 像素 → 符合最低要求,直接保留。
- 第二块:高度为 400 像素,宽度为 900 像素 → 符合最低要求,直接保留。
- 第三块:高度为 400 像素,宽度为 900 像素 → 符合最低要求,直接保留。
- 第四块:高度为 8 像素,宽度为 900 像素 → 不符合最低高度要求(300 像素),需要与前面的块合并。
最终结果:
- 第四块(8 像素) 会与 第三块(400 像素) 合并,生成一个新的片段,高度为 408 像素,宽度为 900 像素。
因此,经过合并后,最终会有 3 个片段:
- 第一块:高度为 400 像素,宽度为 900 像素。
- 第二块:高度为 400 像素,宽度为 900 像素。
- 第三块:高度为 408 像素,宽度为 900 像素。
在主流程中,合并后的片段会并发调用视觉模型(ask_table_from_image
)进行修复,在收集所有片段的修复结果后,代码会将这些片段拼接成完整的 Markdown 表格。
- 第一块 的修复结果会保留表头和分割线。
- 第二块 和 第三块 的修复结果只会保留数据行。
- 最终将所有片段的结果拼接成一个完整的 Markdown 表格。
使用视觉模型修复表格示例效果展示
1 | | tD(on) | - | 20 | - | ns | V_DS=400V, V_GS=0 - 12V, I_D=3A, R_G=30Ω | |
2. 文本内容处理
- 使用 OCR 与 Docling 检测文本段落。
- 文本类型判断:使用 OpenAI 文本模型判断是“标题”还是“正文”。
- 英文分词修复机制:检测长串无空格文本,调用大模型进行英文分词恢复,提高可读性与准确性。
1 | 示例输入: |
3. 图片内容理解
- 对识别出的图像(非表格)调用视觉大模型进行内容描述,生成自然语言图像摘要,并写入 Markdown 与结构 JSON。
- 摘要会插入在图片
alt text
中,例如:
1 |  |
4. 生成Markdown文档
在完成表格和图片的提取、文本处理之后,最终将所有提取的信息转换为Markdown文档,并保存到本地。每个表格、图像、文本都会被格式化成相应的Markdown格式,并以图像和表格形式嵌入。
- Markdown 文档(结构化展示图像、表格、文本,便于人工核查与发布)
- JSON 文档(结构化、含坐标 bbox、页码、分块来源,适合下游知识图谱任务进行锚点的标记)
该项目代码参考 Docling 框架,对 PDF 文件进行结构解析,结合多种大模型能力(如 Qwen-VL、OpenAI 文本模型),实现了文档的多模态理解与 markdown/json 格式结构化输出,为知识图谱构建奠定基础。
但该项目在处理复杂表格时仍存在不足,例如表格中存在字符是横着摆放时,或者是存在图像嵌入在表格中,则无法保证原有的结构。