跳到主要内容

搞懂Tika才能做好RAG文档解析

先来个例子。

朋友小陈做了一个内部知识库系统——员工上传各种产品手册和技术文档,然后通过AI问答来检索。系统上线当天,领导试了一下:

"我们XX-200系列的安装步骤是什么?"

AI回答得特别自信:

"XX-200系列的安装步骤如下:1. 打开包装箱取出主机……2. 连接电源线……"

乍一看挺像那么回事。但问题来了——整个回答跟实际手册上写的完全不一样,AI在一本正经地编。

小陈开始排查。先查向量检索,没问题;再查Embedding模型,也正常;最后把解析出来的文本一看——愣住了。

有三份产品手册上传后的解析结果:

  • 第一份PDF:解析出来全是空的。后来才发现这份PDF是扫描件,里面没有文字层。
  • 第二份Word:解析出来一堆PK开头的乱码。
  • 第三份PDF:倒是解析出东西了,但中文全变成了浜у搧璇存槑这种天书。

三份文档,三种翻车方式。 解析这一步出了问题,后面的切块、向量化、检索全白搭。

这个故事引出了一个很多人忽视的事实:文档解析是RAG流水线上最容易翻车的环节,而且翻车方式千奇百怪。

铁律

垃圾进,垃圾出。 文档没解析好,后面再怎么调优Embedding、向量库、Prompt,都是在沙子上盖楼。

文件不是你以为的那样

在讲怎么解决之前,得先搞清楚:为什么"读文件"这件事这么难?

来打个比方。文件就像快递包裹——你拿到一个包裹,得经过三步才能用上里面的东西:

  1. 看标签:包裹外面贴着"易碎品"标签——但有没有可能贴错了?
  2. 拆包装:有的用纸箱,有的用泡沫,有的用真空袋——拆法完全不同
  3. 看内容:拆开之后,里面可能是中文说明书,也可能是日文说明书——你得看得懂才行

文件也是这三层关系:后缀名是标签,文件格式是包装,内容编码是语言

标签会贴错——后缀名靠不住

文件后缀就是个名字,谁都可以改。实际工作中你会遇到各种奇葩情况:

  • 行政同事把.xlsx报表改成.txt再发邮件,因为公司邮件系统拦Excel附件
  • 某个上游系统吐出来的文件压根没后缀,就叫upload_20240801_001
  • 更离谱的——有人把一个HTML网页另存为.pdf后缀发过来

所以如果你的代码里有这样的逻辑:

if (fileName.endsWith(".pdf")) {
// 按PDF处理
}

那只是在看标签拆包裹,迟早要翻车啊。

包装方式天差地别——文件格式的本质

不同格式的文件,底层结构完全不一样。我们挑最常见的三类来看看它们的"内部"。

第一类:素颜出镜型(纯文本)

.txt.csv.log这些文件最老实,打开就是文字本身,没有任何包装。Files.readString()就能直接读。

第二类:俄罗斯套娃型(Office文档)

.docx文件的真实身份是——一个ZIP压缩包。不信的话,你现在就可以做个实验:随便找个Word文档,把后缀改成.zip,然后解压。

你会看到这样的目录结构:

解压后的.docx/
├── [Content_Types].xml
├── _rels/
├── docProps/
│ ├── app.xml ← 文档属性
│ └── core.xml ← 作者、创建时间等
└── word/
├── document.xml ← 正文藏在这里
├── styles.xml ← 样式
└── media/ ← 图片

正文内容被一层层XML标签裹着:

<w:body>
<w:p>
<w:r>
<w:rPr><w:b/></w:rPr>
<w:t>产品概述</w:t>
</w:r>
</w:p>
</w:body>

你直接用new String(bytes)去读一个.docx,读到的是ZIP的二进制数据,自然是一堆乱码。

.xlsx.pptx也是同样的套娃结构,区别只在于XML的schema不同。

第三类:密码本型(PDF)

PDF是最复杂的。它的文本不是"存"在文件里的,而是在页面上的。

PDF内部用自己的一套指令来描述页面内容:

BT
/F1 12 Tf
100 700 Td
(Hello World) Tj
ET

这段指令的意思是:"用F1字体、12号字,在坐标(100,700)的位置,画出Hello World这几个字。"

所以PDF的文字是"渲染指令",不是你理解的"文本数据"。更麻烦的是,有些PDF的文字干脆就不是指令,而是一张图片——扫描件就是这种情况。

来小总结一下
  • TXT像明信片,内容写在表面,一眼就能看到
  • DOCX像快递箱,得拆开好几层包装才能拿到东西
  • PDF像保险柜,得用专门的钥匙(解析器)才能打开

内容可能是"外语"——编码问题

包裹拆开了,但里面的说明书是外语写的——这就是编码问题。

同一段中文"产品使用说明",用不同编码存储,字节序列完全不同。如果你用错误的编码去解读,就会出现乱码。

最常见的两种编码冲突:

UTF-8文件被当成GBK读

正确内容:使用说明
乱码结果:浣跨敤璇存槑

GBK文件被当成UTF-8读

正确内容:使用说明
乱码结果:ʹ��˵��(或者直接报错)

更头疼的情况是,有些历史遗留系统生成的文档,同一个文件里混用了多种编码。前半段是UTF-8,后半段变成了GBK,这种你手动处理都费劲。

付费内容提示

该文档的全部内容仅对「JavaUp项目实战&技术讲解」知识星球用户开放

加入星球后,你可以获得:

  • 超级八股文:100万+字的全栈技术知识库,涵盖技术核心、数据库、中间件、分布式等深度剖析的讲解
  • 讲解文档:超级AI智能体、黑马点评Plus、大麦、大麦pro、大麦AI、流量切换、数据中台的从0到1的详细文档
  • 讲解视频:超级AI智能体、黑马点评Plus、大麦、大麦pro、大麦AI、流量切换、数据中台的核心业务详细讲解
  • 1 对 1 解答:可以对我进行1对1的问题提问,而不仅仅只限于项目
  • 针对性服务:有没理解的地方,文档或者视频还没有讲到可以提出,本人会补充
  • 面试与简历指导:提供面试回答技巧,项目怎样写才能在简历中具有独特的亮点
  • 中间件环境:对于项目中需要使用的中间件,可直接替换成我提供的云环境
  • 面试后复盘:小伙伴去面试后,如果哪里被面试官问住了,可以再找我解答
  • 远程的解决:如果在启动项目遇到问题,本人可以帮你远程解决
进入星球后,即可享受上述所有服务,保证不会再有其他隐藏费用。
知识星球二维码

1. 打开微信 -> 扫描左侧二维码 -> 加入「JavaUp项目实战&技术讲解」知识星球

2. 查看星球使用指导,获取完整项目讲解资料索引

👉 点击解锁全部付费内容
🎁优惠