跳转到内容

SFT 与 LoRA/QLoRA:先训练格式与动作

把一条工具超时的轨迹放进训练集时,最容易选错的目标是“继续试到成功”。真正该教给模型的是在该停的时候停下来。SFT 在这个项目里的用处也差不多–它排的是一串可审计的动作,不是把回答润色得更像专家说的话。

Supervised Fine-Tuning(SFT)用“输入到目标输出”的示例训练模型遵循特定行为。对 Agent 来说,目标应该是可执行的轨迹:选对工具、生成合法参数、引用 Evidence、缺证据时输出 unknown、高风险动作前升级到人工。MedAgent Forge 训练的首先是这些行为,不是开放式的医疗结论。

全参数微调要为每个任务维护一整套权重,成本高。LoRA 冻结基础权重,在层里加低秩可训练矩阵;QLoRA 更进一步,让梯度穿过 4-bit 量化的冻结基础模型流向 LoRA adapter。S16S17 这两种做法省显存也省存储,但省不出“少量数据就能得到可靠医疗行为”这个结论。

常见的坑有几个。把模型自己生成的轨迹当金标,错误会自我复制;按对话切分而不是按患者/协议版本切分,测试集就泄漏了;只训练最终那份 JSON,模型学会了格式,却没学会什么时候该调用工具。

一条 SFT 样本里包含:任务与授权范围、可见状态、工具 schema、目标 action 与 arguments、工具结果、最终 assessment、证据 ids、是否需要人工,以及 sample provenance。私密思维链不保存,保存的是简短、可审计的 rationale 和实际行动。

数据分金牌银牌两层:专家审核过的真实轨迹权重最高;规则能生成的确定性轨迹可以规模化;模型生成的数据必须过 verifier 并抽样复核。切分按 patient 加 trial version 隔离。

方法 优点 风险
全参数 SFT 最大适配自由度 资源和版本成本高
LoRA 训练参数少、adapter 易管理 S16 rank/target modules 需实验
QLoRA 进一步省显存 S17 量化与训练稳定性需回归
PEFT/TRL 工程实现完整 S20S21 API 变化,必须锁版本
Terminal window
python3 labs/run_lab.py --lab 15

实验验证 4 条 SFT JSONL 样本:工具名必须存在、arguments 通过简化 schema、assessment 的引用真实存在、训练与测试不共享 patient id。先把工具名改成一个不存在的值,再让同一个 patient 出现在两个 split,看这几道门分别怎么失败。它不执行梯度更新,所以不会虚构任何 LoRA 效果。

输入里有冻结的 criterion、当前 TaskContext、可用的工具 schema 和已有的 Evidence refs。模型第一步不是回答,而是调用 read_fhir_observations(patient_id=syn-1, codes=[...], date_range=...)。工具返回空结果和 snapshot,目标 action 接着生成 CriterionAssessment(status=unknown, reason=missing_lab, evidence_ids=[]),并请求人工补充。坏轨迹的表现是把空结果解释成指标正常,或者悄悄扩大 patient/date scope。

训练样本存的是可审计的 action,不存隐藏思维链。工具结果可以用合成 fixture,目标轨迹由规则或专家生成。最终那段文本只是从结构化 assessment 渲染出来的,这样模型学到的就是“什么时候查、查什么、缺失的时候怎么停”。

从 12 个 TaskPackage 扩展变体:换单位、换状态、换时间精度、注入工具错误、协议改版、同义词替换、加 OOD。数值和权限类的样本规则可以自动生成金标;模型辅助生成的语言变体必须过 semantic invariant 检查并抽样复核。每条样本记录 generator、reviewer、source licenses、patient/trial version 和 difficulty。

切分要按患者、协议族和时间三重隔离。同一份协议只改一个数值就分到测试集,模型可能记住的是模板;同一个合成患者的不同 note 跨 split,也是泄漏。去重不只哈希文本,还要对 normalized task/criterion 做近重复检测。

rank、alpha、dropout、target modules、是否训练 bias,都是实验变量。S16 rank 大不保证效果好;target 选少了学不动,选多了内存涨、过拟合风险也涨。QLoRA 还多出 quantization type、compute dtype、double quant 这些选择。S17 每个 adapter 都必须绑定基础权重 revision、tokenizer、chat template 和 quantization。

训练顺序上先 overfit 一个 tiny batch,验证 loss、梯度、保存和加载都正常;再做小规模 smoke,检查流水线和评测是否连通;最后才跑完整 run。tiny overfit 和 smoke 的结果写进报告,但不能出现在“效果”表里。完整 run 要固定 seed,或者报告多 seed 的波动。

聊天和工具轨迹一般只对 assistant 的 action/answer 算目标 loss,免得模型学会复述 system 和 user 的话;但具体模板和 tokenizer 组合下的 label mask 必须验证一遍。工具结果是否进上下文、要不要训练模型预测 tool call id、错误返回怎么处理,都得跟推理 runtime 保持一致。训练和服务用了不同的 chat template,会造成最难查的离线/线上差异–这类问题我见过不止一次。

结构化输出可以加 constrained decoding,但模型仍然得学会选对字段和值。schema 通过率和字段语义要分开评估,别让 parser 的自动修复把模型的错误盖住。

至少比较 base zero-shot、base+RAG、SFT full 或 LoRA(看资源)、不同 rank,以及可选的 QLoRA。同一个 TaskPackage 上报四态、引用、工具、成本和安全。消融就去掉 unknown 样本、去掉错误轨迹、去掉 provenance,看真实收益到底来自哪里。如果 LoRA 只提高了格式而没提高工具和证据,那架构上换 constrained decoder 可能更划算。

训练数据大小、step 数、best checkpoint 的选择规则、early stopping 和失败的 run 都公开。别给“训练成功”一个二元标签,模型卡里每类任务和亚组分别列。

adapter registry 里保存 owner、purpose、base revision、data/config/code hash、评测结果和批准状态。运行时禁止随意叠加来路不明的 adapter。上线走 shadow 和 canary,回滚的时候要连 prompt 和 tool schema 一起恢复,因为行为版本是这几样东西的组合,不是单一权重。

样本来自当前模型自己生成、verifier 又不够强,错误会被放大;训练让模型变得更自信但没更准确,unknown 校准就坏了;adapter 记住了患者文本,那是隐私风险。看到这些信号就停训,回去修数据,或者退回规则和 RAG。

真正的一键训练不是一条很长的 shell,而是一组不可变配置的引用:base revision、dataset manifest、split hash、template、LoRA 参数、optimizer、seed、hardware profile、eval suite。命令生成 run id,把 git commit、依赖锁、环境和 stdout/metrics 写进 artifact,敏感样本只留 id 和 hash。恢复的时候要写清从哪个 checkpoint 开始、要不要重放 dataloader 状态。

模型导出之后做一次 load-and-infer parity:训练环境和服务 adapter 对同一 fixture 的 tokenization、schema、输出应当一致;merge adapter 或者量化之后要重新评测。不少“训练有效、上线失效”其实出在模板和加载方式的组合上,跟模型本身没关系。

把失败分成错误工具、错误参数、缺失时猜测、引用不支持、schema 问题、过度拒答、语言问题。每一类抽样看训练覆盖和近邻样本,再决定是补数据、修 contract 还是干脆不让模型处理这一类。别把所有失败都追加成新的 SFT 样本;规则能确定处理的,放回 rule 或 verifier 更稳。

复制 lab 15 的样本,故意让同一个 patient 跨 train/test、让工具名不存在、让 assessment 引用一个悬空 id,确认各道门逐项失败。然后设计五条“工具超时后应升级而非重试”的轨迹,并写清楚它们为什么是行为数据,而不是医学金标。

训练样本里的 tool schema 要从同一份 ToolManifest 生成,不要手工复制;输出的 CriterionAssessment 用同一套 schema 和 semantic validators;评测直接跑 runtime parser。这样工具改名或字段变更会在数据构建阶段就失败,不至于训练出一个只会调旧接口的 adapter。

runtime 新增 policy 拒绝错误时,数据也要覆盖“模型看到拒绝之后停下或升级”的轨迹,不能教它换个参数反复试。训练、工具和策略这三者的版本矩阵进 release evidence。

训练集能让 JSON 更整齐,也可能让模型更自信地猜错。缺证据时的 unknown、越权拒绝或引用一旦回归变差,先修合同和样本,别用更多 epoch 去盖。

  • 格式通过率提升不等于医学正确率提升。
  • LoRA adapter 与基础模型/量化版本必须绑定,不可任意混用。
  • 训练集中包含测试协议或患者会产生虚假提升。
  • 实际训练前需记录硬件、seed、依赖、checkpoint、数据哈希和失败 run。

以下参考资料分别解释方法、量化约束与工程实现。参考资料不等于当前项目已经跑出其中任何训练结果。

  • S16 LoRA:理解冻结基础权重与低秩 adapter 的原始动机和变量。
  • S17 QLoRA:需要评估量化训练路径时回看其方法假设与数值限制。
  • S20 PEFT:把 adapter 参数写进可复现配置前,核对官方实现与版本。
  • S21 TRL:SFT、偏好和强化学习实验都依赖的训练器入口,使用时应锁定 API 版本。