ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI大模型驱动的地质勘探语料清洗与标注实战

AI大模型驱动的地质勘探语料清洗与标注实战 简介一份面向地质勘探研究人员、工程师与技术管理者的PDF方案文档聚焦于如何用AI大模型构建高质量地质语料库解决勘探数据分散、噪声多、标注难等痛点。文档系统覆盖项目背景、数据源选择与收集、语料清洗原则与算法、标注类别与流程、人员培训管理、数据存储及模型训练应用等完整环节尤其对地质层位、矿体特征、结构特征等标注类别和去重算法进行了细化说明具有较强的工程参考价值。资源为PDF格式仅1个文件压缩包大小约940KB包含完整章节目录与结构化内容便于按模块阅读与复用。方案不仅给出技术实现细节还纳入实施计划、风险管理与未来展望适合用于团队内部方案设计、课题立项参考以及智能勘探系统建设的初始框架搭建。目前已有79人学习下载适合关注地质勘探智能化转型的从业者参考。1. 地勘报告文本是座富矿但不清洗标注就挖不动我接手第一个地质类知识库项目时被一份钻孔编录表卡了三天。上面的岩性描述写着“灰岩夹页岩”同一份报告后面又出现“石灰岩与泥岩互层”——说的是同一段地层。这类问题在历史地勘资料里到处都是直接把原始文本喂给AI大模型检索结果和训练数据都会跑偏。用AI大模型做地质勘探语料清洗和标注真正的价值不是“模型能读懂地质报告”而是把散乱文本变成结构化的术语、实体和关系让下游的知识库和训练集有靠谱的输入。这个方向适合两类人手里攒着几千份老报告、想建行业知识库的地质工程师以及要给行业大模型做训练数据的数据团队。它不会帮你产生新的地质认识但能把手头报告变成机器能用的资产。下面从语料摸底开始把完整方案拆开讲。2. 语料摸底与模型选型先知道手上有多少脏数据再决定花多少钱2.1 地质勘探文本的4类来源与脏数据画像做清洗和标注之前我一般先花两三天时间把语料来源盘清楚。地质勘探数据不是单一格式常见有四类来源每一类的脏数据长相完全不同钻孔编录是表格转文本处理重点是去制表符错位和补深度单位勘查报告和岩矿鉴定报告是长文本处理重点是术语不统一和OCR噪声野外记录本口语化严重简写、错别字、地名误差多测井和采样台账则是单位混用、日期格式混乱、坐标精度缺失。语料来源典型文件最常见的脏数据钻孔编录编录表、柱状图描述岩性名称混用、深度区间缺单位、地层代号误写勘查报告地质勘查报告、岩矿鉴定报告术语不一、表格转文本错乱、缩写无上下文野外记录路线记录、野外记录本口语化描述、简写、地名错别字测井与采样台账测井解释、采样登记表单位混用、坐标精度缺失、日期格式不统一这张画像直接决定清洗策略。同一个模型不会用一套提示词同时处理“表格错位”和“口语简写”前者靠格式修复后者靠术语扩展和上下文推断。如果你跳过摸底直接写提示词后面八成要反复返工。2.2 抽样评估和摸底脚本先定质量基线再谈清洗效果摸清来源之后每类语料抽5到10份人工精修一遍当成黄金样本。清洗效果怎么算合格不能凭感觉要有基线术语统一率、单位规范率、符号正确率、噪声占比四个维度各打一个分数。基线不是用来考核模型的是用来防止你改提示词时把效果改回去的。抽样前先用脚本把语料规模统计出来顺便抓一遍常见脏信号。下面这段是我常用的摸底脚本按来源分类统计文件数、总字符数和几个典型信号# 语料摸底统计各来源文件数、字数和常见脏信号 import glob import re from collections import Counter sources { 钻孔编录: glob.glob(data/drill/*), 勘查报告: glob.glob(data/report/*), 野外记录: glob.glob(data/field/*), } for name, files in sources.items(): if not files: print(name, 没有文件跳过) continue total_chars 0 signals Counter() for fp in files: # 老报告常是GBK或GB18030编码先用errors忽略后面单文件复检 text open(fp, encodingutf-8, errorsignore).read() total_chars len(text) signals[全角引号] len(re.findall(r[“”‘’], text)) signals[数字后无单位] len(re.findall(r\d{2,3}(?[\s,;)]), text)) signals[制表符] text.count(\t) signals[空行过多] text.count(\n\n\n) print(f{name}: 文件{len(files)}个, 总字符{total_chars}) for k, v in signals.items(): print(f {k}: {v})逻辑说明“数字后无单位”这条正则专门抓钻孔编录里最常见的问题深度区间“12.5-14.0”后面没有“m”。全角引号和制表符则反映OCR或输入法时代留下的格式噪声。这些信号只是线索真正的质量基线要人工看样本才能定。参数说明编码先用utf-8加errors忽略跑完脚本后把字符异常的文件单独挑出来用GB18030再解一次。正则里\d{2,3}限定两到三位数字避免把年份、电话号码这类无关数字误伤实际项目里要根据你的文本微调这段。2.3 模型选型API还是本地部署取决于数据能不能出单位内网模型选型其实是个约束问题不是技术问题。语料量小、数据不敏感直接调API成本和效率最优语料量大、单位有数据保密要求或者内网环境出不去就本地部署开源模型。地质勘探文本有一个特点清洗和标注这类结构化任务7B到14B量级的模型就够用没必要上70B推理慢且成本高。选型参数量硬件需求适合场景注意点API调用商用大模型无需要出网小批量、允许出网按token计费清洗要控制输出长度本地GGUF量化7B~14B16GB以上内存或8GB以上显存涉密数据、长期批量任务量化等级影响抽取稳定性本地部署我一般用GGUF量化格式配Ollama或llama.cpp这类推理服务。14B模型用Q4_K_M量化后体量压到10GB左右一张常见显卡或者64GB内存的机器就能跑起来。量化等级别一味追求最小Q4_K_M是清洗标注任务的常用平衡点再低的量化等级会让抽取结果飘。如果你要做清洗结果的实时审核界面可以考虑用SSE流式输出把结果逐段渲染出来配合前端abort中断超时请求。这个后面在参数部分细说。3. 清洗流水线拆成四段的方案与3个必调参数3.1 清洗为什么不能一把梭四段流水线的设计很多人上来就写一个巨型提示词把“去噪、补单位、统一术语”全塞进去让模型一次搞定。结果模型自由发挥把“泥质粉砂岩”改成“泥岩”把“含砾砂岩”里的“砾”删掉你还找不到是哪一步改的。清洗必须拆段每一段只做一类事段与段之间留中间产物。我用的流水线分四段提取去噪、格式规范化、术语统一、规则检核。提取去噪把乱码、页眉页脚、OCR错字清掉格式规范化补单位、统一日期、修全角半角术语统一靠同义词表和上下文判断规则检核用正则和人审兜底。每一段产物都落盘后面发现问题能回滚到任意一步重跑不用整批返工。# 清洗流水线每段独立段间产物落盘方便回滚 import json STEP_QUEUE [ extract_denoise, normalize_format, unify_terms, rule_check, ] def run_pipeline(raw_text: str, step_overrides: dict None) - dict: step_overrides 用于某一段单独调整提示词参数 current {raw: raw_text, text: raw_text, log: []} for step in STEP_QUEUE: if step extract_denoise: current[text] denoise_text(current[text]) elif step normalize_format: current[text] llm_normalize(current[text], overridesstep_overrides) elif step unify_terms: current[text] llm_unify(current[text], glossaryGLOSSARY) elif step rule_check: current[issues] rule_check(current[text]) current[log].append({step: step, len: len(current[text])}) return current逻辑说明流水线是串行的后面每一步的输入是上一步的输出任何一步出问题只需要重跑从该步骤往后的链路。这里的denoise_text是规则函数llm_normalize和llm_unify是调用大模型后面会给出具体实现思路。参数说明step_overrides这个参数很实用当你发现“格式规范化”这步总把数字改坏可以单独给这步传一个更严的temperature或换一份提示词不影响其他段。3.2 提示词模板JSON输出、few-shot和“禁止推测”清洗的提示词核心是三件事强制JSON输出、给1到2个示例、明确禁止补全缺失信息。地质文本里深度、倾角、坐标经常缺模型看到“12.5-14.0”顺手补个“m”看起来更规范但污染了原始数据。所以提示词里必须写死“不要补全”。CLEAN_SYSTEM_PROMPT 你是一个地质文本清洗助手。请只清理格式和术语问题不要补全缺失信息不要删除原文中的数字不要改写地层描述。 要求 1. 保留所有原始信息包括缺失的深度区间原文缺单位就保持原样并标注missing_unit。 2. 把等价术语统一为靠前术语{glossary} 3. 输出JSON{{cleaned_text: ..., changes: [{{original: ..., replaced: ..., reason: ...}}]}} 4. 如果原文不属于地质文本输出{{cleaned_text: , changes: [], not_geology: true}} 逻辑说明changes数组是把改动原因列出来这是让清洗从黑匣子变成白盒的关键。人工抽检时直接看changes就能判断模型是改对了还是改错了不用整篇比对。参数说明{glossary}是术语统一表比如“灰岩石灰岩”但要注意不是所有同义词都能直接替换我后面在避坑章节会展开讲。few-shot示例要包含一个负例比如“原文ZK301 12.5-14.0输出cleaned_text保持12.5-14.0不变不要补m”。3.3 3个必调参数temperature、top_p、max_tokens清洗标注这类抽取生成任务三个参数必须调不调就等着翻车。temperature设置为0或0.1。温度越高输出越随机术语被改错、数字被替换的概率直线上升。top_p设置在0.1到0.3之间进一步压缩采样空间。这两个参数配合能有效减少“同一个文本跑两遍结果不一样”的玄学问题。max_tokens要限制。清洗是压缩任务清洗后的文本应该比原文短或相当。如果max_tokens给太大模型会把一段话扩写成小作文还把原文信息改得面目全非。我一般设1024到2048再通过规则检查“清洗后文本长度是否超过原文1.2倍”超了就报警。# 本地模型调用用OpenAI兼容接口关闭流式 import requests def llm_normalize(text: str, overrides: dict None, max_len: int 800) - dict: payload { model: 你的本地模型名按实际替换, messages: [ {role: system, content: CLEAN_SYSTEM_PROMPT}, {role: user, content: text[:max_len]}, ], temperature: 0, top_p: 0.1, max_tokens: 1024, stream: False, } if overrides: payload.update(overrides) resp requests.post(http://127.0.0.1:11434/v1/chat/completions, jsonpayload, timeout120) resp.raise_for_status() return resp.json()[choices][0][message][content]逻辑说明这里用OpenAI兼容接口本地推理服务基本都支持不绑定特定厂商。max_len把超长文本截断到800字符再清洗避免模型注意力在长文本里分散、漏看中间内容。参数说明timeout设120秒本地量化模型在纯CPU上跑单条文本可能要一两分钟。如果你在审核界面做实时渲染可以把stream设为True按行解析SSE数据流前端用abort中断批量任务则关闭流式简化日志和重试逻辑。3.4 规则检核清洗完不能全信模型大模型清洗完必须过一道规则检核用正则和词典兜底。规则不能替代模型但能拦截大部分“新增数字”“术语改错”这类问题。# 规则检核找模型可能改错的地方 import re def rule_check(cleaned_text: str) - list: issues [] # 1. 深度区间后面必须有单位没有就报警 issues re.findall(r\d{2,3}(?:\.\d)?-\d{2,3}(?:\.\d)?(?!\s*m\b), cleaned_text) # 2. 术语白名单之外出现“疑似新词” # 实际项目里维护一个术语表清洗后全量比对 return issues逻辑说明第一条正则专门盯“深度区间缺m”第二条在白名单之外找异常词。规则检核的产出是issues列表不是直接改文本。把这些报警喂给人工抽检比让模型自己检查自己靠谱得多。注意规则检核要和日志配套使用。每一段清洗产物的落盘文件里都带版本号和时间戳这样报警出来能快速定位是哪个步骤、哪一批数据引入的问题直接回滚重跑那一段不用从头再来。4. 标注实现实体schema、预标注与人工审核闭环4.1 地质实体与关系的schema先定类型再谈抽取清洗完的文本只能算半成品知识库和训练集要的是结构化标注。地质语料标注不是给句子贴个分类而是要抽实体、定关系、判属性。最容易翻车的是schema没定清楚就让标注员或大模型上手结果标出来的东西五花八门返工成本极高。实体类型不要超过6类关系不要超过5类。类型越多标注一致性越差大模型和人工都记不住边界。我常用的地质文本标注schema长这样{ entities: { stratum: {desc: 地层/岩性描述, props: [name, age, thickness]}, lithology: {desc: 岩石名称, props: [name, color, texture]}, structure: {desc: 褶皱/断层/节理, props: [type, attitude]}, mineral: {desc: 矿物/矿产, props: [name, occurrence]}, depth_interval: {desc: 深度区间, props: [start, end, unit]} }, relations: { overlies: 整合/不整合覆盖下伏地层, intrudes: 侵入体与围岩关系, contains: 地层包含岩性或矿物, crossed_by: 被断层/岩脉切穿 } }逻辑说明深度区间单独作为一个实体类型因为它在钻孔编录里出现频率极高边界清晰下游做剖面图、三维建模都要用。关系只保留最稳定的四种像“形成于”“属于”这类模糊关系先不标等数据多了再说。参数说明props里的属性按需增减。thickness不是每个stratum都有没有就留空不要为了让模型“完整”而逼它编造。4.2 标注工具选型文本标注用Label Studio影像点云用CVAT标注工具选型要看数据形态。文本实体和关系标注我一般用Label Studio它支持导入预标注JSON、自定义标签体系、多人协作和审核流。注意Label Studio直接用官方镜像或者打包好的安装方式就行别自己从源码编译前端依赖一大堆编译半天可能只是版本对不上。如果你的语料里有遥感影像、3D点云这类空间数据比如要做地质体边界勾画或点云分类那应该用CVAT或者专门的点云标注工具它们的核心能力是画框、画多边形、做实例分割。目标检测常用的LabelImg也是图像标注工具但不适合文本实体标注别混用。注意文本标注、图像标注、点云标注是三条不同的工具链不要试图用一套工具通吃。一个项目里同时有文本报告和影像数据就分开建两个标注项目互不干扰。4.3 大模型预标注低置信度进人工池高置信度直接过初审标注的核心思路是“大模型预标注人工审核”。让大模型先把实体抽出来低置信度的样本进人工池高置信度的直接过初审。这样能把标注员的工作量集中在模型拿不准的地方。# 预标注用大模型抽实体输出带置信度的标注结果 def preannotate_with_llm(text: str, schema: dict) - list: prompt f你是地质文本标注助手。请从文本中抽取实体输出JSON数组。 实体类型{list(schema[entities].keys())} 只输出实体不要输出关系。格式 [{{type: stratum, start: 0, end: 4, text: 灰岩, props: {{thickness: 12.5m}}}}] # 调用方式和清洗一致省略重复的requests细节 result llm_chat(prompt, temperature0, max_tokens2048) return json.loads(result) def to_labelstudio(pre_results: list) - list: 转成Label Studio的prediction格式带score字段 return [{ result: [ {id: i, from_name: label, to_name: text, type: labels, value: { start: r[start], end: r[end], text: r[text], labels: [r[type]]}} ], score: 0.9 if r.get(props) else 0.6 } for i, r in enumerate(pre_results)]逻辑说明preannotate_with_llm让模型只输出实体数组不输出关系关系标注留给人工因为关系判断上下文跨度大模型容易漏。to_labelstudio把结果转成Label Studio的prediction格式带score字段。参数说明score阈值刚开始设0.7低于0.7的进人工池。跑两轮后统计人工修正率如果修正率很低可以把阈值放宽到0.6减少无意义的人工审核量。4.4 一致性管理用Kappa值和争议样本闭环标注质量不能靠感觉要用一致性指标量化。常见做法是让两个人各标50条相同的文本算Cohens Kappa。Kappa值低于0.8说明schema定义或者标注指南有歧义要回头改否则下游训练出来的模型也会学偏。另一个容易被忽略的环节是争议样本回灌。大模型预标注和人工审核不一致的样本不要改完就扔收集起来这些就是最天然的few-shot示例。下次再跑prompt时把几个典型争议样本塞进去模型会明显收敛。这个闭环跑起来之后标注不一致率会逐步下降而不是靠运气。5. 避坑地质语料清洗标注里容易翻车的5个场景5.1 五个典型踩坑记录坑1模型把缺失深度“脑补”出来了。 现象原文写“12.5-14.0”清洗后变成“12.5m-14.0m”看起来更规范但原始文本并没有单位。原因模型在“修复”数据而不是清洗数据提示词里没写禁止推测。解决系统提示词里加“不要补全缺失信息”规则检核里加“清洗后新增单位或数字则报警”。坑2术语统一改错了方向。 现象“灰岩”和“灰质页岩”被统一成“石灰岩”把两类不同的东西合并了。原因同义词表只映射了“灰岩→石灰岩”没考虑“灰质”作为修饰语的场景。解决术语统一表要经过地质人员审核统一完再抽30条人工目检。坑3地层代号被当成化学元素改掉。 现象“C2ym”二叠系下统栖霞组一段代号被模型改成“C 2ym”或者直接标注成碳元素。原因地层代号短和化学符号撞车模型缺地质领域知识。解决把地层代号白名单写进提示词明确说明“以下代码是地层代号不是化学式”。坑4本地部署并发一高就超时。 现象批量清洗跑到200条接口开始大量超时队列积压最后发现模型服务挂了。原因GGUF量化模型在CPU上推理慢并发线程开太多内存带宽被打满。解决并发降到2到4加任务队列超时重试用指数退避审核界面用流式输出配abort挂死的请求主动取消。坑5标注一致性差同一实体前后不一。 现象同一个“断层F1”前文标成structure后文标成geological_body。原因schema里这两个类型边界模糊标注员各凭理解。解决缩小schema把模糊类型合并成“geological_structure”标注指南里给正反例。5.2 通用排查套路先复现、再比对、后隔离遇到清洗或标注异常我的排查顺序是固定的。先在单个样本上复现看是流程问题还是模型问题再把清洗前后文本做diff定位改动位置最后按段落隔离只重跑出问题的段落不整篇重来。# 排查对比清洗前后文本差异快速定位模型改错的段落 diff -u data/cleaned/z301.txt data/original/z301.txt \ | grep -E ^[-] | grep -E [0-9]|m | head -50逻辑说明diff里出现“”号开头的新增数字或单位基本就是模型在脑补。grep的[0-9]|m把数字和单位相关的改动过滤出来优先看这类高嫌疑改动。参数说明head -50限制输出行数避免刷屏。如果改动集中在某一段把该段从源文件单独切出来调整提示词或参数只对这一条重跑验证没问题再放回批量流程。6. 进阶黄金测试集和增量微调才是长期资产前面几章讲的是一条能跑通的流水线但项目能不能长期用下去取决于两件事黄金测试集和增量微调。我第一次做地勘语料清洗时吃了亏prompt一改整个流程要全部回归手里没有可对比的数据只能人工抽看效率极低。后来养成的习惯是每个项目开跑前人工精标30到50条文本作为黄金集条目不用多但要覆盖每类语料和每种脏数据。每次换模型、改提示词、调参数都在黄金集上跑一遍把一致性分数记下来。# 黄金集回归计算清洗结果和人工精标的字符级一致率 import difflib def consistency_score(gold_text: str, model_text: str) - float: return difflib.SequenceMatcher(None, gold_text, model_text).ratio()逻辑说明字符级一致率比较粗糙但成本低、可每天跑。真正要看的还有实体级一致率——拿清洗后的文本去跑一遍预标注和黄金集的人工标注比对算实体级别的精确率和召回率。两套指标配合才能判断清洗和标注各自有没有退化。参数说明分数低于阈值就报警不要直接回滚先看差异集中在哪个类型多半是提示词或同义词表改坏了。增量微调的前提是攒够经人工复核的清洗标注结果五千条以上就有价值。用GGUF量化一个7B小模型本地就能跑微调目标是让它在“地质文本抽取”任务上更稳把通用大模型的调用量降下来。但别指望微调一步到位黄金测试集是唯一裁判分数没涨就回滚。做这类项目我的习惯是先把“怎么判断做对了”定下来再让模型上场。清洗和标注的每一步都留日志、留中间产物即使翻车也有后悔药。这个习惯让我少踩了很多坑希望帮到你。本文还有配套的精品资源点击获取
返回列表