深色模式
SFT 数据构建与清洗
摘要:SFT(监督微调)决定模型「怎么做」,而其上限由数据质量决定。本文给出生产可用的 SFT 数据格式(Alpaca / ShareGPT / ChatML)、质量优于数量的工程原则、去重与脱敏流水线,以及防止灾难性遗忘的回放(replay)配比。适用于 Llama / Mistral / Qwen 等 decoder-only 模型的指令微调。
适用版本与前提
- 框架:
transformers4.40+(chat template 机制)、datasets2.20+ - 数据形态:JSONL,单轮用 Alpaca,多轮用 ShareGPT,ChatML 兼容 OpenAI 风格
- 规模经验:几百条高质量样本往往优于数万条脏数据;OpenAI 公开建议至少 10 条起步、50–100 条可见改善、500+ 条显著增益(第三方经验,[版本相关],非硬性阈值)
核心概念:SFT 教的是「行为」不是「知识」
SFT 与 CPT 的边界
- SFT:用「指令—回答」示范数据,教模型遵循格式、风格、任务行为。模型不认识的概念,SFT 很难凭空补出知识。
- CPT(继续预训练):用无标注领域语料继续做下一词预测,注入领域词汇与事实分布(见
cpt.md)。 - 经验法则:不认识词 → CPT;认识但不会好好用 → SFT;会用但品味不对 → 偏好对齐(DPO/RLHF)。
数据格式
json
// Alpaca(单轮任务型)
{"instruction": "将下面的句子翻译成英文", "input": "今天天气很好", "output": "The weather is very nice today."}1
2
2
json
// ShareGPT(多轮对话)
{"conversations": [
{"from": "human", "value": "帮我写一首关于春天的诗"},
{"from": "gpt", "value": "春风轻抚柳丝长……"},
{"from": "human", "value": "改成七言绝句"},
{"from": "gpt", "value": "春风拂柳绿如烟……"}
]}1
2
3
4
5
6
7
2
3
4
5
6
7
json
// ChatML(显式 system/user/assistant,便于对齐 chat template)
{"messages": [
{"role": "system", "content": "你是严谨的运维助手。"},
{"role": "user", "content": "K8s Pod 一直 CrashLoopBackOff 怎么查?"},
{"role": "assistant", "content": "先看 kubectl logs 与 describe……"}
]}1
2
3
4
5
6
2
3
4
5
6
格式一致性
所有样本字段必须完整且一致;input 为空时用 "" 而非省略字段。框架(Axolotl / TRL)会按 chat template 把 messages 渲染成 token,字段不一致会导致掩码错位、训练目标错误。
架构与原理:数据流水线
生产实践
质量优于数量
- 黄金样本优先:500 条经人工核验的样本,常优于 5 万条噪声样本。
- 覆盖边界:必须包含错误拒绝、异常输入、边界场景,否则模型只会在「 happy path」上表现好。
- 系统提示一致:生产若用 system prompt,每条训练样本都应带上,否则线上分布不一致。
- 多样性:用词嵌入聚类检查指令多样性,避免大量近重复样本稀释训练。
操作步骤:清洗与脱敏流水线
python
# sft_clean.py —— 最小可用清洗流水线(示例,需按业务补充规则)
import json, re, hashlib
PII_PATTERNS = [
(re.compile(r'\b[\w.+-]+@[\w-]+\.[\w.-]+\b'), '[EMAIL]'), # 邮箱
(re.compile(r'\b1[3-9]\d{9}\b'), '[PHONE]'), # 手机号
(re.compile(r'\b\d{6,}\b'), '[ID]'), # 长数字(脱敏需谨慎)
]
def redact(text: str) -> str:
for pat, repl in PII_PATTERNS:
text = pat.sub(repl, text)
return text
def validate(rec: dict) -> bool:
# Alpaca 校验示例
if "instruction" not in rec or "output" not in rec:
return False
if not rec["instruction"].strip() or not rec["output"].strip():
return False
return True
seen, out = set(), []
with open("raw.jsonl") as f:
for line in f:
rec = json.loads(line)
if not validate(rec):
continue
rec["output"] = redact(rec["output"])
key = hashlib.md5((rec.get("instruction","")+rec.get("output","")).encode()).hexdigest()
if key in seen: # 精确去重
continue
seen.add(key)
out.append(rec)
print(f"保留 {len(out)} / 去重 {len(seen)-len(out)}") # [未实测具体输出]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
近重复去重
精确哈希只能去完全相同样本。对「改了几个字」的近重复,需用句子嵌入(如 sentence-transformers)计算余弦相似度,聚类后每簇保留代表。Datawhale 实践建议去重率控制在 < 5%,过高说明数据源同质化严重。
回放配比:防灾难性遗忘
混合通用数据
只训垂直领域数据,模型会「忘记」通用能力(如基础数学、指令遵循)。生产做法:
- 混合 10%–30% 通用指令数据(如 OpenOrca、自我构造的通用样本)作为 replay buffer。
- 多任务差异过大时,按任务数量取平方根归一化(temperature sampling)或手动设各任务上限,避免模型偏向最大任务。
- 始终切出 10% 验证集监控 loss,再另留不参与的 test 集做最终评估(见
post-eval.md)。
验证
bash
# 1) 统计检查(长度分布 / 字段完整性)
python -c "import json; rows=[json.loads(l) for l in open('clean.jsonl')]; \
print('n=',len(rows),'avg_out_len=',sum(len(r['output']) for r in rows)//len(rows))"
# [未实测具体输出]
# 2) 抽样人工复核 10%–20%:事实正确性、格式合规、风格一致
# 3) 小样本预训练(50–100 条)先验证 pipeline 是否工作,再放量1
2
3
4
5
6
7
2
3
4
5
6
7
回滚与清理
数据版本化
- 训练数据的快照(含清洗规则版本)必须版本化(git / 对象存储),保证可复现。改了清洗规则 = 换了数据集。
- 删除原始含 PII 的临时文件时,使用安全擦除而非简单
rm;确认备份与下游均已迁移。 - 若发现污染(训练集泄漏评测题),必须重做去污染并重新训练,旧 checkpoint 不可上线。
故障排查
- 训练 loss 不降:检查 chat template 是否正确、labels 掩码是否把 prompt 也算进 loss(应只算回答部分)、学习率是否过低的。
- 模型学会格式噪声:说明数据里混入了 typo / 不一致格式,回到校验步骤收紧规则。
- 过拟合快:数据量太小或多样性不足;加回放、降 epoch、加
lora_dropout。 - 评测集污染:用
--check_integrity(lm-eval)与自有私有 golden set 复核(见post-eval.md)。
安全与合规
数据泄露是第一风险
- PII / 密钥 / 商业机密:SFT 数据进入梯度会被记忆。上线前必须脱敏(正则 + 人工抽检),并对含密数据做访问审计。
- 合成数据边界:用强模型(GPT-4o / Claude)蒸馏生成的「合成黄金」受教师模型质量上限约束,且可能引入版权/合规风险,需评估数据源许可。
- 合规留存:领域数据(医疗/法律/金融)受行业监管,保留数据来源与处理记录以备审计。
- 越权访问:训练数据落在共享存储时,按最小权限设置 ACL,避免跨团队可读。
成本与性能(估算,[未实测])
| 环节 | 成本构成 | 备注 |
|---|---|---|
| 人工标注 500 条 | 人力成本为主 | 黄金样本单价高但 ROI 最高 |
| 蒸馏生成 1 万条 | API 调用费(按 token) | 需叠加质量 judge 成本 |
| 清洗/去重 | 计算可忽略 | 主要是工程时间 |
| 存储 | JSONL 极小 | 远小于模型权重 |
备注
数据工程通常是微调项目里最耗时的环节,但 ROI 最高——修 10 条坏样本往往比加 100 条新样本更能提升质量。数据成本相对 GPU 训练可忽略,瓶颈在人力与标注质量。[时长为经验估计,非实测]