上个月接了个挺特别的活儿帮某地质队的项目组把一批陈旧勘查报告整理成一套能直接对话的中文地质问答系统。接到需求时我以为这就是套个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系而不是通用API2.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”和“120136米”要归一三是把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跑起来。但如果你想把它真正变成自己能长期维护的工具至少要把检索封装和提示词模板读透否则出了问题根本不知道从哪排起。最后再分享一个小体会用大模型做专业领域问答九成功夫都在数据身上模型更像是一个学会规矩的“转述者”。我建议你拿到源码之后先别急着调参数而是找一两份真实报告把清洗、切块、入库、问答这个闭环完整走一遍。只要这一步扎实了后面换行业、换场景都只是换数据源的问题。