ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

探矿数据进RAG前的清洗全攻略:TXT、Word、PDF、网页四类文档处理实践

探矿数据进RAG前的清洗全攻略:TXT、Word、PDF、网页四类文档处理实践 1. 探矿数据进RAG之前为什么必须先过清洗这一关1.1 探矿领域的文档生态比想象中更杂做探矿业务的知识库和做通用知识库完全是两码事。通用场景里的文档再乱基本也就是网页、PDF、Word这几类格式相对规整。探矿业务呢我见过最典型的场景是一个钻孔编录报告集里既有上世纪八十年代的扫描件PDF也有地质队员用老式文本编辑器保存的TXT台账还有从OA系统导出的带修订痕迹的Word以及从各省地质资料网站抓下来的公示文件。这四类东西要同时灌进一个RAG知识库里如果不先把清洗这一步做扎实后面检索出来的结果基本没法看。先说TXT。探矿行业很多老一辈地质工作者留下的原始记录存的就是纯文本。这些TXT文件的问题不是“缺格式”而是编码混乱。同一批文件中GB2312、GBK、UTF-8、甚至个别BIG5编码混在一起你用默认的UTF-8去读GBK文件满屏乱码向量化之后整个块就是一堆无意义字符。Word文档呢问题在“看不见的格式污染”。修订痕迹、批注、域代码、目录域这些内容你在屏幕上看见的是正常文字但是一旦用脚本抽取批注和隐藏域内容会混进来。PDF最麻烦扫描件要OCR文字版要处理双栏和表格稍微处理不当一整段的地层描述就被切得七零八落。网页倒是相对干净但导航栏、页脚、cookie弹窗这些噪声会稀释正文的比重导致分块后语义模糊。这些文档还有一个共同特征专有名词密度极高。岩性名称闪锌矿、黄铁矿、矽卡岩地层代号D2、C1、Pt1化验指标单位g/t、ppm、μg/g这些词汇一旦被错误切分或识别检索效果立刻崩盘。RAG系统检索的是一段段的语义单元如果语义单元里掺杂着乱码、残缺表格、OCR错字用户问“某矿区铜矿体平均品位”系统可能把这段信息错误匹配到“某矿区钻孔柱状图”的无关片段上。所以在探矿业务里清洗不是可选项而是决定RAG能不能落地的关键环节。我自己的经验是清洗做到位检索命中率能提升一个量级清洗不到位后面所有向量化、检索、重排的努力都会被噪声淹没。这篇文章就围绕探矿业务中最常见的四类数据——TXT、Word、PDF、网页——把每一类数据的清洗思路和实操方案讲透从乱码处理到结构化恢复再到检索精度验证给你一条可以直接照做的路径。1.2 脏数据进了向量库检索精度会一路崩到谷底有人可能觉得向量化模型不是对噪声有鲁棒性吗句子里面有几个乱码字符、几个多余符号向量应该还是能抓住语义吧。这个想法在通用语料上也许成立但在探矿数据上行不通。原因很简单探矿文本里的关键信息往往集中在非常短的片段里而且这些片段之间的区分度不高。举个例子一份钻孔岩心编录表里每行记录就是一个深度区间和对应的岩性描述。比如“120.5-121.3m 灰白色中粒花岗闪长岩含少量黄铁矿”。如果把表格转成了文本、格式又乱了变成“120.5-121.3m 灰白色中粒花岗闪长岩含少量黄铁”或者“120.5-121.3m 灰白色中粒花岗闪长岩含少量黄铁矿续”那这块内容的向量就和其他钻孔的内容高度相似用户真正想查的“黄铁矿富集层位”就淹没在一堆相似向量里了。再比如储量计算报告里的化学分析结果表如果表格被拆散、单位被截断问答系统给出的数值可能就是错的。探矿业务里一个数值错误可能影响整个矿体圈定结果的判断。还有一类问题是数据版本。探矿项目的文档有严格的版本链条初勘报告、详勘报告、补充勘探报告、储量核实报告每一份都是后续报告的基础。如果把不同版本的表格数据混在一起灌进知识库RAG在回答“该矿体平均品位是多少”的时候可能同时检索到初勘和详勘两个版本的数据系统不知道选哪个只能瞎拼。清洗阶段就必须对文档做版本标注或者明确处理优先级否则精准检索永远只是空谈。这一章先把问题背景讲清楚接下来每一章进入具体的数据格式清洗路径。先说最古老也最容易翻车的TXT。2. TXT类数据乱码不是编码问题那么简单还有语义碎片2.1 编码识别与转换先把乱码一次性解决TXT在探矿业务里的典型来源有几类早期地质软件导出的文本、老同志的手打记录、从PDF和Word转出来的中间格式、以及各种设备导出的日志。其中最有时代特色的是老电子文档存盘年代在1990到2005年之间编码基本以GB2312和GBK为主少数来自港台设备的文件可能是BIG5。如果你不加处理直接读十个文件里至少有三四个是乱码。乱码的根源就一句话字符集对不上。文件的字节序列是按GBK编码写的你用UTF-8解码自然全是“锟斤拷”“烫烫烫”这类经典乱码。反过来UTF-8文件被GBK解码会出现一堆奇奇怪怪的汉字组合。处理思路很清晰先识别编码再统一转成UTF-8。Python里最常用的工具是chardet可以给出一段字节的编码概率估计。import chardet with open(old_report.txt, rb) as f: raw f.read() result chardet.detect(raw) print(result) # 示例输出{encoding: GB2312, confidence: 0.99}识别出编码之后转成UTF-8同时处理BOM问题。BOM是藏在文件头部的几个特殊字节有些Windows下的TXT会带BOM不处理的话写入文件时会多出一个不可见字符可能在向量化时产生一个异常标记位。def normalize_text_file(input_path, output_path): with open(input_path, rb) as f: raw f.read() detected chardet.detect(raw) encoding detected[encoding] if detected[encoding] else utf-8 text raw.decode(encoding, errorsreplace) # 去除BOM字符 text text.lstrip(\ufeff) with open(output_path, w, encodingutf-8) as f: f.write(text)这里有个细节errorsreplace会把无法解码的字节替换成“”这不是彻底解决办法。如果文件里乱码量不大可以接受如果乱码率超过一定比例比如5%建议人工复查原始文件很可能文件本身就是损坏的或者被传输过程截断过。编码转换是TXT清洗的第一步也是最机械的一步真正有技术含量的是乱码消除之后的语义碎片重组。2.2 文本碎片重组让被切断的段落重新长回来TXT数据的语义碎片问题比乱码更隐蔽。最常见的情况是原始文件里一个完整段落因为换行符位置错乱被拆成了好几行或者从PDF转出来的TXT每一行都被强制切成了固定长度再或者表格转成文本之后单元格内的内容被割裂成多行列对应关系完全丢失。先看段落重组。地质报告有一段描述通常长达几百字比如“该矿区位于XX背斜南翼出露地层主要为二叠系下统栖霞组P1q岩性为灰黑色厚层状灰岩夹燧石结核局部见方解石脉充填……”如果这段文字在TXT里被按照屏幕宽度切成了五行那你直接按行分块就会把一个完整的地层描述拆成五个毫无意义的小块。正确做法是先做“行合并”如果某一行结尾没有句号、感叹号、问号等结束标点并且下一行不是章节标题就把下一行拼接到当前行后面。import re def merge_lines(text): lines text.split(\n) merged [] current end_punct set(。) for line in lines: line line.strip() if not line: if current: merged.append(current) current continue if current and line and not line[0].isupper() and current[-1] not in end_punct: current line else: if current: merged.append(current) current line if current: merged.append(current) return \n.join(merged)这只是基本逻辑实际处理时还要搭配标题识别如果某一行是“一、区域地质”“二、矿区地质”这种章节标题即使上一行没有结束标点也不能接续到上一段文字里。所以合并行的前提是先做一轮标题行标记。为了避免一条条写正则我建议先构建一份“探矿业务章节标题词表”把常见章节名绪言、区域地质背景、矿床地质特征、矿石类型及品位、资源储量估算、探矿工程布置、采样及化验方法等整理出来用精确匹配或前缀匹配去识别。这个动作别看简单它能保住文本的层级结构对后续RAG的分块策略非常关键。再一个典型碎片是表格转文本后的列错位。探矿TXT台账里经常有这样的内容ZK101 120.5-121.3 灰白色中粒花岗闪长岩 黄铁矿 2% 1.35g/t ZK101 121.3-122.5 深灰色细粒闪长岩 磁铁矿 5% 0.89g/t ZK102 88.2-90.1 灰岩 方解石脉 3% /这种文本如果直接整体入向量库检索“ZK101钻孔黄铁矿品位”的时候系统可能只能捕捉到这一行的一部分字符更麻烦的是表格列数不一致时单位与数值对齐错位检索“1.35g/t”可能匹配到别的行。对于这类行结构明显的文本清洗思路是先把它们从正文里剥离出来按行解析成结构化记录比如用pandas读入按空格或制表符分列然后统一编码单位、加工成CSV或JSON作为独立数据表入库。正文文本和结构化表格分开走两条线互不干扰检索效果反而更好。import pandas as pd rows [] for line in text.split(\n): if re.match(r^ZK\d\s, line): parts re.split(r\s, line.split(//, 1)[0].strip()) rows.append(parts) df pd.DataFrame(rows) df.columns [钻孔编号, 区间, 岩石名称, 矿物, 含量, 品位] df.to_csv(drillholes.csv, indexFalse, encodingutf-8)2.3 正则清理与专有名词保护TXT文件的噪声还有几类页眉页脚残留比如“XX地质大队 1987年”出现在每一页顶端、字符上下标丢失后的变形比如“m2”其实想写的是平方米、OCR造成的错别字如果TXT是从扫描件转的这个很常见、以及多种空白符和分隔符混用。正则清理的要点是“先保护再清理”。把地质专有名词、地名、样品编号、钻孔编号先提取出来占位或加边界符再执行删除操作避免误伤。比如你想删掉含“第 页”的页脚但正文里可能有“第X勘探线”这种内容不加保护就一起删了。我一般用一个地质术语词典做保护词典除了常见的岩性矿物名称还包括地层代号P1q、T3f、J2x这种格式、化探元素符号Cu、Pb、Zn、Au、Ag、Mo、单位组合g/t、m%、10^-6。正则可以匹配这些模式提前用标记符替换清理完后再还原。单位规范化也是探矿数据清洗里的高频操作。一份文档可能同时出现“克/吨”“g/t”“0.0001%”三种表达方式检索“品位g/t”时命中率肯定会受影响。清洗时建议统一成标准形式。这个操作不复杂但很值得做因为探矿用户提问时常常直接说“查一下品位单位g/t的矿体”如果你的库里面存的是“克/吨”匹配难度就会增加。TXT清洗做到位之后素材里最常见的问题已经消灭了一大半。但探矿业务里大部分核心报告都不是TXT而是Word。Word文档的格式污染问题比乱码更让人头疼。3. Word文档看不见的格式污染比内容错误更致命3.1 修订痕迹、批注和域代码进向量库前必须处理探矿业务里Word文档几乎绕不开。从储量核实报告、勘查设计书到采样方案、环境恢复治理方案全部以Word形式流转。而且这些文件很多经过了多轮审核修订文件里带着大量修订痕迹、批注和域代码。你直接在Word里打开看到的可能是“已接受修订”的干净版本但如果你用python-docx或者Apache POI去抽取段落抽取出来的内容可能同时包含删除线文字、批注文字、域代码的指令内容。这里就容易出问题。假设一份报告里有这么一句被删除的修订“该矿体倾向南西倾角40°”审稿人删掉了“40°”改成“45°”修订痕迹完整保留了。你用脚本抽取全部段落时如果没做修订过滤两个数值都会被抽出来向量的语义就自相矛盾了。RAG检索系统可不认识修订前后的逻辑关系它只会把这句自相矛盾的话当一个完整语义单元。处理方案是抽取段落时过滤掉修订删除的内容如果需要保留修改后的内容优先提取修订接受状态下的文本。python-docx处理修订痕迹比较麻烦它不像浏览Word的批注窗格那么直观需要操作w:ins和w:del等底层XML标签。Apache POI处理Word表格的单元格宽度是强项但对修订痕迹的处理同样绕不开XML解析。我的建议是如果是带修订痕迹的复杂Word文档先用Word桌面版或WPS执行“接受全部修订并保存”再进入后续抽取流程。这一步人为操作一劳永逸比写脚本解析XML省心得多。批注的处理原则只有一个全部剔除。批注是给审稿人看的交流信息不是报告内容的一部分。python-docx提取批注相对容易doc.comments就能拿到的批注内容抽取正文时直接跳过。域代码也同理域代码的显示结果一般是正确的我们要的是显示文本不是域的指令字段。宏也要注意。部分老式Word文档带有宏可能有宏安全风险。处理这类文档时不要用你自己的办公软件直接打开并允许宏运行我习惯用python-docx在只读模式下抽取或者先转成docx副本再处理。清洗环节本身就要规避执行宏安全永远是第一位的。3.2 标题层级与表格结构提取策略决定分块质量Word清洗里我比较看重的是标题层级提取。一份储量报告动辄几百页章节编号有“第1章”“1.1”“1.1.1”三层甚至还有“附则”“附表”分区。如果抽取出来做成纯文本流水账后续不管是按固定长度切块还是按段落切块都会切出大量跨章节碎片。准确提取标题层级让文档形成树状结构才能保证RAG分块在“章节语义完整”的边界上进行。python-docx读取段落样式是常规思路from docx import Document def extract_headings(path): doc Document(path) for p in doc.paragraphs: if p.style.name.startswith(Heading): print(p.style.name, p.text)但实际情况里很多探矿报告的标题不是使用“标题1”“标题2”样式而是通过手动改字体大小实现的。遇到这种情况python-docx没法直接告诉你哪段是标题只能靠特征判断居中、加粗、编号开头如“第1章”“1.1”“一、”。这类规则容易误判我的建议是构建一个探矿报告章节编号正则库用正则匹配“第[一二三四五六七八九十百]章”“[0-9](.[0-9])*”“[一二三四五六七八九十]、”等模式再叠加字体特征双重校验。宁可少数漏判也不要错判把正文当标题因为错判带来的分块错误是灾难性的。表格的提取策略更细。探矿报告里的表格主要有两类一类是钻孔一览表、样品分析结果表、资源量估算表这类数据型表格需要完整结构另一类是描述性、说明性表格结构相对松散。数据型表格我建议提取为结构化数据再入库和TXT台账走同一条路。处理Word表格时Apache POI的setColumnWidth这类宽度控制用得很多但清洗场景我们更关心内容抽取。python-docx可以直接读取doc.tables遍历每个表格的rows和cells输出CSV。需要注意跨页表格问题。长表格在Word里经常跨页有的表格会拆分成多个物理Table或者表头重复出现。抽取时要判断相邻表格是否可能是同一张表依据是表头是否重复、列数是否一致。如果有图表编号“表4-1 钻孔岩心采样分析结果”直接用编号把跨页片段串起来。这一步如果漏了一张完整的钻孔化学成分表会被拆成好几块检索“表4-1 中ZK103的Au品位”时只命中其中一块数值不完整。3.3 公式、图表与版本混乱探矿报告里的公式主要是储量计算相关比如块段法储量计算公式、体积公式、加权平均品位公式。Word里的公式可能是MathType或OMML格式清洗时有两种处理路径简单场景把公式的文本描述抽出来比如“Q V × d式中Q为矿石量V为体积d为矿石体重”复杂场景建议将公式从Word里导出为图片再把公式的LaTeX或文本描述作为相邻文本补充。热词里有“Word公式转LaTeX”探矿报告里的公式普遍不难转成LaTeX或文本描述完全够用不需要保留图片做识别这一步能大幅降低向量化的噪声。注意MathType和OMML的解析工具不完全一样MathType对象是OLE嵌对象python-docx直接读变量内容可能不够需要单独处理。图表更简单也更重要图片本身不进入RAG文本链路但图片的标题、图例说明必须保留。很多勘探图件的说明文字里包含了岩性、构造、矿体形态特征是检索的高价值信息。清洗时把图表标题“图2-3 XX矿区地质简图”和紧随其后的图例说明作为独立段落提取归入对应章节的上下文。版本混乱是Word清洗的最后一道坎。同一份储量报告可能同时存在“储量报告(最终版).docx”“储量报告(终版).docx”“储量报告(再也不改版).docx”内容可能还各不相同。清洗入库前必须先做版本核对比对目录、页数、修改时间保留内容最新且完整的那一版如果拿不准宁缺毋滥不要多个版本都进库。RAG最怕的就是一个知识点有多个版本互相打架。说完Word最重的戏来了PDF。探矿业务的老档案基本都是PDF而且什么形态都有。4. PDF的三种形态扫描件、原生文本、表格混排的处理差异4.1 文字版PDF抽取顺序与布局还原的坑先分清PDF的类型类型不同处理路径完全不同。我见过太多人拿到一个PDF就直接跑OCR结果一个文字版PDF还被OCR出大量错字得不偿失。判断是否文字版很简单用工具直接抽取看看有没有文本层。PyMuPDFfitz是一个我长期在用的库速度快抽取质量高。import fitz doc fitz.open(勘探报告.pdf) for page_num in range(len(doc)): page doc[page_num] text page.get_text(text, sortTrue) print(text)文字版PDF的麻烦不在于抽不出来而在于抽取顺序。双栏排版的地质报告很常见左栏是正文右栏是表格或图件说明有些报告还有页眉页脚。用get_text(text)抽取时默认按文档内部结构顺序输出经常出现“左栏半段、右栏半段、再回左栏下半段”这种跳读顺序。处理方式是先用get_text(blocks)拿到块的位置坐标然后按横坐标排序区分栏位再按纵坐标合并。def extract_sorted_text(page): blocks page.get_text(blocks) # block结构(x0, y0, x1, y1, text, block_no, block_type) blocks.sort(keylambda b: (round(b[1] / 20), b[0])) lines [] for b in blocks: lines.append(b[4].strip()) return \n.join(lines)这个按y分粗组再按x排序的操作本质上是把同一水平线上的块按从左到右排列跨栏顺序就不会乱了。实际效果因文档而异需要抽样验证。文字版PDF的表格抽取可以交给pdfplumber它能识别线条并还原表格结构import pdfplumber with pdfplumber.open(矿产储量报告.pdf) as pdf: for page in pdf.pages: tables page.extract_tables() for table in tables: for row in table: print(row)pdfplumber对有线表格识别效果好对无线边框的表格很多化学分析表只是空格对齐识别一般。无线表格我倾向于退回到按坐标抽文本再拿正则去切分虽然慢但可控。还有一类坑是页眉页脚贯穿文本层。比如“XX矿区勘查报告 - 第 23 页”这一串字符会出现在每一页的文本抽取结果里如果不去掉整份文档里同一个页眉会重复出现几十次RAG在检索“XX矿区”的时候可能被这个高频短语带偏。清洗时先用正则匹配页眉页脚的固定模式删掉再逐页拼接正文。4.2 扫描件PDFOCR流程与词典校准扫描件PDF在探矿领域极其常见特别是上世纪的地质报告、老图纸、岩心照片扫描版。这些文件没有文本层只能OCR。OCR的选择很多Python生态里PaddleOCR和Tesseract是比较实用的两个。个人经验中英文混排、含大量表格的地质报告PaddleOCR识别率更好纯英文文献或字符规整的页面Tesseract也够用。两个配合着用按文档类型分流。paddleocr --image_dir page_001.png --lang ch --use_gpu False --output_dir ./ocr_resultOCR本身的流程不多说重点在校准和后处理。地质文本里有很多普通OCR模型容易出错的词包括岩性名称“闪长玢岩”容易被识别成“闪长粉岩”、元素符号“Ag”识别成“Aq”、“Au”识别成“A”、地层代号“P1q”识别成“P1g”以及单位“g/t”识别成“g/I”。针对这个问题我的做法是准备两份词典地质专有名词词典从术语标准、勘探规范里提取核心词条。OCR常见混淆词典记录模型容易出错的字符对比如0/O、1/l/I、2/Z、6/G、8/B、g/9/q等以及“黄铁”被识别成“黄钱”这类整词错误。后处理时先跑一遍OCR得到原始文本再对文本里出现的候选词做词典匹配替换。替换逻辑要小心不要整篇文章无差别替换只处理高置信度的混淆词。举例corrections { 闪长粉岩: 闪长玢岩, 黄钱矿: 黄铁矿, Aq: Ag, } for wrong, right in corrections.items(): text text.replace(wrong, right)还有一个非常实用的小技巧OCR前先做图像预处理。老扫描件经常有倾斜、暗角的毛病用OpenCV做一次二值化和倾斜校正识别率能提升一大截。倾斜页面里的表格线会变成折线影响表格识别校正角度一般在10度以内校正效果较好。扫描件里的表格识别属于高难操作。如果表格区域是完整的矩形线条框PaddleOCR的表格结构识别模型TableRec可以输出HTML结构再转成CSV如果是手绘表格或者表格线模糊人工勾选区域反而更快。探矿业务的扫描件表格价值很高像老的地质剖面表、钻孔柱状图的数据表值得花人工做几份高质量的构建一个结构化样本再反哺自动化脚本。OCR输出的表格结构完整性决定后续数值检索的精读质量这个钱和时间不该省。4.3 混排表格PDF结构化提取与回填大量勘探报告属于第三类文字版PDF里嵌着表格、图件、甚至部分扫描插入页。处理这种混排文档不能单一用文字抽取或单一用OCR而是要把页面拆开处理。我通常的做法是先用PyMuPDF检测每一页的文本覆盖率。如果某页文本量极低、但包含图像判定为扫描页或图件页进入OCR链路如果文本量正常但存在大块跨栏图片则保留文本层只对图片做区域识别针对图件中的标注文字。表格用pdfplumber识别再和文本抽取结果做拼接。输出格式上强烈建议把清洗后的文档转成带层级标记的Markdown而不是纯文本。好处在于后续RAG分块时可以直接按Markdown标题层级来做边界划分即使用固定窗口切割也能感知当前的章节归属。示例## 2.3 矿区地质特征 该矿区出露地层主要为二叠系下统栖霞组P1q岩性为灰黑色厚层状灰岩夹燧石结核局部见方解石脉充填。 表2-1 主要岩石化学成分分析结果 | 样品编号 | SiO2(%) | Al2O3(%) | Fe2O3(%) | |------|------|------|------| | H-01 | 63.25 | 15.42 | 4.81 |PDF清洗到这个程度才能说具备了进RAG的基本素质。但这还只是单一文件层面的清洗网页数据这一类体量不大但格式问题突出的数据源也需要单独处理。5. 网页抓取正文提取、去广告与结构化编号保留5.1 从导航页到正文抓取流程与噪点过滤探矿业务里需要抓取的网页数据通常有几类地质资料馆的公开目录页、招标公告、行业标准的在线版本、政府公示的勘查许可证信息、以及相关新闻动态。网页数据的特点是不需要做编码转换基本都是UTF-8但页面结构噪声非常多顶部导航、侧栏推荐、页脚版权、Cookie弹窗、相关链接推荐都会混进正文抽取结果。直接用requests加BeautifulSoup硬解析是最容易踩坑的方式。每次改版、每个网站结构不同解析规则就要跟着改。我的经验是优先用专门针对正文提取的工具比如trafilatura或readability-lxml它们会自动识别正文区域去除导航和页脚输出干净文本。trafilatura还能保留标题层级和段落结构对RAG友好。import trafilatura downloaded trafilatura.fetch_url(https://example.com/notice/12345) text trafilatura.extract(downloaded, include_commentsFalse, include_tablesTrue, output_formatmarkdown) print(text)动态渲染页面是另一类难题。很多地质公告页面用JavaScript渲染内容直接抓HTML可能拿不到正文。这种页面需要先渲染再提取可以在本地起一个Playwright或Selenium脚本等页面加载完再执行trafilatura的抽取逻辑。注意渲染会显著增加抓取成本只对确实需要的页面走这条通路不要把整站都动态渲染。网页正文抽取完成之后还要做一轮针对网页噪声的清洗去掉“收藏”“打印”“字号”“责任编辑”这类的功能性文字去重同一公告可能在不同栏目重复发布把常见无信息量的段落“关于我们”“联系我们”从正文里剔除。清洗后的网页文本同样统一转成Markdown保留标题层级。5.2 法规与公告的编号结构只能在清洗时保住探矿业务里有一类非常重要的网页文本是法规、标准和公告。这些文本的结构化程度很高有编号如“第XX号令”、有条文序号第X条、有章节结构第一章总则、第二章勘查许可还会引用其他法规条款。如果清洗时把这些编号全抹掉RAG在回答“关于探矿权延续登记的具体规定在第几条”这类问题时就完全没有引用依据。所以清洗策略和普通文本不同条文编号必须保留而且要作为结构锚点。我建议把法规网页转换为结构化度更高的格式——每一“条”作为一个语义单元前面加编号标记。## 第三章 探矿权转让 第二十四条 探矿权转让应当符合下列条件 一持有探矿权满2年 二已缴纳探矿权使用费 三完成了规定的最低勘查投入 ……这里的一二三子项也要保留很多检索场景是用户问“探矿权转让需要满足什么条件”子项的完整性直接决定回答质量。网页抓取时还经常遇到一个问题页面正文和上下文的关联信息丢失。比如一份公告说“依据××规定第九条”但前文对××规定的完整引用可能在另一个页面。清洗时要考虑跨页面合并把同一政策不同页面的内容拼成一份完整文档这样后续RAG不会在回答中引用一个“看情况再说”的悬空条款。5.3 时效性与链接去重网页数据的时效性比TXT、Word、PDF都要强。地质公告有发布期限勘查许可证有有效期行业标准有废止和替代关系。清洗入库时一定要增加两个字段发布时间和时效状态。发布时间可以直接从页面正文或数据字段里提取时效状态则需要判断比如页面标注“已废止”“已失效”“自2023年5月1日起施行”清洗时要自动识别并标记。时效状态的判断在RAG链路里特别重要。用户提问“现在还需要提交××材料吗”如果库里的依据是已废止的文件系统会理直气壮地给出一个过时答案。所以清洗时不但要保留时效字段还要把它和分块内容绑定或者在文本头部加一行的概述比如“注意本文件已于2024年1月废止”。这样即使被切分到的块也能让模型感知到状态信息。链接去重也别忽略。同一份公告可能同时存在于“通知公告”和“政策法规”两个栏目页面URL不同但正文完全一致。清洗时用正文的哈希值做去重保留来源可靠、发布时间最早或最新的一份。数据量大的时候还可以用MinHash或局部敏感哈希做近似去重处理那些只有细微差别的页面。网页清洗相对于文档清洗来说工程量不大但容易让人掉以轻心——往往是抓了几千个页面正文里混着导航词和页脚词灌进去之后一搜全是不相关内容。到这里四类数据的清洗路径都说完了。但清洗完不等于能上线你还需要验证清洗效果否则可能带着问题上线而不自知。6. 清洗效果怎么验证从召回率到答案准确率6.1 规则阀门机器自查的硬指标清洗完一批文档第一件事不是急着向量化而是跑一轮规则阀门。规则阀门是一组轻量脚本检查清洗后文本是否还残留典型的脏数据模式。我的检查项包括乱码残留率文本里是否还出现“锟斤拷”“”和异常Unicode字符。空行比例清洗后文档是否还有大量连续空行。段落平均长度如果一段话少于15个字符多半是页眉页脚或表格碎片残留。重复率相邻段落是否存在重复文本比如页眉重复。结构完整率一个文档应该有多少章标题实际识别到多少。编码一致性清洗后文档是否统一为UTF-8无BOM。这些检查项可以用脚本批量跑生成一份报告。报告里把不合格的文件挑出来重新处理。规则阀门的意义在于把清洗从“手工作坊”变成“可度量流程”每一步都能知道丢了多少数据。6.2 检索链路验证用真实业务问题集打分规则阀门解决的是“清洁度”问题但清洁度高不等于检索精度高。要验证清洗是否真正提升了RAG效果还需要一组真实业务问题作为评测集。探矿业务问题集我一般分三类来构造术语实体类比如“闪锌矿的赋存层位是什么”“矿区出露的地层有哪些”.这类问题考察专有名词和实体的召回能力。数值检索类比如“ZK103钻孔在120米处的岩性是什么”“铜矿体平均品位是多少”。这类问题考察表格抽取和结构还原效果。规范引用类比如“申请探矿权延续登记需要提交哪些材料”。这类问题考察条文编号和章节结构的保留情况。构造好问题集之后跑一遍RAG链路对每个问题检查两个指标top-K命中率正确答案是否在检索返回的前几块里和最终答案准确率基于检索结果的生成回答是否可接受。我还要强调一个非常容易被忽视的细节检索命中率比生成答案准确率更能反映清洗效果。生成答案可以靠模型“脑补”蒙对但检索命中率直接反映清洗质量——相关资料没有被搜到就是向量化之前的清洗没做好。实操中清洗前和清洗后的对比结果非常直观。我之前处理过一批老的地下岩心编录扫描件PDF清洗前问“矿区矽卡岩的分布范围”检索返回的是OCR错字“砂卡岩”的乱文本块回答完全不可用清洗后同一个问题检索返回了目标段落的准确上下文答案可以直接采纳。这就是为什么要花时间在清洗上——它直接影响数据进库后的可用性。6.3 分块与清洗的配合光清洗不够还要切得对清洗产出的是干净的Markdown文本下一步是分块。分块策略的选择要和清洗方式强配合。如果清洗时保留了标题层级分块边界就能按章节语义划分一个标题下设一个块块的内容是这个标题下的完整段落集。块过大超过1000字符会稀释语义块过小少于100字符会丢失上下文。探矿报告里一块200到800字符之间通常效果较好但具体要根据文档类型调整钻孔编录短小精悍可以分小块储量报告章节丰富适合用章节边界划分。分块时还要考虑重叠overlap策略。清洗后的文档本身段落间有强逻辑关系如果分块完全无重叠跨段落的问答比如“根据上一段内容这个矿体的平均品位如何”会丢失信息。适当设置20-50字符的重叠可以缓解这个问题。分块完成后需要对每个块再抽检一遍看是否出现跨表格、跨章节的内容拼接。出现这种情况优先调整分块边界而不是硬调向量化参数。很多人在RAG精度不足时第一反应是换更好的向量模型但模型换完了效果依然一般问题往往就出在清洗和分块环节。验证通过之后可以进入实际使用阶段。但探矿数据的清洗不是一次性的库会增长文档会更新清洗规则也要跟着迭代。这些是落地时的经验问题最后单独说。7. 落地过程中的真实体会与建议7.1 先建清洗流水线再谈知识库探矿业务的数据清洗千万不要做成一次性的“大扫除”。真实情况是每隔一段时间就会有一批新文档进来比如新完成的勘查报告、新公示的出让公告、新修订的规范。如果每次都重新跑一遍手工脚本效率太低且容易漏步骤。我强烈建议把清洗流程脚本化、流水线化第一步文件格式识别分发到对应清洗模块。第二步各模块执行格式清洗输出标准Markdown和结构化CSV。第三步规则阀门自动质检。第四步人工抽检通过后进入向量化入库。流水线的价值不只是节省人力更在于清洗规则可以版本化管理。每次发现一个之前没覆盖的乱码模式或OCR错词就更新规则库流水线重跑一遍历史数据也不会遗漏。这个机制让清洗质量持续进化而不是做完一次就停滞。7.2 清洗规则与词典要持续更新没有哪个体量足够的探矿数据能靠一次性正则清干净。每个矿区的文档都有自己的行文习惯每个时期的地质报告也有不同的格式偏好。比如有些老报告用“品位1.35克/吨”新报告用“品位1.35g/t”你需要不断把这类变体纳入规范化词典。地质专有名词词典同样如此不同矿种有新术语比如随着稀有金属勘探的展开锂辉石、花岗伟晶岩这类词汇会频繁出现词典里没有就容易被OCR或分块环节误处理。我维护的词典是一个单独的文本文件每个词条一行里面不仅有标准术语还有常见的错误拼写映射。更新流程很简单在质检阶段发现某个词频繁出问题就追加到词典。方法论不重要重要的是坚持记录。7.3 人工抽检由业务人员来做开发人员只做兜底清洗脚本质检能抓住大部分机器可识别的问题但有一些错漏是脚本发现不了的。比如OCR把“矽卡岩型铜矿床”识别成了“砂卡岩型铜矿床”单独看这个词似乎没什么问题但在地质语境里“矽卡岩”才是标准写法。这种问题规则阀门很可能判断“合格”但业务人员一眼就能看出来。所以清洗流程的最后一道质检必须由业务人员参与。抽检比例不用太高每批抽30%到50%就够了。更有效的做法是让地质工程师直接试用检索系统发现检索结果里出现怪异词汇或错误术语反馈回来再去修正清洗规则。这样形成一个闭环——清洗、入库、检索测试、反馈、再清洗比一次性追求极致的清洗质量更现实。7.4 宁缺毋滥让合格的数据进库最后一条经验也是我踩过最多坑之后总结出来的清洗环节一定要敢做减法。一个PDF扫描件OCR之后文本质量实在不行与其硬着头皮入库不如标记为“待人工处理”暂时不参与检索。RAG的精度取决于最高质量的上下文一条脏数据有可能会把正确答案的排序挤下去。宁可库里少几份文档也比让脏数据污染答案强。文件级别的质量阈值也要设置清楚。我的经验是OCR错字率超过5%的文档或者表格结构完全无法还原的文档先挂起等人工处理或找替代来源。很多老报告网上有二次整理的Word版或重新录入版质量比直接OCR高得多优先用高质量来源。7.5 一个实用的小技巧优先清洗高频、高价值文档如果你手头的文档数量特别大比如几千份而人力资源有限不要平均用力。把所有文档按使用频率和价值分两级高频高价值文档——储量报告、采样分析数据、勘探规范、招拍挂公告——优先清洗建立严格的质量标准长尾文档——行业新闻、历史动态、周边资讯——可以放宽阈值用一条简单流水线批量处理。先让核心数据保证高精度再逐步扩大清洗范围。我见过太多项目一上来就追求“把全部数据洗得干干净净再上线”结果洗到一半失去了耐心反而拖垮了整个落地节奏。正确的路子是小步快跑核心优先。探矿业务的RAG清洗本质上是在做一件很枯燥但价值极高的事把历史数据从“能看”提升到“能查、能答、能引用”。从TXT的乱码与碎片重组到Word的格式污染清理再到PDF的OCR校准与表格结构化最后是网页的正文抽取和时序标记每一类数据都有自己的方法论。清洗完再用问题集验证检索效果形成闭环。这套流程跑通之后你手里的知识库才真正具备高精度检索的底子。我也还在不断迭代自己这套清洗规则每次处理新批次的数据都能发现一些没见过的脏数据形态。这个过程没有终点但每一步的改进都在实打实地提升回答质量这就是做这件事最有价值的地方。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表