别再只会“抽字”了:PDF 转 Markdown 真正难的是结构恢复,PP-StructureV3 一键搞定

0 阅读9分钟

摘要

很多人以为 PDF 转 Markdown 很简单:把字抽出来,再套一层 Markdown 语法就完了。
但真正做过 RAG、知识库、企业文档检索的人都知道,最容易翻车的从来不是“没识别到字”,而是标题层级丢失、表格被打散、公式错乱、多栏顺序混乱、图片和正文混在一起。最后你喂给大模型的,不是知识,而是噪声。本文就用 PP-StructureV3 来讲清楚一件事:PDF 转 Markdown,本质上不是抽字,而是一项文档结构恢复任务。


正文

一、PDF 转 Markdown,很多人一开始就把任务理解错了

第一次做 PDF 转 Markdown 时,很多人都会下意识觉得:
不就是把 PDF 里的文字提取出来,然后换成 Markdown 格式吗?

真做起来才发现,事情根本没这么简单。

因为对大模型、RAG、知识库来说,真正有价值的从来不只是“字”,而是结构化信息
比如:

  • 哪些是一级标题,哪些是二级标题
  • 哪些是正文,哪些是图注
  • 哪些内容属于表格
  • 多栏排版到底应该先读左边还是先读右边
  • 公式、图片、图表要不要保留,怎么保留

所以更准确的说法应该是:

PDF 转 Markdown,不是“抽字 + 套格式”,而是一项以 OCR 为底座的文档结构恢复任务。

这也是很多工具“看起来能转,实际不好用”的根本原因。因为它们做到了“有输出”,但没做到“可用输出”。而你原文里提到的判断非常关键:
PDF → Markdown 的可用性,不只是文本正确,还取决于布局、顺序、元素结构和序列化是否正确。


二、为什么很多 PDF 转 Markdown 工具,最后都卡在“能看但不能用”?

这个问题特别真实。

很多方案转完以后,乍一看内容都在,但你一旦拿去做检索、切块、问答、知识库,就会立刻暴露问题:

1. 标题层级没了

整篇文档变成一坨平铺文本,后续 chunking 根本没法优雅做,检索边界也会失真。

2. 表格被打散

单元格顺序乱了,列和列之间关系丢了。对合同、财报、说明书这种文档,几乎是致命问题。

3. 阅读顺序错乱

尤其是多栏 PDF、脚注、页眉页脚、图文混排场景,最容易出现“识别率看着还行,读起来像随机拼接”的情况。

4. 公式、图表、图片信息丢失

很多技术文档的重要信息根本不在纯正文里。你只抽字,等于把文档价值砍掉一大截。

所以问题不在于“有没有转成 Markdown”,而在于:

你转出来的是不是一份真正适合大模型消费、适合后续检索和切分的 Markdown。


三、从 OCR 强,到 PDF 转 Markdown 强,中间其实差了一整条能力链

这是很多人最容易忽略的一点。

“OCR 很强”≠“PDF 转 Markdown 很强”。
中间其实隔着一整条链路,而且哪一层做不好,最终结果都会崩。

你原文里把这条链拆得很清楚,我把它改成更适合 CSDN 读者理解的版本:

第 1 层:先把字读对

标题错字、表格漏字、公式符号错识别,后面的结构恢复都会被连带放大。

第 2 层:再把版面块分对

标题、正文、表格、图片、图注,必须先分清,后面才能导出结构化结果。

第 3 层:再把阅读顺序排对

多栏、脚注、图文混排最考验这一层。很多“识别率不行”的问题,本质上其实是顺序错了。

第 4 层:再把关键元素还原对

表格还是表格,公式还是公式,图还是图,而不是全部压平成普通文本。

第 5 层:最后稳定导出 Markdown

只有前面都做对,最后这份 Markdown 才真正“能看、能切、能检索、能喂模型”。

这也是为什么,真正靠谱的 PDF 转 Markdown 方案,不能只讲 OCR,而要讲整条文档结构恢复链路


四、为什么我更看好 PP-StructureV3 这条路线?

因为它更接近“把问题做对”的思路。

PP-StructureV3 的价值,不只是一个 OCR 模型,而是它更像一条完整的结构化文档解析链:
版面分析、文本识别、表格识别、公式识别、阅读顺序恢复,以及 Markdown/JSON 导出。

这点特别重要。

很多工具的问题是:
先 OCR 一下,后面再“想办法拼一拼”。

但 PP-StructureV3 更接近的思路是:
从底层文字,到页面结构,到输出格式,一开始就按“结构化文档解析”来做。

换句话说,它更贴近真实工程目标:

不是把 PDF 变成一堆文本,而是把复杂 PDF 还原成可继续处理、可供大模型消费的结构化文档。


五、先别空谈,直接上手:环境准备

如果你只是想快速验证,环境其实并不复杂。my.feishu.cn/docx/Rj3Xdk…

1. 安装 PaddlePaddle(GPU 示例)

python -m pip install paddlepaddle-gpu==3.3.0 -i https://www.paddlepaddle.org.cn/packages/stable/cu118/

这里有一个很容易踩坑的点:
模型缓存路径尽量不要出现中文,否则实际运行时可能会遇到识别或路径相关问题。

2. 安装 PaddleOCR

全量安装:

python -m pip install "paddleocr[all]"

如果你这次重点就是文档解析,其实更推荐直接装这个:

python -m pip install -U "paddleocr[doc-parser]"

安装完之后,可以顺手检查一下 Paddle 是否识别到 GPU:

python -c "import paddle; print(paddle.__version__); print(paddle.device.is_compiled_with_cuda()); print(paddle.get_device())"

如果输出里是 True,并且设备显示 gpu:0,说明 GPU 环境已经识别成功。


六、实战:把整份 PDF 合并成一个 Markdown

这一步很关键。

因为很多人第一次跑 PP-StructureV3,会发现它默认是按页处理 PDF
但真正的业务需求通常不是“每页一个 md”,而是最后拿到整份完整 Markdown

你文档里的这段脚本就很适合拿来直接做首轮验证:

from pathlib import Path
from paddleocr import PPStructureV3

pdf_path = Path(r"C:\Users\小周\Desktop\实验报告1.pdf")
output_dir = Path(r"D:\pp_output")

pipeline = PPStructureV3()
results = pipeline.predict(str(pdf_path))

markdown_list = []
markdown_images = []

for res in results:
    md_info = res.markdown
    markdown_list.append(md_info)
    markdown_images.append(md_info.get("markdown_images", {}))

merged_markdown = pipeline.concatenate_markdown_pages(markdown_list)

output_dir.mkdir(parents=True, exist_ok=True)

md_file = output_dir / f"{pdf_path.stem}.md"

if isinstance(merged_markdown, dict):
    markdown_text = merged_markdown.get("markdown_texts", "")
else:
    markdown_text = getattr(merged_markdown, "markdown_texts", str(merged_markdown))

with open(md_file, "w", encoding="utf-8") as f:
    f.write(markdown_text)

for item in markdown_images:
    if item:
        for rel_path, image in item.items():
            img_path = output_dir / rel_path
            img_path.parent.mkdir(parents=True, exist_ok=True)
            image.save(img_path)

print(f"Markdown 已保存: {md_file}")

这段代码最实用的地方,不只是“能跑”,而是它把两个工程上很真实的需求一起做了:

  1. 把多页 PDF 合并成一份 Markdown
  2. 把 Markdown 里引用到的图片资源也一起落盘

这样你拿到的结果,就不是一个孤零零的 .md 文件,而是一份真正能继续处理的文档输出。

然后我在github里面上传了PP-StructureV3跑数据集OmniDocBench的代码,大家感兴趣也可以去跑一下。

github.com/PrayerQX/PP…

指标显示PP-StructureV3的表现不错。


七、这几个坑,我建议你别等踩了再回头

1. 纯英文 PDF,别直接用默认配置

如果文档是纯英文,直接切英文配置,通常会更稳:

pipeline = PPStructureV3(lang="en")

2. 扫描件、拍照页、歪斜页,不要默认配置一把梭

这类文档建议把方向分类、去畸变、文本行方向这些开关打开:

pipeline = PPStructureV3(
    use_doc_orientation_classify=True,
    use_doc_unwarping=True,
    use_textline_orientation=True,
)

3. 输出路径尽量给目录,不要硬写成单文件

因为 PDF 是逐页产出结果的,直接写死单文件路径,后面很容易覆盖资源、搞乱引用关系。

4. 不要把原始 Markdown 直接扔进向量库

这个点非常重要。真正影响 RAG 效果的,很多时候不是“有没有转出来”,而是“转出来以后有没有清洗”。

至少建议做这些后处理:

  • 去页眉页脚
  • 合并断裂段落
  • 规范标题层级
  • 清洗空行
  • 检查图片路径
  • 对表格做必要修复

很多人以为模型不行,实际问题可能根本不在模型,而在后处理太粗糙


八、工程落地别“一把梭”,分流才是正解

如果你只是做 demo,当然所有 PDF 都可以直接丢给一个统一流程。
但如果你做的是项目、服务、批量处理,那我非常认同你文档里的思路:

不要让所有 PDF 都走同一条解析链路。

更合理的方式是分三层:

方案 A:简单电子版走轻量路线

如果 PDF 有文字层、排版简单,就先走轻量流程,节省成本和时间。

方案 B:复杂文档切到 PP-StructureV3

比如这些特征出现时,就值得升级解析链路:

  • 扫描件
  • 中文复杂版面
  • 表格密集
  • 多栏
  • 公式较多
  • 阅读顺序容易混乱

方案 C:统一后处理

无论前面走哪条路,最后都做一次 Markdown 清洗和规范化。

这样做的好处非常现实:

  • 简单文档跑得快
  • 复杂文档质量稳
  • 整体成本更可控

这才是更接近生产环境的思路。


九、结论:如果你要的是“能喂给大模型的 Markdown”,重点就不是提取文字,而是恢复结构

这篇文章真正想说清楚的,其实只有一句话:

PDF 转 Markdown,不是把字抠出来就结束了,而是要尽量把文档结构恢复出来。

如果你只是想把 PDF 里的文字抽出来,工具很多。
但如果你的目标是:

  • RAG
  • 知识库
  • Agent 文档理解
  • 企业级 PDF 解析
  • 后续结构化检索

那真正关键的就不是“提取文字”,而是“恢复结构”。

从这个角度看,PP-StructureV3 值得重视的地方也很明确:

  • 它不只是 OCR
  • 它更强调结构恢复
  • 它更适合复杂 PDF
  • 它更适合 Markdown / JSON 这类结构化输出
  • 它更适合作为 RAG 前处理的一环

所以,如果你的 PDF 转 Markdown 目标不是“能看”,而是“能用”,那 PP-StructureV3 确实是一条值得优先尝试的路线。