外观
微调你自己的 LLM
微调(Fine-tuning)是在一个预训练大模型的基础上,用你自己的数据继续训练,让模型"学会"你的业务语言、输出格式与行为偏好。 配合 LoRA(Low-Rank Adaptation) 这类参数高效微调技术,这件事在今天已经不再是少数大厂的专利:一张 8GB 显存的消费级显卡、一份几千到几万条的高质量指令数据、一个下午的时间,你就能把 Qwen 或 Llama 调教成懂你业务的小助手。
本文不重复微调的理论推导,而是回答三个实战问题:你的场景到底该不该微调?显存和软件环境怎么准备?从数据到部署的完整流程长什么样? 全文是一份可以照抄的操作手册,从数据准备、LoRA 训练、合并导出到推理验证,每一步都配有可运行代码。微调背后的原理(为什么 LoRA 有效、低秩近似是怎么回事)见微调与 PEFT(LoRA),本文聚焦"怎么把它跑起来"。
前置知识:建议先了解大语言模型(LLM)的基础概念,并亲手跑过一次提示词工程与 RAG 应用。文中的每个环节在站内都有对应的深度文章,随时给出链接。
一、先做决策:你的场景值不值得微调
1. 一句话判断
先用提示词,再用 RAG,最后才考虑微调。 微调不是"更高级",而是"更昂贵"——它需要数据、算力、迭代时间,且每次改动都要重训。绝大多数业务问题在提示词和 RAG 阶段就已经解决了。
| 维度 | 提示词工程 | RAG | 微调(LoRA) |
|---|---|---|---|
| 改动成本 | 几分钟,改 Prompt 即可 | 改检索库与索引 | 数小时到数天,重训模型 |
| 需要的数据 | 少量示例(few-shot) | 文档库 | 千条级高质量标注数据 |
| 知识时效性 | 好 | 最好(即改即生效) | 差(训练时固化) |
| 深度领域能力 | 弱 | 中等 | 强 |
| 私有知识 | 依赖提示词注入 | 最适合 | 可固化,但易过时 |
| 输出格式/风格控制 | 中等 | 弱 | 强 |
| 部署成本 | 最低 | 需检索栈 | 模型与显存开销变大 |
| 典型场景 | 通用助手、临时需求 | 客服知识库、企业问答 | 领域语言、固定格式输出 |
值得微调的四个信号:
- 模型对领域术语、行话、专有名词的理解明显不对,而 RAG 检索到的文档无法"教会"它(例如医疗、法律、特定行业的黑话);
- 你需要稳定且固定的输出格式(特定 JSON schema、特定风格的回复),Prompt 经常跑偏;
- 你要在离线 / 本地 / 内网部署,不能每次请求都携带超长上下文;
- 推理成本敏感:与其每条请求塞 2 万 token 上下文,不如把高频知识直接微调进权重。
该踩刹车的情况:
- 知识会频繁更新 → 用 RAG 而不是微调;
- 数据不足或质量存疑(拿不出 500 条以上高质量样本)→ 先打磨提示词;
- 没有验证集和评估手段 → 先读搭建一套 LLM 评估,否则微调完你无法判断好坏。
2. 基座模型怎么选
基座模型选错,后面全部白费。选择看三个维度:中文 vs 英文、模型规模 vs 显存、指令模型 vs 基座模型。各模型参数规模与榜单数据见模型与榜单速查。
| 模型 | 规模 | 特点 | 适合场景 |
|---|---|---|---|
| Qwen2.5-7B-Instruct | 7B | 中文强、指令遵循好、生态成熟 | 中文业务、通用微调入门 |
| Llama-3.1-8B-Instruct | 8B | 英文强、社区生态最丰富 | 英文任务、工具调用 |
| Mistral-7B-Instruct | 7B | 推理高效、显存友好 | 英文、资源紧张 |
| Qwen2.5-14B / Llama-3.1-13B | 14B / 13B | 更强但更吃显存 | 数据量大、效果优先 |
| Qwen2.5-3B / Llama-3.2-3B | 3B | 极小显存即可跑 | 教学、边缘设备 |
三条经验判断:
- 中文业务优先 Qwen,英文通用优先 Llama,这是社区反复验证的经验,具体对比数据见模型与榜单速查;
- 从 7B / 8B 起步:在消费级 GPU 上 7B 是性价比甜点,13B 以上显存和训练时间会陡增;
- 选"指令模型"而非基座模型:
-Instruct/-Chat版本已经过对齐(RLHF/DPO),微调后更听话;直接微调 base 模型需要你自己补足对话能力,一般不建议。
二、环境准备:显存账本与依赖
1. 显存需求表(经验值)
微调显存由四部分组成:模型权重 + 梯度 + 优化器状态 + 激活值。全参数微调(FFT)要同时维护这三份完整状态,显存需求通常是 QLoRA 的 5-10 倍。下表为经验值(单位 GB),实际随 max_seq_len、batch_size 浮动:
| 模型规模 | 全参数微调(BF16) | QLoRA(4-bit + LoRA) | 建议 GPU |
|---|---|---|---|
| 2B / 3B | 约 18 GB | 约 3-4 GB | 6-8 GB 即可 |
| 7B / 8B | 约 60-70 GB(需 A100/H100 级) | 约 7-9 GB | RTX 4070 / 3090 |
| 13B / 14B | 约 120-140 GB(多卡) | 约 12-15 GB | RTX 4090 |
| 70B | 多机多卡 | 约 35-45 GB | A100 80G / 多卡 |
结论很明确:消费级 GPU 上 QLoRA 是唯一现实选择。QLoRA 把 4-bit 量化(NF4)与 LoRA 结合——基座权重被压缩到原来的 1/4 且全程冻结,可训练参数只占全部参数的 0.1%-1%。量化原理见推理优化与量化。
显存不够怎么办?
依次拧三个旋钮:max_seq_length 从 2048 降到 1024 → per_device_train_batch_size 降为 1 并用 gradient_accumulation_steps 补回等效批大小 → LoRA 的 r 从 16 降到 8。其中"batch=1 + 梯度累积"在效果上几乎无损,是最优先的手段。
2. 安装依赖
bash
# 推荐 Python 3.10+,建议先创建独立环境
conda create -n ft python=3.10 -y && conda activate ft
pip install "transformers>=4.43" "peft>=0.11" "trl>=0.9" \
"datasets>=2.19" "bitsandbytes>=0.43" "accelerate>=0.32"| 包 | 职责 |
|---|---|
| transformers | 模型与 tokenizer 加载、训练核心 API |
| peft | LoRA 配置与模型包装(LoraConfig / get_peft_model) |
| trl | SFTTrainer、DPOTrainer 等高级训练器 |
| datasets | 数据集加载与预处理 |
| bitsandbytes | 4-bit / 8-bit 量化底层库(QLoRA 必需) |
| accelerate | 分布式与混合精度训练基础设施 |
Linux + NVIDIA 驱动是官方支持最好的组合;Windows 上 bitsandbytes 从 0.43 起也提供官方支持,但推荐 WSL2。Mac(MPS)不支持 4-bit 训练,可改用 8-bit 或小模型。
三、数据准备:微调成功率的 80%
业界流传一句话:LoRA 微调的瓶颈从来不是算力,而是数据。一份高质量指令数据 > 三份低质量数据。
1. 指令数据集格式
微调的本质是"教模型学会输入 → 输出的映射"。最通用的格式是 Alpaca 风格三元组:
json
[
{
"instruction": "请用一句话解释什么是向量数据库",
"input": "",
"output": "向量数据库是一种以向量索引为核心、专门用于存储和检索高维向量的数据库,通常配合嵌入模型用于语义检索和 RAG 场景。"
},
{
"instruction": "把下面的产品描述改写成适合电商平台的 20 字以内广告语",
"input": "这是一款支持无线充电、IP68 防水、续航 7 天的智能手表",
"output": "七天续航,无线快充,陪你上山下海。"
}
]instruction:任务描述;input:任务输入(可为空);output:期望的模型回答。
训练前需要把它拼成带角色标记的完整对话文本(ChatML 格式,Qwen 官方训练格式):
python
from datasets import load_dataset
def format_example(example):
user = example["instruction"]
if example.get("input"):
user += "\n" + example["input"]
return {
"text": (
f"<|im_start|>user\n{user}<|im_end|>\n"
f"<|im_start|>assistant\n{example['output']}<|im_end|>\n"
)
}
ds = load_dataset("json", data_files="data.jsonl", split="train")
ds = ds.map(format_example, remove_columns=ds.column_names)
print(ds[0]["text"]) # 训练前务必打印一条,逐字符检查模板2. 公开数据集起步
不想从零造数据?直接复用社区公开数据集,完整清单见数据集与工具档案:
| 数据集 | 规模 | 特点 | 适用 |
|---|---|---|---|
| Alpaca(stanford_alpaca) | 52k | 指令微调的"祖师爷",英文通用 | 通用能力增强 |
| alpaca-cleaned / 中文版 | 52k | 清洗版、中文翻译版 | 中文通用微调 |
| ShareGPT | 90k+ | 真实多轮对话 | 对话风格学习 |
| OpenOrca / SlimOrca | 500k+ | 质量较高的英文指令 | 大规模通用微调 |
| 自定义业务数据 | 几百到几万 | 你的领域 | 领域微调 |
关键提醒:公开数据与业务数据要混合使用,比例通常在"通用 : 业务 = 3:1 到 1:1"。纯业务数据微调会快速过拟合并破坏通用能力(见本文常见坑一节)。
3. 数据清洗的六个要点
- 去重:重复样本会让模型"背高频内容"而不是学会泛化,用哈希或 embedding 相似度去重;
- 长度过滤:过滤过短(< 10 token)和过长(超过
max_seq_length80%)的样本; - 格式一致性:所有样本字段语义必须统一(如
input是空字符串还是 null,只选一种),否则模型学到"时灵时不灵"; - 答案质量审查:指令数据最常见的缺陷是答案本身错误——抽 100 条人工过一遍,错误率超过 5% 就回去改数据;
- 隐私与敏感信息:训练数据会"住进"模型权重,PII(手机号、身份证)要么脱敏要么剔除;
- 分布覆盖:检查业务场景是否全覆盖,尤其要包含边界 case(歧义输入、超长输入、特殊字符)。
四、分步实现:从加载到部署的五个步骤
下面用一个端到端示例串起完整流程:用 Qwen2.5-7B-Instruct + LoRA,在消费级 GPU(约 8GB 显存)上微调一个"懂向量数据库知识"的助手。
步骤 1:加载模型与 tokenizer(4-bit QLoRA 配置)
python
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
model_id = "Qwen/Qwen2.5-7B-Instruct"
# 4-bit NF4 量化配置(QLoRA 的核心)
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4", # 4-bit NormalFloat
bnb_4bit_use_double_quant=True, # 二次量化,再省约 0.4 bits/参数
bnb_4bit_compute_dtype=torch.bfloat16,
)
tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
# 部分中文模型需要显式设置 pad token
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained(
model_id,
quantization_config=bnb_config,
device_map="auto", # 自动分配显存/CPU
trust_remote_code=True,
)
model.config.use_cache = False # 训练阶段关闭 KV cache,省显存要点:
bnb_4bit_compute_dtype=torch.bfloat16让计算发生在 bf16,既省显存又保留精度,是 QLoRA 默认推荐;device_map="auto"会把层分配到 GPU,放不下的层落到 CPU(会很慢,尽量调小模型或序列长度)。量化与推理优化的完整讨论见推理优化与量化。
步骤 2:LoRA 配置与 PEFT 包装
LoRA 的核心思想:冻结原权重,只训练注入的低秩矩阵,训练后再把增量合并回去。原理见微调与 PEFT(LoRA)。
python
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
# QLoRA 要求:先把量化模型权重转为可训练布局
model = prepare_model_for_kbit_training(model)
lora_config = LoraConfig(
r=16, # 低秩矩阵的秩:越大表达能力越强、显存越多
lora_alpha=32, # 缩放系数,通常取 r 的 1-2 倍
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM",
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"], # 注意力 + FFN 全部注入
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# 输出形如:trainable params: 21,626,880 || all params: 7,683,094,528 || trainable%: 0.2815参数速查:
| 参数 | 含义 | 建议 |
|---|---|---|
r | 低秩秩,LoRA 注入矩阵的宽度 | 8(小数据/省显存)到 64(大数据) |
lora_alpha | 缩放系数,实际缩放比为 alpha / r | 常取 2 × r,不必精调 |
lora_dropout | 注入层的 dropout | 0.05-0.1 |
target_modules | 对哪些线性层注入 LoRA | 默认 q/k/v/o;加上 FFN 层效果更好 |
步骤 3:训练(trl SFTTrainer)
python
from trl import SFTTrainer, SFTConfig
training_args = SFTConfig(
output_dir="./qwen2.5-7b-lora",
per_device_train_batch_size=1,
gradient_accumulation_steps=16, # 等效 batch size = 1 × 16 = 16
learning_rate=2e-4, # LoRA 常用 1e-4 ~ 5e-4
num_train_epochs=3,
lr_scheduler_type="cosine",
warmup_ratio=0.03,
optim="paged_adamw_8bit", # 8-bit 优化器,进一步省显存
logging_steps=10,
save_steps=200,
save_total_limit=3,
max_seq_length=1024, # 训练序列最大长度
bf16=True, # 有 Ampere 及以上 GPU 时用 bf16
report_to="none",
)
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=ds,
processing_class=tokenizer, # trl >= 0.12 的写法;旧版为 tokenizer=tokenizer
)
trainer.train()
trainer.save_model("./qwen2.5-7b-lora/final") # 只保存 LoRA 适配器超参速查表(经验值):
| 超参 | 含义 | 经验范围 | 说明 |
|---|---|---|---|
learning_rate | 学习率 | 1e-4 ~ 5e-4(LoRA) | 全参数微调用 1e-5 量级,LoRA 可以更激进 |
num_train_epochs | 训练轮数 | 1-3 | 小数据(< 5k)跑 3 轮,大数据 1-2 轮 |
per_device_train_batch_size | 单卡批大小 | 1-4 | 受显存限制,通常取 1 |
gradient_accumulation_steps | 梯度累积步数 | 8-32 | 等效 batch = batch_size × 累积步数 |
max_seq_length | 序列长度 | 512-2048 | 决定激活值显存,够用即可 |
warmup_ratio | 预热比例 | 0.03-0.1 | 稳定训练前期 |
三个训练纪律
- 盯住训练 loss 曲线:理想情况是平滑下降并在 1-3 轮内稳定;loss 不降先查学习率(过大震荡、过小不降)。
- 别追求 train loss 归零:归零 = 过拟合,模型把训练数据背下来了。
- 定期保存 checkpoint:
save_steps每次保存,训练崩溃不用从头再来。
步骤 4:合并与导出
LoRA 训练的产物是一套几十 MB 的 adapter 文件,推理时要合并回基座模型,或直接用 peft 的适配器加载。导出为标准模型:
python
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
base_model_id = "Qwen/Qwen2.5-7B-Instruct"
adapter_path = "./qwen2.5-7b-lora/final"
export_path = "./qwen2.5-7b-merged"
# 用 BF16 重新加载基座(不量化),再挂上 LoRA 适配器
base = AutoModelForCausalLM.from_pretrained(
base_model_id, torch_dtype=torch.bfloat16, device_map="auto",
)
model = PeftModel.from_pretrained(base, adapter_path)
model = model.merge_and_unload() # 把 LoRA 增量合并进权重
model.save_pretrained(export_path)
AutoTokenizer.from_pretrained(base_model_id).save_pretrained(export_path)
print("merged model saved to", export_path)合并后的模型可直接用 AutoModelForCausalLM.from_pretrained(export_path) 加载。生产部署与推理优化(量化、vLLM、并发控制)见部署与推理优化实战。
步骤 5:推理验证——微调前后对比
训练完成后的第一件事:拿训练时没见过的样本,对比微调前后模型的回答。
python
def chat(model, tokenizer, prompt, max_new_tokens=128):
messages = [{"role": "user", "content": prompt}]
text = tokenizer.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True
)
inputs = tokenizer(text, return_tensors="pt").to(model.device)
out = model.generate(**inputs, max_new_tokens=max_new_tokens, do_sample=False)
return tokenizer.decode(out[0][inputs["input_ids"].shape[1]:],
skip_special_tokens=True)
# 微调后的模型
finetuned = AutoModelForCausalLM.from_pretrained(
export_path, torch_dtype=torch.bfloat16, device_map="auto"
)
# 微调前的基座(用于对比)
base = AutoModelForCausalLM.from_pretrained(
"Qwen/Qwen2.5-7B-Instruct", torch_dtype=torch.bfloat16, device_map="auto"
)
test_prompt = "用一句话向产品经理解释 HNSW 索引"
print("微调前:", chat(base, tokenizer, test_prompt))
print("微调后:", chat(finetuned, tokenizer, test_prompt))一份典型的对比输出:
微调前: HNSW 索引是一种基于图的近似最近邻搜索算法,在高维空间中构建分层图结构,通过贪心搜索找到最近邻居。
微调后: HNSW 是一种"跳表 + 图"的分层小世界网络索引,专门解决高维向量的最近邻检索。对产品经理来说记住三点:查询快(毫秒级)、内存可控、支持增量插入。注意微调后的变化:更短的句子、更贴合内部口径的类比、稳定的"小结句式"——这正是"学会了你的数据分布"的表现。如果两者差别不大,问题几乎一定出在数据上,而不是训练上。
五、评估迭代:别用"感觉"验收微调
1. 建立验证集
从数据集中抽出 10%-20% 永不参与训练的样本作为验证集(或专门构造 30-100 条"考试题")。训练中每几个 epoch 在验证集上跑一次推理,用搭建一套 LLM 评估里的指标打分。如果训练集指标上涨、验证集不动甚至下降,就是过拟合——此时停训、减 epochs、降学习率。
2. 人工抽检是最低要求
自动指标(loss、BLEU)对开放式回答的感知有限,每次迭代至少人工看 20-50 条真实输出,对照检查三类问题:
- 幻觉:模型是否编造了训练数据里没有的"事实";
- 风格漂移:是否把内部腔调带偏(如训练数据大量英文、线上却要求中文输出);
- 边界行为:面对训练分布之外的输入(脏话、超长问题、空输入)是否失控。
3. 与评估体系对接
微调不是"训完就完",而是评估循环中的一个环节。把微调后的模型接入你的评估体系,与基座模型或上一个版本在黄金数据集上做 A/B 对比,用数据而不是印象决定是否上线。评估指标的选择、LLM-as-judge 的用法见LLM 评估与基准。
六、常见坑:一张表排查
| 坑 | 症状 | 原因 | 排查 / 修复 |
|---|---|---|---|
| 数据格式错误 | 训练正常但生成乱码、重复"assistant"标记 | ChatML 模板与 tokenizer 不匹配、丢了 `< | im_end |
| 过拟合小数据 | 训练 loss 低但验证集差、回答像"背课文" | 数据少(< 1k)、epochs 多、r 过大 | 减少 epochs、混合通用数据、数据增强 |
| 灾难性遗忘 | 通用能力下降(数学、代码变笨) | 纯业务数据微调、原有知识被覆盖 | 按 3:1 混入通用数据;做多任务混合训练 |
| 中文分词问题 | 中文回答断句奇怪、丢字 | tokenizer 缺 pad token、序列被截断 | 显式设置 pad_token = eos_token;检查 max_seq_length |
| 显存 OOM | 训练中途崩溃 | 序列过长 / batch 过大 | 降 max_seq_length、batch=1 + 梯度累积、r 降到 8 |
| 量化加载失败 | bitsandbytes 报错 | 驱动 / CUDA 版本不匹配 | pip install -U bitsandbytes,检查 nvidia-smi |
| 训练 loss 不降 | 从一开始就震荡 | 学习率过大 | lr 降到 5e-5 重试 |
一句话总纲:微调出现任何问题,先怀疑数据,再怀疑训练配置,最后才怀疑代码。更全面的训练与部署陷阱清单见常见陷阱与反模式。
七、进阶:DPO 与多轮对话
1. DPO:用偏好数据让模型"更讨喜"
SFT 只能教会模型"正确回答",学不会"哪种回答更好"。DPO(Direct Preference Optimization) 不需要训练奖励模型,直接用"好回答 vs 坏回答"的对比数据优化策略,是对齐的一线方法,原理见对齐:RLHF 与 DPO。
python
from trl import DPOConfig, DPOTrainer
dpo_config = DPOConfig(
output_dir="./qwen2.5-7b-dpo",
per_device_train_batch_size=1,
gradient_accumulation_steps=8,
learning_rate=1e-6, # DPO 通常用更小的学习率
num_train_epochs=1,
bf16=True,
beta=0.1, # DPO 温度系数,控制对偏好的跟随强度
)
dpo_trainer = DPOTrainer(
model=model, # 可复用 SFT 后的 LoRA 模型
args=dpo_config,
train_dataset=dpo_ds, # 每样本三字段:{prompt, chosen, rejected}
processing_class=tokenizer,
)
dpo_trainer.train()dpo_ds 的每条样本包含三个字段:prompt(用户问题)、chosen(更优回答)、rejected(较差回答)。偏好数据可以从人工标注、用户反馈(点赞/点踩)、或两个模型的对比输出中积累——后者的采集链路见搭建一套 LLM 评估的生产评估一节。
SFT → DPO 是标准组合拳:先用 SFT 把模型拉到领域,再用 DPO 精调风格与偏好。预算或时间有限时,先只做 SFT。
2. 多轮对话微调
单轮指令数据训练出的模型会"忘记"历史。多轮对话微调用 ShareGPT 格式,每条样本是完整对话历史:
json
{
"conversations": [
{"from": "human", "value": "帮我推荐一款适合跑马拉松的耳机"},
{"from": "gpt", "value": "考虑佩戴稳固性和续航,推荐 XX 骨传导耳机,续航 10 小时。"},
{"from": "human", "value": "预算 500 以内呢?"},
{"from": "gpt", "value": "那推荐 YY,同样骨传导,续航 8 小时,399 元。"}
]
}多轮样本的构造要点:保留完整历史,让模型学会"在上下文中理解指代";同时保留一部分"从中间截断"的样本,模拟真实对话被切掉开头的情况。对话格式与模板的底层原理见大语言模型(LLM)。
八、延伸阅读
- 微调与 PEFT(LoRA) —— 本文的技术理论篇:低秩近似的原理、不同 PEFT 方法对比
- 提示词工程 —— 微调之前先试的手段,两者常配合使用
- 检索增强生成(RAG) —— "该微调还是该 RAG"决策的另一半
- 推理优化与量化 —— QLoRA 的量化原理与部署时的推理优化
- 搭建一套 LLM 评估 —— 微调后的验收工具,本文第五节的对接入口
- LLM 评估与基准 —— 评估指标与基准的完整体系
- 对齐:RLHF 与 DPO —— 第七节 DPO 的完整理论
- 部署与推理优化实战 —— 微调完之后怎么上线
- 常见陷阱与反模式 —— 训练与部署陷阱大全
- 模型与榜单速查 —— 基座模型选择的依据
- 数据集与工具档案 —— 微调数据集的来源
- 大语言模型(LLM) —— 微调之前先建立的模型认知
参考资料
- Hu et al. LoRA: Low-Rank Adaptation of Large Language Models (ICLR 2022) —— LoRA 原始论文,本文所有 LoRA 配置的出处
- Dettmers et al. QLoRA: Efficient Finetuning of Quantized LLMs (NeurIPS 2023) —— QLoRA 原始论文:NF4 量化、double quant、paged optimizer
- Hugging Face PEFT 文档 —— LoraConfig、get_peft_model、merge_and_unload 的官方 API 说明
- Hugging Face TRL 文档 —— SFTTrainer / DPOTrainer 的官方文档
- bitsandbytes 官方仓库 —— 4-bit 量化底层库
- Stanford Alpaca 项目 —— 52k 指令数据集的源头
- ShareGPT 数据集(Hugging Face) —— 多轮对话微调常用数据
- Rafailov et al. Direct Preference Optimization (NeurIPS 2023) —— DPO 原始论文
- OpenAI Fine-tuning 指南 —— 走托管 API 微调的可选路径(不想自己管理 GPU 时)
- Qwen 官方微调文档 —— 本文示例模型 Qwen 的官方训练指南
建议顺序:先跑通步骤 1-5 的最小示例(哪怕数据只有 100 条)→ 用真实业务数据替换 → 在验证集上人工抽检迭代 2-3 轮 → 用评估体系验收 → 再考虑 DPO 精调。