做 RAG 的朋友应该都有过这种体验:花了大把时间调 embedding、调 prompt、调检索策略,最后回头一看,真正拖后腿的往往是那些看起来人畜无害的 PDF 文档。标题里提到的 pdf-inspector,严格来说它不是一个能装完就用的独立部署项目,而是一类"入库前文档体检"的工具和方法论。我在实际项目里已经把它当成一条成文流程:任何 PDF 想进知识库,先过一遍检查器,把文档的底细摸清楚,再决定后续的解析方案。
这个工具思路解决的是 RAG 链路里最容易被低估的一环:文档质量。你用什么向量模型、用什么 rerank 策略,都是天花板以上的问题;而 PDF 里藏着多少乱七八糟的东西,决定了你的天花板本身有多高。PDF 不是一张白纸,它有元数据、有注释、有表单、有多栏布局、有扫描图片,甚至有嵌入文件,这些东西全部会在你不知道的时候污染知识库。pdf-inspector 就是帮你把这些问题在入库之前全部暴露出来,让你知道"这份文件到底能不能直接用",以及"如果不能用,该走哪条处理路线"。
这篇文章我会从 RAG 场景下的文档痛点讲起,拆解 pdf-inspector 这类工具的核心功能应该覆盖哪些方面,再结合我实际跑过的清洗流程,把每一步怎么检查、怎么判断、怎么处理讲清楚。最后会聊一个很多人忽略的问题:PDF 检查完之后,不同文档类型该怎么接进不同的知识库方案,包括和知识图谱、Ontology 这类结构知识的配合。内容偏实操,适合正在做 RAG、被 PDF 解析折磨过、或者准备搭知识库但还没想清楚文档预处理该怎么设计的同学。
1. 为什么做 RAG 要先搞定 PDF 这道坎
1.1 文档质量决定 RAG 效果的天花板
很多人做 RAG 的第一步是选向量库、选 embedding 模型、选切分策略,这些当然重要,但它们都建立在一个前提上:你的文本是干净、完整、有序的。问题在于 PDF 天生不是为机器阅读设计的,它的本质是一个"打印页面描述",里面没有文档结构,没有明确的段落边界,甚至连文本都不一定以正确的阅读顺序存储。
我见过一个真实的线上故障:某个知识库接了一批产品手册,检索"设备无法开机"时,召回出来的片段全是页眉页脚的内容。排查了很久才发现,这批 PDF 每页顶部都有"产品安全规范 V3.2"的重复文本,切分之后这些小碎片成了高频向量,污染了整个召回结果。类似的问题还有扫描 PDF 提取出乱码、加密 PDF 导致解析器直接报错、多栏论文被按单栏顺序读导致语义完全断裂。这些问题,embedding 模型再强也救不回来。
所以 RAG 的工程质量,大部分取决于你对输入文档的把控。pdf-inspector 要做的就是这件事:在文档真正进入切分和向量化之前,先用一个独立的检查环节把文件的物理属性和内容质量全部摸清。它能告诉你每份 PDF 有多少页、是否扫描版、是否有文本层、是否加密、是否包含嵌入对象、页面方向是否正常、文本密度是否合理。这些信息单独看没什么,组合起来就能帮你做出"这份文件能不能直接走常规解析"的判断。
1.2 工具定位:pdf-inspector 检查的是什么
要理解 pdf-inspector,先把它和常见的 PDF 解析库区分开。PyPDF2、pdfplumber、pymupdf 这些工具干的是"提取"——把 PDF 里的文本、表格、图片取出来。而 pdf-inspector 干的是"体检"——它不负责把 PDF 变成可用的文本,它负责告诉你这份 PDF 有没有问题、有什么问题、适合用什么方式处理。
打个比方,解析库像一个翻译,你把 PDF 给它,它给你文本;pdf-inspector 像一个质检员,它在翻译之前先看这份文件是印刷体还是手写体、有没有缺页、有没有涂改、是不是倒着放的。翻译再厉害,拿到一份倒置的复印件也翻不对。
我实际用下来,pdf-inspector 在流程中承担三个角色:第一是入站检查,批量扫描一个目录下的所有 PDF,生成一份每个文件的质量报告;第二是异常预警,把加密、损坏、扫描件、含嵌入宏等高风险文件标记出来,不让它们悄悄混进知识库;第三是路由依据,根据检查结果决定这份 PDF 应该走文本解析、走 OCR 还是走多模态模型。这个"先体检、再分流"的思路,是 RAG 文档预处理里最值钱的经验。
2. 核心功能拆解:一份 PDF 检查报告应该长什么样
2.1 元数据与文件属性检查
第一层检查是文件的基础信息,这是最容易拿到也最容易被忽略的。PDF 文件头里记录了版本号、生产者、创建工具、页面尺寸、旋转角度这些信息,它们看似琐碎,但能暴露很多问题。
比如我遇到过一个供应商发来的一批合同扫描件,PDF 版本是 1.3,Producer 字段为空,所有页面都带着 90 度旋转属性。解析的时候如果不处理旋转信息,文本提取出来是横着的,切分之后每个 chunk 都带着大量空白。这种问题如果不提前看元数据,要等入库之后查效果才能发现,来回浪费一整天。
文件属性检查里,页面大小的一致性也很重要。有些文档是几份材料拼在一起扫描的,前半部分是 A4,后半部分是 A3 或者信纸,直接解析会导致某些页面的内容被裁掉。pdf-inspector 会把每一页的尺寸、旋转、是否有文本层按页列出来,让我一眼看到这份文件是不是"拼盘文档",如果是,就得考虑按页拆分或者单独调整解析参数。
还有一个值得关注的点是加密状态。PDF 有两种密码:打开密码和权限密码。打开密码会导致解析器直接拒绝访问,权限密码则限制复制和打印。很多时候文档加了权限密码,解析库照样能打开,但提取出的文本会被截断或者无法复制。检查报告里如果显示"Encrypted: yes,Permission: no text extraction",那这份文档就得先走解密流程,不能直接往知识库里塞。
2.2 文本内容质量与噪声评估
元数据看完之后,第二步是看文本层本身。很多 PDF 看起来是电子版,实际上内容是图片贴上去的,只是外面套了一层壳。判断方法很简单:抽取每一页的文本,看字符数。如果一页 A4 上只有几十个字符,而页面视觉上明明有大段文字,那就说明文本层是空的,这是一份"伪电子版",实际需要走 OCR。
文本噪声评估也是这一层的核心工作。这里说的噪声不是指乱码,而是指对 RAG 切分有害的重复信息和格式残留。最常见的三类:页眉页脚、页码、版权声明。任何一份几十页的 PDF,页眉页脚重复几十次,如果不提前识别,切分的时候就会产生大量内容高度相似的小 chunk,这些 chunk 会占用向量空间,还会在检索时频繁干扰相关性排序。
pdf-inspector 的思路是对每一页取前几行和后几行字符,计算跨页重复度。如果某个片段在超过 80% 的页面上都出现,就可以判定为页眉页脚,后续清洗时可以直接按页剔除。这个方法不复杂,但比人工翻文档高效得多。还有一个隐藏噪声是 PDF 生成时嵌入的字体信息异常,某些 PDF 的字符映射表是错的,提取出来会变成乱码。检查器会统计文本里"不可识别字符"的比例,如果超过阈值,就会标记为编码异常,这类文件需要换解析器或者走 OCR,不能硬用。
2.3 布局与阅读顺序分析
RAG 里有个经典难题:多栏文档到底怎么读。人类看论文的时候,会自然地按"左栏从上到下、右栏从上到下"的顺序阅读,但 PDF 的文本存储顺序不一定如此。有时候是按栏存储的,有时候是跨栏存储的,有时候完全乱序。如果直接按存储顺序切分,一个 chunk 里可能先出现左栏的中段,再接右栏的段落,语义彻底断裂。
我对 pdf-inspector 的期望就是能在入库前判断出"这份文档是不是多栏布局"。实现思路不算复杂:拿到每页的字符坐标,按 x 轴统计文本分布。如果文本明显集中在两个水平区域,中间有大片空白,基本可以断定是双栏结构。再进一步,还可以看 y 轴上的段落间距和首行缩进,辅助判断段落边界。
检查出多栏布局之后,后续解析就要做"分栏重排":先按 x 坐标把文本分成左栏和右栏,再分别按 y 坐标排序,最后按"左栏全部文本 + 右栏全部文本"的形式拼接。这个步骤对论文、证券报告、行业白皮书这类文档特别重要。我处理过一批行业研报,没做分栏重排前,切分出的 chunk 检索效果一团糟;做了之后,完全换了个世界。布局检查的意义就是提前把这个处理开关打开。
2.4 安全与异常对象检测
这层是很多人没意识到、但实际非常重要的检查项。PDF 是容器格式,里面可以嵌入 JavaScript、Flash(虽然现在不流行了)、外部文件引用、注释、表单字段、甚至完整的可执行文件。如果一份 PDF 是从不可信渠道获取的,直接扔进解析流程,风险不只是数据污染层面的事。
从 RAG 场景来看,嵌入文件和注释是最常见的干扰源。我检查过一份法律合同,正文之外每页都堆着大量黄色高亮注释,这些注释在文本提取时会被某些解析器当作正文带出来,导致知识库里混入大量"某某方提交的证据清单"这类元信息。另外有些 PDF 会带有附件,比如一份招标文件里嵌了 Excel 报价表,不进检查流程根本发现不了附件已经被解析器自动解码并污染了内容。
pdf-inspector 会在这一层列出文件里的注释数、表单字段数、嵌入文件数、JavaScript 片段数。看到这些数据,你就可以决定:注释要不要保留(对某些场景,注释是有价值的信息;对另一些场景,它们是噪声),嵌入文件要不要单独提取出来另作处理。安全检查还有一个实际价值:某些 PDF 被解析器打开时会尝试联网或者执行脚本,在隔离环境里跑解析之前先过一遍检查器,能让你的解析流程安全很多。
3. 实操过程:把 pdf-inspector 跑起来
3.1 先明确你要处理什么样的 PDF 集合
实操第一步不是写代码,而是先看你手上的 PDF 是什么形态。我习惯先把文件目录列出来,按几个维度粗略分组:电子版还是扫描版、单文件还是多文件拼接、是否加密、体积大小。这些信息可以通过一个很简单的脚本快速获取,不需要复杂的工具。
我用 pymupdf 做快速扫描,核心就几步:遍历目录下所有 PDF,打开每个文件,读取页数、文件大小、是否加密、每页平均字符数。跑一遍之后,你会得到一张表,里面大概长这样:
| 文件名 | 页数 | 大小 | 加密 | 平均每页字符数 | 疑似扫描版 |
|---|---|---|---|---|---|
| 合同_2023.pdf | 32 | 45MB | 否 | 0.2 | 是 |
| 产品手册.pdf | 18 | 3MB | 否 | 580 | 否 |
| 某证券报告.pdf | 60 | 8MB | 是 | 12 | 是 |
这张表就是 pdf-inspector 的第一份产出。平均每页字符数极低的,基本是扫描件;加密的,要先解密或确认权限;体积异常大的,里面很可能嵌了大图片或者附件。我通常按这份表把文件分成三批:可直接解析的、需 OCR 的、需先解密的。这个分流动作,能让后续所有处理流程清晰很多。
有一个很多人踩过的坑:批量扫描时不要把所有文件都塞进内存。一个 60MB 内含高清扫描图的 PDF,如果用 pymupdf 默认设置打开并逐页渲染,内存直接飙到几个 GB。我一般会在扫描阶段就把渲染参数压低,不渲染图片,只看字体信息和坐标信息,速度和内存都会好很多。
3.2 检查流程与报告解读
拿到文件清单后,下一步是对每份 PDF 做精细检查。我会对每一页提取以下信息:页面尺寸、字符数、图片数量、字体列表、文本块坐标。把这些信息汇总成 JSON 或 DataFrame,再按前面说的标准做标记。
举个例子,判断扫描版我不仅看平均字符数,还会叠加图片数。大多数扫描 PDF 是"一页一个大图",所以如果某页图片数量大于等于 1、字符数近乎为 0,基本可以认定是扫描页。判断多栏我按文本块 x 坐标聚类,如果一页文本被分成左右两块,且中间空白区宽度超过页面宽度的 15%,就标记为双栏。判断页眉页脚我用的是跨页文本重复检测:统计 Top 3 行和 Bottom 3 行的文本,如果某条文本在超过 20 页重复出现,且长度小于 50 个字符,标记为页眉或页脚。
报告解读这件事,我建议做成一眼能看懂的概览,而不是堆一堆指标。我自己的输出格式是一个 CSV + 一个 JSON 摘要。CSV 给每页一行记录,方便在 Excel 里筛选;JSON 给每份文件存一个 summary,包含判断结论和原因。后续接自动化流程时,直接读这个 JSON 就能决定走哪条处理分支。
我踩过的一个具体坑是:判断"伪电子版"时,只看了平均字符数,结果有一份文件,文本层不是空的,但所有字符都是乱码,字符映射表坏了。平均字符数显示正常,提取出来却不能用。后来在检查项里加了"不可识别字符比例"这个指标,把乱码文件单独标出来,问题才解决。所以说 pdf-inspector 这类工具不是看一个指标就行的事,关键指标要叠加使用。
3.3 基于检查结果做清洗与切分
检查不是目的,清洗才是。这一步我把前面得到的检测结果转化成具体的处理动作,基本流程是:剔除页眉页脚、处理加密、分栏重排、统一页面方向、再导出为干净的文本。
剔除页眉页脚,我用的方式是按页读取前 3 行和后 3 行的文本片段,和全局重复片段做比对,命中就删掉。删的时候要注意保留页面的主体文本,不能把正文第一行误判成页眉。我实际的做法是先检测"重复出现的片段"再按位置删,而不是直接删前 3 行,否则很容易误伤。
加密文件处理,如果是权限密码(打开密码为空、权限受限),用 pymupdf 的authenticate方法传空密码或者已知密码就能解除大多数限制。如果是打开密码,那需要先从文档所有者那里拿到密码,这一步是业务流程问题不是技术问题。我的建议是:知识库建库之前,先和文档提供方确认授权,别等到入库的时候才发现一堆加密文件挡路。
分栏重排这里我再强调一遍:把文本块按 x 坐标聚类,如果检测出来是双栏,就把左边栏的文本块按 y 坐标排序、右边栏同理,然后拼接。拼接顺序是左栏全部内容接右栏全部内容。这里有个细节,如果页面顶部有横跨两栏的标题,要先把标题提取出来单独放,不要让它混进左栏或者右栏。处理完之后,把重排结果渲染成文本,再做一次字符数校验,确保没有内容丢失。
清洗完的文本再进入切分环节,我的切分是按固定 token 数加滑动窗口,但在此之前会先做一次"语义段落合并":把清洗后的文本按照空行和标题层级拆成大段,再在大段内部按 token 限制切分。这样做能最大程度避免把一个完整段落切断。切分完的 chunk 我会再加一层过滤,凡是长度小于 30 个 token 且不是结构化数据的,直接丢弃,减少无效向量。
4. 检查之后:不同 PDF 该怎么接进知识库
4.1 文本型 PDF 与扫描型 PDF 的入库路线
分工序聊清楚一件事:检查器输出的结果,不只是为了清洗,更是为了决定后续路线。文本型 PDF 走的标准路线是:提取文本 -> 清洗 -> 切分 -> embedding -> 入库。这条线路上,pdf-inspector 的产出就是清洗规则和切分边界,它告诉你哪几页需要合并、哪几页需要跳过、哪些文本块要重排。
扫描型 PDF 的路线就不同了,它不能直接提取文本,得先走 OCR。OCR 的选择上,如果文档质量好、语言单一,tesseract 或者云端 OCR 都够用;如果表格复杂、有公式、有手写批注,建议直接用多模态模型或者结构化文档解析模型。我的经验是:先看 pdf-inspector 里渲染出的页面图像清晰度,如果扫描分辨率太低、字体模糊,OCR 效果会很差,这时候不如直接用视觉问答类的模型做内容和结构识别,虽然成本高,但准确率更可控。
这里有一个常被忽略的问题:扫描版 PDF 的 OCR 结果本身也需要检查。OCR 出来的文本经常有错字、有错误的段落断行、有误识别的表格。所以我的流程里会有第二次质检:把 OCR 文本和原页面图像的关键结构做比对,比如表格行列数、标题层级,不一致就打回重跑。这一步很耗时,但对知识库质量影响极大。
4.2 知识库到底能不能存图片和多模态内容
很多人在做 RAG 时困惑一个问题:知识库里能不能存图片?网上回答五花八门,实际区分开来看就行。如果你的检索是纯文本向量检索,那图片本身不能被检索,"图片的描述"可以。也就是说,想要让图片内容参与检索,需要先对图片做解析,生成文字描述、OCR 结果、或者结构化标签,再把这些文本作为 chunk 入库。图片文件可以单独存在对象存储里,但检索时命中是它的文本表示。
这里正是 pdf-inspector 发挥作用的地方。PDF 里的插图、截图、扫描页,在检查报告里会有明确的坐标范围和图片类型标记,我可以据此决定:哪些图片需要抽取出来单独生成描述,哪些图片只是装饰性元素可以直接忽略。一份产品手册里,一张设备连接示意图的价值远大于一张纯背景图。没有坐标信息的话,这些判断就全凭运气。
还有一种更重的方式是用多模态 embedding 模型,把图片本身向量化,拿图搜图、拿文搜图。这种方式适合图片占比特别高的文档集,比如设计图纸、医疗影像报告。但部署成本高得多。我的建议是:大多数知识库场景,先用"图片转描述文本"的办法就够了,效果足够好,且能和现有文本检索无缝衔接。
4.3 知识图谱、Ontology 与结构知识库的结合点
再聊一个热词背后大家真正关心的问题:rag 知识库、结构知识库、知识图谱,到底区别在哪,什么时候该用哪种。我自己的理解是:rag 知识库的核心是"召回的文本片段",适合回答"文章中有什么";结构知识库的核心是"实体和关系",适合回答"这些数据之间是什么关系";知识图谱是结构知识库的一种实现形式,用三元组来组织"节点-边-节点"。
这三种不是互相替代的关系,更多是互补。比如一个内部运维知识库,PDF 里有大量故障处理文档,这些走 RAG 没问题;但如果要回答"这个故障影响了哪些设备、设备属于哪个站点、站点的负责人是谁",你需要的是一张结构化的关系网,单靠文本检索很难回答。这时候需要从文档里抽实体、抽关系,构建图谱层。
那 pdf-inspector 和 Ontology 有什么关系?我做过的项目里,最常见的流程是:先用 pdf-inspector 把 PDF 文档清洗成干净文本,再用信息抽取模型从文本中抽取实体和关系,最后按预定义的 Ontology 结构把抽取结果灌进知识图谱。这一步里,文档清洗的质量直接影响抽取效果。PDF 里如果有页眉页脚、乱码、错乱的表格结构,抽取出来的实体和关系噪声非常大。我在做图谱构建时,对源文档的质量要求比 RAG 还要高,因为三元组一旦错了,后面所有推理都建立在错误之上。
所以我的建议是:别把 RAG 和知识图谱搞成二选一。文档先过 pdf-inspector 体检,清洗后的文本一部分直接向量化进 rag 知识库,一部分走信息抽取进结构化知识库。同一个源文档,喂给两条线,查询端根据问题类型自动路由。这个方案我在实际项目里落地过,效果比单一 RAG 或者单一图谱都好。至于具体怎么构建 Ontology,那要看你领域里的核心实体有哪些,先把实体和关系定义好,再让抽取模型去填充。工具链上,可以用 protégé 来维护 Ontology 文件,用 neo4j 保存图谱数据,向量和文本放回原来的向量库就行。
5. 常见问题与排查实战
5.1 扫描版 PDF 提取不出文本怎么办
这是我在项目里遇到频率最高的问题。表现是:pdf-inspector 报告里某页字符数接近 0,但页面图像正常。很多新手拿到这种 PDF 会以为是解析库的问题,去换库、换参数,折腾半天还是提取不出东西,原因很简单,这页根本不是文本 PDF。
正确的处理顺序是:先确认是不是扫描件,看平均每页字符数和图片数,再看图像分辨率。如果确认是扫描件,先评估图像质量,质量不高就先做图像增强(调整对比度、去偏斜),再做 OCR。如果文档里混合了文本页和扫描页,比如一部分是电子排版、一部分是扫描插入的,那就要按页混合处理,不能一刀切全走 OCR。混合型 PDF 我见得很多,尤其是合同和招投标文件,检查报告里按页标记会救你一次。
5.2 页眉页脚污染切分结果怎么排除
污染的表现是:某些重复出现的短语频繁被检索出来,却和用户的问题不相关。比如一份几十页的公司制度文档,每页页脚都有"第 N 页 / 共 N 页"和公司网址,切分后这些内容成了大量相似 chunk,占用了向量空间。
我的处理方式是两层:第一层在清洗阶段直接删除全文档重复的页眉页脚;第二层在切分后再做一次去重,对 chunk 向量两两计算相似度,超过 0.95 的保留一个。这样即使第一层漏掉了部分噪声,第二层也能兜底。不过要注意,第二层去重的阈值要谨慎,别把正常的相关内容误删。相似度阈值 0.95 以上基本是重复模板,0.9 到 0.95 之间的要人工复核。
5.3 多栏排版在向量化后语义跳跃怎么解决
多栏文档的直接问题是切分后 chunk 内上下文断裂。比如一篇双栏论文,左栏底部的内容和右栏顶部的内容在原文上毫无关联,但如果你按文本存储顺序切分,它们会被塞进同一个 chunk,检索到的时候就会给你一段前言不搭后语的文本。
解决的起点还是在 pdf-inspector 的布局检测。检测结果是双栏,就分栏重排后再切分;检测结果混合(有的页单栏有的页双栏),就按页处理。这里我想强调一点:不要只在代码层面处理,最好在入库后的 chunk 信息里保留一列"原页面布局类型"。后续分析检索问题时,可以快速定位到是不是某类布局文档在拖后腿。这个字段在排查问题的时候非常好用。
5.4 报告显示正常,但入库后检索质量仍然差
如果 pdf-inspector 报告显示文本干净、布局正常、切分合理,但检索效果还是不好,那问题大概率不在文档层,而在检索链路层。常见的原因有三个方向:embedding 模型对长文档语义理解不够强;chunk 切分粒度和问题粒度不匹配;元数据没有充分利用。
关于元数据,我多说两句。很多人入库时只把文本丢给向量库,完全不管文档的标题、章节、页号、文件名。但高质量的 RAG 检索非常依赖元数据过滤。比如用户只查 2024 年的文档,你如果没有年份字段,就只能在所有年份里硬检索。pdf-inspector 在检查时顺便提取了每页的标题层级和文件属性,这些信息完全可以转成元数据字段,跟 chunk 一起存进向量库。检索时先按元数据过滤,再走向量相似度,效果提升非常明显。
这个问题的排查思路是:先用检查报告确认文档本身没问题,再用基线测试评估当前的检索效果,最后逐步增加元数据过滤和 rerank。不要一上来就换 embedding 模型,那是最后一步,不是第一步。
6. pdf-inspector 在实际项目中的定位和边界
聊了这么多,最后把工具定位再说透。pdf-inspector 不是一个装了就能一劳永逸的银弹,它更像一个守门员——把坏文档挡在知识库大门之外,把好文档标记清楚放进去。它本身不产出最终答案,但少了它,整个 RAG 链路就像在流沙上盖房子,后面再怎么优化都是补救。
我现在的项目流程已经固定下来了:接收新文档 -> pdf-inspector 快速体检 -> 生成按页标记的检查报告 -> 按报告分流解析 -> 清洗 -> 切分 -> 带元数据入库。这个流程跑顺之后,知识库质量的返工率明显下降,而且每次检索效果出问题的时候,回头查一下对应 chunk 的检查记录,基本都能快速定位到是解析问题还是检索问题。
根据我个人的实操经验,做 RAG 的同学真的值得在文档预处理上多花点时间。最后再分享一个小技巧:检查报告别只保存当场看一眼就删掉,把它和文档一起归档,每次知识库更新的时候对比新旧两版报告的差异,能帮你发现文档变更带来的潜在风险。这一步成本很低,长期回报却很高,强烈建议用起来。
祝你的 RAG 项目少踩文档的坑。