
做探矿业务知识库这一年多我最深的体会是RAG系统的上限往往在数据清洗阶段就被定死了。地质报告、钻孔编录、化探分析、储量估算说明书……这些文档从TXT、Word、PDF、网页各种渠道汇集过来没有一份是“干净”的。这里可能有一个GBK编码的TXT文件在你UTF-8的解析程序里变成满屏乱码那里一份扫描版PDF用OCR跑出来一堆错字。好不容易过了清洗关分块又切断了矿体描述检索出来的结果驴唇不对马嘴。这篇文章把我踩过的坑、试过的方案、最终沉淀下来的清洗流程整理出来给同样在探矿或者类似重文档行业里做RAG的朋友一个参考。我尽量少讲虚的多给能直接落地的细节。1. 探矿知识库的“数据底子”有多难搞1.1 地质资料不是普通文档先给不熟悉探矿业务的朋友交代一下背景。我们说的“探矿业务”不是拿着金属探测器在野外转一圈就完了而是从区域地质调查、化探扫面、物探异常查证到槽探、钻探、坑探工程再到样品化验、储量估算、编写勘探报告的一整条流程。这条流程里沉淀下来的文档类型非常杂区域地质报告、物化探工作报告、钻孔柱状图与岩芯编录表、坑道编录本、化探样品分析结果表、岩矿鉴定报告、储量估算说明书、野外记录本扫描件以及项目管理系统里的网页数据页。这些资料时间跨度可能从上世纪八十年代直到现在格式从手写扫描件、DOS时代的TXT文件到近年来越来越多的PDF报告和Word文档。这些文档有一个共同特点知识密度高单份动辄几百页而且同一矿区的信息散落在不同格式、不同年代的资料里。这也是我当初决定上RAG的原因——传统的关键词搜索根本没法把“某矿段深部是否存在隐伏矿体”这种需要跨报告综合的问题回答出来。但真正落地以后我才发现RAG的每一步都建立在数据质量之上而这个行业的数据质量恰恰是最难啃的骨头。1.2 检索精度从哪一步开始掉链子很多团队把RAG项目做成“解析—切块—向量化—检索”四步走上了线才发现效果完全不对。我在排查了十几次之后总结出一个规律检索精度的问题十有八九在解析和清洗阶段就已经注定了。典型的失败链路是这样的——某个TXT格式的钻孔编录文件原始编码是GB2312里面还有大量“◆”“○”“△”这类岩性符号。程序用UTF-8去读符号全变成“锟斤拷”式的乱码后续无论切块还是向量化喂进去的都是无意义字符。再比如一份Word版的地质报告里面的矿体品位表被作者做成了图片抽文本的时候表格内容直接消失检索“平均品位”永远命中不了。更隐蔽的问题是“错位”PDF解析时目录和正文混在一起或者Word里嵌入了多个文本框抽取出来的文字顺序完全不对。这些问题在人工阅读时根本不存在因为人的眼睛会自动纠正但机器不会向量化的模型更不会。垃圾进去垃圾出来检索精度就是在这一个个细节里被吃掉的。1.3 清洗工作在RAG流程中的真实位置我后来画过一张自己项目的流程图发现清洗不是一个“预处理步骤”而是贯穿整个数据侧的主干工程。从文件接入、格式识别、编码检测、乱码修复到文本抽取、表格还原、图片OCR、结构清理、元数据提取再到分块策略调整每一环都在影响最终检索的精度。所以这篇文章讨论的不是“该不该清洗”这种原则问题而是探矿场景下具体怎么洗、用什么工具洗、洗到什么程度才算达标。我把整个过程拆成“格式清洗”和“语义清洗”两层格式清洗解决的是“机器能不能读到正确字符”的问题语义清洗解决的是“读到的字符能不能形成有意义的段落”的问题。后续所有章节都会围绕这两层展开。2. 四类文档格式的清洗难点拆解2.1 TXT与编码乱码的真正源头TXT在探矿业务里的占比远超很多人想象。钻孔编录、化探采样记录、物探数据导出的剖面数据很多老资料都是TXT。这类文件的好处是结构简单、体积小坏处是编码乱得让人想摔键盘。国内早期地质资料最常用的编码是GB2312和GBK部分老系统甚至可能用GB18030或者更冷门的编码。如果你的解析Pipeline缺了编码检测这一步默认用UTF-8去读GBK编码的中文就会变成典型的乱码。注意乱码不是“完全看不出内容”而是“锟斤拷”“烫烫烫”这类替换字符或者成片的不明方块。识别乱码还有一种更隐蔽的情况文件本身是GBK编码但内容里恰好有一部分被以UTF-8方式截断保存整份文件变成了“半乱码”用单一编码规则根本解不干净。我在项目里最终确定的处理方式很简单读文件时先用二进制方式读取一段内容用chardet或charset-normalizer做编码检测检测置信度超过0.9就按其结果解码低于这个阈值就用GBK尝试解码并检查替换字符比例。另外遇到“半个字符被截断”的情况可以用errorsignore先把坏字节丢掉再用人工或正则补查关键字段。这一步看起来基础但它决定了后续所有环节能不能拿到可用的文本我做过的项目中仅这个动作就挽回了一半左右的TXT数据。2.2 Word抽文字只是第一步现在的探矿报告很多用Word撰写尤其储量估算说明书、设计评审文件这类“新文档”。很多人觉得Word好处理python-docx跑一遍就完了实际上Word里的问题比TXT隐蔽得多。第一个坑是“图片化表格”。在Word里有人会把化验结果表、钻孔柱状图、剖面图做成嵌入图片段落抽取时能拿到文字表格数据全丢了。解决这个问题需要两步第一步把Word里的内嵌图片全部导出第二步调用OCR或者图像识别管线把表头、数值、单位结构化出来再分别入库。这个工作量不小但探矿文档里这些表格恰恰是最值钱的定量数据丢不得。第二个坑是文本框与分栏。地质报告为了排版好看经常用文本框放图注、用分栏放对比内容。python-docx默认只遍历document.paragraphs文本框里的文字根本取不到。你需要额外遍历document.element.body里的w:txbxContent节点或者干脆把Word转成PDF再用PDF解析器处理后者在某些场景下反而更省事。第三个坑是修订痕迹与批注。老专家用修订模式改过的报告正文里会残留删除标记和批注文本。清洗时最好先接受所有修订、删除批注后另存一份干净版本再进解析管线不然检索出来的内容会带一堆“【批注】此处待定”之类的噪声。2.3 PDF一套策略应付不了所有文件探矿行业的老报告、出版成果、扫描归档资料绝大多数是PDF。PDF是我踩坑最多的格式因为它的内部结构千差万别一套解析策略根本打不了天下。我自己按“文本型、扫描型、混合型”三类分开处理。文本型PDF指那些由Word或排版软件直接生成的PDF文字信息完整可提取。这种用PyMuPDFfitz提取文本又快又准配合PDFMiner或pdfplumber处理精细排版的表格也可以。扫描型PDF是纸面报告扫描成图片后再合成的根本没有文本层必须OCR。中文OCR推荐PaddleOCR或RapidOCR地质报告里常见的手写体数字和特殊符号比如品位符号、化学元素下标得专门处理或做后处理。混合型PDF最常见——正文是文字层但图表、附件是扫描图。这种要先按页判断“是否有可提取文本”文本页走PyMuPDF无文本页走OCR再把两部分按页码拼接。还有个容易忽略的坑CAD导出的PDF。探矿报告里的地质图、工程布置图很多是从CAD打印出来的图层多、线条密常规文本提取只能拿到标注文字图例和符号信息会丢失。这类文件我的建议是不要强求文字提取而是把图纸单独存为图文档用多模态模型理解或者只保留其中的图名、比例尺、坐标等关键标注。2.4 网页结构噪声与动态加载探矿业务里的网页文档主要来自两类一类是单位内部的地质资料管理系统、项目数据库的详情页另一类是地质资料馆、行业信息公示平台上的成果发布页面。网页数据看着好拿实际上有两个麻烦。第一个麻烦是结构噪声。网页里除了正文还有导航栏、面包屑、侧栏推荐、页脚声明、弹窗广告。拿BeautifulSoup抓下来只取text的话这些噪声全混进正文。我的做法是先定位正文容器通过id、class或者正文密度算法只抽取容器内的文本再用正则去掉“发布时间”“来源”“阅读量”这类元信息行。还有一个细节很多资料类网页的正文是表格排版表格里的标题和内容在DOM上可能是平级节点直接抽取文字顺序会乱要根据表格行的语义重新拼接。第二个麻烦是动态加载。页面数据不是HTML里自带的而是通过JavaScript异步从接口拿的。用requests直接抓HTML什么正文都拿不到。解决方式有三种用Selenium或Playwright做真实浏览器渲染后再提取或者直接在浏览器开发者工具里找到数据接口拿到接口的JSON后解析字段。探矿业务里我优先推荐找接口因为数据系统一般返回结构化JSON清洗成本最低。实在找不到接口再上浏览器渲染不过要小心站点的访问频率别把自己搞成攻击流量。四类格式的核心清洗策略我整理了一张速查表方便对照格式最常见陷阱核心清洗策略推荐工具TXT编码错乱、地质符号乱码编码检测、乱码替换、符号映射charset-normalizer、chardetWord图片化表格、文本框、修订痕迹遍历段落/表格/文本框、图片导出OCRpython-docxPDF扫描版、多栏错位、CAD图纸分类型解析、按页分流OCRPyMuPDF、pdfplumber、PaddleOCR网页结构噪声、异步加载正文容器定位、接口直联抓取Playwright、BeautifulSoup3. 实操搭一条探矿文档清洗管线3.1 整体流程设计与工具选型说了这么多难点下面给一套我跑通过的清洗管线方案。整体流程按“入口判断—格式解析—内容清洗—结构还原—质量校验—导出标准文本”六段来设计。入口判断这一步要识别文件的真实格式不能只看扩展名。很多TXT文件其实内容是用Word排版后存成纯文本的有些PDF内部嵌入了Word源文件。我用一个简单的策略先读文件头判断是Zip、PDF、还是纯文本Zip开头的docx文件用python-docx处理纯文本文件做编码检测后再解析PDF文件继续判断是否带文本层。工具选型方面文件格式识别用filetype编码检测用charset-normalizerWord解析用python-docxPDF文本层用PyMuPDF扫描件OCR用PaddleOCR网页抓取用Playwright加BeautifulSoup最后的文本标准化用半规则半人工的方式。这一套工具全部开源免费部署成本低对探矿这类预算敏感的项目尤其友好。下面是处理流程的示意# 伪代码示意清洗流程生产环境需补全异常处理和日志 # 1. 读取文件头判断真实格式 # PDF - fitz.open逐页 get_text()无文本层页面转 OCR # ZIP - python-docx 遍历 paragraph / table / textbox # 纯文本 - charset_normalizer 检测编码按检测结果解码 # 2. 对抽取文本做字符规范化、乱码标记、表格结构还原 # 3. 清洗后文本落盘供后续切块与向量化使用3.2 清洗核心环节的实现要点编码清洗与字符规范化。文本抽取完成后先做字符层面的清洗把全角字符统一成半角把各种引号统一样式把连续空白压缩成单个空格把乱码替换字符单独标记出来。探矿文档里常见的地质符号如“⊙”“∟”“△”不建议强行转成普通字符最好保留在原位并在后面加文字标注例如“△”标注为“岩性符号角砾状构造”。这一步需要建一个“地质符号映射表”前期花点时间后期收益很高。表格结构还原。探矿文档里最核心的表格是化验结果表、钻孔编录表和储量计算表。表格还原的目标不是把格子打平而是保留“行—列—单元格”的三维关系。Word表格可以用python-docx直接遍历PDF表格用pdfplumber的extract_table网页表格直接解析HTML的table标签。还原后的每张表建议单独存成Markdown表格或JSON结构同时保留一个“表格标题首行表头”的摘要方便后续切块时把表格作为独立单元处理。段落合并与章节识别。原始抽取的文本经常被PDF分页打断比如“矿体特征”四个字在第10页正文内容从第11页开始。清洗时要根据页眉页脚、页码、章节编号如“第四章”“4.1”重新拼接段落。我用一个技巧先把PDF每页的文本按页尾标记切掉页脚再保留页首标题然后按“章节编号开头”或“上一行末尾无标点”来判断段落是否续接。这一环节做得越细后面RAG切块时上下文完整度越高。3.3 清洗质量如何客观验证清洗完了不能拍脑袋说“看起来干净了”得用指标说话。我在项目里用三把尺子量清洗质量。第一把尺子是“字符级有效比例”清洗后的文本中可打印有效字符占总字符的比例。乱码替换字符如UFFFD、控制字符、异常空白的比例越低越好。第二把尺子是“字段级完整性”从清洗后的文本中随机抽样50条人工核对关键字段矿区名称、钻孔编号、取样深度、品位值是否完整出现。这个指标用来发现解析丢失比如表格图片没OCR导致的数字缺失。第三把尺子是“检索级召回”在清洗后的语料上建立一次临时RAG索引用10组业务问题去查统计Top-5命中率。这一把尺子最接近最终效果排查问题时也最有效。我在实际项目中设定了一个最低门槛字符级有效比例不低于98%字段级完整性不低于90%检索级召回不低于80%。达不到就回头查清洗环节而不是急着调embedding模型或切块参数。记住清洗管线的产出物不是一堆“看起来能读”的文本而是“关键业务信息不丢失、检索能命中”的语料库。4. 从清洗走向高精度检索的进阶配置4.1 地质术语词典与同义词扩展清洗做得差不多了检索精度要再上一个台阶就得在语义层面做文章。探矿领域的专业术语有个特点同一个概念在不同报告里写法完全不一样。比如“黄铁矿”有时候写“FeS2”有时候写“硫铁矿”老报告里还可能直接叫“黄铁”“铅锌矿”经常写成“Pb-Zn”“激电中梯”在物探报告里叫“中梯装置”在化探报告里又变成“IP中梯”。如果只用原词去检索跨报告查“硫化矿”相关问题时向量检索大概率漏掉大量资料。解决办法是建一张领域别名表。清洗过程中可以把识别到的“规范术语别名英文缩写”写入别名表比如“黄铁矿—FeS2—硫铁矿—pyrite”“铅锌矿—Pb-Zn—方铅矿—闪锌矿”。这张表在检索端有两种用法一种是在查询时做同义扩展把用户问题里的词替换或补充成多个同义词后再去检索另一种是在索引端把文章中的别名统一规范化后再向量化减小语义漂移。两种方案我都试过实际效果是“索引端规范化查询端同义扩展”双管齐下最好检索召回率能提高10到20个百分点。4.2 分块策略要跟着文档结构走RAG里的切块策略很多教程都是建议按固定长度切512或1024个token。探矿文档里如果这么干大概率把一段完整的矿体描述切成两半检索时要么召回一半内容要么答案上下文不全。我的做法是“结构优先长度兜底”。对结构化明显的文档先按章节切比如“第四章 矿区地质”整章作为一个大块对表格把一张完整的化验表作为一个块并给它一个带表格标题和字段名的摘要前缀对段落式的描述文本按“段落上下文摘要”切块段落太长的再做语义分割。每一类块都可以在向量化之前给文本前面拼接一段“元数据头”例如“【文档类型】储量估算说明书【矿区】XX矿区【章节】第四章”。这样向量检索时即使正文语义不明显光凭元数据也能把候选文档拉回来重排阶段再筛选效果立竿见影。顺便提一下chunk大小的选择逻辑块太大embedding的语义会被稀释检索精度下降块太小上下文缺失答案生成的质量下降。探矿文档里的描述性文字我最终用的是800到1200字左右的块配合50到100字的重叠。这个数值不是拍脑袋定的而是用检索级召回指标在50份报告上做了两轮对比后选出来的。4.3 检索链路里的“最后一公里”清洗和切块都到位了最后的检索精度还与两件事有关embedding模型和重排器。探矿文档以中文为主、夹杂大量数字和字母我用的是针对中文优化的大规模向量模型效果比通用英文模型好得多。模型选型上不要迷信榜单直接用你的清洗后语料建一个小规模的检索评测集对比两三个模型的命中率再定。重排器是很多人忽略的环节。第一次向量检索拿回Top-50如果不做重排直接喂给大模型噪声会很大。我加了bge-reranker这一类的交叉编码器把Top-50精排成Top-5再从Top-5里取出最相关的文本块作为大模型的上下文。这一步的收益非常明显尤其在“跨报告综合”类问题上重排能把正确答案从一堆相似但无关的段落里捞出来。另外阈值设定也很重要检索相似度低于0.6的结果基本不要进重排直接丢弃省时又降噪。5. 实战问题速查与踩坑记录5.1 编码问题排查清单探矿TXT文件乱码排查顺序建议是先用chardet检测原始编码如果检测出来是GB2312换成GBK重新解码如果解码后仍然有零星乱码检查文件是否被多次转换过——比如原本GBK转成Unicode又转回GBK这类文件内容会二次变形处理方式是每个字段单独做乱码识别保留能恢复的部分如果连检测都检测不出来直接用二进制模式搜索关键ASCII串比如钻孔编号格式把文件切成几段分别处理。5.2 PDF解析失败排查清单遇到“解析出来全是空白”或“文字顺序乱”的PDF先检查是否是扫描版用fitz打开后看每页的get_text长度接近零的就是扫描页走OCR。文字顺序乱通常是多栏排版的PDF被当成单栏抽取了用pdfplumber按列切分可以解决。“字体缺失导致文字丢失”也很常见这时候优先用系统字体补全或者改用其他解析器交叉验证。还有一个我经常踩的坑PDF保护密码。很多老报告有打开密码但内容是公开的可以在合规前提下做密码解除处理后再解析。5.3 检索效果差该怎么定位搜索“检索不准”时我用逐层定位法快速找到瓶颈现象排查方向常见原因检索不到相关内容语料层文档未清洗成功、未入库或清洗时内容被误删能检索到但命中错误段落索引层切块过大导致语义被稀释或元数据头缺失命中正确但答案质量差组装层未加重排、阈值不当、上下文截断不合理具体操作上先检查清洗后的语料里是否真的有能回答这个问题的文本如果没有问题在数据缺失回去补数据。再单独检查某一篇文档能否被检索到用文档中的一句话作为查询词看向量检索能不能命中原文如果命中不了问题在索引或embedding去调切块或换模型。如果文档能被检索到但答案质量差问题在上下文组装或大模型指令调prompt或加重排。这样逐层排查基本十分钟内能定位到瓶颈。5.4 我从项目里总结的几条教训写到这里分享几条被现实按在地上摩擦出来的心得。第一条清洗管线一定要保留中间产物。每个环节输出的清洗后文本、表格JSON、元数据文件都落盘出了问题可以直接排查是哪个环节掉的链子不用重跑全流程。第二条地质符号和单位符号别乱删。我曾为了“干净”把“Φ75mm”里的Φ删了结果检索“75mm孔径”永远查不到后来才知道Φ是钻孔孔径的标准符号。第三条人工抽检永远不能省。自动指标再漂亮也要让人随机翻几份清洗后的语料因为地质报告里有大量“看起来像乱码其实是专业符号”的特例只有做过这个行业的人才能分辨。我个人在实际操作中的体会是探矿业务里的RAG项目与其说是在做算法优化不如说是在做数据工程里的精细活。每一次检索精度的提升背后都是一个个字符、一张张表格、一条条字段的较真。把清洗这关打通了后面的路自然就好走了。这套方法不止适用于探矿在能源、环境、地质调查这些同样依赖老旧多格式文档的行业里思路都是相通的。