在大模型微调的实战中,数据的质量直接决定了模型的最终表现。业界有句行话:“数据质量决定了模型的上限,而模型架构只是决定了逼近这个上限的速度。” 换句话说,即使你的模型再强大,如果投喂的是低质量的数据,最终效果也会大打折扣。
4.1 微调数据的三种核心格式:指令、对话与续写
根据不同的任务目标,微调数据主要有三种格式。选对格式是成功的第一步。
1. 指令格式 (Instruction Format)
适用于单轮问答或任务执行场景,比如翻译、总结、分类。
{
"instruction": "将以下英文翻译成中文",
"input": "Machine learning is a subset of artificial intelligence.",
"output": "机器学习是人工智能的一个子集。"
}
2. 对话格式 (Conversation Format)
适用于多轮交互场景,例如客服机器人、聊天助手。
{
"conversations": [
{"role": "system", "content": "你是一个专业的技术客服"},
{"role": "user", "content": "我的订单怎么还没发货?"},
{"role": "assistant", "content": "让我帮您查一下...订单 #1234 已于今天下午发出"},
{"role": "user", "content": "大概几天能到?"},
{"role": "assistant", "content": "预计 3-5 个工作日送达"}
]
}
3. 续写格式 (Completion Format)
适用于文本生成、代码补全等需要模型根据上文进行延续的任务。
{
"text": "def fibonacci(n):\n if n <= 1:\n return n\n return fibonacci(n-1) + fibonacci(n-2)"
}
4.2 数据质量远比数据数量重要
多少数据量才够用?关键在于“精”而非“多”。以下是高质量微调数据的五个黄金标准:
✅ 准确性:答案必须基于事实,正确无误。
✅ 一致性:面对相似的问题,回答的风格和逻辑应当保持一致。
✅ 完整性:回答应尽可能覆盖用户问题的所有方面,避免遗漏。
✅ 格式规范:输出格式统一(如JSON、Markdown、特定排版),便于模型学习。
✅ 多样性:样本需要覆盖目标应用场景下的各种情况和问题变体。
根据数据量的不同,所能达到的效果和应用场景也有所区别:
| 数据量 |
预期效果 |
适用场景 |
| 50~200 条 |
学习基本的回答风格和输出格式 |
简单的风格迁移、格式统一 |
| 500~1000 条 |
获得不错的领域适应能力 |
特定任务(如客服对话、简单问答) |
| 1000~5000 条 |
实现良好的领域专精 |
专业问答、复杂指令遵循 |
| 5000+ 条 |
掌握深度领域知识 |
医疗、法律等专业性强、容错率低的场景 |
💡 核心原则:500条精心准备的高质量数据,其效果远胜于5000条随意收集的低质量数据。与其盲目追求数据规模,不如先花时间打磨好一个高质量的种子数据集。
4.3 构建训练数据的实用方法
数据从哪儿来?这里有几个经过验证的实用方法:
# ── 方法 1:利用 GPT-4 / Claude 等大模型生成种子数据 ──
prompt = """你是一个数据标注专家。请为‘中文客服助手’生成 10 条高质量训练数据。
要求:
- 格式为 JSON,包含 user 和 assistant 字段
- 涵盖:退货、物流查询、产品咨询、投诉处理
- assistant 的回答要专业、友好、简洁
请直接输出 JSON 数组。"""
# 流程:用提示词从大模型获取初始数据 → 人工审核修正 → 形成最终的训练集
# ── 方法 2:从真实业务日志中提取 ──
# 例如,将客服系统中的真实聊天记录进行脱敏处理,筛选出优质对话,然后格式化。
# ── 方法 3:Self-Instruct(自我指令生成) ──
# 用少量高质量的种子数据作为引导,让模型自动生成更多类似的数据,最后通过人工进行过滤和校准。
4.4 对话模板 (Chat Template):不可忽视的细节
每个开源大模型(如 Qwen、Llama、ChatGLM)都有自己特定的对话格式模板。微调时必须使用与基座模型完全匹配的模板,否则训练效果会大打折扣。
让我们看看如何正确使用 Transformers 库来处理:
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-7B-Instruct")
messages = [
{"role": "system", "content": "你是一个有帮助的助手。"},
{"role": "user", "content": "你好"},
{"role": "assistant", "content": "你好!有什么可以帮你的?"},
]
# apply_chat_template 会自动按照模型预设的格式编排对话
text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=False)
print(text)
# 输出示例(Qwen2.5的格式):
# <|im_start|>system
# 你是一个有帮助的助手。<|im_end|>
# <|im_start|>user
# 你好<|im_end|>
# <|im_start|>assistant
# 你好!有什么可以帮你的?<|im_end|>
💡 关键原则:永远使用 tokenizer.apply_chat_template() 来格式化你的对话数据,不要手动拼接字符串。不同模型的特殊标记(Token)千差万别(例如 <|im_start|>、[INST]、<s>),用错了会导致模型无法正确理解对话结构,训练效果自然不好。
4.5 实战:构建一个中文客服微调数据集
理论说再多,不如动手实践。下面我们一步步构建一个可用的数据集。
import json
# ── 1. 准备训练数据(示例) ──
training_data = [
{
"conversations": [
{"role": "system", "content": "你是智能客服小助手,回答要简洁专业、语气友好。"},
{"role": "user", "content": "我想退货,怎么操作?"},
{"role": "assistant", "content": "好的,退货流程如下:\n1. 进入‘我的订单’页面\n2. 找到要退货的商品,点击‘申请退货’\n3. 选择退货原因并提交\n\n审核通过后会发送退货地址,7个工作日内退款到账。还有其他问题吗?"},
]
},
{
"conversations": [
{"role": "system", "content": "你是智能客服小助手,回答要简洁专业、语气友好。"},
{"role": "user", "content": "我的快递显示已签收但我没收到"},
{"role": "assistant", "content": "很抱歉给您带来不便。这种情况可能是:\n1. 快递被放在了驿站或快递柜\n2. 被家人/邻居代收\n\n建议您先确认一下以上情况。如果确实没有收到,我帮您联系快递公司核实,请提供一下您的订单号。"},
]
},
# ... 在此添加更多高质量数据(建议目标500条以上)
]
# ── 2. 保存为 JSONL 格式(每行一个JSON对象) ──
with open("customer_service.jsonl", "w", encoding="utf-8") as f:
for item in training_data:
# 使用 ensure_ascii=False 保证中文字符正常存储
f.write(json.dumps(item, ensure_ascii=False) + "\n")
# ── 3. 使用 Hugging Face Datasets 库加载 ──
from datasets import load_dataset
dataset = load_dataset("json", data_files="customer_service.jsonl")
print(dataset)
# 输出示例:
# DatasetDict({
# train: Dataset({features: ['conversations'], num_rows: 500})
# })
这个流程清晰地展示了从数据构造到格式保存,再到利用高效工具(如 Hugging Face Datasets)进行加载的完整路径。掌握这些关于数据准备的核心要点,你的 LoRA/QLoRA 微调项目就成功了一半。将高质量的数据与正确的工具方法结合,是模型表现出色的基石。更多深度学习与模型训练技巧,欢迎在云栈社区交流探讨。