数据集准备:采集、清洗、去重、jsonl、质检
硬件前提
不需要 GPU。微调任务 80% 的工作量在这里,而且这一步不需要算力,最适合先做。
先定任务类型,再定数据格式
| 任务 | 数据形态 | 常见量级 |
|---|---|---|
| 格式/字段输出稳定 | 输入 → 严格 JSON | 200~1000 条 |
| 语气/话术/领域风格 | 输入 → 期望回答 | 500~3000 条 |
| 判断/分类 | 输入 → 标签(含边界与「无」类) | 每类 50~300 条 |
| 复杂推理链 | 输入 → 推理过程 → 结论 | 成本高,先确认前面的量不够用 |
先做 200 条高质量数据跑通全流程,再决定要不要扩到几千条。一上来堆一万条脏数据是最常见的浪费。
jsonl 格式(微调通用)
{"messages": [{"role": "system", "content": "你是客服助手,只根据资料回答。"},
{"role": "user", "content": "订单 123 什么时候发货?"},
{"role": "assistant", "content": "资料未提及该订单,无法确认发货时间。"}]}
约定:
- 一行一条样本,UTF-8,不带 BOM;
system内容全数据集保持一致(训练时改 system 措辞 = 换任务);- 训练集/验证集划分 90/10,验证集不参与清洗之外的任何加工。
采集:三个来源的优先级
- 真实线上数据(脱敏后)——最值钱,分布最真;
- 人工撰写/修正——质量最高,量上不去;
- 大模型合成——最快最便宜,但会自我强化偏差。
用合成数据的纪律:合成 → 人工抽检 ≥10% → 不合格整批重做。完全没人工抽检的合成数据集,通常把大模型的毛病原样复制进你的小模型。
清洗清单(按顺序做)
| 步骤 | 具体检查 |
|---|---|
| 去噪 | 空回答、纯标点、编码乱码、长度异常(过短/过长) |
| 脱敏 | 手机号、证件号、邮箱、密钥、内网地址 → 占位符替换 |
| 格式校验 | JSON 可解析、字段齐全、角色顺序正确(不能连续两个 assistant) |
| 去重 | 完全重复直接删;近似重复(改写级)保留 1~2 条 |
| 一致性 | 同类输入不能给出互相矛盾的答案 |
| 泄漏检查 | 验证集样本不得出现在训练集(含近似重复) |
近似去重的实操做法:按字符 n-gram 做 minhash 聚类,每簇保留最长的 1~2 条。
质检:三个必须过的指标
- 格式合法率 100%:一条坏样本就可能导致训练报错或学到坏格式。
- 标签/答案一致率:随机抽 50 条人工复核,一致率低于 90% 就别训,先修数据。
- 分布覆盖:按业务维度(意图、语言、长度)分桶看数量。某个桶只有 5 条,模型在该场景一定不稳。
边界样本必须存在:空结果、拒答、超长输入、错别字、多语言混杂。缺了这些,线上第一次遇到就崩。
常见坑
| 坑 | 后果 |
|---|---|
| 数据里带真实客户信息 | 合规事故,且模型可能复述出来 |
| 只有「正常」样本 | 遇到异常输入硬凑答案 |
| 答案风格不统一(多人各写各的) | 模型输出风格漂移 |
| 用大模型生成 5000 条没抽检 | 幻觉与套话被固化 |
| 训练集里含评测集原题 | 分数虚高,上线即崩 |
| 频繁改 system 措辞 | 任务定义漂移,效果无法归因 |
完成标志
- 一个版本化的
train.jsonl/val.jsonl(带条数与清洗脚本); - 三个质检数字:格式合法率、抽检一致率、分桶覆盖;
- 一份「边界样本」子集(拒答、空结果、异常输入)。
数据准备好之后,下一篇(LoRA 微调)只是跑几条命令的事。