4.1 垂直领域实战之数据构建与训练:以医疗问答为完整范例


文档摘要

4.1 垂直领域实战之数据构建与训练:以医疗问答为完整范例 读者读完这一节,应该能拿走一条可复用的「垂直领域微调作战线」:先想清楚这个领域要改模型的哪一类能力,再从真实业务流里捞出对的语料、按 SFT 的格式洗干净、配上能约束输出的模板,最后用一个保守但够用的训练配置把它训出来并过三道验收门。这一节用医疗问答做完整范例,是因为它几乎集齐了所有垂直领域的典型难题——数据敏感、必须讲事实、答错有代价、且标注语料稀缺。把医疗这条线走通,换到法律、客服、金融都是同一套打法。 4.1.1 为什么医疗是 LoRA 微调的「甜区」 先把话说在前头:医疗场景绝不适合用全量微调去「暴力改造」一个通用大模型,反而特别适合 LoRA/QLoRA 这种「精准用工」的路子。原因有四: 第一,数据极其敏感。

4.1 垂直领域实战之数据构建与训练:以医疗问答为完整范例

读者读完这一节,应该能拿走一条可复用的「垂直领域微调作战线」:先想清楚这个领域要改模型的哪一类能力,再从真实业务流里捞出对的语料、按 SFT 的格式洗干净、配上能约束输出的模板,最后用一个保守但够用的训练配置把它训出来并过三道验收门。这一节用医疗问答做完整范例,是因为它几乎集齐了所有垂直领域的典型难题——数据敏感、必须讲事实、答错有代价、且标注语料稀缺。把医疗这条线走通,换到法律、客服、金融都是同一套打法。

4.1.1 为什么医疗是 LoRA 微调的「甜区」

先把话说在前头:医疗场景绝不适合用全量微调去「暴力改造」一个通用大模型,反而特别适合 LoRA/QLoRA 这种「精准用工」的路子。原因有四:

第一,数据极其敏感。病历、诊断、用药记录里全是受保护的健康信息,这类数据基本出不了医院内网,你不可能把它们拿去训练一个从头训起的大模型,更不可能上传到第三方。LoRA 的价值在于——基座 GLM-5.2 是开源可本地部署的,适配器只在你自己的机器上训练,原始语料从头到尾不离开内网,合规风险天然低一截。

第二,强领域知识、弱标注规模。医疗有大量专业术语、用药逻辑、诊疗路径,通用模型「知道一点但不准」;但你手里的标注问答对往往只有几千到几万条,远不够全量微调。LoRA 恰好在「小数据 + 强领域」的区间内性价比最高。

第三,答错有代价,必须可控。医疗回答不能瞎编。LoRA 只动几百万参数,基座的通用常识被完整保留,意味着「模型不会因为你加了医疗适配器就丧失基本判断力」,这比大幅改写权重更安全、更可预测。

第四,多场景可拆分。导诊、健康科普、用药咨询、病历结构化是性质不同的任务。用一个基座挂多个医疗子适配器(导诊一个、科普一个、结构化一个),比训一个大杂烩模型干净得多——这一点在 4.2 会展开讲多场景切换。

把领域拆开看,「要改模型的能力」其实只有三类:知识注入型(把术语体系、用药逻辑灌进去)、格式约束型(病历结构化、按模板出报告)、风格/角色型(用温和、专业的口吻做健康科普)。医疗里三类全占,所以它是练手的绝佳范本。

```mermaid graph TD A[医疗垂直领域] --> B[知识注入型: 术语/用药逻辑] A --> C[格式约束型: 病历结构化/报告] A --> D[风格角色型: 科普温和口吻] B --> E[LoRA 改 FFN 投影 容量大] C --> F[模板+SFT 约束输出] D --> G[系统提示+少量样本] E --> H[一个基座多适配器] F --> H G --> H ```

4.1.2 数据构建:从真实业务流里「捞」对的语料

新手最大的误区是「先去找一堆现成数据集,再想怎么用」。正确的顺序是反过来的:先定义你要解决的业务问题,再去你的真实业务流里捞对应的语料。医疗场景里,语料通常来自这四口井:

  • 历史问诊记录:医患对话里天然包含「患者描述症状 → 医生给出判断/建议」的问答对,是 SFT 最宝贵的原料。
  • 知识库与指南:临床指南、药品说明书、疾病百科,适合做成「根据指南,某病的首选用药是什么」这类知识问答。
  • 病历与报告模板:已经写好的结构化病历,可以反推出「非结构化主诉 → 结构化字段」的配对,用于病历结构化任务。
  • 人工标注的难例:医生在日常中纠正过的模型错误回答,是最该收录的「高价值负样本」。

捞出来之后,要统一成 SFT 需要的「指令-回答」对(instruction-input-output 或纯 instruction-output)。下面是一份医疗 SFT 样本的骨架:

{ "instruction": "根据以下患者主诉,给出需要进一步询问的关键症状和初步分诊建议。", "input": "患者男,32岁,发热两天,体温38.5℃,伴咳嗽、乏力,无明显呼吸困难。", "output": "建议补充询问:1)是否接触过呼吸道感染患者或近期去过疫区;2)咳嗽是否带痰及痰色;3)有无胸闷、血氧下降。初步分诊:若精神状态好、无呼吸急促,可居家观察并多饮水;若出现持续高热>3天、呼吸急促、血氧<93%,应及时线下就诊。" }

注意这里 output 的写法:它给的是「建议进一步询问 + 分诊」,而不是替医生下诊断。医疗垂直模型最危险的越界就是「直接给确诊结论」,所以数据构造时就要把边界写进样本——模型学会的是「辅助分诊与信息收集」,而非「替代医生」。这条边界要贯穿所有样本,否则训出来的模型会养成乱下诊断的坏习惯。

4.1.3 数据清洗与「去毒」:医疗场景的不能省的一步

通用语料清洗是「去重、去噪、去空」,医疗清洗还要多加一道安全与事实门。我建议按这张流水线过一遍:

```mermaid graph LR R[原始业务语料] --> S1[脱敏: 去除姓名/身份证/手机号/病历号 PHI] S1 --> S2[去重: 相似度>阈值合并] S2 --> S3[事实校验: 用药/剂量/禁忌需医生复核] S3 --> S4[边界标注: 标注'辅助非诊断'类输出] S4 --> S5[质量门: 长度/格式/拒答样本抽检] S5 --> T[可用 SFT 数据集] ```

几个踩坑点必须说:

  • 脱敏不能只靠正则。姓名、科室、医生签名、检查单编号常常以非标准形态出现,纯正则漏检率高。建议做一次人工抽检 + 简单实体识别兜底,宁可多删一条敏感样本也别漏一条。
  • 用药剂量是事实红线。任何涉及「每次几毫克、每日几次」的样本,必须医生复核,因为错误剂量在 SFT 里会被模型当成「正确答案」学进去,上线后就是真实风险。
  • 必须混入拒答样本。要专门构造一批「超出模型能力范围」的问题(如「帮我开一张处方」「我是孕妇能吃这个药吗,你确定吗」),并给出「建议咨询专业医师/线下就诊」的标准拒答。没有拒答样本,模型会在任何问题上都硬编答案。
  • 去重别过度。医疗问答里「同样的主诉、不同分诊建议」可能是合理的多解,按字符串去重会误删有价值的多样性。建议用语义相似度而非精确匹配。

4.1.4 SFT 模板设计:用模板把输出「框」住

数据干净了,接下来是模板。医疗任务的失败,一半坏在「模型答得没错但格式没法用」。解决办法是在系统提示和样本结构里就把输出格式定死。

一个病历结构化任务的模板可以这样设计:

系统提示:你是某三甲医院的病历结构化助手。只输出 JSON,字段固定为 age/sex/complaint/duration/vitals/suspect。不得输出任何解释性文字。若某项信息缺失,填"未提及"。 用户输入:患者女,45岁,反复上腹疼痛一周,伴反酸,进食后加重。 期望输出: { "age": "45", "sex": "女", "complaint": "上腹疼痛、反酸", "duration": "1周", "vitals": "未提及", "suspect": "未提及" }

模板设计的三条原则:

  1. 系统提示写死角色与边界:「只输出 JSON」「不得输出解释」「信息缺失填未提及」这类硬约束,比在样本里反复示范更有效,因为系统提示对每一条样本都生效。
  2. 输出格式要和下游消费方式对齐:如果结构化结果要进数据库,就逼模型出 JSON;如果给人看的健康科普,就别加格式枷锁,放它用自然语言。
  3. 思维链要慎用:诊断推理用 CoT(先列症状再下结论)能提升准确率,但医疗科普问答用 CoT 反而会让用户看到一堆「内心戏」。按任务性质选,不要无脑全上。

4.1.5 训练配置落地:以医疗为范例给一套可抄的参数

数据、模板齐了,落到训练配置。下面是一份 QLoRA 4-bit 训练医疗适配器的示例配置(写法基于 PEFT + transformers 的 SFTTrainer,API 为公开稳定接口,具体模块命名以智谱官方文档为准):

from peft import LoraConfig, get_peft_model from transformers import BitsAndBytesConfig bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype="bfloat16", ) lora_config = LoraConfig( r=16, lora_alpha=32, # alpha/r = 2,稳妥起点 target_modules=["q_proj","k_proj","v_proj","o_proj", "gate_proj","up_proj","down_proj"], # 医疗偏知识注入,FFN 也挂上 lora_dropout=0.05, bias="none", task_type="CAUSAL_LM", ) model = get_peft_model(model, lora_config) model.print_trainable_parameters() # 确认真实命中层与可训练参数量

训练超参给一个医疗场景的保守起点(非铁律):学习率 2e-4、轮次 3~5、批次按显存调、warmup 比例 0.03、加 cosine 调度。为什么保守?因为医疗样本少、错答案代价高,宁可不收敛到完美,也不要学飞。如果训练后发现「模型太保守、答不出专业内容」,再小步把学习率提到 3e-4 或轮次加到 6;如果发现「开始编造罕见病用药」,立刻降学习率并复查拒答样本比例。

```mermaid graph TD CFG[训练配置] --> R[r=16 alpha=32] CFG --> LR[学习率 2e-4 保守] CFG --> EP[轮次 3~5] CFG --> TGT[target: 注意力+FFN 全挂] R --> OUT[容量够+步幅稳] LR --> OUT EP --> OUT TGT --> K[知识注入型任务适配] OUT --> K ```

4.1.6 验收:过三道门,医生人审兜底

训练跑完不等于能用。医疗适配器必须过三道门:

  • 格式门:结构化任务 100% 能解析成目标格式(JSON 校验通过),科普任务无乱码、无截断。
  • 事实门:抽样让医生盲评,用药、剂量、禁忌类回答必须零错误;允许模型「不确定就建议线下就诊」,但不允许「编一个看起来合理的错答案」。
  • 稳健门:换一种问法、加干扰信息、诱导式提问(「你就告诉我吃这个肯定没事吧」),模型是否仍守住边界、不越界下诊断。

只有三道门全过,才进灰度。上线后仍保留「低置信度转人工/转医生」的开关——这是医疗场景不可省的护栏。走完这一节,你已经拥有了一条从数据到上线的完整医疗微调链路;下一节把它抽象成可迁移的方法,套到法律、客服两个场景,并讲清楚多场景怎么共用一个基座。

```mermaid graph LR M[医疗适配器训练完成] --> G1[格式门: 解析校验] M --> G2[事实门: 医生盲评零错] M --> G3[稳健门: 诱导/换问法守边界] G1 --> PASS[三道门全过→灰度] G2 --> PASS G3 --> PASS PASS --> HUMAN[低置信转人工/医生] ```

4.1.7 上线不是终点:医疗适配器的数据回流闭环

很多团队把「训完上线」当成结束,这是浪费。LoRA 最被低估的价值恰恰是——适配器天然适合做持续学习,而且回滚几乎零成本。医疗线上每天都会产生三类高价值信号:医生在后台纠正过的模型误答、用户反复追问暴露的模型盲区、以及触发拒答后转人工的真实疑难。这些日志比任何离线构造的语料都珍贵,因为它们来自真实分布。

回流的链路很简单:线上日志先走一遍 4.1.3 的脱敏与事实门(这一步医疗绝不能省),由医生标注「对/错/边界」并修正输出,再并入增量数据集;之后用 resume_from_checkpoint 在上一版适配器基础上做小步增量训练,而不是从零重训——这能避免新数据把旧能力冲掉。重训完必须重新过 4.1.6 的三道门,灰度通过后再替换线上版本,同时永远保留上一版适配器文件作为回滚支点。因为 LoRA 只动几百万参数,存十个历史版本也不过几百 MB,这种「训错就退一步」的底气,是全量微调给不了的。

走完这一节,你已经拥有了一条从数据到上线的完整医疗微调链路;下一节把它抽象成可迁移的方法,套到法律、客服两个场景,并讲清楚多场景怎么共用一个基座。


发布者: 作者: 渗透测试失败者的小龙虾 转发
评论区 (0)
U