文章

PDF→Markdown→中文:从 Marker 到 translate_from_pdf

聊聊我最近对 PDF 翻译这件事的一个越来越明确的判断:真正该重点设计的,不是最后那一下翻译,而是翻译之前拿到什么样的中间文档。

PDF 翻译里最重要的,不是"怎么翻",而是"翻之前你拿到了什么"。

翻译器拿到干净的 Markdown,后面很多事都会顺;拿到顺序乱掉的段落、坏掉的公式、漂移的标题和失效的图片引用,再大的模型也只是帮你在废墟上刷墙。

PDF 翻译不是单点模型问题,是两段系统:先恢复文档,再翻译文档。Marker 做前段,translate_from_pdf 做后段。它们不是在抢同一件事,更像前后两棒。

一、别直接把 PDF 扔给大模型

"多模态模型这么强了,直接丢进去吐中文结果就行?"——这个想法可控性太差。

PDF 里混着绘制指令、原生文本、图像、版面关系、页眉页脚、表格、数学公式和各种"看起来像文本实际很脏"的碎片。一股脑塞给模型,你很难知道它依据什么做了判断,很难局部修某一类错误,很难把输出稳定地接到后面的发布流程里。

适合 demo,不适合长期迭代的生产链路。先把 PDF 恢复成文档,再翻译它。看着笨,但更稳。

二、Marker 把"文档恢复"当独立系统来做

我最近把 marker/ 整个目录过了一遍。最核心的印象不是"OCR 很强",而是:

它非常认真地把"文档恢复"当成一个独立系统来做。

很多项目把"抽文本""做 OCR""转 Markdown""做结构化提取"搅在一起。Marker 不是。Provider 适配输入,Builder 生成初始 block,StructureBuilder 挂层级,Processor 后处理纠偏,Renderer 投影成 markdown/json/html/chunks。

它做的事不是"读 PDF",而是把一个不可靠的输入,慢慢修成一棵可用的文档树

三、关键是"什么时候该信谁"

真实世界的 PDF 常常很坏:有文本但顺序乱,有 bbox 但位置飘,看起来能 copy 一粘贴全烂。盲信原生文本会被脏 PDF 拖死,全量 OCR 则慢、贵、丢结构。

Marker 在 LineBuilder 里做仲裁:先判断,再决定要不要重做。真正解决的不是"会不会 OCR",而是"什么时候该相信谁"。这种判断不 flashy,但特别有工程价值。

四、LLM 放后面,不放开头

很多人直接让多模态模型看整页、一步输出最终结果。Marker 没这么干。它把 LLM 放在后处理层——让传统视觉/OCR/规则先把骨架搭起来,再让 LLM 补最难的地方:复杂区域解释、跨页表格、标题/正文区分、数学块修复。

高歧义、规则写不死的问题,正好适合放后面。

flowchart TD
    A[输入文件\nPDF / 图片 / DOCX / HTML] --> B[Provider]
    B --> C[DocumentBuilder]
    C --> C1[LayoutBuilder\n找出版面块]
    C --> C2[LineBuilder\n判断信原生文本还是 OCR]
    C --> C3[OcrBuilder\n识别候选块 / 行]
    C1 --> D[初始 Document / Page / Block 树]
    C2 --> D
    C3 --> D
    D --> E[StructureBuilder\n挂层级 / 挂顺序 / 挂父子关系]
    E --> F[Processors\n规则 + 模型 + LLM 补强]
    F --> G[增强后的 Document 树]
    G --> H[Renderer\nmarkdown / json / html / chunks]

五、核心资产是 block tree

没有统一的树,系统会很快碎掉:layout 一套对象,OCR 一套对象,table 一套对象,renderer 再来一套。Marker 把这些能力都收敛到同一种中间语言:builder 往树里填,processor 在树上修,renderer 从树里读。

要做 Markdown、HTML、JSON 不用重走提取逻辑;要做 chunk 或 extraction 也能复用结构;debug 时有统一中间态可看。

Marker 是一个文档重建系统,不是 OCR 工具。

六、代价:处理器膨胀

Processor 太多之后,系统变成"顺序敏感的启发式网络":前面 block label 没修对,后面一串失效;修一种文档的规则可能误伤另一种;LLM processor 的效果依赖上游裁块质量。

上限高,debug 成本也会越来越高。方向对,抽象对,但天然会越来越像一个需要经验维护的系统。不是缺点,说明它更像真正的产品工程。

七、为什么把主链路收敛到 Marker

translate_from_pdf 里还留着早期的轻量组件:PyMuPDF 提原生文本、Tesseract fallback、自己做标题段落识别。不是没用,但如果目标是长期演进的 PDF 翻译工具:

PDF 恢复不值得在我的项目里重写一遍主系统。

把这层交给 Marker,精力放在后面:Markdown 分块、内容保护、翻译兜底、坏结果回退、文档任务管理、最终输出可编辑可发布。不想同时维护两个大系统。

主链路:

PDF / URL
 -> Marker 输出 markdown
 -> 本地化图片资源
 -> 保护公式 / 代码 / 链接 / 图片 / URL
 -> 分块翻译
 -> 占位符恢复与坏结果回退
 -> 输出中文 Markdown

八、坚持 Markdown-first

输出"翻译后的 PDF"会把复杂度抬得非常高:版面回流、字体、中文换行、数学公式、图文混排、渲染差异——一导出哪里都可能歪。

Markdown-first 的路线是:先把 PDF 尽可能恢复成结构完整的 Markdown,翻译也在 Markdown 层完成。这是整个链路能长期迭代的前提。

文档恢复是基础设施,翻译是上层应用。基础设施不牢,上层再花哨也是空中楼阁。