课程0基础Agent开发课 / 模型微调 / 微调数据集准备与质量评估
— 29 min read

微调数据集准备与质量评估

*微调数据集准备完整流程 — 从原始数据到训练就绪*

微调数据集准备与质量评估

1. 为什么数据准备是微调中最重要的环节

微调数据集准备流程图
微调数据集准备完整流程 — 从原始数据到训练就绪

很多人第一次做微调时,把大量时间花在选模型、调超参数、研究 LoRA 配置上,结果数据随便弄了一些就开始训练——然后发现效果惨不忍睹,比基础模型还差。

这是一个非常常见的错误。经验规律是:微调项目 60-70% 的工作量应该在数据准备上,而不是模型训练上

原因很简单:微调的本质是监督学习(Supervised Learning),模型通过你的示例学习"输入→期望输出"的映射。如果你的示例本身有问题——格式不一致、输出质量低、覆盖不够、存在矛盾——模型就会忠实地学到这些问题,甚至把问题放大。

三个典型的数据问题

格式不一致:同样是 JSON 输出,有些样本用双引号,有些用单引号;有些数字是字符串,有些是整数。模型学到的结论是"两种格式都对",于是在生产中随机选一种,导致格式错误率居高不下。

质量参差不齐:你用 GPT-4 生成了一批数据,然后为了凑数量,把 GPT-3.5 生成的那批质量稍差的数据也加进去了。模型会把"差一点的回答"学成"也是可以接受的",整体质量下滑。

矛盾示例:同一个类型的输入,有时候要求简短回答,有时候要求详细回答,两者混在一起。模型无法判断哪种是"正确"的,只能在两者之间随机跳动。

"100 条精心设计的数据往往超过 1000 条凑数的数据"——这不是夸张,而是实际经验。


数据质量决定微调质量。这句话听起来像废话,但实际工程中有大量的团队在数据上翻车:花了两周准备数据、一天跑完训练,结果模型表现比基础模型还差——原因往往就是数据质量不过关。

本章目标:让你能独立制作一批可以真正用于训练的高质量数据集。

2. 为什么数据质量对微调如此关键

微调的本质是监督学习(Supervised Learning):给模型展示"输入→期望输出"的范例,模型通过梯度下降调整参数,使得它的输出越来越接近这些范例。

这个学习机制意味着:模型会精确地学习你的示例,包括示例里的错误

如果训练数据里有 10% 的格式不一致(比如同样是 JSON 输出,有些带空格,有些不带),模型就会以 10% 的概率随机决定是否加空格——它认为这两种格式都是"正确"的。如果数据里有两条相互矛盾的示例(同一种输入给了不同的期望输出),模型会陷入困惑,在这类输入上的表现会变得不稳定。

这就是为什么"100 条精心设计的数据往往超过 1000 条凑数的数据"。数量增加只是给模型更多样例参考,但如果这些样例本身有问题,增加数量反而会强化错误。

数据质量的三个关键维度:

  1. 一致性:相同类型的输入,期望输出的格式和风格必须完全一致。不一致是最常见的数据问题,也是最容易被忽视的。
  2. 代表性:训练数据要覆盖实际使用中可能出现的各种情况,包括边界情况。如果实际场景中有 20% 的输入是长文本,训练数据里长文本的比例也应该接近 20%。
  3. 准确性:每条数据的期望输出必须是真正"好"的回答,不能是"凑合能用"的回答。模型会把训练数据里的"凑合"当成标准。

3. 微调数据的格式

3.1. 指令微调格式(Alpaca格式)

最常见的格式,来自斯坦福的 Alpaca 项目(2023年斯坦福发布的开源指令微调数据集和训练方法,instruction/input/output 三字段结构被广泛沿用,成为指令微调的事实标准格式):

json
[
  {
    "instruction": "将以下中文翻译成英文",
    "input": "今天天气很好",
    "output": "The weather is very nice today."
  },
  {
    "instruction": "用一句话总结以下文章的主要观点",
    "input": "人工智能正在改变医疗诊断...(文章内容)",
    "output": "AI技术正在通过提升诊断准确率和效率来革新医疗行业。"
  }
]

三个字段的含义:

  • instruction:告诉模型"要做什么任务"
  • input:任务处理的原始材料(可以为空字符串 ""
  • output:期望模型输出的高质量回答

3.2. 对话格式(Chat Format)

如果你的目标是训练一个对话助手,推荐使用多轮对话格式。这种格式也叫 ShareGPT 格式(因最早由 ShareGPT 网站收集的对话数据推广而来):

json
[
  {
    "messages": [
      {"role": "system", "content": "你是一个Python专家助手,擅长用简单的语言解释编程概念。"},
      {"role": "user", "content": "什么是装饰器?"},
      {"role": "assistant", "content": "装饰器是Python中一种设计模式,允许你在不修改原函数代码的情况下,给函数添加额外功能。\n\n最简单的例子:\n```python\ndef log_decorator(func):\n    def wrapper(*args, **kwargs):\n        print(f'调用函数: {func.__name__}')\n        return func(*args, **kwargs)\n    return wrapper\n\n@log_decorator\ndef say_hello():\n    print('Hello!')\n```\n\n调用 `say_hello()` 时会自动打印日志。"}
    ]
  }
]

选哪种格式?

场景 推荐格式
文本分类、翻译、摘要等单轮任务 指令微调格式
客服机器人、问答助手等对话任务 对话格式
代码生成助手 对话格式(便于多轮澄清需求)

4. 如何写好 instruction(最重要的技能)

这是本章最关键的内容,却是被大多数教程忽略的部分。

instruction 质量直接影响模型学到的行为。模型通过大量样本"感知"你想要它做什么。如果 instruction 写得含糊,模型就会学到含糊的行为模式。

理解这背后的学习机制:模型在训练时,会在 instruction 的表示(内部向量)和 output 的表示之间建立关联。如果 instruction 信息量不足(比如只是"回答用户问题"),模型无法从 instruction 中获取足够的约束信号,只能从 input 本身猜测应该怎么回答,泛化能力就会很差。反之,详细的 instruction 给了模型清晰的"任务规格",它就能学会在新输入上也按同样的规格输出。

4.1. 好的 instruction vs 坏的 instruction

示例1:客服回复场景

code
坏的 instruction:
"回答用户问题"

好的 instruction:
"你是一名电商客服,用户反映商品未按时到达。请以专业、同理心的态度回复,
说明可能的原因,并提供具体的解决方案(如查询物流、申请补偿)。
回复字数控制在100-200字。"

差距在哪里?坏的 instruction 太宽泛,模型不知道:是什么角色?回复要多长?什么语气?要不要给解决方案?

示例2:代码生成场景

code
坏的 instruction:
"写Python代码"

好的 instruction:
"用Python编写一个函数,实现以下功能:
1. 接受一个字符串列表作为输入
2. 移除列表中的重复元素,同时保持原有顺序
3. 函数需要有类型注解和docstring
4. 提供使用示例"

示例3:领域知识问答场景

code
坏的 instruction:
"解释这个医学概念"

好的 instruction:
"用通俗易懂的语言向没有医学背景的普通人解释以下医学概念。
避免使用专业术语,如需使用请加括号解释。回答结构清晰,
先给出定义,再举一个生活中的类比。"

4.2. instruction 质量检查清单

在制作数据集时,对每条 instruction 问自己以下问题:

  • 角色清晰:模型知道自己扮演什么角色吗?
  • 任务具体:任务的边界是否清楚?(输入是什么,输出是什么)
  • 格式约束:对输出格式有要求吗?(字数、结构、语言风格)
  • 质量标准:什么算好?(专业度、简洁性、完整性)
  • 边界案例:覆盖了常见的边界情况吗?(空输入、超长输入等)

5. 数据量需求

任务类型 最少数据量 推荐数据量 说明
简单格式化任务 100-500条 1000-2000条 如固定模板回复、格式转换
领域知识注入 1000-5000条 5000-20000条 如医疗、法律专业问答
对话风格调整 500-1000条 2000-5000条 如语气、风格、角色扮演
复杂推理任务 5000-10000条 20000+条 如数学推理、代码调试

务实建议:

  • 先用100-200条数据做一次"探索性微调",验证方向是否正确
  • 确认方向对了,再花时间扩充到推荐量级
  • 数据质量优先于数量:100条精心设计的数据往往超过1000条凑数的数据

6. 数据收集方法

6.1. 方法1:用GPT-4生成合成数据

对于大多数小团队,这是最高效的起点。

python
# 安装依赖
# pip install openai

from openai import OpenAI
import json
import time

client = OpenAI()  # 需要设置 OPENAI_API_KEY 环境变量

def generate_training_data(topic: str, n_examples: int = 20) -> list:
    """
    用GPT-4生成微调训练数据。

    Args:
        topic: 数据主题,如"Python异常处理"
        n_examples: 每次生成的条数(建议不超过30,避免质量下降)

    Returns:
        包含 instruction/input/output 的字典列表
    """
    prompt = f"""生成{n_examples}条关于"{topic}"的高质量训练数据。

每条数据必须包含以下三个字段:
- instruction: 具体、清晰的任务描述(不少于15个字)
- input: 任务处理的原始材料(如果任务不需要额外输入,填空字符串"")
- output: 高质量的期望回答(不少于50个字)

要求:
1. 覆盖不同难度(初级/中级/高级各占约三分之一)
2. 覆盖不同角度(概念解释、代码示例、常见错误、最佳实践等)
3. 回答要专业、准确、有实用价值
4. instruction字段要具体,不能是"解释X"这种过于宽泛的描述

必须以如下JSON格式返回,外层键名必须是"data":
{{"data": [
  {{"instruction": "...", "input": "...", "output": "..."}},
  ...
]}}"""

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}],
        response_format={"type": "json_object"},  # 强制JSON格式输出
        temperature=0.8  # 稍高的温度增加多样性
    )

    raw = json.loads(response.choices[0].message.content)

    # 容错处理:GPT-4有时会用不同的键名
    # 按优先级尝试常见键名
    examples = (
        raw.get("data") or          # 我们要求的格式
        raw.get("examples") or      # 另一种常见键名
        raw.get("training_data") or # 另一种可能的键名
        raw.get("items") or
        []
    )

    # 如果上面都找不到,尝试找第一个列表类型的值
    if not examples:
        for value in raw.values():
            if isinstance(value, list) and len(value) > 0:
                examples = value
                break

    print(f"成功生成 {len(examples)} 条训练数据")
    return examples


def batch_generate(topic: str, total: int = 200, batch_size: int = 20) -> list:
    """
    分批生成大量训练数据,避免单次请求质量下降。

    Args:
        topic: 主题
        total: 总条数
        batch_size: 每批条数
    """
    all_data = []
    batches = (total + batch_size - 1) // batch_size  # 向上取整

    for i in range(batches):
        print(f"生成第 {i+1}/{batches} 批...")
        batch = generate_training_data(topic, batch_size)
        all_data.extend(batch)
        time.sleep(1)  # 避免触发API限流

    print(f"总计生成: {len(all_data)} 条")
    return all_data


# 使用示例
if __name__ == "__main__":
    # 生成关于"Python异常处理"的训练数据
    data = batch_generate(topic="Python异常处理", total=100, batch_size=20)

    # 保存到文件
    with open("training_data_raw.json", "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

    print(f"数据已保存到 training_data_raw.json")

6.2. 方法2:从HuggingFace数据集获取

使用已有的开源数据集作为起点,再做领域适配:

python
# pip install datasets

from datasets import load_dataset

# 加载经典的Alpaca数据集(52000条英文指令数据)
dataset = load_dataset("tatsu-lab/alpaca", split="train")
print(f"Alpaca数据集: {len(dataset)} 条")

# 过滤出特定类型的数据(比如代码相关)
code_data = dataset.filter(
    lambda x: any(kw in x['instruction'].lower()
                  for kw in ['python', 'code', 'function', 'program'])
)
print(f"代码相关数据: {len(code_data)} 条")

# 中文数据集推荐
# load_dataset("BelleGroup/train_1M_CN")  # 中文指令数据集,100万条
# load_dataset("shibing624/alpaca-zh")    # 中文Alpaca数据集

6.3. 方法3:从业务数据中提取

如果你有真实的业务数据(如客服对话记录、用户反馈等),这是质量最高的数据来源:

python
import pandas as pd

# 假设你有一份客服对话记录的CSV文件
# 列名:question, answer, satisfaction_score
df = pd.read_csv("customer_service_logs.csv")

# 只保留用户满意度高的对话(高质量数据)
high_quality = df[df['satisfaction_score'] >= 4]

# 转换为训练格式
training_data = []
for _, row in high_quality.iterrows():
    training_data.append({
        "instruction": "你是一名专业的客服代表,请回答用户问题。",
        "input": row['question'],
        "output": row['answer']
    })

print(f"从业务数据提取了 {len(training_data)} 条训练样本")

7. 数据质量评估

在清洗之前,先了解数据的全貌:

python
import json
import statistics
from collections import Counter

def analyze_dataset(data_path: str) -> dict:
    """
    全面分析数据集质量,输出关键统计指标。

    Args:
        data_path: JSON数据文件路径

    Returns:
        包含各项统计指标的字典
    """
    with open(data_path, 'r', encoding='utf-8') as f:
        data = json.load(f)

    print(f"{'='*50}")
    print(f"数据集分析报告")
    print(f"{'='*50}")
    print(f"总数据量: {len(data)} 条")

    # 1. 长度分布分析
    output_lengths = [len(d.get('output', '')) for d in data]
    instruction_lengths = [len(d.get('instruction', '')) for d in data]

    print(f"\n[输出长度分布]")
    print(f"  最短: {min(output_lengths)} 字符")
    print(f"  最长: {max(output_lengths)} 字符")
    print(f"  平均: {statistics.mean(output_lengths):.0f} 字符")
    print(f"  中位数: {statistics.median(output_lengths):.0f} 字符")

    # 长度分段统计(直观了解分布)
    length_buckets = Counter()
    for l in output_lengths:
        if l < 50:
            length_buckets["<50字符(极短)"] += 1
        elif l < 200:
            length_buckets["50-200字符(短)"] += 1
        elif l < 500:
            length_buckets["200-500字符(中)"] += 1
        elif l < 1000:
            length_buckets["500-1000字符(长)"] += 1
        else:
            length_buckets[">1000字符(极长)"] += 1

    print(f"\n[输出长度分段]")
    for bucket, count in sorted(length_buckets.items()):
        pct = count / len(data) * 100
        print(f"  {bucket}: {count}条 ({pct:.1f}%)")

    # 2. 重复数据检测
    outputs = [d.get('output', '') for d in data]
    instructions = [d.get('instruction', '') + d.get('input', '') for d in data]
    output_duplicates = len(outputs) - len(set(outputs))
    instruction_duplicates = len(instructions) - len(set(instructions))

    print(f"\n[重复数据]")
    print(f"  重复输出: {output_duplicates} 条")
    print(f"  重复指令+输入组合: {instruction_duplicates} 条")

    # 3. 多样性分析(instruction 关键词分布)
    # 统计 instruction 中出现频率最高的词,判断是否过于单一
    all_words = []
    for d in data:
        words = d.get('instruction', '').split()[:5]  # 取前5个词
        all_words.extend(words)

    top_words = Counter(all_words).most_common(10)
    print(f"\n[Instruction 关键词 Top10](多样性参考)")
    for word, count in top_words:
        print(f"  '{word}': {count}次")

    # 4. 格式一致性检查
    missing_instruction = sum(1 for d in data if not d.get('instruction', '').strip())
    missing_output = sum(1 for d in data if not d.get('output', '').strip())

    print(f"\n[格式检查]")
    print(f"  缺少instruction字段: {missing_instruction} 条")
    print(f"  缺少output字段: {missing_output} 条")

    # 5. 质量评分(综合得分)
    problems = output_duplicates + instruction_duplicates + missing_instruction + missing_output
    short_count = length_buckets.get("<50字符(极短)", 0)
    problems += short_count

    quality_score = max(0, 100 - (problems / len(data)) * 100)
    print(f"\n[综合质量评分]: {quality_score:.1f}/100")
    if quality_score >= 90:
        print("  评级:优秀,可以直接用于训练")
    elif quality_score >= 70:
        print("  评级:良好,建议清洗后再训练")
    else:
        print("  评级:需要大量清洗工作")

    return {
        "total": len(data),
        "output_lengths": output_lengths,
        "duplicates": output_duplicates,
        "quality_score": quality_score
    }


# 使用示例
stats = analyze_dataset("training_data_raw.json")

8. 数据清洗

了解数据问题后,进行有针对性的清洗:

python
import re

def clean_dataset(data: list,
                  min_output_length: int = 50,
                  max_output_length: int = 2000) -> list:
    """
    清洗数据集,移除低质量和重复数据。

    参数说明:
    - min_output_length=50:过滤掉50字符以下的输出。
      依据:经验表明,少于50字符的回答通常是"好的"、"知道了"等无实质内容的
      回复,或者是生成失败的截断输出。50字符大约等于2-3句完整的中文短句,
      是一个有意义回答的最低标准。如果你的任务天然就需要短回答(如情感分类
      返回"正面"/"负面"),应把这个值调小到5-10。

    - max_output_length=2000:过滤掉2000字符以上的极长输出。
      依据:过长的输出在训练时会截断,被截断的训练样本会让模型学到"回答可以
      被中途打断"的错误行为。2000字符约等于800-1000汉字,对于大多数问答场景
      已经足够。如果你的任务需要长文生成,应该增大这个值。

    Args:
        data: 原始数据列表
        min_output_length: output字段的最小字符数
        max_output_length: output字段的最大字符数

    Returns:
        清洗后的数据列表
    """
    cleaned = []
    seen_keys = set()  # 用于去重(基于 instruction + input 的组合)

    removed_stats = {
        "empty": 0,
        "too_short": 0,
        "too_long": 0,
        "duplicate": 0,
        "format_error": 0
    }

    for item in data:
        # 检查必填字段是否存在
        if not isinstance(item, dict):
            removed_stats["format_error"] += 1
            continue

        instruction = item.get('instruction', '').strip()
        output = item.get('output', '').strip()
        input_text = item.get('input', '').strip()

        # 过滤空输出
        if not output:
            removed_stats["empty"] += 1
            continue

        # 过滤空 instruction
        if not instruction:
            removed_stats["format_error"] += 1
            continue

        # 过滤过短输出(去掉截断失败的生成结果)
        if len(output) < min_output_length:
            removed_stats["too_short"] += 1
            continue

        # 过滤过长输出(避免训练时截断)
        if len(output) > max_output_length:
            removed_stats["too_long"] += 1
            continue

        # 去除重复(相同的 instruction + input 组合)
        dedup_key = instruction + "|||" + input_text
        if dedup_key in seen_keys:
            removed_stats["duplicate"] += 1
            continue
        seen_keys.add(dedup_key)

        # 文本规范化:去除多余空白
        item['instruction'] = instruction
        item['input'] = input_text
        item['output'] = output

        cleaned.append(item)

    # 输出清洗报告
    print(f"清洗前: {len(data)} 条")
    print(f"清洗后: {len(cleaned)} 条")
    print(f"\n移除原因:")
    for reason, count in removed_stats.items():
        if count > 0:
            labels = {
                "empty": "空输出",
                "too_short": f"输出过短(<{min_output_length}字符)",
                "too_long": f"输出过长(>{max_output_length}字符)",
                "duplicate": "重复数据",
                "format_error": "格式错误"
            }
            print(f"  {labels[reason]}: {count} 条")

    return cleaned


# 使用示例
with open("training_data_raw.json", "r", encoding="utf-8") as f:
    raw_data = json.load(f)

# 根据你的任务调整参数
# 如果是分类任务(输出是"是"/"否"/"正面"等),min_output_length 设为 1
cleaned_data = clean_dataset(
    raw_data,
    min_output_length=50,   # 通用问答任务的推荐值
    max_output_length=2000  # 根据你的模型最大序列长度调整
)

# 保存清洗后的数据
with open("training_data_clean.json", "w", encoding="utf-8") as f:
    json.dump(cleaned_data, f, ensure_ascii=False, indent=2)

print(f"\n清洗后数据已保存到 training_data_clean.json")

9. 数据质量评估的具体指标

清洗完成后,用以下三个维度评估数据集是否达到训练标准:

9.1. 指标1:多样性(Diversity)

多样性差的数据集会导致模型只会回答同一类问题。检测方法:

python
from collections import Counter
import math

def measure_diversity(data: list) -> float:
    """
    用词汇多样性粗略衡量数据集的多样性。
    返回值越接近1,多样性越高。
    """
    # 统计所有 instruction 中出现的词
    all_words = []
    for item in data:
        words = item.get('instruction', '').replace(',', ' ').replace('。', ' ').split()
        all_words.extend(words)

    total_words = len(all_words)
    unique_words = len(set(all_words))

    diversity_ratio = unique_words / total_words if total_words > 0 else 0
    print(f"词汇多样性: {diversity_ratio:.3f} (总词数{total_words}, 不重复词数{unique_words})")

    if diversity_ratio > 0.5:
        print("  -> 多样性良好")
    elif diversity_ratio > 0.3:
        print("  -> 多样性一般,建议增加更多覆盖角度")
    else:
        print("  -> 多样性较差,数据集过于单一")

    return diversity_ratio


### 9.2. 指标2:长度分布(Length Distribution)

理想的数据集长度分布应接近正态分布,而不是两极分化:

def check_length_distribution(data: list):
    """检查输出长度是否分布均匀。"""
    lengths = [len(d.get('output', '')) for d in data]

    mean = statistics.mean(lengths)
    std = statistics.stdev(lengths) if len(lengths) > 1 else 0

    # 变异系数(Coefficient of Variation)衡量分布均匀程度
    # CV < 0.5 表示分布较均匀,CV > 1 表示分布非常不均匀
    cv = std / mean if mean > 0 else 0

    print(f"长度分布: 均值={mean:.0f}, 标准差={std:.0f}, 变异系数={cv:.2f}")
    if cv < 0.5:
        print("  -> 长度分布均匀,良好")
    elif cv < 1.0:
        print("  -> 长度分布有些不均匀,可接受")
    else:
        print("  -> 长度分布非常不均匀,建议检查是否有数据生成异常")

9.3. 指标3:格式一致性(Format Consistency)

如果你的训练数据要求特定格式(如 JSON 输出、带编号的列表等),验证一致性:

python
def check_format_consistency(data: list, expected_pattern: str = None) -> float:
    """
    检查数据集中有多少条符合预期格式。

    Args:
        expected_pattern: 正则表达式,如 r'^\d+\.' 检查是否以数字开头

    Returns:
        符合格式的比例(0-1)
    """
    if not expected_pattern:
        print("未指定格式要求,跳过格式一致性检查")
        return 1.0

    pattern = re.compile(expected_pattern)
    consistent = sum(1 for d in data if pattern.search(d.get('output', '')))
    ratio = consistent / len(data)

    print(f"格式一致性: {ratio:.1%} ({consistent}/{len(data)} 条符合格式要求)")
    return ratio


# 综合评估示例
print("\n=== 综合质量评估 ===")
with open("training_data_clean.json", "r", encoding="utf-8") as f:
    clean_data = json.load(f)

diversity = measure_diversity(clean_data)
check_length_distribution(clean_data)
# 如果你的输出要求以序号开头,可以这样检查:
# check_format_consistency(clean_data, expected_pattern=r'^\d+[\.\、]')

10. 完整流程整合

以下是从零开始准备一批训练数据的完整脚本:

python
import json
import time
from openai import OpenAI
import statistics

client = OpenAI()

# 第1步:生成原始数据
print("步骤1:生成原始训练数据...")
raw_data = []
topics = [
    "Python装饰器的使用场景和最佳实践",
    "Python异常处理与错误调试",
    "Python列表推导式和生成器表达式",
]

for topic in topics:
    batch = generate_training_data(topic, n_examples=20)
    raw_data.extend(batch)
    time.sleep(2)

print(f"原始数据: {len(raw_data)} 条")

# 第2步:数据清洗
print("\n步骤2:数据清洗...")
cleaned = clean_dataset(raw_data, min_output_length=50, max_output_length=2000)

# 第3步:质量评估
print("\n步骤3:质量评估...")
measure_diversity(cleaned)
check_length_distribution(cleaned)

# 第4步:保存最终数据集
output_path = "training_data_final.json"
with open(output_path, "w", encoding="utf-8") as f:
    json.dump(cleaned, f, ensure_ascii=False, indent=2)

print(f"\n最终数据集: {len(cleaned)} 条,已保存到 {output_path}")
print(f"下一步:用这份数据集运行 QLoRA 微调(见下一章)")

11. 小结

好的微调数据集需要做好五件事:

  1. 格式正确:选对 Alpaca 格式还是 Chat 格式(看任务类型)
  2. Instruction 质量高:具体、有角色定义、有格式约束(这是最容易被忽视的)
  3. 数量适当:先用100-200条验证方向,确认有效再扩充
  4. 清洗彻底:移除空数据、过短数据、重复数据
  5. 多维度评估:多样性、长度分布、格式一致性都要检查

数据准备占微调工作量的60-70%,但也是影响最终效果的最大变量。在这一步投入时间是值得的。

下一章我们将用这份准备好的数据集进行 QLoRA 微调训练。

本页目录