搞懂Tika才能做好RAG文档解析
先来个例子。
朋友小陈做了一个内部知识库系统——员工上传各种产品手册和技术文档,然后通过AI问答来检索。系统上线当天,领导试了一下:
"我们XX-200系列的安装步骤是什么?"
AI回答得特别自信:
"XX-200系列的安装步骤如下:1. 打开包装箱取出主机……2. 连接电源线……"
乍一看挺像那么回事。但问题来了——整个回答跟实际手册上写的完全不一样,AI在一本正经地编。
小陈开始排查。先查向量检索,没问题;再查Embedding模型,也正常;最后把解析出来的文本一看——愣住了。
有三份产品手册上传后的解析结果:
- 第一份PDF:解析出来全是空的。后来才发现这份PDF是扫描件,里面没有文字层。
- 第二份Word:解析出来一堆
PK开头的乱码。 - 第三份PDF:倒是解析出东西了,但中文全变成了
浜у搧璇存槑这种天书。
三份文档,三种翻车方式。 解析这一步出了问题,后面的切块、向量化、检索全白搭。
这个故事引出了一个很多人忽视的事实:文档解析是RAG流水线上最容易翻车的环节,而且翻车方式千奇百怪。
垃圾进,垃圾出。 文档没解析好,后面再怎么调优Embedding、向量库、Prompt,都是在沙子上盖楼。
文件不是你以为的那样
在讲怎么解决之前,得先搞清楚:为什么"读文件"这件事这么难?
来打个比方。文件就像快递包裹——你拿到一个包裹,得经过三步才能用上里面的东西:
- 看标签:包裹外面贴着"易碎品"标签——但有没有可能贴错了?
- 拆包装:有的用纸箱,有的用泡沫,有的用真空袋——拆法完全不同
- 看内容:拆开之后,里面可能是中文说明书,也可能是日文说明书——你得看得懂才行
文件也是这三层关系:后缀名是标签,文件格式是包装,内容编码是语言。
标签会贴错——后缀名靠不住
文件后缀就是个名字,谁都可以改。实际工作中你会遇到各种奇葩情况:
- 行政同事把
.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的问题提问,而不仅仅只限于项目
- 针对性服务:有没理解的地方,文档或者视频还没有讲到可以提出,本人会补充
- 面试与简历指导:提供面试回答技巧,项目怎样写才能在简历中具有独特的亮点
- 中间件环境:对于项目中需要使用的中间件,可直接替换成我提供的云环境
- 面试后复盘:小伙伴去面试后,如果哪里被面试官问住了,可以再找我解答
- 远程的解决:如果在启动项目遇到问题,本人可以帮你远程解决
