# 扫描书转 EPUB 时，脚注为什么会指错？PDF Craft 的 JEV 复核方法

从逐页调用 LLM 到传统算法闭环，再到用 JEV 筛出可疑页面：记录 PDF Craft 修复扫描书籍脚注关系的一次设计迭代。

![旧书页的正文引用与页底脚注通过细线相连，旁边是可重排的阅读页](https://pdfcraft.ai/zh-CN/images/blog/jev-footnote-review.webp "概念插图：转换时要保留正文与脚注之间的阅读关系。")

当你把扫描书转成 EPUB，最让人出戏的错误之一，是正文里的脚注标记点开后找不到说明，或跳到了另一条注释。字都识别出来了，读者却没法顺着作者的论述读下去。我开发 PDF Craft，是想让扫描书不仅能重新排版、检索和摘录，也能保住正文与注释之间的关系。

旧书、学术资料和个人藏书经常有大量脚注。读者希望在手机上读到能调字号、可搜索的版本，遇到标记时也能找到对应的解释。本文讲的是我们怎样从“让模型检查每一页”，走到“先筛出可疑页再修复”。如果你只想检查自己的转换结果，可以直接看[扫描 PDF 转 EPUB 的流程](https://pdfcraft.ai/zh-CN/blog/scanned-pdf-to-epub/)和[公式、脚注检查清单](https://pdfcraft.ai/zh-CN/blog/check-formulas-footnotes-after-ocr/)。

## 识出文字后，还要找对脚注

文字识别（OCR）能告诉程序页面上有哪些字，却未必知道它们在书里扮演什么角色。页底的小字可能是脚注，也可能是排到页底的正文；正文右上角的圈号可能是引用标记，也可能是普通序号。一条注释甚至可能被拆成两块，跨到下一页。

只要有一处关系判断错了，输出就会出现古怪的阅读体验：标记点下去没有脚注，两条脚注粘成一条，页码混进句子，或者上一页的末句接到了下一页的栏头。脚注一直是 PDF Craft 中最难处理的老问题之一。

## 一年前：让 LLM 读过每一页

最初的办法很直接：既然传统程序难以理解语义，就把整页交给大语言模型。它能看出页底的小字是在解释正文，也能理解星号、圈号、罗马数字或汉字序号可能是引用标记。判断跨页句子时，它还可以参照上下文。

单页效果令人期待，整本书的成本却很快显现。几百页意味着几百次模型调用；每一页都要等待，失败后还要重试。跨页判断需要附带相邻内容，输入随之变长。更重要的是，绝大多数页面原本没有问题。为了修复少数页面，却让昂贵而缓慢的模型重新阅读整本书，用户也很难判断处理是否卡在了某一页。

## 回到传统算法，先把主流程做成闭环

后来的版本逐渐移除了逐页 LLM，改由 OCR 和确定性规则完成主体工作：区分正文与脚注，合并自然段，拆出一条条注释，再把正文标记与注释配对。这条流程速度快、结果稳定，也能重复运行。

对大多数页面，它已经足够好。但书籍排版变化太多：脚注可能在页底或栏间，标记可能是数字或星号，页码、栏头和装饰字符也会混入识别结果。有些异常终究需要理解一句话的意思。完全依赖传统算法，会留下少数难题；让 LLM 接管整本书，又太慢、太贵。

## 转折：先找出可疑页面

问题不在于 LLM 不够强，而在于分工。已有算法能处理整本书，真正缺少的是一个快速的质检环节：翻过每一页，只挑出值得怀疑的页面，再交给 LLM 精修。

我把 JEV 放在这个位置。你可以把它理解成一个逐页的质检员：它只回答**这一页的分析结果能否原样通过**，并给出用于筛选的概率。它不重写文字，也不负责修脚注；通过概率高的页面继续走原流程，可疑页面才交给后面的模型修复。

审查单位是整页，而不是现有的每条注释。如果算法彻底漏掉一条注释，逐条审查便没有对象可查；页面级判断仍有机会发现引用缺失、归属错误、跨页异常或页码混入正文。我宁愿多抓几页，也不愿漏掉真正出错的一页：误报增加一次模型检查，漏报则可能让错误进入最终 EPUB。这个取舍仍需要更多样本校准。

```mermaid
flowchart TB
  accTitle: 从整页审查到有约束的修复
  accDescr: OCR 与传统算法先处理页面；JEV 判断是否原样通过。可疑页交给 LLM 修复，再由程序检查。通过后进入章节组装，不通过则重试。
  A[OCR 与传统算法] --> B{JEV：页面可信？}
  B -- 是 --> F[章节组装与输出]
  B -- 否 --> C[LLM 只修复当前页]
  C --> D{程序完整性检查}
  D -- 通过 --> F
  D -- 重试 --> C
```

## 可疑页面交给 LLM，但修改范围有边界

LLM 会看到连续三页的文字结构：上一页、当前页和下一页；它只能修改中间这一页。相邻页面提供上下文，帮助判断句子是否跨页延续。模型不接收页面图片，因为 OCR 已经保留了文字、位置和布局信息；此处要做的是语义校正，而不是再做一次 OCR。

模型也不能自由改写原文或改变页面结构。它可以重新标注正文、脚注和页码，修正段落连接，重新配对正文标记与注释。提交后，程序检查脚注索引是否有序、引用与注释是否对应、跨页连接的两端是否一致，以及标记位置能否在指定文本中被无歧义地找到。如果结果不合格，程序把具体错误交还给模型，请它重新提交完整结果。约束不能为了减少重试而放松。

## 一份 26 页样本给我的提醒

在一次包含大量脚注的 26 页测试 PDF 上，JEV 挑出 6 页交给 LLM。这 6 页的首次提交都通过了完整性检查；原本正确的 22 组正文引用与脚注关系也全部保留。

真正改动的是几处朴素却影响阅读的问题：印刷页码被 OCR 当成正文；一处页码错误地成为前后段落的“桥”；还有一段引导读者阅读下文的话，被传统算法与后面的缩进引文合并。LLM 根据语义和缩进信息把它们重新断开。

这只是一次样本观察，不能据此推断所有书籍的准确率或成本。它让我看到的是：修复系统不必为了证明自己做了事而大改页面。保留已经正确的关系，只改有明确证据的问题，更符合阅读者的利益。

## 让昂贵的判断只出现在必要的地方

传统算法完成大多数确定性工作；JEV 快速筛选可疑页面；LLM 处理少数需要语义理解的难题；程序约束守住输出的完整性。修复后的页面回到同一条流水线，后续章节组装、Markdown 和 EPUB 渲染无需为它开辟另一套流程。

这套方案还要在更多语言、排版风格和厚书上检验，尤其要观察 JEV 的漏报率并校准进入 LLM 的阈值。至少方向已经清楚：不必让 LLM 从第一页读到最后一页，只为了寻找藏在书页角落里的几处错误。

如果你正在处理自己的扫描书籍，可以从 [PDF Craft 转换页面](https://pdfcraft.ai/zh-CN/pdf-craft/)挑一份含脚注的短样本开始，逐项核对正文标记、注释内容和跨页段落，再决定是否处理整本书。
