SFT 过程及技巧详解

1. SFT 是什么?

SFT,全称 Supervised Fine-Tuning ,即监督微调

在大语言模型训练流程中,SFT 通常位于预训练之后,用于让基础模型学会按照人类指令、对话格式、业务规范或特定任务要求进行输出。

可以简单理解为:

预训练让模型"会语言、懂知识",SFT 让模型"会按要求回答"。

SFT 的输入通常是:

text 复制代码
指令 / 问题 / 多轮对话 / 上下文

输出是:

text 复制代码
标准答案 / 人工示范回答 / 结构化结果

模型通过学习大量"输入 → 标准输出"的样本,逐渐掌握目标任务的回答方式。


2. SFT 的核心目标

对于自回归语言模型,SFT 本质上仍然是 next-token prediction,即预测下一个 token。

假设输入为:

x x x

标准答案为:

y=(y1,y2,...,yT) y = (y_1, y_2, \dots, y_T) y=(y1,y2,...,yT)

模型参数为:

θ \theta θ

则 SFT 的优化目标是最大化标准答案在模型下的条件概率:

max⁡θ∑t=1Tlog⁡πθ(yt∣x,y<t) \max_{\theta} \sum_{t=1}^{T} \log \pi_{\theta}(y_t \mid x, y_{<t}) θmaxt=1∑Tlogπθ(yt∣x,y<t)

等价于最小化负对数似然损失:

LSFT(θ)=−∑t=1Tlog⁡πθ(yt∣x,y<t) \mathcal{L}{\mathrm{SFT}}(\theta)= -\sum{t=1}^{T} \log \pi_{\theta}(y_t \mid x, y_{<t}) LSFT(θ)=−t=1∑Tlogπθ(yt∣x,y<t)

如果数据集中有多个样本:

D={(xi,yi)}i=1N \mathcal{D}= \{(x_i, y_i)\}_{i=1}^{N} D={(xi,yi)}i=1N

整体训练目标为:

LSFT(θ)=−1N∑i=1N∑t=1Tilog⁡πθ(yi,t∣xi,yi,<t) \mathcal{L}{\mathrm{SFT}}(\theta)= -\frac{1}{N} \sum{i=1}^{N} \sum_{t=1}^{T_i} \log \pi_{\theta}(y_{i,t} \mid x_i, y_{i,<t}) LSFT(θ)=−N1i=1∑Nt=1∑Tilogπθ(yi,t∣xi,yi,<t)

其中:

  • xix_ixi 表示第 iii 个样本的输入;
  • yiy_iyi 表示第 iii 个样本的标准答案;
  • yi,ty_{i,t}yi,t 表示第 iii 个答案中的第 ttt 个 token;
  • πθ\pi_{\theta}πθ 表示当前模型策略;
  • TiT_iTi 表示第 iii 个答案的长度。

3. SFT 与预训练的区别

对比项 预训练 SFT
数据形式 大规模无标注文本 指令-答案、对话、结构化样本
训练目标 学习语言建模能力 学习任务执行与指令跟随
数据规模 通常非常大 相对较小但质量要求高
关注重点 知识、语法、语言规律 格式、风格、流程、任务能力
输出特征 自然续写 按用户要求回答
典型阶段 Foundation Model 训练 Instruction Model 训练

预训练更像是"读大量书",SFT 更像是"看标准答案学怎么答题"。


4. SFT 的典型数据格式

4.1 单轮指令格式

json 复制代码
{
  "instruction": "解释 SFT 和 DPO 的区别",
  "input": "",
  "output": "SFT 是基于标准答案的监督微调,DPO 是基于偏好对的直接偏好优化。"
}

4.2 多轮对话格式

json 复制代码
{
  "messages": [
    {
      "role": "system",
      "content": "你是一个专业 AI 工程助手。"
    },
    {
      "role": "user",
      "content": "请解释 SFT 的训练目标。"
    },
    {
      "role": "assistant",
      "content": "SFT 的训练目标是最大化标准答案在模型条件分布下的概率。"
    }
  ]
}

4.3 结构化输出格式

json 复制代码
{
  "messages": [
    {
      "role": "user",
      "content": "从 OCR 结果中抽取左比分、右比分和比赛时间。"
    },
    {
      "role": "assistant",
      "content": "{\"left_score\":33,\"right_score\":35,\"game_clock\":\"02:15\"}"
    }
  ]
}

5. SFT 的完整流程

5.1 明确训练目标

在开始 SFT 前,必须明确模型要学什么。

常见目标包括:

目标 说明
指令跟随 让模型理解用户指令并正确执行
多轮对话 保持上下文一致性
领域问答 适配医疗、法律、工业、机器人、OCR 等领域
代码生成 提升代码生成、补全、解释和调试能力
结构化输出 输出 JSON、SQL、Markdown、XML 等格式
工具调用 学会函数调用、API 调用或 Agent 动作规划
风格对齐 固定回答语气、长度、格式和专业程度
安全对齐 学会拒绝违规请求或给出安全替代方案

对于工程型模型,目标应该更加具体,例如:

text 复制代码
让模型能够根据 OCR 部署需求生成设计文档
让模型能够根据 C++ 编译错误定位问题
让模型能够根据检测结果输出结构化 JSON
让模型能够解释 YOLO、ONNX、MNN、TensorRT 部署流程

5.2 选择基座模型

选择基座模型时需要考虑以下因素:

因素 建议
语言能力 中文任务优先选择中文能力强的模型
模型规模 7B/8B 适合低成本训练,14B/32B 效果更强
上下文长度 长文档和多轮任务需要长上下文
推理成本 边缘部署需要小模型或量化模型
是否已有 Instruct 版本 通用助手任务优先从 Instruct 模型继续微调
许可证 商业项目必须检查模型 License

一般建议:

text 复制代码
通用助手任务:选择 Instruct 模型继续 SFT
领域适配任务:可选择 Base 模型或 Instruct 模型
结构化输出任务:优先选择格式跟随能力强的模型
边缘部署任务:优先选择小模型 + LoRA/QLoRA + 量化

5.3 数据收集

SFT 数据质量通常比数量更重要。高质量数据能够明显改善模型的指令跟随和回答风格。

常见数据来源:

数据来源 说明
人工标注数据 质量最高,但成本高
真实业务日志 最贴近真实需求
专家问答 适合垂直领域模型
文档转问答 适合技术文档、产品手册、规范文档
强模型合成 可快速扩充数据,但需要清洗
开源指令数据 可作为通用能力补充
错误案例修正 对提升模型鲁棒性非常有价值

5.4 数据清洗

数据清洗是 SFT 中最重要的步骤之一。

需要清理的数据包括:

text 复制代码
空样本
乱码样本
重复样本
答非所问样本
事实错误样本
格式错误样本
过短无信息样本
过长低质量样本
包含无关广告或噪声的样本
包含错误角色标记的样本

推荐检查项:

检查项 说明
空值检查 instruction、input、output 是否为空
长度检查 是否超过 max_seq_len
格式检查 JSON、Markdown、代码块是否闭合
角色检查 是否只包含 system、user、assistant
重复检查 完全重复和近似重复
安全检查 是否包含敏感或违规内容
质量检查 是否存在明显错误或胡编内容

5.5 数据去重

重复数据会导致模型过拟合固定句式或模板。

常见去重方式:

text 复制代码
精确去重
基于文本 hash 的去重
基于 SimHash / MinHash 的近似去重
基于 embedding 相似度的语义去重

推荐流程:

text 复制代码
先做 exact dedup
再做 near dedup
最后人工抽查高频模板样本

5.6 构造训练模板

SFT 训练模板必须与推理模板一致。

例如 ChatML 风格:

text 复制代码
<|system|>
你是一个专业 AI 工程助手。
<|user|>
请解释 SFT 的训练过程。
<|assistant|>
SFT 的训练过程包括数据准备、模板构造、loss mask、模型训练、评估和部署。

如果训练时使用一种模板,推理时使用另一种模板,模型可能出现:

text 复制代码
角色混乱
不按格式回答
重复用户问题
无法正常停止
输出特殊 token
多轮对话上下文异常

核心原则:

训练时怎么拼接 prompt,推理时就应该怎么拼接 prompt。


6. Loss Mask 设计

SFT 中非常关键的一点是:通常只对 assistant 的回答部分计算 loss

6.1 普通对话样本

对于如下样本:

text 复制代码
system: 你是一个专业助手。
user: 请解释 SFT。
assistant: SFT 是监督微调,用于让模型学习指令跟随能力。

训练时通常只计算 assistant 部分的 loss:

text 复制代码
system 部分:mask
user 部分:mask
assistant 部分:计算 loss

6.2 Loss Mask 公式

设完整 token 序列为:

z=(z1,z2,...,zL) z = (z_1, z_2, \dots, z_L) z=(z1,z2,...,zL)

mask 为:

mt∈{0,1} m_t \in \{0, 1\} mt∈{0,1}

其中:

  • mt=1m_t = 1mt=1 表示该 token 参与 loss;
  • mt=0m_t = 0mt=0 表示该 token 不参与 loss。

则带 mask 的 SFT 损失为:

LSFT(θ)=−∑t=1Lmtlog⁡πθ(zt∣z<t)∑t=1Lmt \mathcal{L}{\mathrm{SFT}}(\theta)=- \frac{ \sum{t=1}^{L} m_t \log \pi_{\theta}(z_t \mid z_{<t}) }{ \sum_{t=1}^{L} m_t } LSFT(θ)=−∑t=1Lmt∑t=1Lmtlogπθ(zt∣z<t)

对于常见的对话 SFT:

mt={1,zt∈assistant response0,zt∈system or user prompt m_t = \begin{cases} 1, & z_t \in \text{assistant response} \\ 0, & z_t \in \text{system or user prompt} \end{cases} mt={1,0,zt∈assistant responsezt∈system or user prompt


6.3 为什么不训练 user 和 system?

如果 user 和 system 部分也参与 loss,模型可能学到:

text 复制代码
复述用户问题
生成 system prompt
自问自答
角色错乱
输出训练模板

因此工程中通常会将 prompt 部分 label 设置为:

python 复制代码
-100

在 PyTorch 的 CrossEntropyLoss 中,ignore_index=-100 表示该位置不参与损失计算。


7. EOS Token 的重要性

EOS token 表示回答结束。

如果训练数据中没有正确加入 EOS,或者 EOS 没有参与 loss,模型可能出现:

text 复制代码
停不下来
重复输出
无限续写
多轮对话边界混乱

推荐做法:

text 复制代码
每个 assistant 回复末尾加入 EOS
EOS 参与 loss
推理时配置正确的 stop token
训练模板和推理模板保持一致

8. SFT 的训练方式

8.1 全参数微调

全参数微调会更新模型的全部参数。

优点:

text 复制代码
效果上限高
适合大规模领域迁移
适合有大量高质量数据和充足算力的场景

缺点:

text 复制代码
显存占用高
训练成本高
容易灾难性遗忘
保存和部署成本高

适合场景:

text 复制代码
数据量较大
领域差异明显
模型需要深度适配
企业有充足算力

8.2 LoRA 微调

LoRA 通过在模型部分线性层旁边加入低秩矩阵,仅训练新增的低秩参数,冻结原模型参数。

对于原始权重矩阵:

W0∈Rd×k W_0 \in \mathbb{R}^{d \times k} W0∈Rd×k

LoRA 不直接更新 W0W_0W0,而是学习一个低秩增量:

ΔW=BA \Delta W = BA ΔW=BA

其中:

B∈Rd×r,A∈Rr×k,r≪min⁡(d,k) B \in \mathbb{R}^{d \times r}, \quad A \in \mathbb{R}^{r \times k}, \quad r \ll \min(d, k) B∈Rd×r,A∈Rr×k,r≪min(d,k)

最终权重为:

W=W0+ΔW=W0+BA W = W_0 + \Delta W = W_0 + BA W=W0+ΔW=W0+BA

通常还会加入缩放因子:

W=W0+αrBA W = W_0 + \frac{\alpha}{r} BA W=W0+rαBA

其中:

  • rrr 是 LoRA rank;
  • α\alphaα 是 LoRA scaling 系数;
  • AAA 和 BBB 是可训练低秩矩阵;
  • W0W_0W0 是冻结的原始模型权重。

LoRA 优点:

text 复制代码
显存占用低
训练速度快
可插拔
适合多任务 adapter 管理
适合单卡或低成本训练

LoRA 缺点:

text 复制代码
效果上限可能低于全参数微调
rank 设置不合理会影响效果
不同任务之间 adapter 管理复杂

8.3 QLoRA 微调

QLoRA 是 LoRA 的低显存版本。它通常将基座模型量化到 4-bit,然后冻结量化后的基座模型,只训练 LoRA adapter。

典型特点:

text 复制代码
4-bit 量化加载基座模型
冻结基座模型参数
只训练 LoRA 参数
显著降低显存占用
适合单卡训练较大模型

常见配置:

yaml 复制代码
load_in_4bit: true
bnb_4bit_quant_type: nf4
bnb_4bit_compute_dtype: bfloat16
lora_r: 16
lora_alpha: 32
lora_dropout: 0.05

9. 常用超参数建议

9.1 LoRA / QLoRA 常用参数

参数 推荐范围
learning_rate 1e-5 ~ 2e-4
epochs 1 ~ 3
max_seq_length 2048 / 4096 / 8192
batch_size 根据显存设置
gradient_accumulation_steps 4 ~ 32
warmup_ratio 0.03 ~ 0.1
weight_decay 0 ~ 0.1
lora_r 8 / 16 / 32 / 64
lora_alpha 16 / 32 / 64 / 128
lora_dropout 0.05 ~ 0.1
precision bf16 优先,fp16 次之
lr_scheduler cosine / linear
optimizer AdamW / paged_adamw_8bit

9.2 7B/8B 模型起步配置

yaml 复制代码
learning_rate: 2e-4
num_train_epochs: 2
max_seq_length: 4096
per_device_train_batch_size: 1
gradient_accumulation_steps: 8
warmup_ratio: 0.03
lora_r: 16
lora_alpha: 32
lora_dropout: 0.05
bf16: true
gradient_checkpointing: true

9.3 14B 模型 QLoRA 配置

yaml 复制代码
learning_rate: 1e-4
num_train_epochs: 2
max_seq_length: 4096
per_device_train_batch_size: 1
gradient_accumulation_steps: 16
warmup_ratio: 0.03
load_in_4bit: true
bnb_4bit_quant_type: nf4
lora_r: 32
lora_alpha: 64
lora_dropout: 0.05
bf16: true
gradient_checkpointing: true

9.4 小数据集配置

如果只有几百到几千条高质量数据:

yaml 复制代码
learning_rate: 5e-5
num_train_epochs: 2
lora_r: 8
lora_alpha: 16
lora_dropout: 0.1

小数据集不建议使用过高学习率或过多 epoch,否则容易过拟合。


10. 数据配比技巧

SFT 数据不应简单混合,而应按照任务目标设计配比。

例如通用 AI 工程助手:

数据类型 推荐占比
通用指令跟随 20%
技术解释 25%
代码生成与调试 20%
工程方案设计 20%
结构化输出 10%
安全边界样本 5%

如果是 OCR / 目标检测 / 机器人 / 多模态部署方向,可以设计为:

数据类型 推荐占比
OCR 部署与识别问答 20%
目标检测与跟踪方案 20%
多模态模型部署 15%
C++ / ONNX / MNN / TensorRT 排错 20%
机器人感知与 SLAM 15%
技术文档生成 5%
结构化 JSON 输出 5%

技巧:

text 复制代码
不要让单一类型数据占比过高
不要让长答案样本压倒短答案样本
不要让 JSON 样本过多影响普通问答
保留一定比例的通用能力样本
保留真实错误修正样本

11. 长度控制技巧

SFT 会明显影响模型输出长度。

如果训练数据中大量答案都很长,模型会倾向于长篇输出。

如果训练数据中大量答案都很短,模型可能回答不充分。

建议按任务区分长度:

任务类型 推荐答案长度
简单问答
概念解释 中等
工程方案 较长
技术文档
JSON 抽取 极短
代码生成 根据需求变化
报错排查 先结论,后解释

可以在 instruction 中加入明确约束:

text 复制代码
请用三句话回答
请输出 Markdown
请只输出 JSON
请先给结论,再给原因
请给出表格和代码示例

12. 结构化输出技巧

如果目标是让模型稳定输出 JSON、SQL、XML 或 Markdown,需要专门设计格式数据。

12.1 JSON 输出样本

推荐:

json 复制代码
{
  "task": "extract_scoreboard",
  "input": "左侧比分 33,右侧比分 35,时间 02:15",
  "output": {
    "left_score": 33,
    "right_score": 35,
    "game_clock": "02:15"
  }
}

不推荐:

text 复制代码
左边比分是33,右边比分是35,大概还有2分15秒。

12.2 强制格式约束

训练时应增加以下类型样本:

text 复制代码
只输出 JSON
不要添加解释
字段缺失时输出 null
无法判断时输出 unknown
数组为空时输出 []
数字字段保持数字类型

12.3 自动校验

结构化任务推荐加入自动校验:

text 复制代码
JSON parse valid rate
字段完整率
字段类型正确率
枚举值合法率
多余字段比例

13. 防止过拟合

过拟合表现:

text 复制代码
固定开头,例如"好的,下面我将详细解释"
固定结尾,例如"总之,SFT 是非常重要的"
回答结构高度模板化
训练集问题回答很好,测试集明显变差
输出训练数据中的具体样本内容
通用能力下降

解决方法:

text 复制代码
减少 epoch
降低 learning rate
降低 LoRA rank
提高 dropout
增强数据多样性
去重
加入验证集 early stopping
混入通用指令数据

14. 防止灾难性遗忘

灾难性遗忘指模型经过 SFT 后,虽然目标任务变强,但原有通用能力下降。

常见原因:

text 复制代码
领域数据占比过高
训练轮次过多
学习率过大
全参数微调过强
数据风格过于单一

缓解方法:

text 复制代码
使用 LoRA / QLoRA
降低学习率
减少 epoch
混入 10% ~ 30% 通用指令数据
保留数学、代码、常识、推理样本
使用验证集做回归评估

15. 评估方法

不要只看训练 loss。SFT 的最终目标是提升实际任务表现。

15.1 自动评估指标

指标 适用场景
Exact Match 分类、抽取、固定答案
F1 实体抽取、信息抽取
JSON Valid Rate 结构化输出
Field Accuracy 表单抽取、OCR 结构化
Pass@k 代码生成
Win Rate 与旧模型或基座模型对比
Refusal Accuracy 安全拒答
Hallucination Rate 事实一致性

15.2 人工评估维度

维度 说明
正确性 内容是否正确
完整性 是否覆盖关键点
格式符合度 是否满足输出格式
专业性 是否符合领域表达
可执行性 工程建议是否能落地
简洁性 是否没有无意义废话
稳定性 多次生成是否一致
安全性 是否遵守安全边界

15.3 测试集设计

建议至少准备:

text 复制代码
常规样本
困难样本
边界样本
反例样本
真实业务样本
模型历史错误样本

16. 常见问题与修复

16.1 模型复述用户问题

原因:

text 复制代码
user 部分参与了 loss
loss mask 设置错误
训练模板混乱

修复:

text 复制代码
只对 assistant 部分计算 loss
检查 labels 中 user token 是否为 -100
统一训练和推理 chat template

16.2 模型停不下来

原因:

text 复制代码
EOS token 未加入训练
EOS token 没有参与 loss
推理 stop token 设置错误

修复:

text 复制代码
assistant 回复末尾加入 EOS
EOS 参与 loss
推理时配置正确 eos_token_id 和 stop token

16.3 输出格式不稳定

原因:

text 复制代码
格式数据太少
结构化样本不规范
同一任务混入多种输出风格

修复:

text 复制代码
增加结构化样本
自动校验 JSON / SQL / XML
统一字段名和字段类型
加入格式错误修正样本

16.4 模型变啰嗦

原因:

text 复制代码
训练数据中过长回答比例太高
所有样本都要求"详细解释"

修复:

text 复制代码
加入简洁回答样本
控制答案长度分布
在 instruction 中明确回答长度

16.5 模型领域能力强但通用能力下降

原因:

text 复制代码
领域数据占比过高
训练轮次过多
学习率过大

修复:

text 复制代码
混入通用数据
降低学习率
减少 epoch
使用 LoRA / QLoRA

17. SFT 与 CPT、DPO、RLHF 的关系

方法 数据形式 目标 适合场景
CPT 大量无标注领域文本 注入领域知识和语言分布 行业语料、代码库、文档
SFT 指令 + 标准答案 学会如何回答 指令跟随、格式、任务流程
DPO chosen / rejected 偏好对 学会偏好更好的回答 风格优化、偏好对齐
RLHF / PPO 奖励模型 + 强化学习 最大化人类偏好奖励 高成本复杂对齐

推荐训练顺序:

text 复制代码
预训练模型
→ CPT,可选,用于领域知识继续预训练
→ SFT,用于学习任务和标准回答方式
→ DPO,用于偏好优化
→ RLHF/PPO,可选,用于更复杂的人类反馈对齐

18. SFT 与 DPO 的区别

SFT 学的是:

标准答案是什么。

DPO 学的是:

两个答案中哪个更好。

SFT 数据形式:

text 复制代码
输入 x
标准答案 y

DPO 数据形式:

text 复制代码
输入 x
更优答案 y_w
较差答案 y_l

DPO 的常见损失函数为:

$$

\mathcal{L}_{\mathrm{DPO}}(\theta)

\log

\sigma
\left(
\beta
\left[
\log
\frac{
\pi_{\theta}(y_w \mid x)
}{
\pi_{\mathrm{ref}}(y_w \mid x)
}

\log

\frac{

\pi_{\theta}(y_l \mid x)

}{

\pi_{\mathrm{ref}}(y_l \mid x)

}

\right]

\right)

$$

其中:

  • ywy_wyw 表示 preferred / chosen response;
  • yly_lyl 表示 rejected response;
  • πθ\pi_{\theta}πθ 表示当前训练模型;
  • πref\pi_{\mathrm{ref}}πref 表示参考模型;
  • β\betaβ 控制偏好优化强度;
  • σ(⋅)\sigma(\cdot)σ(⋅) 是 sigmoid 函数。

对比:

对比项 SFT DPO
数据 标准答案 偏好对
学习目标 模仿标准答案 偏向更优答案
适合阶段 对齐初期 SFT 之后
优点 简单稳定 能优化回答偏好
缺点 依赖标准答案质量 依赖偏好对质量

19. 工程实践路线

阶段一:小规模试训

目标:

text 复制代码
验证数据格式
验证 chat template
验证 loss mask
验证训练脚本
验证输出是否正常

推荐数据量:

text 复制代码
500 ~ 2000 条

推荐训练:

text 复制代码
LoRA / QLoRA
1 ~ 2 epoch

阶段二:领域 SFT

目标:

text 复制代码
提升领域问答能力
提升工程方案生成能力
提升代码解释和排错能力
提升结构化输出能力

推荐数据量:

text 复制代码
5K ~ 50K 条

推荐训练:

text 复制代码
LoRA / QLoRA
2 ~ 3 epoch

阶段三:困难样本增强

收集模型错误样本,例如:

text 复制代码
答非所问样本
格式错误样本
幻觉样本
拒答错误样本
边界条件失败样本
多轮上下文失败样本

将这些样本修正后加入训练集,进行二次 SFT 或 DPO。


阶段四:偏好优化

当模型已经具备基本能力后,可以构造偏好对进行 DPO。

例如:

text 复制代码
同一个问题下:
A 答案:结构清晰、准确、可执行
B 答案:啰嗦、遗漏关键步骤

将 A 作为 chosen,将 B 作为 rejected。


阶段五:部署和回归测试

部署前需要检查:

text 复制代码
推理速度
显存占用
量化后效果
多轮稳定性
结构化输出合法率
长上下文表现
安全拒答能力
历史测试集回归结果

20. 推荐项目目录结构

text 复制代码
sft_project/
├── data/
│   ├── raw/
│   ├── cleaned/
│   ├── train.jsonl
│   ├── val.jsonl
│   └── test.jsonl
├── configs/
│   ├── qlora_sft.yaml
│   └── lora_sft.yaml
├── scripts/
│   ├── clean_data.py
│   ├── check_format.py
│   ├── build_dataset.py
│   ├── train_sft.py
│   ├── eval_model.py
│   └── merge_lora.py
├── outputs/
│   ├── checkpoints/
│   ├── logs/
│   └── merged_model/
└── README.md

21. SFT 数据检查脚本示例

python 复制代码
import json
from pathlib import Path


def check_jsonl(path):
    bad_lines = []
    with open(path, "r", encoding="utf-8") as f:
        for idx, line in enumerate(f, 1):
            try:
                obj = json.loads(line)
            except Exception as e:
                bad_lines.append((idx, f"json_error: {e}"))
                continue

            if "messages" not in obj:
                bad_lines.append((idx, "missing messages"))
                continue

            messages = obj["messages"]
            if not isinstance(messages, list) or len(messages) == 0:
                bad_lines.append((idx, "empty messages"))
                continue

            roles = [m.get("role") for m in messages]
            if "assistant" not in roles:
                bad_lines.append((idx, "missing assistant"))

            for m in messages:
                if m.get("role") not in {"system", "user", "assistant"}:
                    bad_lines.append((idx, f"invalid role: {m.get('role')}"))

                if not str(m.get("content", "")).strip():
                    bad_lines.append((idx, "empty content"))

    return bad_lines


if __name__ == "__main__":
    path = Path("train.jsonl")
    errors = check_jsonl(path)
    print(f"bad samples: {len(errors)}")
    for e in errors[:20]:
        print(e)

22. 最佳实践总结

SFT 的关键经验可以总结为以下几点:

  1. 数据质量优先于数量
  2. 训练模板必须和推理模板一致
  3. 通常只对 assistant 部分计算 loss
  4. EOS token 必须正确加入并参与训练
  5. 小数据集不要训练太多 epoch
  6. LoRA / QLoRA 是大多数工程场景的首选方案
  7. 结构化输出任务必须做格式校验
  8. 训练集要包含真实失败案例和边界案例
  9. 混入一定比例通用数据,避免灾难性遗忘
  10. 不要只看 loss,要看任务成功率和人工评估结果
  11. 先小规模试训,再扩大数据和训练规模
  12. SFT 解决"怎么答",CPT/RAG 解决"知道什么",DPO 解决"哪个答法更好"。

23. 总结

SFT 的本质是:

用高质量示范数据告诉模型:面对某类输入时,应该以什么角色、什么格式、什么逻辑和什么风格输出答案。

它不是简单地"灌知识",而是让模型学会更稳定、更符合业务需求地执行任务。

相关推荐
七牛开发者1 小时前
从 Claude 案例看 Coding Agent 的计划层设计
人工智能·ai·agent·claude·claudecode
子非鱼9211 小时前
机器学习之决策树与集成学习
决策树·机器学习·集成学习
蒟蒻的贤1 小时前
从线性分类器到两层神经网络:为什么我们需要非线性?
人工智能·深度学习·神经网络
zy_destiny1 小时前
【大模型应用】用千问大模型实现屋顶材质分类算法实现
人工智能·深度学习·机器学习·计算机视觉·数据挖掘·材质·通义千问
米核AI易山1 小时前
扣子工作流实战:多节点串联打造 AI 内容自动化流水线
人工智能·自动化·coze·扣子工作流·米核ai易山
qxq_sunshine1 小时前
千问(Qwen)模型Linux部署操作手册
人工智能·gpt·语言模型
刘一说1 小时前
AI科技热点日报 | 2026年06月03日
人工智能·科技
papership1 小时前
prompt 设计简介(AI对话技巧)
人工智能·prompt
蒟蒻的贤1 小时前
为什么加入 ReLU 后,神经网络可以学习线性可分的特征?
人工智能·神经网络·学习