微调数据准备实战
"微调圈有句行话:garbage in garbage out——数据质量决定一切。本文讲清微调数据怎么准备:指令对格式、数据收集与清洗、质量把控(去重/去噪/一致性)、合成数据的用法与风险、数据增强,以及用 LLM 辅助生成训练数据的正确姿势。"
本文要点
- 主题聚焦:大模型、开源
- 适合人群:独立开发者、全栈工程师、AI 应用开发者
- 核心价值:快速理解背景、实践路径、常见误区和工程建议
上一篇《LoRA/QLoRA 微调实战入门》讲完训练流程,这篇专攻那个被一句话带过、却决定成败的环节——数据准备。
微调圈有句行话:garbage in, garbage out。模型架构再好、学习率调得再精、LoRA rank 选得再准,喂进去的是垃圾,出来的也是垃圾。反过来,数据够好,简陋的训练流程也能出惊艳效果。这篇讲清微调数据该怎么准备:格式、收集、清洗、质量把控、合成数据、增强、规模。每一步都带实战观点。
一、质量即生命:LIMA 与"少而精"的启示
先建立一个可能反直觉的认知:微调数据,质量远远大于数量。
最强证据是 LIMA(Less Is More for Alignment)论文。作者只用 1000 条精心人工撰写的高质量样本,就把一个基座模型微调到了接近 GPT-4 的对话水平。1000 条——还没你一次爬虫抓得多。但它每一条都是领域专家逐字打磨、覆盖多样场景、回答堪称范本的"金标准"。
对比之下,很多团队拿几十万条从网上爬的、质量参差的指令对去训,效果反而不如 LIMA。为什么?
- 微调本质是调整模型的输出分布,让它朝你期望的行为靠拢。噪声样本会把分布往错误方向拉。
- 模型会学习数据里的所有模式,包括坏模式:啰嗦、跑题、答非所问、格式混乱。这些学了就难纠正。
- 冗余样本浪费训练信号。1 万条各不相同的优质样本,信息量远高于 10 万条雷同的平庸样本。
所以准备数据第一原则:先把质量做到极致,再谈数量。 宁可 2000 条精品,不要 5 万条杂草。后面所有步骤——清洗、过滤、去重——本质都是在守住这条底线。
二、指令对格式:数据长什么样
指令微调数据的核心结构是三元组:instruction(指令) + input(可选输入) + output(期望输出)。最经典的 Alpaca 格式长这样:
{
"instruction": "把下面句子翻译成正式中文",
"input": "hello world",
"output": "你好,世界"
}
没有 input 时留空即可(如"写一首关于秋天的诗")。这是单轮指令格式,Alpaca、Vicuna 早期都用变体。
但真实场景更多是多轮对话,这时要换成对话序列格式。ChatML 是当前事实标准(被 Qwen、Llama、InternLM 等广泛采用),用特殊 token 标记角色:
<|im_start|>user
帮我总结下面这段文字:<文章内容><|im_end|>
<|im_start|>assistant
这段文字讲的是...<|im_end|>
<|im_start|>user
再用英文说一遍<|im_end|>
<|im_start|>assistant
The passage is about...<|im_end|>
存储时通常用更结构化的 JSON(每条样本一个对话列表):
{
"messages": [
{"role": "user", "content": "帮我总结下面这段文字:<文章>"},
{"role": "assistant", "content": "这段文字讲的是..."},
{"role": "user", "content": "再用英文说一遍"},
{"role": "assistant", "content": "The passage is about..."}
]
}
实战提醒三点:
- 格式必须和训练框架对齐。LLaMA-Factory、Unsloth、Axolotl 各有数据集 schema,选框架前先看它要啥格式,别造完数据才发现喂不进去。
- 只在 assistant 部分算 loss。多轮对话训练时,user 的内容是条件,不参与损失计算(否则模型学着"生成用户的话")。主流框架默认这么做,但自训脚本人务必确认。
- EOS token 不能丢。每条 output 结尾要有结束符,否则模型推理时不知道何时停,会一直絮叨到 max_tokens。
三、数据从哪来:三条路子
指令对从哪搞?三条主流路径,各有取舍。
1. 人工标注——贵但准。 找领域专家写 instruction 和 output。LIMA、Dolly 都是这路子。质量天花板最高,因为人能写出模型想不到的好回答,且天然多样。缺点:贵、慢、规模受限。一条高质量人工样本成本几块到几十块,搞几千条就上万。适合核心种子数据、高价值任务。
2. 真实用户日志——最真实,但要脱敏。 如果你已经有产品在跑(比如一个客服 bot、一个编程助手),用户的真实提问 + 理想答案就是金矿。它的分布天然匹配线上场景——没有比这更真实的了。但两个坑:
- 脱敏是红线。用户日志里有 PII(姓名、手机号、身份证、内部代码),必须清洗替换才能进训练集,否则既有合规风险,模型也会泄漏。
- 原始答案质量不够。用户对话里 bot 的回答未必好(可能就是你想替换掉的旧模型)。要么只用 user 侧 + 人工重写答案,要么只挑高赞/被采纳的对话。
3. 合成数据——便宜但有偏。 用强模型(GPT-4、Claude)生成训练对。便宜、快、规模大,是当下扩数据的主流手段。但风险也最高——下一节专门讲。
实战常见配方:人工种子(几百条)打底质量 + 合成数据(几千到几万条)扩规模 + 用户日志(持续)对齐真实分布。三者按比例混,别单一来源。
四、清洗:去重、去噪、过滤、一致性
无论数据从哪来,清洗都不能省。这是"垃圾变可用"的关键工序,通常四步。
1. 去重。 分两种:
- 完全去重:整条样本字符串完全相同。一行 Python 搞定:
df.drop_duplicates(subset=['instruction','output'])。 - 近似去重:内容高度雷同(只差几个字、换个问法)。这才是大头——爬来的数据里大量是模板套话改写。用 MinHash + LSH(datasketch 库)或 SimHash 算相似度,相似度高于阈值(如 0.8)的视为重复,保留一条。
近似去重常被忽略,但它对质量提升巨大。一份 10 万条的"看似多样"数据,近似去重后可能只剩 3 万条真不一样的——那 7 万条冗余不仅没用,还会让模型过拟合到那些套话。
2. 去噪。 剔除明显有问题的样本:
- 乱码:编码错误、不可见字符、HTML 标签残留。
- 截断:output 半句就结束(爬取时被截了)。
- 空/极短:output 不到几个字、几乎没有信息。
- 跨语言混杂:本该中文的样本混进大片英文。
一段实战清洗脚本骨架:
import re, pandas as pd
from datasketch import MinHash, MinHashLSH
def is_clean(text, min_len=10, max_len=4000):
if not text or len(text) < min_len or len(text) > max_len:
return False
if re.search(r'<[^>]+>', text): # HTML 标签
return False
if len(re.findall(r'[\x00-\x1f]', text)) > 5: # 控制字符
return False
return True
df = df[df['output'].apply(is_clean)]
# 近似去重
def make_minhash(text, num_perm=64):
m = MinHash(num_perm=num_perm)
for w in set(text.split()):
m.update(w.encode('utf-8'))
return m
lsh = MinHashLSH(threshold=0.8, num_perm=64)
keep = []
for i, row in df.iterrows():
mh = make_minhash(row['instruction'])
if not lsh.query(mh): # 没见过相似的,保留
lsh.insert(str(i), mh)
keep.append(i)
df = df.loc[keep]
3. 过滤。 按业务规则筛掉不该训的:
- 长度过滤:过短无信息,过长可能是文档误入。
- 毒性/安全:用分类模型(如 Perspective API、OpenAI moderation)剔掉有害内容。别让模型学到你不想要的行为。
- 语言:用 fastlid 或 langdetect 保留目标语言。
- 任务相关性:用 embedding 相似度,剔掉和你的目标领域无关的样本。
4. 一致性校验。 这步很多人省了,但很重要:instruction 和 output 真的匹配吗? 合成数据里常见"问 A 答 B"——instruction 问翻译,output 却是摘要。用强模型做一致性判断(下一节展开),或简单规则(如 instruction 含"翻译",output 语言要对得上)粗筛。不一致的样本是强噪声,直接误导模型。
五、质量把控:抽样、模型裁判、bad case
清洗完不算完,还要主动质检。三个手段配合用。
1. 抽样人工审。 最朴素也最有效。从清洗后的数据里随机抽 100-200 条,人逐条读:instruction 清不清楚?output 对不对、好不好?有没有错别字、事实错误、格式问题?
这一步能暴露你想象不到的系统性问题——比如合成数据全是"首先...其次...最后"的开头,或者用户日志里 80% 都是问候语。抽样审不是为了逐条改,是为了发现数据集整体的偏差。 发现偏差回去重洗。
2. 强模型当裁判(LLM-as-a-judge)。 人工审覆盖不了几万条,用强模型批量打分。给 GPT-4 / Claude 一个评分 prompt:
你是一个严格的数据质量评审员。请对下面这条指令微调样本打分(1-5 分):
Instruction: {instruction}
Output: {output}
评分维度:
1. Instruction 是否清晰、可独立理解
2. Output 是否正确回答了 instruction
3. Output 的质量(准确性、完整性、无冗余)
4. 格式是否规范
请先给出简短理由,最后输出一行 "SCORE: X"。
跑一遍,挑出 SCORE ≤ 2 的样本人工复核或直接剔除。裁判模型不必完美,它能筛掉明显差的就够了。注意裁判模型最好比你微调的基座强一个档次——用同档模型自评容易"互相包庇"。
3. Bad case 剔除。 准备一个"反面清单":你不希望模型出现的行为。比如:
- 不要回复"我是一个 AI,我不能..."这种逃避。
- 不要每次都先复述用户问题。
- 不要输出"希望对你有帮助!"这类废话结尾。
用规则或小分类器扫一遍数据,把含 bad case 的样本剔掉或重写。模型学不到坏模式,自然不会输出坏模式——这比训练后用 RLHF 纠正便宜得多。
六、合成数据:便宜但有代价
合成数据是当下扩数据的主力,但它是把双刃剑,用对是利器,用错埋雷。
正确姿势:
- 给好种子。 不要让强模型凭空生成(它会塌缩到最常见的几种问法)。先人工准备一批多样化的 seed instructions,让模型基于种子扩展。种子质量决定上限。
- 显式要求多样化。 Prompt 里强制要求"主题、难度、长度、风格、语言风格各不相同",并用 self-instruct 的思路(让模型先生成大量候选 instruction,再聚类采样,保证主题覆盖)。
- 用强模型生成 output,再用裁判模型筛一遍(上一节的流程)。生成 + 过滤双保险。
- Evol-Instruct 思路:对已有指令做"进化"(加约束、增深度、改复杂度),生成更难的变体,提升数据难度分布。
风险必须知道:
- 模式坍缩(mode collapse)。强模型生成的样本,风格会高度同质化(都像 ChatGPT 说话)。微调后你的模型也只会"ChatGPT 体",失去个性。
- 偏见放大。强模型自带的偏见(立场、口吻、规避倾向),会通过合成数据传给你的模型,甚至放大。这就是为什么一些微调模型越来越"政治正确、车轱辘话"。
- 模型坍缩(model collapse)。如果用模型 A 生成数据训练模型 B,再用 B 生成数据训练 C......多代之后,数据分布尾部消失,模型越来越平庸。合成数据最好只做"扩量",基座多样性仍需真实数据兜底。
- 真相盲区。强模型不会的知识,合成数据里也不会。领域专家知识还是得靠人工标注或真实文档。
我的实战建议:合成数据占比别超过 60-70%,核心种子和领域关键样本必须人工。纯合成数据训出来的模型,初看惊艳,上线遇到长尾问题就露馅。
七、数据增强:扩量同时保质量
数据不够、又不想过度依赖合成?用数据增强——把现有优质样本变着法扩展,信息密度不降。
常见三种:
1. 改写(paraphrasing)。 用模型把同一条样本换种说法:instruction 换问法、output 换表达,语义不变。原数据 1 条变 3-5 条,增加表述鲁棒性。注意只对高质量样本改写,垃圾改 5 遍还是垃圾。
2. 回译(back-translation)。 中文→英文→中文,得到自然多样的中文表达。这是 NLP 老技巧,在指令数据上依然有效,能打破原始数据的句式惯性。多语言场景还能顺带产出多语言训练对。
3. 格式变换。 同一个任务,换不同的输出格式:
- "列出三点原因" → 用 markdown 列表、用编号、用表格、用段落。
- 摘要 → 一句话版、三句话版、要点版。
这让模型学到"内容稳定、格式可控"——正是微调最想达成的目标之一。
增强的纪律: 每条增强样本都该过一遍质量过滤(去重、裁判打分),不能因为是增强来的就免检。增强是放大器——放大的优质,也放大缺陷。
八、规模参考:到底要多少条
最后一个高频问题:微调需要多少数据? 没有标准答案,但给个实战区间:
| 任务类型 | 数据量参考 | 说明 |
|---|---|---|
| 指令遵循/通用对话 | 1k – 10k | LIMA 用 1k,多数场景 3k–5k 高质量样本就出明显效果 |
| 风格定制(语气、品牌) | 500 – 3k | 风格信号强,少量样本即可;太多反而过拟合到固定句式 |
| 特定任务(抽取、分类、格式化) | 1k – 10k | 任务越窄,需要越少;越开放,需要越多 |
| 领域适配(医疗、法律、客服) | 10k – 100k+ | 要学领域知识和术语,量更大;但仍质量优先 |
几个判断维度:
- 任务复杂度:开放生成(写文章)需要更多样本覆盖多样输出;封闭任务(分类、抽取)少量即够。
- 基座模型能力:基座越强(已是强 instruct 模型),需要微调的"修正量"越小,数据越少。基座是 base 模型,需要更多。
- 变化频率:数据会变(客服话术、产品规则)就少训点、勤迭代;稳定的(写作风格)可以多投入。
- 过拟合红线:指令微调 epoch 一般 2-3,数据少到几百条时要特别小心过拟合——模型会死记样本,泛化崩塌。低于 500 条,考虑先用增强和合成扩到 1k+ 再训。
一个朴素的经验法则:先用你能搞到的最高质量 1k-2k 条训一版,看效果,再决定要不要加量。 不要一上来就堆几万条没清洗的——你会分不清是数据多了起的作用,还是噪声混进来的副作用。
小结
微调数据准备,本质上是在做一件事:把"模型该怎么做"这件事,用最少、最准、最干净的样本讲清楚。
- 质量 > 数量:LIMA 用 1000 条打败几十万条。先把质量做到极致,再谈规模。
- 格式对齐框架:Alpaca 三元组 / ChatML 多轮,务必和训练工具对齐,assistant 部分才算 loss,别忘 EOS。
- 三条数据来源:人工(准但贵)、用户日志(真但要脱敏)、合成(便宜但有偏),混着用。
- 清洗四步:去重(尤其近似去重)、去噪、过滤、一致性校验。这步省了,后面全白干。
- 质检三板斧:抽样人工审、强模型当裁判打分、bad case 剔除。
- 合成数据有上限:种子要多样、生成要过滤、占比别超 60-70%,警惕模式坍缩和偏见放大。
- 规模按任务:指令遵循 1k-10k 起,领域适配可到 10k+,但永远从少量高质量起步迭代。
记住那句金句:微调的 70% 是数据,30% 才是训练。 调学习率、换 LoRA rank、加 epoch,这些都是数据够好之后的微调(双关)。把数据这道工序做扎实,后面事半功倍;数据糊弄,再炫的训练技巧也救不回来——这也是为什么真正会微调的人,时间都花在数据上。
Related