1. 先别急着上RAG探矿文档的乱得先说清楚做探矿业务相关的工作手里攒下的资料十有八九是这样的20世纪90年代打印的老区调报告、某个地质队扫描存档的钻孔柱状图、Word里排版混乱的物化探异常查证记录、还有从地方矿政系统网页上复制下来的公告信息。平时找资料靠人工翻档案柜倒还凑合但一旦想把这些资料喂给RAG检索增强生成系统做智能问答第一步就卡住了——乱码。我接手这个项目时最大的感触是探矿领域的文档问题不是简单的格式解析而是文字压根读不出来和读出来了却检索不准的叠加。先说乱码的三个来源分清楚了后面清洗才知道往哪儿使劲。一是编码错乱。很多历史文档是早期DOS环境下用GB2312、GBK甚至Big5编码存的拿到现代环境下用UTF-8解析必然乱码。探矿数据里还有一个特殊场景野外采集仪器导出的数据文件编码方式完全取决于仪器厂商的固件设置同一个型号的仪器在不同年份导出的文件编码都可能不一样。二是字体与字形缺失。地质报告里大量使用了生僻字和专有符号比如矽卡岩的矽、铷元素的铷、地层符号里面带上下标的希腊字母。字体不支持时PDF解析出来全是方框或者问号。更麻烦的是不少老文档用了自造字在TrueType时代之前嵌入的私有字形现在的解析引擎根本识别不了。三是扫描件没有文字层。这个在探矿行业尤其严重。早期很多野外记录本、化探采样单、矿权登记表根本没有电子版只有扫描图片或者照片。这类文档在RAG里根本检索不了必须先过OCR。除了乱码还有一个比乱码更隐蔽的问题版式和语义错位。RAG的检索粒度是chunk如果chunk切得不对内容再干净也检索不到。举个例子一张区域地质调查报告里的地层特征表跨页被切开后上半页的表格标题在下一条chunk里完全找不到对应关系卷帘查询的时候就会漏掉关键地层描述。所以从乱码到高精度检索这个目标实际上要解决三层问题文字层可读、结构层清晰、检索层精准。这三层是递进关系前面的没做好后面的再好也没用。2. 清洗流水线的总体设计先分类再对症下药探矿业务数据的类型可以粗分为四类TXT日志或数据文件、Word报告、PDF扫描与电子版、网页公告或在线数据库内容。我之前犯过一个错误一上来就写了一个统一的清洗脚本结果Word里面的表格被干掉了PDF里的坐标被识别成特征词网页里的页眉页脚变成了噪声。后来我才意识到RAG清洗不是一道工序而是一条按文档类型分支的流水线。2.1 文档四分类与处理优先级先做好分类和优先级排序再动手处理。类型典型样例核心问题优先级TXT类野外仪器导出数据、日志文件、老式目录文本编码误判、定界符混乱高体量大Word类地勘报告、设计书、年度工作总结样式丢失、表格嵌套、宏污染高格式复杂PDF类区调报告扫描件、矿权图件附件扫描无文字层、版式错乱中解析难度大网页类矿政公告、网上公示、行业数据库页面页面噪声多、正文提取不完整中时效性强处理优先级不按文件格式来而按业务查询频率来。比如野外仪器导出的TXT文件工区内的钻孔编录、物探数据文件是日常检索的高频对象必须先清洗一些早期扫描报告查阅频率低可以排后面。优先级排序能避免把有限的时间耗在低频历史文档上。2.2 清洗链路的分层架构我的清洗链路大致分成四层。这个结构建议直接复用因为它天然对应了RAG管道的上游节点。第1层格式识别与分类。不看扩展名用Magic Number和内容嗅探判断真实格式。探矿行业很多文件扩展名是错的比如把PDF改成TXT方便邮件传输这一步不能省。第2层编码归一化。统一成UTF-8为所有下游组件建立一致的数据入口。这里的难点不是编码转换本身而是编码的自动检测准确率。第3层内容抽取与结构还原。按格式分支处理TXT做文本清洗、Word做样式与表格抽取、PDF做双轨解析文字版式和OCR、网页做正文提取。抽取结果统一转成带元数据的Markdown或JSON结构。第4层切分与后处理。清洗好的文本按照业务语义做切分给chunk打上来源标签文件路径、页码、表格编号、图件坐标等输出给向量化环节。这四层链路里最容易偷懒的是第4层很多人直接把文本按固定字符数切了就完事这在探矿场景里特别吃亏。地质报告里的一个重要矿化体描述可能跨越好几页固定字符数切分等于把完整语义切碎。3. 四种格式的清洗实操TXT、Word、PDF和网页各走各的路3.1 TXT的清洗编码检测比正则替换重要得多探矿领域接触的TXT文件我一个一个说仪器导出文件。最常见的是化探样品分析数据、物探测量原始记录。这类文件的定界符不一定是制表符可能是空格、逗号、竖线甚至混合使用。清洗策略是先按行读取统计第一行的字符组成判断是固定宽度还是定界符模式再做字段映射。老式档案文本。有些老资料是从印章版材料手工录入的段落之间会有全角空格、连续换行、页眉重复还有OCR造成的同音字错误。这类文本处理重点是去重段落头部的统一格式、统一换行符、修正明显的OCR错误比如把钾识别成甲、岩心识别成言心。编码检测是TXT清洗里决定成败的一步。Python里老牌的chardet库效果还行但速度慢且大文件容易误判我后来换成了charset-normalizer准确率和速度都更好。实测下来有个经验不要盲目信任检测结果先抽样检测再结合文件内容特征交叉验证。比如一个文件名带物探的TXT检测出来是ISO-8859-1那大概率是误判——物探数据文件不太可能用西文编码存中文内容。此时要回退到GB18030尝试解码。还有一个小技巧检测到编码不一致时优先用GB18030而不是GBK因为GB18030是GBK的超集覆盖面更广。3.2 Word的清洗技术难点在样式还原和表格抽取探矿业务的Word文档大多是技术人员自己写的报告格式非常「个性化」。字体混用、标题层级乱套、表格里套表格、嵌入对象地图、剖面图满天飞。对于RAG来说Word清洗的核心不是追求视觉上和原文档一致而是让文本内容和结构关系能被准确抽取。我用的是python-docx做基础抽取但有几个坑一定要避开坑一正文内容和文本框内容分离。python-docx默认只读取body里的段落而地质报告里的图签、图注经常放在文本框TextBox里。需要额外遍历document.part.package里的XML把w:txbxContent节点里的文字也提取出来。坑二表格结构容易丢。探矿报告里的地层简表、岩石化学分析结果表简直是重灾区——单元格合并、跨页断行、列宽设置变形抽取出来经常是乱的。我的处理方式是对每一个表格对象先读列宽信息判断表格方向横向表还是纵向表再逐行逐单元格唯一标识后拼接。遇到合并单元格需要先通过gridSpan和vMerge判断跨度否则数据会错位。这一步没法完全自动化我最终保留了人工抽查的兜底。坑三宏污染。从外部收来的Word文档经常带宏python-docx读取时不会执行宏所以没影响但如果直接用VBA或Docx2Txt工具批量转换宏可能会触发安全警告拖慢进程。安全的做法是先把文档转成docx格式如果还是老版本.doc再用LibreOffice无头模式转成纯文本或中间格式。实测LibreOffice的docx转换效果比很多第三方库稳定对表格和样式的保留率更高。如果你处理的Word文档量特别大建议直接用Pandoc做一次中间转换数据流这样走docx → pandoc → markdown保留表格线→ 清洗脚本 → 结构化的纯文本。Pandoc对Word表格的支持比直接读XML省事得多但遇到病态文档比如嵌套表格超过三层也会崩需要脚本兜底。3.3 PDF的清洗双轨解析是唯一出路PDF是探矿文档里最令人头疼的格式。地质报告往往同时存在两种形态文字版PDF从Word直接转换而来和扫描版PDF从纸质档案扫描。两者处理方式完全不同必须分开。文字版PDF核心是坐标信息保留和阅读顺序还原。我强烈建议用PyMuPDFfitz而不是pdfplumber做RAG清洗的前置解析。PyMuPDF的优势是速度快、能拿到每个文本块的坐标框。拿到坐标后先把页面按物理布局切分成区块标题、正文、页脚、页眉再按坐标从上到下、从左到右排序。这一步做不对段落顺序是乱的——很多地质报告是双栏排版默认按流式读取会把左栏前半部和右栏前半部拼到一起。具体操作上我的脚本逻辑是遍历page.get_text(dict)拿到每个block的bbox和text按block的y0坐标排序同一行的x0坐标再排序。遇到跨栏文本块通过列宽百分比判断是否属于同一流。地学报告经常有标题跨双栏、正文分两栏的情况需要额外判断当前block是否横跨页面中线的左右两侧——如果横跨则看作通栏段落否则按左右分栏处理。这个逻辑让我处理几百份报告的准确率从70%提到了92%左右。扫描版PDF没有文字层直接进OCR。这个在后面的章节单独展开说因为探矿行业的OCR有特殊难点。另有一个容易忽略的点PDF里的图件地质图、剖面图、柱状图是以矢量图形存在的PyMuPDF能提取出嵌入的图片但图片本身没有语义。如果检索需求涉及图件里的内容比如查一下矿区南部有哪些断层单纯文本层是不够的。我目前的做法是把图件先抽取出来单独归档图名、图例和相邻段落文本作为元数据关联检索时需要语义匹配图件元数据来间接定位。这个方案不完美但能应付大多数查询场景。3.4 网页的清洗正文提取要专门做探矿业务的网页信息来源很杂矿政管理部门的公告栏、地质资料馆的在线目录、行业协会的新闻页、学术数据库的摘要页。RAG如果要覆盖这些信源清洗的重点是把正文和页面噪声分离。我测试过几款主流正文提取工具对探矿类网页的效果差异很大工具效果适用场景Trafilatura稳定、抽取速度快政府公告类、新闻类页面Readability对长文效果好学术文本、PDF化网页BeautifulSoup 手写规则高度可控定制化站点抓取Trafilatura是目前我用得最多的它对页面的页脚版权信息、导航栏、广告区识别得比较干净而且支持多种元数据抽取标题、日期、作者、URL这些元数据在RAG里可以作为有用的过滤条件。但Trafilatura对表格的处理比较弱探矿公告里经常有矿业权审批结果表这类带表格的内容提取出来会被压扁成一坨文本检索精度受影响。我的处理方式是先检查页面里是否有table标签如果有先单独把表格提出来做结构化再对剩余正文做文本提取最后把表格Markdown和正文拼接成一个文档块。网页清洗还有一个探矿场景特有的需求坐标信息的正则抽取。矿政公告里经常包含矿区坐标范围类似东经115°30′00″~115°45′00″这样的关键数据。这类信息用通用清洗流程很容易被当作普通文本处理掉。我的做法是在清洗脚本里专门加了地理坐标正则命中后自动转为十进制度数并附加到文档元数据里这样后续按工区范围过滤检索结果时就能直接用了。4. 图片型PDF和扫描件的OCR攻坚——探矿业务没法绕过这道坎4.1 什么时候必须上OCR以及识别前的关键预处理判定一份PDF是否需要OCR不能只看有没有文字层还要抽查文字层的质量。有些扫描版PDF虽然做过OCR但质量差识别结果全是口口口或错字连篇这种比没有文字层还危险——因为下游检索会把这些乱码当成有效内容拉低整体精度。我的判断标准是随机抽3页按页提取文字如果乱码字符比例超过5%就整份文件重新走OCR。真正的扫描件OCR在探矿领域有几个通用方案解决不了的痛点痛点1图表混排。地质图件上既有线划又有注记OCR引擎常常把线条识别成文字笔画。我处理这类页面的策略是先用OpenCV做连通域分析检测大面积的线状连通域并填充为背景色再送OCR。实测对地质剖面图的注记识别率有明显提升。痛点2手写体。野外记录本上的手写采样记录目前没有完美的自动方案。折中的办法是识别印刷体标题和表格框架手写部分转成图片单独存储同时生成图片存在的文本标记。这样可以保证RAG不会因为缺少这部分内容而误答同时又不会因为OCR错误把手写内容识别得面目全非。痛点3分栏与阅读顺序。很多地质报告是双栏排版OCR引擎默认按单栏流式输出。PaddleOCR提供了版面分析功能PP-Structure能输出每个文本块的位置坐标和版面顺序这个对恢复双栏阅读顺序很有帮助。建议多花点时间在版面分析上而不是直接调识别接口。4.2 OCR流水线的具体搭建我当前的OCR流程是PDF按页转图片用PyMuPDF将页面渲染成300 DPI的PNG。精度太低识别率上不去太高文件体积暴涨。300 DPI对大部分印刷体中文够了对密集表格可以按需调至400 DPI。图像预处理灰度化、降噪、二值化。这里有个技巧灰度化后不要直接二值化先用自适应阈值如Otsu看看效果很多地质报告的纸张底色发黄固定阈值会把背景噪声一股脑识别成文字。版面分析用PaddleOCR的det和rec模型分开调用det用于文本检测rec用于文字识别中间加一个cls方向分类器处理倒置文字。注意PaddleOCR默认输出是逐行文字没有排版信息一定要开启use_angle_cls处理倾斜。结果结构化把识别出的每行文字和坐标位置对齐再按上一节提到的坐标排序逻辑重建阅读顺序。术语纠错加载自定义地质术语词典做后处理。这一步是精度倍增器后面单开一小节讲。4.3 OCR错误修正地质专业词汇表必须融入后处理OCR识别的错字分布不是随机的而是集中在笔画复杂的字、生僻字和专有名词上。地质资料里砂岩可能被识别成砂石、泥岩被识别成泥言、花岗岩被识别成花冈岩。这些错误如果只是个别字偏差语义检索或许还能扛住但辉绿岩识别成灰绿岩后向量表征会偏离检索精度下滑得非常明显。我的修正方案分两层第一层词典替换。整理一份常见地质术语的词频表包含矽卡岩大理岩玄武岩等数百个高频词。OCR后处理时对识别结果做模糊匹配优先用编辑距离在1-2范围内的词典词替换。这层能修掉大约60%的术语错误。第二层特殊规则修复。探矿文本里有不少化学式、地层代号和同位素符号OCR识别经常把下划线、上标丢掉。我写了正则把K2O这一类的化学式、地层符号如J2代表中侏罗统抽出来统一转成标准形式比如将J_2明确标记为J2。注意不要强制性规范化所有符号否则会把J2(下段)和J2(上段)混到一起语义就丢了。提示OCR后处理词典要按工区/矿区定制。不同矿区的矿物名称差异很大金矿和铁矿的岩性描述完全不是一回事。我在处理一个多金属矿区时把当地最常见的30个地层和岩性术语单独抽出来做成短列表修正效果比通用大词典好得多。5. 清洗完还不行我得让检索效果被测出来清洗到这一层很多人的任务就结束了。但高精度检索才是最终目标。清洗做得到不到位得用检索指标来验证。我搭建的验证流程是这样的5.1 构建探矿语境的检索测试集通用RAG评估用的公共数据集比如Natural Questions不适合探矿场景。我按照矿区实际情况构造了三类测试问题实体型问题矿区内三叠系地层的主要岩性有哪些关系型问题XX断裂带与矿化体的空间位置关系是什么数值型问题某矿区伴生金品位最高达到多少每类问题准备30条每题预先从报告、表格或网页里标注出正确答案的位置哪个文档、哪一页甚至哪一段。这样在清洗后跑一遍检索就能算出Top-K召回率和命中位置的中位数——这个中位数非常直观清洗前可能命中在第30个chunk清洗后提到第3个chunk提升效果一目了然。5.2 清洗质量不高时重排序也救不了你现在有不少RAG框架自带了重排序Rerank模块可以先用向量召回候选再用Cross-Encoder精排。有一个常见的误解是清洗不行靠Rerank兜底。我实测过Rerank确实能把排名靠前的错误结果压下去但如果清洗阶段把关键信息切碎或污染了召回阶段根本找不回那个chunkRerank再强也无济于事。所以清洗验证和Rerank调优要分开做先验证召回率再加Rerank看最终准确率哪一环都别跳过去。5.3 中文分词的坑和命名实体保护最后一个影响检索精度的问题是分词。探矿文本里大量专业术语在通用分词器里会被拆碎。矽卡岩型铜矿可能被拆成矽卡岩型铜矿那就完全没法建立语义关联。解决方式有两个一个是给分词器加载用户自定义词典。Jieba这类分词器支持添加自定义词把探矿术语词典加进去后分词结果明显改善。另一个是评估向量模型对领域术语的敏感度。embedding模型如果是通用于新闻、百科的对蚀变带激电异常视电阻率这些词的空间表征不够准确。条件允许时收集几万条探矿报告文本做继续预训练或微调效果提升非常明显。我个人的体会是先别急着换大模型把分词语料和领域embedding做扎实提升的幅度比你想象的大得多。6. 走过的弯路三个容易翻车的细节6.1 编码误判比不判还糟之前处理一批物探仪器导出的TXT时检测出来是UTF-16我直接转换了。下游确实不再乱码但坐标数据全乱套了——因为原始数据是GBK编码其中一部分中文注释被误判成UTF-16后二进制层面发生了位移。后来我加了一个硬规则凡是检测结果与实际内容明显矛盾比如文件名含中文但检测为西文编码时自动尝试所有候选编码并对每种结果做中文字符占比评分选最高的那个。这个规则上线后误判率降到了3%以内。6.2 表格切碎后的上下文丢失探矿报告里大表很多动态切分chunk时表头被隔离到上一个chunk表体到了下一个chunk。检索某地层的地球化学特征时向量匹配到的是表体但表头列名在另一个chunk里导致系统不知道这些数值对应的是Au金含量还是Ag银含量。我最后的解决方法是切分时把表格整体作为一个chunk不做内部切分。如果表格超过chunk最大长度就按行拆成两块但每块前面都重复一遍表头。这个操作虽然费一点存储但检索精度确实有提升。6.3 清洗过度把格式信息全删了反而不利于检索展示一个我自己踩过的坑刚开始写清洗脚本时我追求纯净文本把段落缩进、层级的序号、表格线、页眉页脚全部删除。结果发现一些查询比如第三章讲了什么召回时找不到层级信息。后来调整思路清洗的目标不是把文本变干净而是把信息变成可检索的结构。章节标题和层级编号要保留因为这些是语义锚点页眉页脚这种与正文无关的重复信息要删因为它们会干扰embedding的表征。区分这两者的关键是删除的内容是否承载着定位信息——能帮检索定位到这是哪个章节、属于哪张表的内容都值得保留。一些最后想说的话这套清洗链路从搭建到调优我走了将近三个月其中大概有一半时间都花在数据探查和踩坑修复上。探矿业务的资料特殊性决定了它没法直接用通用RAG流程套完就跑。你如果也要处理类似场景我建议从优先级最高的那10份文档开始把清洗、切分、检索、评估这个闭环先跑通再逐步扩大清洗范围——不要一上来就追求全量清洗。清洗是一个持续迭代的过程不是一次性预处理任务。还有一点想提醒你市面上有不少号称全自动文档解析的RAG工具它们对通用办公文档效果不错但对探矿这种专业性强、历史资料杂、扫描件占比高的场景还是要自己掌握清洗的控制权。工具可以帮忙做初筛但最终的清洗规则、术语表、切分策略必须基于对业务文档的深入理解来定制。这也是从乱码到高精度检索这条路上任何框架都替代不了的部分。
阅读完成 · 觉得有帮助?