煤矿安全问答这事,通用大模型是真的搞不定。问"采煤工作面回风流中甲烷浓度达到多少必须报警",通用模型要么给一段正确但没用的废话,要么把不同版本规程的条款混在一起瞎编。我们这个项目就是把 internlm2 这个开源基座模型拿过来,用煤矿事故案例和安全规程知识做指令微调,训练出一个真正懂煤矿安全的智能问答模型。整个过程覆盖数据清洗、LoRA微调、效果评估、部署上线,踩过不少坑,也沉淀了一些验证有效的做法。这篇文章把完整流程拆开复盘一遍,数据怎么来、参数怎么定、问题怎么排,都会写清楚,适合正在做行业大模型、或者打算往安全垂直领域做智能问答的团队参考。
1. 项目定位与整体设计
1.1 煤矿安全知识问答,到底难在哪
通用大模型在开放域对话上确实很强,但落到煤矿安全这种垂直场景,问题非常具体。
首先是知识专业性太强。煤矿安全涉及一通三防(通风、防瓦斯、防煤尘、防灭火)、采掘机运通五大系统、水害火灾等灾害治理,每个分支都有严格的技术参数和操作规程。通用模型的预训练语料里,这些行业精品内容占比极低,它可能连"上隅角""回风隅角""瓦斯抽采"这些基础词都没见过几次,回答全靠上下文硬凑,凑出来的东西自然没法用。
其次是安全答案的容错率极低。普通聊天回答错了顶多被调侃两句,煤矿安全问答错了可能涉及误判、误导,这是性质完全不同的问题。所以模型输出必须严谨、有依据、可溯源,而不是"我猜大概是这个数"。
还有一点是术语和表述必须入行。行业内说"回风隅角",你写成"角落";规程上说"瓦斯超限断电",你写成"气体太多要停电",工人看不懂,技术人员觉得不专业。微调的本质,就是让模型的语言分布对齐行业语料分布,把术语体系、表述习惯、知识边界全部"接上轨道"。
项目初期我们先用某个主流通用模型做了基线测试,50 个安全生产问题里,能给出像样答案的不到 15 个,而且大量答案把条款条件弄混了。比如问"瓦斯超限时现场人员应该怎么办",它给出的是"建议咨询专业人员"这种正确的废话。结论很明确:不做领域适配,通用模型在这个场景下基本不可用。
1.2 为什么选 internlm2 作为基座
模型选型阶段,我们对比了好几条路线,最终定了 internlm2,核心是这几个理由。
第一,中文能力扎实。internlm2 系列在中文理解和生成上做过针对性优化,而煤矿安全语料几乎全是中文,基座模型的中文基础素质直接决定微调的上限。第二,开源且权重可商用,不用从零预训练,基于开权重直接微调,成本完全可控。第三,基座指令遵循能力均衡。我们要做的是问答系统,基座模型本身要能听懂指令、按格式回答,微调才能把行业知识顺利"接"上去。第四,社区生态成熟,HuggingFace、各类微调框架对 internlm2 的支持都很完善,遇到问题能找到现成方案。
备选路线也试过其他开源中文模型,实测下来 internlm2 在长条款理解和多轮指令跟随上的稳定性更好。7B 这个体量是刻意选的:再大的模型推理成本高、部署门槛高,放到煤矿现场的边缘设备上根本跑不动;7B 配合量化之后单卡就能部署,性价比正好。
这里多说一句,模型选型没有绝对最优,只有场景适配。如果团队算力充足,也可以上更大体量的基座,但训练和部署成本会同步上涨。我的建议是先用 7B 把整个流程跑通,验证数据有效、评估体系可靠之后,再考虑升级基座,风险小得多。
2. 数据工程:微调效果的天花板
微调圈有句话叫"垃圾进,垃圾出",在这个项目里尤其贴切。模型能不能答好煤矿安全题,七成取决于数据,模型结构反而没那么关键。这部分多写一些,因为这是最容易翻车也最容易被忽视的环节。
2.1 数据从哪里来
我们当时的数据来源分为四大类,每一类的用途都不一样。
第一类是法规标准类,包括最新版煤矿安全规程、各专项规定、行业技术标准。这类数据是问答的"硬依据",凡是涉及数值、流程、责任的问题,答案必须出自这里。特别提醒一下版本问题,旧版条款可能已经废止,清洗时要只保留现行有效版本,否则模型很容易学到过时条款。
第二类是事故案例类,包括典型煤矿事故调查报告和案例分析材料。事故案例的价值在于它提供了"情景—原因—教训—措施"的结构化知识,非常适合做成问答题。比如用户问"某类瓦斯爆炸通常是怎么发生的",模型应该能结合案例讲清事故链条、直接原因、间接原因和防范要点,而不是背一段安全口号。
第三类是技术手册与操作规程,覆盖一通三防作业要点、采掘作业规程、机电运输安全要求等。这类数据决定了模型回答的"专业颗粒度",能不能说出具体操作步骤和工艺参数,全靠这部分语料支撑。
第四类是应急响应与救援知识,包括瓦斯超限处置流程、透水征兆识别、井下避灾路线选择、自救器使用步骤等。这是问答系统里实用价值最高的部分,也是通用模型表现最差的——因为它既不知道处置顺序,也不知道阈值标准。
四类数据的配比大概控制在 3:3:3:1,法规、案例、规程打底,应急类做补充。全套下来积累了 2 万多条高质量问答对,这个量级对 7B 模型做领域微调是够用的,再多就要警惕噪声了。
2.2 数据清洗与格式化
原始资料不可能直接拿去训练,必须经过几道处理。第一道是知识点抽取。从规程和技术文档里抽知识点,一条知识一个主题,避免把大段文字混在一起。我们当时是按"主题—对象—条件—数值—动作"的结构拆解,比如"采煤工作面回风隅角甲烷传感器报警浓度设为大于等于 1.0%""超限后必须切断相关区域电源"这样一条条拆干净。
第二道是构造问答对,这一步最费人力。我们用了规则生成加人工改写两种方式结合。规则生成是根据条款模板批量产出问题,比如"XX 规定的内容是什么""违反 XX 条款怎么处理",但模板生成的问法很僵硬,必须人工过一遍,把问法改成工人和技术人员真实会问的方式。我们让煤矿专业背景的同事参与改写,效果提升非常明显,这条经验强烈建议复制。
第三道是质量控制。每条数据都要做一致性检查,确认答案确实出自原始资料,数值、单位、适用条件没有被改错。这里宁可少留数据也别留脏数据。一条错误条款进了模型,后面要花十倍精力去纠正,而且安全场景下错误知识的代价是不可接受的。
格式化方面,我们用的结构很简单,一条样本就是指令、上下文、回复三段,类似下面这样:
{ "instruction": "采煤工作面回风隅角甲烷传感器报警浓度是多少?", "input": "", "output": "根据现行煤矿安全规程,采煤工作面回风隅角甲烷传感器的报警浓度设为大于等于1.0%,超过该值必须按规定切断相关区域非本质安全型电气设备电源并撤出人员。" }input 字段大多数场景为空,保留是为了兼容需要结合上下文回答的情况。格式统一、模板一致,是后续微调能否稳定收敛的基础,这一点后面还会提到。
2.3 数据量级与配比的实操建议
很多第一次做微调的同学会陷入"数据越多越好"的误区。实际经验是,对 7B 模型做 LoRA 微调,领域问答数据 1 万到 3 万条是比较舒服的区间。低于 5000 条,模型学不到稳定的领域模式;高于 5 万条,如果数据质量没有同步跟上,反而会引入大量噪声,模型开始学坏。
数据配比上还有一个容易被忽略的点:通用语料和领域语料的比例。如果全部用领域数据微调,模型容易"丢失通用能力",连日常对话和格式遵循都变得机械。我们当时在训练集里保留了 10% 到 15% 的通用指令数据,和领域数据混在一起,效果明显更稳。这个比例可以按自己的场景调,但完全不要通用数据这条路我试过,不推荐。
另外强烈建议在数据准备阶段就做一次全量抽样审查。我们当时从 2 万条数据里随机抽了 200 条,由专人核对答案和原始资料的对应关系,发现了一批数值错误和条款张冠李戴的问题。这一道关把好了,后面的训练会省心很多。
3. 微调实现:从基座模型到行业助手
3.1 环境准备与工具链
训练环境方面,我们用的是单机多卡,两块 80G 显存的卡跑 7B 微调完全够用。如果只有一块 24G 消费级显卡,配合 LoRA 加梯度累积同样能跑,就是慢一些。显存不够又想跑大模型,本质上是拿时间换空间,需要自己对训练时长有预期。
工具链强烈建议用现成的微调框架,没必要自己写训练循环。我们用的是 LLaMA-Factory,它对 internlm2 支持很友好,数据格式配置好之后一条命令就能开训。选它的理由是社区维护活跃、支持多种数据格式、对 LoRA 和量化方案兼容好。框架只是工具,不用纠结哪个最好,用熟一个就行。
训练脚本大概长这样,以 LoRA 微调为例:
CUDA_VISIBLE_DEVICES=0,1 python src/train_bash.py \ --model_name_or_path internlm2-7b \ --stage sft \ --do_train \ --dataset coal_safety_qa \ --template internlm2 \ --finetuning_type lora \ --output_dir output/coal_lora \ --per_device_train_batch_size 4 \ --gradient_accumulation_steps 8 \ --learning_rate 2e-4 \ --num_train_epochs 3.0 \ --lr_scheduler_type cosine \ --warmup_ratio 0.1 \ --bf16 True \ --lora_rank 64 \ --lora_alpha 128 \ --lora_dropout 0.05 \ --logging_steps 10 \ --save_steps 500 \ --cutoff_len 2048这里每个参数都不是拍脑袋定的,下面逐个说明依据。
3.2 关键参数与调参心得
微调参数网上教程很多,但能讲清楚"为什么这么设"的很少。我把几个最关键的参数结合实际跑出来的经验拆开讲。
学习率。LoRA 微调的学习率一般比全参微调大一个量级。全参微调常见 1e-5 到 5e-5,LoRA 我们实测 1e-4 到 3e-4 表现比较好,最终定在 2e-4。学习率太大会导致损失震荡不收敛,太小则领域知识接入太慢,训练好几轮效果还是温温吞吞的。如果你发现 loss 曲线一直在高位徘徊,先怀疑学习率,再怀疑数据。
LoRA 秩和缩放系数。我们用的 lora_rank=64、lora_alpha=128。rank 决定低秩矩阵的容量,rank 太小学到的领域知识有限,rank 太大训练显存和耗时都上涨。alpha 是缩放系数,一般设为 rank 的两倍左右。这个组合我们在多轮实验里最稳,也符合社区里 7B 模型 LoRA 微调的常用区间。如果你用的框架默认 rank 是 8,做行业微调时可以适当往上提。
批次大小与梯度累积。per_device_train_batch_size=4 配合 gradient_accumulation_steps=8,等效批次大小是 32。批次太小梯度噪声大,训练不稳定;批次太大容易过拟合且显存压力大。等效 32 是 7B 微调比较通用的区间。显存小的场景可以降 batch 加累积,等效批次维持不变即可。
训练轮数。我们试过 2 到 5 轮,3 轮在效果和泛化之间最平衡。轮数太少领域知识学不透;轮数多了以后,验证集指标停滞甚至下降,说明开始过拟合训练集里的问法了。这里还要配合 checkpoint 选取使用,后面细说。
还有两个容易忽略的参数。一是 bf16,硬件支持的话务必打开,既省显存又稳定。二是 cutoff_len 设 2048,煤矿安全条款很多表述很长,低于 1024 会把关键内容截断,导致模型学到残缺知识,这点在安全场景相当致命。
3.3 训练过程监控
训练不是把命令丢出去就完事,盯住几个信号能帮你提前发现大部分问题。
第一是训练损失曲线。正常情况应该是稳步下降然后趋于平缓。如果出现 loss 突然飙升再回落的大尖峰,多半是数据里混入了异常样本,比如超长文本被截断后内容残缺,或者 JSON 格式错误。建议定位到对应 batch 后清洗数据。如果 loss 一直下不去,优先检查数据格式和学习率,这两个是最大的嫌疑。
第二是分阶段 checkpoint 对比。我们在训练到一半、三分之二、结束时各保存一份 checkpoint,用同一份评测集做对比测试,看哪个 checkpoint 的实际问答质量最好。有个很常见的现象:loss 还在下降,但验证集问答的"废话率"反而上升了,这就是过拟合的前兆。最终部署用的不一定是最后一个 checkpoint,而是验证表现最好的那个。这一点很多人不知道,以为训练完自然用最后一个,其实对比一下往往有惊喜。
第三是显存和训练速度的排查。单卡 24G 跑 LoRA 时,batch_size 要降到 1 到 2,梯度累积加大到 16 到 32。跑全量数据之前,先拿一个小数据集试跑一遍,确认能正常跑完一个 epoch 再放开。这个习惯能帮你省下大量排查时间,我们项目里所有成员都被要求必须走这一步。
4. 效果评估与案例分析
4.1 评估集怎么建
模型训练完,第一件事不是急着部署,而是建一套能反映真实使用场景的评估集。我们建评估集时坚持三个原则:真实性、覆盖度、难度分层。
真实性是指问题必须来自实际使用场景。我们让一线安全管理人员和工程技术人员提问题,而不是自己闭门造车。他们关心的是"上隅角瓦斯超限了,现场第一处置动作是什么""井下发现透水征兆,撤人路线怎么确定"这种非常具体的问题。覆盖度是指评估集要覆盖一通三防、采掘机运通、应急逃生、事故案例几个主要模块,确保模型不是只在某一个子领域表现好。难度分层是把问题分成三类:条款检索型,答案在规程里直接写死;综合分析型,需要结合多条知识推理;案例问答型,需要理解事故案例并提炼经验。三类比例大概 4:4:2。
评估集规模不用太大,180 到 200 条足够。每条问题配好标准答案要点,评分采用"要点匹配加人工判断"的双重方式,先自动检查答案是否覆盖标准答案里的关键要点,再由煤矿专业同事做最终人工打分。双重评分比只看一个分数可靠得多,因为自动匹配容易漏判语义等价,而纯人工又太慢。
4.2 微调前后的效果对比
评估做完,效果对比非常直观。我们拿同一份 200 题评估集,分别让通用基座模型和微调后的模型作答,结果差异明显。
| 对比维度 | 通用基座模型 | 微调后模型 |
|---|---|---|
| 准确率 | 不足三成 | 约八成五 |
| 术语规范度 | 经常出现不准确表述 | 能准确使用行业术语 |
| 答案可溯源 | 基本无法给出依据 | 能引用条款要点 |
| 废话率 | 高,大量安全建议式套话 | 明显降低,答即所问 |
举两个具体例子。第一条是条款检索型问题:"矿井主要通风机停止运转时,必须采取什么措施"。微调前模型回答"要立即采取措施恢复通风,确保人员安全",没错但等于没说。微调后模型能直接答出"立即通知调度部门,启动备用通风机,井下作业人员停止作业并撤出,在规定时间内恢复通风,同时设置明显警标",这才是现场真正需要的回答。第二条是综合分析型问题:"回采工作面回风隅角瓦斯局部积聚,分析可能的原因"。微调后模型能结合通风系统布置、采空区漏风、瓦斯涌出异常等多个维度给出分析和处置建议,逻辑链条完整,而不是堆砌安全口号。
这里补充一个量化评估之外的观察:微调后模型在"答即所问"上进步很明显。通用模型往往会绕圈子,问 A 答 B;微调模型能把回答聚焦在问题上,这个变化在人工评测时感受特别深。
4.3 边界与风险控制
模型效果好了,不等于可以随便用。煤矿安全场景对模型的边界认知要求很高,我们在系统里做了两层约束。
第一层是知识边界提示。当用户问的问题超出训练数据覆盖范围,模型不能不懂装懂。我们在微调数据里刻意加入了一批"超出知识范围"的样本,训练模型学会回答"这个问题超出我的知识范围,建议查阅最新规程或咨询专业技术人员",而不是强行编造。这个设计在安全场景里非常重要,因为胡说八道的危害远大于说不知道。
第二层是应用边界。问答系统定位是知识助手,不能替代现场安全管理和专业人员判断。系统界面上明确提示回答仅供参考,现场处置必须以规程和专业人员指令为准。这一点不仅是技术问题,也是责任边界问题,上线之前一定要和相关业务部门确认清楚。
5. 常见问题排查与避坑指南
这一部分是实操中踩出来的经验,按问题出现频率整理,遇到类似情况可以直接对照排查。
5.1 训练阶段的高频问题
样本格式错误导致训练中断。这是最常见的问题,JSON 里多一个引号、少一个逗号,都会让你白跑几个小时。建议训练前先写一个数据校验脚本,把所有样本完整跑一遍,格式有问题的直接定位报错。我们后来把校验集成到了数据生成流程里,从源头杜绝,这比事后排查省力得多。
loss 震荡不收敛。优先检查两件事:数据里有没有超长截断后内容残缺的样本,学习率是不是过大。另外,不同样本之间长度差异过大会造成梯度不稳,可以在数据打包时按长度做分组,让同一个 batch 里的序列长度尽量接近,这个技巧对训练稳定性帮助不小。
过拟合导致通用能力退化。如果微调后的模型连"你好"都回得很机械,说明领域数据比例太高,通用能力被挤掉了。我们在 2.3 节提到的保留 10% 到 15% 通用数据就是针对这个问题的。另一个办法是减少训练轮数,从 5 轮降到 3 轮往往立竿见影。还有一种情况是模型把训练集里的问法背下来了,换一种问法就答不好,这时候要在数据层面增加问题改写多样性,而不是继续加训练轮数。
5.2 生成质量问题的处理
回答内容正确但表述呆板。这个问题多半出在数据里问题的问法太单一。解决办法是扩充数据里知识点的问法多样性,同一个知识点准备三到五种问法。我们后来尝试过用大模型自己做问题改写增强,效果不错,但必须人工抽检,防止改写过程中引入错误。这里要把握好度,改写过度会让问题偏离真实场景。
关键数值答错。这是安全场景最不能容忍的问题,排查思路要按顺序来。先确认训练数据里数值有没有错,再确认是不是多种来源数据里数值冲突导致模型学混了。我们就踩过这个坑:两个版本的资料对同一传感器报警阈值的表述不一致,模型学到的是混乱版本。后来做了数值一致性专项排查,以现行有效规程为准统一所有冲突条目,问题才解决。涉及数值的知识必须做交叉核对,这是安全场景微调的底线要求。
5.3 部署与上线注意事项
推理框架我们用了 vLLM,吞吐量比原生推理高不少。针对 7B 模型,16G 以上显存的卡跑 FP16 完全没问题;如果要在低配机器上跑,可以做 INT8 量化,实测回答质量损失在可接受范围内,但关键数值的准确性要专门测一遍。量化对数值类任务的影响不小,量化前后用同一份评估集各跑一遍,对比数值类问题的回答是否保持一致。
还有一个关键细节:训练和推理的提示词模板必须完全一致。我们用 internlm2 的官方模板训练,推理时也必须用同一模板包装用户输入,否则效果大打折扣。这个细节坑了不少人,我见过好几个项目因为在推理时代码里换了模板,导致模型表现断崖式下降,排查了好几天才发现。另外上线前的安全提示不能省,涉及现场处置的问题,即使答案正确,也要在系统层面加一道"仅供参考,以规程为准"的兜底提示。
6. 实操心得与后续扩展
最后分享几点个人体会。做行业大模型,最难的不是模型训练本身,而是对行业知识的理解和建模。我们项目能有效果,很大程度上是因为让懂煤矿安全的人深度参与了数据构建和效果评估。如果你准备做类似的垂直领域大模型,建议第一时间找到懂行的业务专家,让他们嵌入数据环节,这比调任何参数都重要。数据标注和改写的质量,直接决定了模型的天花板,技术手段只能逼近这个天花板,突破不了。
另一个体会是微调不是终点,数据迭代是常态。我们上线后的第一个月就收集了两百多条真实用户问题,发现有不少在训练数据里覆盖不足,于是又补了一轮数据,重新微调了一版。行业知识在更新,模型也需要跟着迭代,数据回流机制最好在项目一开始就设计好,不然后面每次迭代都要从零开始收集,成本很高。
后续我们计划做两个方向的扩展。一是把知识库和模型检索结合起来,让模型在回答高价值安全问题时能引用具体条款原文,增强可追溯性。二是加入更多场景能力,把设备监测数据、现场图片等纳入辅助判断,扩展系统的应用范围。这些都要在现有基础上逐步推进,先把问答这件事做扎实,再考虑更多可能性。
数据这块再提一个小技巧:保留一份"错误修正记录",把历史上发现的所有错误数据、错误条款、错误参数都记下来。模型每迭代一版,都要拿这份记录去回归测试,确保之前修过的问题没有复现。安全场景下,旧问题复现比新问题出现更让人头疼,这个习惯救了我们好几次。