ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于ChatGLM的地质知识库问答系统:从微调到本地部署全复盘

基于ChatGLM的地质知识库问答系统:从微调到本地部署全复盘

上个月接了个挺特别的活儿:帮某地质队的项目组把一批陈旧勘查报告整理成一套能直接对话的中文地质问答系统。接到需求时我以为这就是套个ChatGPT网页壳子的事,真正动手后才明白,领域问答和通用聊天完全不是一回事:答案要带钻孔号、深度和出处,术语口径要对得上报告原文,数据还不能传公网。前后折腾了两周,最后基于一套可白嫖源码的ChatGLM大语言模型项目,跑通了“本地部署 + 知识库检索 + 领域微调”的完整闭环。

这篇复盘我尽量讲清楚三件事:为什么选ChatGLM而不是直接调通用接口、地质语料从清洗到向量化的具体做法、以及源码跑通和落地部署时最容易踩的几个坑。想复现这套系统,或者打算把大模型引入传统行业知识库的朋友,看完应该能少走不少弯路。

1. 这不是“套壳聊天”:地质问答真正要过的三关

1.1 通用大模型答不好“专业填空”

先说个直观例子。随便找个通用大模型问“什么是矽卡岩型矿床”,它能答得头头是道;可如果你问“某矿区ZK301钻孔揭露到的蚀变矿物组合说明成矿流体发生了什么变化”,通用模型大概率只会给出一句“成矿流体变化复杂,需结合具体资料分析”。这种“正确的废话”对现场人员毫无价值。

地质问答的本质不是百科问答,而是把外部报告里的碎片信息当成“已知条件”,再结合地质规律做推理。它要求系统既能理解“蚀变分带”“矿体赋存标高”这种行话,又能从几十份报告里精准召回某个钻孔、某段深度的实际数据。把这种场景硬塞给一个只经过通用语料训练的聊天机器人,效果可想而知。

1.2 第一关:术语与同义表达满天飞

地质资料里的写法极其不统一。同一口钻孔,文字报告里叫“ZK301”,表格里可能写成“zk-301”,剖面图属性表里又叫“ZK0301”;同一类岩石,“白云质灰岩”和“灰质白云岩”经常被混用,“黄铜矿”有时被记成“Cpy”,有时写成“铜矿化”。如果检索模块按字面分词,关键词差一个字就全部召回失败。

所以系统第一步要做的,不是向量化,而是建一套术语归一化层,把几十种别名映射到同一个实体上。这一步做与不做,检索命中率差得非常明显。

1.3 第二关:答案必须带坐标和出处

地质人员看一个回答,第一眼看的不是结论,而是这个结论来自哪个位置:矿区编号、钻孔号、钻孔深度区间、图幅编号、报告页码。缺了这些信息,结论再合理也没法直接用,因为别人没法复核,也没法写进正式成果里。

这决定了系统的答案必须可溯源。模型不能凭空生成“品位约0.8%”这种话,必须明确说出“根据某某报告第X页,ZK205钻孔在120-136m段取样结果显示……”同时给出原文片段供人查看。通用大模型没有能力记住某份具体报告里的表格数据,只能靠上层检索模块把相关原文喂进去。

1.4 第三关:数据出不去,只能本地干

很多地质资料要么涉及商业勘探成果,要么有内部管理要求,不可能直接上传到公网接口。这让“远程调用大模型API再挂个知识库”的方案从一开始就被否决了。整个系统必须放在单位内网服务器上,模型权重、知识库、推理服务全部本地化。正是这一条,让我最终投向开源权重、可私有化部署的ChatGLM系模型。

想清楚这三关之后,我对系统的目标也明确了:能回答常规地质概念问题,能从本地知识库召回具体报告片段,能给出带来源出处的结构化答案,并且全程不需要外部网络。

2. 选型心得:凭什么选ChatGLM系而不是通用API

2.1 开源权重是硬门槛,不是偏好问题

对地质单位这类场景,最省事的做法是买大模型API,按token付费,注册就能用。但数据出域这个坎过不去:你要把报告内容作为检索上下文发给外部接口,就相当于把核心资料交给第三方。大部分项目组连这关都过不了,更别提后续的合规审查。

开源模型权重可以完整下载到内网服务器,所有数据不出局域网,这是ChatGLM系模型进入候选名单的根本原因。另外它社区活跃,文档和部署案例多,遇到问题搜得到答案。对于没有专职算法工程师的单位,这比模型本身更值钱。

2.2 中文语料优势:长句和地层单位它读得懂

地质报告里的中文有一个特点:长句极多,而且充满层级嵌套。比如“下白垩统某组上段凝灰质砂岩与花岗斑岩接触带附近的硅化、绢云母化蚀变强烈”,这种句子要拆成正确的主谓宾和修饰关系,对模型的中文语法感知能力要求很高。

ChatGLM系模型在通用中文语料上训练充分,对这类书面化的技术长句理解得比很多英文为主的开源模型更自然。实测直接拿基础权重回答一般性地学问题,判断基本准确;但要做深度领域问答,还得靠后面说的微调和检索配合。选型阶段别指望开箱即用,但它至少给了一个不差的中文底座。

2.3 资源门槛:一张24G显卡就能跑起来

很多人一听说本地部署大模型就以为要上八卡顶配服务器。实际上地质问答这种场景,压根不需要跑超大底座模型。通用做法是拿中尺寸稠密模型做4比特量化推理,单张24G显存即可稳定支撑几十人小团队的日常使用。我整理了实操中的参考配置:

部署方式显存需求并发能力适用场景
4bit量化中尺寸模型12G-16G5-10并发个人机、项目组内网试用
8bit量化/FP16中尺寸模型24G-32G10-30并发单位内部知识库正式服务
更大底座模型64G以上更高但边际效益低大型知识库,成本需精算

提示:并发数还跟输入输出长度强相关,表格里只是我自己实测的参考。地质检索通常要喂给模型一大段上下文,实际并发会低于纯粹闲聊场景。

3. 真正花时间的环节:把地质资料加工成模型能吃的“饲料”

3.1 原始资料五花八门,清洗比建模更头疼

地质问答系统的知识来源包括:区域地质调查报告、固体矿产勘查报告、水文地质钻孔记录、地质灾害评估文本、遥感解译说明书,偶尔还有老式图件导出的属性表。这些资料有Word、PDF扫描件、Excel台账、MapGIS导出文本,格式乱七八糟。

第一步不是向量化,而是清洗。清洗有三件事最花时间:一是去掉页眉页脚、水印和无关批注,否则切块后模型会把“机密”“附件”这类词当成正文内容;二是统一数字和单位格式,比如“m”和“米”全角半角混用,深度区间“120-136m”和“120~136米”要归一;三是把PDF里的表格抽出来,转成带表头的文本块,让模型能理解“孔深、岩性、采取率”三列之间的关系。表格一旦被拍平成无结构文字,答案质量立刻崩掉。

3.2 切块长度和重叠窗口:调一次就记住的参数

RAG系统里,文本切块策略对召回质量影响极大。地质报告的段落长短很不均匀:规范条文可能就一句话,钻孔柱状描述却连续几十行。我反复试验下来,每块300到500字、块与块之间重叠50字左右,检索效果最稳定。

为什么不能太小?太小则上下文不足,模型只能看到“中粒花岗岩”却看不到这个岩石属于哪个地层组。为什么不能太大?太大则一块文本里塞了多个主题,向量化后互相稀释,相关程度被平均掉。重叠窗口则是为了让跨块的同一句话不至于被拦腰截断。这套参数在不同行业知识库之间有通用性,可以直接复用。

3.3 同义词词典:肉眼可见涨点的一步

地质语料必须做同义词映射。我的做法是维护一张标准实体表,在文本进入切块前先做一次轻量替换。下面几条是实际工程里最实用的映射:

原文常见写法标准化实体
黄铜矿化 / Cpy / 铜矿化(需语境判断)黄铜矿
白云质灰岩 / 灰质白云岩 / 白云岩化灰岩白云质灰岩
Qz / 石英脉 / 硅质脉体石英
上统 / 上段 / 上部层位上位地层单元

这里有个坑:某些词不能无脑替换。“铜矿化”在不同句子里可能指原生铜矿物也可能泛指铜矿化现象。我的经验是先在短语级别做边界识别,再根据相邻词判断,比如“铜矿化+黄铁矿+石英脉”这种组合,就倾向替换成“黄铜矿化”。硬替换不如不替换,错了反而带偏检索。

3.4 向量的类型与索引:别只依赖一种召回方式

中文地质词汇专业性太强,通用Embedding模型对“矽卡岩”“蚀变分带”这类复合词的编码并不理想。我测试了多个方案后,最终选了在中文长文本上表现较好的Embedding接口,同时叠加一层BM25关键词检索做融合召回。

具体做法是:语义检索和关键词检索各返回一批候选,加权合并后统一排序。语义召回能处理“哪段报告提到了蚀变矿物的分带规律”这类模糊查询,关键词召回则能精确锁定“ZK301 岩心 采取率”这种强标识信息。两条路互补,实测把检索命中率提高了差不多两成,尤其在处理钻孔号、图幅号这类文本时效果明显。

向量化之后,每条知识块会带上一份结构化的元信息,方便后续溯源:

{ "id": "doc_zk301_005", "source": "ZK301钻孔柱状图描述", "content": "0-12.5m:第四系覆盖层;12.5-46.8m:灰白色中粒花岗岩,见绿泥石化、绢云母化蚀变,局部黄铁矿化。", "meta": { "borehole": "ZK301", "depth": "12.5-46.8m", "report": "某矿区详查报告" } }

只有把元信息保存好,后面做答案溯源才有依据。这一步别省,否则回答里永远只有一段光秃秃的文字,没法让用户回溯到原始报告。

4. 让模型说“内行话”:指令微调与检索增强的双修路线

4.1 两条技术路线,不要二选一

做领域问答有两条主流路线:微调领域模型,或者通过检索注入外部知识。我一开始想只做微调,把几百份报告文本灌给模型去学,效果很差。模型记住了一堆零碎名词,可一旦问到没见过的钻孔号,照样一本正经地编答案。

最后还是回到“微调 + 检索增强”的双修路线:微调负责教会模型地质表达的句式和推理习惯,检索负责给模型提供具体、新鲜的现场资料。两者解决的是不同问题,硬分高下没意义。

4.2 微调数据怎么造?半自动矿工式挖掘

最理想的训练数据是让地质工程师现场标注,但项目组根本抽不出人手。我用了一个更原始的办法:从报告里半自动抽取“问题—上下文—答案”三元组。具体就是拿段落里的关键句反推用户提问,再把原句改写成答案。比如报告写着“矿体主要赋存于燕山早期花岗岩内接触带,形态呈脉状”,我就生成问题“矿体赋存位置和形态特征是什么”,答案保留原文关键信息。

按这个办法凑了3000多条指令数据,覆盖岩性识别、矿体产状、储量估算规则、灾害成因判断等高频问题。每条数据又让项目朋友人工抽查了一遍,宁可少一百条,也不要留一条对应错误。

4.3 LoRA微调:照着这份配置起步

我用的是LoRA低秩适配,不需要全量微调,显存压力和训练时间都可控。参考配置如下:

  • 基础模型:ChatGLM系中尺寸底座权重
  • LoRA秩:32
  • 学习率:2e-4
  • 批次大小:4,梯度累积8步
  • 训练轮数:3轮
  • 最大输入长度:2048

跑下来我的体会是,只要不出现明显过拟合,这些参数没什么可反复调的。真正决定效果好坏的还是训练数据的覆盖度和准确率。训练轮数从3轮加到5轮,指标不升反降,因为模型开始逐字背训练集了。

4.4 提示模板也要管教:让模型守规矩

系统给模型的提示模板必须明确三件事:角色、来源范围、答题纪律。我的模板大概长这样:

你是一名地质工程师。请根据“知识库资料”提供的信息回答问题,不得使用资料之外的内容。若资料中没有明确答案,必须回答“资料不足,暂无法判断”,禁止编造。回答尽量包含矿区编号、钻孔号、深度区间、岩矿名称、构造期次等结构化要素。

加了这个约束之后,幻觉率直线下降。用户问一个知识库没覆盖的问题时,模型不再硬编,而是老老实实说查不到。这才是领域系统该有的姿态——不够聪明可以理解,但不能胡编。

5. 从源码到能用的那段距离:部署实战和踩坑记录

5.1 拿到源码第一件事不是跑,是改路径

从网上下载的源码压缩包,解压后最容易踩的第一个坑就是路径写死。这份中文地质问答系统源码里,模型加载路径、知识库目录、缓存目录全都指向了作者本机的绝对路径。

我的建议是:不要急着执行start命令,先把配置文件完整读一遍,把所有本地路径、模型路径、知识库路径全部改成自己的目录结构。很多新手报错其实根本不是环境问题,就是路径对不上。

5.2 首字太慢,三个优化一起上

部署完成之后最让人难受的是首字延迟。地质问答的输入上下文往往很长,模型要读完整个检索片段才开始输出,用户体验很差。我做了三件事:

第一,开启流式输出。用户看到内容逐字蹦出来,心理等待时间大幅缩短。第二,把输入长度从4096限制到2048,减少无关长文对显存的占用。第三,命中相同问题的回答做缓存,重复提问直接返回历史结果。

这三招做完,体感流畅度提升很明显,尤其是项目组同事反复拿同一批问题测试时,缓存几乎秒回。

5.3 答案说到一半被截断,不是显存不够

实测中遇到的另一个怪问题是:答案生成到一定长度突然停止,后面内容直接消失。排查了很久,并不是显存溢出,而是生成配置里的最大新token数默认只有512。地质答案要给出矿体描述、来源引用和深度区间,经常超过512个token。

把max_new_tokens调到1024之后,长答案基本完整。同时需要注意生成参数里的重复惩罚因子,设太高会导致“某组某组某组”这类叠字反复出现,设太低又会啰嗦。我最终用的是0.7,效果相对自然。

5.4 给答案装一个“引用来源”的后处理模块

做专业领域问答,信任比速度更重要。我专门在服务端写了一个后处理函数:检索命中的文档ID和原文片段会被拼到回答末尾,格式类似:

[来源:某矿区详查报告-第三章-钻孔ZK301柱状图-原始片段]

这个模块代码量不大,但价值极高。项目组同事拿到答案后可以一键回看原文,自己判断模型有没有断章取义。系统上线之后,很多原本存疑的用户就是靠这个功能慢慢建立起信任的。

6. 源码里值得反复读的模块,以及几个扩展方向

6.1 值得先读的三个模块

如果你拿到了这份源码,我建议按这个顺序读代码。

第一个是检索服务封装。它把文件格式解析、文本切块、向量化、相似度排序做成了统一接口,读懂了就明白系统是怎么把不同格式的资料变成可召回的知识块的。第二个是提示词模板。模板里很多细节能看出作者踩过的坑,比如明确禁止模型输出不存在的钻孔数据。第三是前端流式交互实现。它对服务端SSE事件流的封装很标准,直接剪下来用到别的项目里也完全没问题。

6.2 别停在问答,能做的东西还有很多

这套系统本质是一个“领域知识库 + 大模型 + 对话界面”的样板间,二次开发空间很大。

第一个方向是让材料更厚:目前依赖文字报告,很多地质结论其实是画在图上的。可以接入图像识别模型,让系统读懂地质剖面图、柱状图、遥感影像图例,回答“图上某条断层倾向多少度”这类问题。第二个方向是让录入更省事:野外记录很多时候是语音和照片,可以加语音转写,把野外口述直接转成结构化描述入库。第三个方向是自动出文档:问答只是输入输出,进一步可以让系统根据多轮问答结果直接生成一段项目简报,省掉工程师大量写报告的时间。

6.3 学会站在框架上做自己的项目

这套系统最大的价值,不是“拿过来就能用”的成品,而是一个相当完整的地基。它把大模型接入、知识库管理、前端交互、接口封装这几件麻烦事都串好了。你自己要做的,就只是把地质资料换成别的行业资料,把提示词换成对应领域的说法。

如果只是部署试跑,不求二次开发,按我前面写的步骤按部就班,一天左右就能把Demo跑起来。但如果你想把它真正变成自己能长期维护的工具,至少要把检索封装和提示词模板读透,否则出了问题根本不知道从哪排起。

最后再分享一个小体会:用大模型做专业领域问答,九成功夫都在数据身上,模型更像是一个学会规矩的“转述者”。我建议你拿到源码之后先别急着调参数,而是找一两份真实报告,把清洗、切块、入库、问答这个闭环完整走一遍。只要这一步扎实了,后面换行业、换场景都只是换数据源的问题。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进