generative-ai-for-beginners 第 18 课实战:如何微调(Fine-Tuning)大语言模型——从训练数据准备到模型验证
本篇技术指南基于 generative-ai-for-beginners 课程第 18 课(保加利亚语版课本文档,其英文原文为 18-fine-tuning/README.md),系统讲解大语言模型微调(fine-tuning)的核心概念、决策时机与完整操作流程。读完本文,你将能够回答"什么是模型微调""何时该选择微调而不是提示工程""微调一个预训练模型需要哪些要素"等问题,并能按照仓库自带的 Jupyter Notebook 与训练数据样例,独立走通"准备 JSONL 数据集 → 上传 → 创建微调任务 → 跟踪任务 → 验证微调后模型"的完整实战链路。
课程定位与学习目标
大型语言模型(LLM)的定义特征是:它们在来自互联网等多样来源的海量文本上**预先训练(pre-trained)**而来。课程前面的章节已经介绍过两类改善模型回答质量的技术:
- 提示工程(prompt engineering):通过修改输入提示本身来引导模型;
- 检索增强生成(RAG):在提示中注入从自有数据中检索到的上下文。
这两类技术的共同点是只改提示、不改模型。而第 18 课讨论的是第三种技术——微调(fine-tuning):用额外数据重新训练模型本身,从根本上提升其在特定任务或领域上的表现。
本课的学习目标(即读完应能回答的问题)是:
- 什么是语言模型的微调?
- 什么时候、以及为什么微调是有用的?
- 如何微调一个预训练模型?
- 微调的局限性是什么?
微调的定义:从 few-shot 学习的瓶颈说起
在提示工程中最流行的一族技术是:给模型更多"回答应该是什么样"的指引,方式有二:
- 提供指令(instructions)——显式指引;
- 给出若干示例(a few examples)——隐式指引。
这种做法被称为 few-shot 学习,但它存在两个固有局限:
- token 上限约束:模型的上下文窗口限制了你能塞进多少个示例,直接限制了 few-shot 的效果上限;
- token 成本约束:每次请求都要重复携带示例,token 开销大,也限制了提示设计的灵活性。
微调正是对这两个瓶颈的回应。微调是机器学习系统中的常见做法:拿一个预训练模型,用新数据继续训练,以提升其在特定任务上的表现。在语言模型场景下,你可以用为某个任务或应用领域精心策划的示例集去微调预训练模型,得到一个定制化模型(custom model)——它在目标任务/领域上往往更准确、更相关。一个附带收益是:微调后 few-shot 所需的示例数量会下降,从而减少推理时的 token 使用量与相关成本。
注意术语边界:本课所讨论的微调是监督微调(supervised fine-tuning),即通过加入原本不在初始训练集中的新数据来重新训练;这与无监督微调不同——后者是在原始数据上、以不同超参数重新训练模型。
何时、以及为何要微调:一份决策检查清单
在动手之前必须记住:微调是一项进阶技术,需要一定水平的专业能力才能拿到理想结果。如果操作不当,它不仅可能达不到预期改进,甚至可能让模型在目标领域上的表现退化。
因此,在学"如何"微调之前,先要回答"为什么"要走这条路、"何时"启动微调流程。课文档给出的自检问题如下:
- 用例(Use Case):你的微调用例是什么?你想改善当前预训练模型的哪方面表现?
- 替代方案(Alternatives):你是否试过其他技术来达到同样效果?把它们作为对比基线。
- 提示工程:尝试 few-shot 提示(附带相关回答示例),评估回答质量;
- 检索增强生成:尝试用自有数据的检索结果来增强提示,评估回答质量。
- 成本(Costs):你是否识别了微调的完整成本?
- 可微调性(Tunability)——目标预训练模型是否开放微调;
- 工作量(Effort)——准备训练数据、评估与迭代模型所需投入;
- 算力(Compute)——运行微调任务与部署微调后模型的算力;
- 数据(Data)——是否有足够数量的高质量示例来支撑微调效果。
- 收益(Benefits):你是否确认了微调收益?
- 质量——微调后模型是否超过基线;
- 成本——是否通过简化提示降低了 token 用量;
- 可扩展性——能否把基座模型复用到新的领域。
回答完这些问题后,你才能判断微调是否是用例的正确方案。理想情况下,只有当收益超过成本时,微调才成立。
微调一个预训练模型需要什么
课文档明确指出,微调一个预训练模型需要准备四个要素:
- 一个可供微调的预训练模型;
- 一套用于微调的数据集;
- 一个运行微调任务的训练环境;
- 一个部署微调后模型的托管环境。
这四个要素恰好对应仓库自带实战 Notebook 的四个工作阶段,下一节将逐一展开。
实战:仓库内置的 OpenAI 微调完整链路
仓库在 18-fine-tuning/python/openai/oai-assignment.ipynb(保加利亚语翻译版见 translations/bg/18-fine-tuning/python/openai/oai-assignment.ipynb)提供了一个端到端的微调示例:训练一个用五句诗(limerick)回答元素周期表问题的聊天机器人 "Elle"。注意:仓库版本中的 Notebook 仅作为参考资料复现,课程方建议以官方原始教程为准获取最新版本。
步骤一:准备并格式化训练数据
实战场景是单轮对话(chat completion),训练数据采用 JSONL 格式(每行一条 JSON 记录),并且每条记录必须定义在单独一行内,不能像普通格式化 JSON 那样跨行展开。仓库自带的样例数据 18-fine-tuning/python/openai/training-data.jsonl 包含 10 条示例,前两条记录的真实内容如下:
{ "messages": [{"role": "system", "content": "Elle is a factual chatbot that answers questions about elements in the periodic table with a limerick"}, {"role": "user", "content": "Tell me about Gallium"}, {"role": "assistant", "content": "Gallium, oh gallium, so light - Melts in your hand, oh what a sight - At 86 degrees - Its liquid with ease - And in semiconductors, it's out of sight"}]}
{ "messages": [{"role": "system", "content": "Elle is a factual chatbot that answers questions about elements in the periodic table with a limerick"}, {"role": "user", "content": "Tell me about Hydrogen"}, {"role": "assistant", "content": "Hydrogen, the first in the line - The lightest of all, so divine - It's in water, you see - And in stars, it's the key - The universe's most common sign"}]}
从样例数据结构可以看出三条要点:
- 每条记录是
messages数组,包含system(角色设定)、user(提问)、assistant(期望回答)三类消息; system消息承载"目标行为"(Elle 用五句诗回答元素问题),微调正是在学习这种格式与风格的映射;- 真实场景中需要远多于 10 条的示例,示例数量与响应质量、微调耗时/成本之间存在权衡——本例刻意用小数据集以便快速跑通流程。
如果预期是多轮对话内容,Notebook 提示应改用官方多轮示例格式,其中带有 weight 参数,用来标记哪些消息应(或不)参与微调。此外,微调一个之前已经微调过的模型也是允许的,即支持迭代式改进。
步骤二:上传数据集
运行上传代码的前置条件(来自 Notebook 说明):
- 已安装
openaiPython 包,且版本 >= 0.28.0 以使用最新 API; - 已设置环境变量
OPENAI_API_KEY(本地环境的完整配置步骤参见课程 00-course-setup/02-setup-local.md)。
上传使用 Files API,代码与仓库 Notebook 完全一致:
from openai import OpenAI
client = OpenAI()
ft_file = client.files.create(
file=open("./training-data.jsonl", "rb"),
purpose="fine-tune"
)
print(ft_file)
print("Training File ID: " + ft_file.id)
关键参数是 purpose="fine-tune",它向服务端声明该文件的用途,服务端会随后对文件格式做校验。
步骤三:创建微调任务并跟踪状态
上传完成后,用 SDK 创建微调任务:
from openai import OpenAI
client = OpenAI()
ft_filejob = client.fine_tuning.jobs.create(
training_file=ft_file.id,
model="gpt-3.5-turbo"
)
print(ft_filejob)
print("Fine-tuning Job ID: " + ft_filejob.id)
重要前提说明:仓库文档与 Notebook 均注明,部分旧教程中引用的
gpt-35-turbo/gpt-3.5-turbo已同时停止推理与微调支持。如果今天启动新的微调任务,应改为当前受支持的模型(文档给出的示例是gpt-4o-mini或gpt-4.1-mini),以提供方公布的"可微调模型列表"为准。教程中的概念与步骤流程仍然适用。
任务创建后的监控手段(client.fine_tuning.jobs API 提供):
jobs.list(limit=<n>)—— 列出最近 n 个微调任务;jobs.retrieve(<job_id>)—— 获取指定任务详情;jobs.cancel(<job_id>)—— 取消任务;jobs.list_events(fine_tuning_job_id=<job_id>, limit=<n>)—— 列出任务事件。
流程的第一步是校验训练文件,确认数据格式正确;之后可轮询任务状态与已训练 token 数:
response = client.fine_tuning.jobs.retrieve(ft_filejob.id)
print("Job ID:", response.id)
print("Status:", response.status)
print("Trained Tokens:", response.trained_tokens)
也可以以事件粒度跟踪进度,刷新到出现 The job has successfully completed 消息为止:
response = client.fine_tuning.jobs.list_events(ft_filejob.id)
events = response.data
events.reverse()
for event in events:
print(event.message)
Notebook 中附带的控制台截图记录了一个真实的排障过程:第一次运行因 JSON 文件格式不正确而失败,修复记录格式后第二次运行成功,模型随之可用。这个细节印证了课文档的判断——训练数据格式错误是微调最常见的失败原因,也是"校验训练文件"这一步存在的意义。
步骤四:获取模型 ID 并验证微调效果
任务成功后,从任务对象中提取微调后模型的 ID:
response = client.fine_tuning.jobs.retrieve(ft_filejob.id)
fine_tuned_model_id = response.fine_tuned_model
print("Fine-tuned Model ID:", fine_tuned_model_id)
随后即可用该 ID 直接发起推理请求:
completion = client.responses.create(
model=fine_tuned_model_id,
input=[
{"role": "system", "content": "You are Elle, a factual chatbot that answers questions about elements in the periodic table with a limerick"},
{"role": "user", "content": "Tell me about Strontium"},
],
store=False,
)
print(completion.output_text)
验证的另一个入口是控制台的 Playground:在 Models 下拉框中选择新微调的模型,或使用 Fine-tuning 面板中的 "Playground" 入口打开对比视图——基座模型与微调模型并排展示,对同一 system 上下文与提问给出各自的输出、token 数与推理耗时,便于快速评估差异。
Notebook 对验证结果有一个清醒的提醒:本例是演示流程的玩具案例,两个模型的输入 token 相同(system 与 user 提示一致),微调模型反而推理耗时更长。真实场景(例如用产品目录数据微调客服模型)中,基座模型要达到同等质量往往需要更复杂的提示工程,从而推高 token 用量与推理耗时——那才是微调的成本收益真正显现的地方。
多提供方微调路径
课文档的 "Fine-Tuning In Action" 一节按提供方整理了五条可对照执行的教程路径,需要相应平台的账号、模型与数据访问权限:
| 提供方 | 教程主题 | 说明 |
|---|---|---|
| OpenAI | How to fine-tune chat models | 以"菜谱助手"为例,学习准备训练数据、运行微调任务,并用微调后模型做推理;原始目标模型为 gpt-35-turbo(新任务请换用当前受支持模型) |
| Azure OpenAI | GPT 3.5 Turbo fine-tuning tutorial | 在 Azure 上微调 gpt-35-turbo-0613:创建并上传训练数据、运行微调任务、部署并调用新模型 |
| Hugging Face | Fine-tuning LLMs with Hugging Face | 使用 transformers 库与 TRL(Transformer Reinforcement Learning)库,配合 Hugging Face 开放数据集微调开源 LLM(如 CodeLlama 7B) |
| AutoTrain | Fine-tuning LLMs with AutoTrain | Hugging Face 的 Python 库,支持多种任务(含 LLM)微调;无代码方案,可在自有云、Hugging Face Spaces 或本地运行;支持 Web GUI、CLI 与 YAML 配置文件训练 |
| Unsloth | Fine-tuning LLMs with Unsloth | 开源框架,支持 LLM 微调与强化学习(RL);提供即用 Notebook 简化本地训练、评估与部署;另支持 TTS、BERT 与多模态模型 |
微调的局限性与后续学习
综合课文档与实战 Notebook 的表述,可以归纳出微调的几个明确限制:
- 进阶门槛:微调需要相当的工程能力,执行不当不仅无改善,反而可能劣化模型在目标领域的表现;
- 成本多维:数据准备、评估迭代、算力消耗都是真实开销,且不是所有基础模型都开放微调能力(需查阅提供方最新支持列表);
- 数据集质量敏感:格式错误(如 JSONL 记录跨行、字段不符)会直接导致任务失败;示例数量不足时效果有限,规模与成本需要权衡;
- 基线优先:只有当提示工程、RAG 等低成本手段的基线结果仍不满足需求、且收益超过成本时,微调才是合理选择。
课程任务(Assignment)要求:从上述教程中任选一条完整走通一遍。
延伸阅读方面,保加利亚语版与英文版各有一份配套资源清单,分别收录了 OpenAI 与 Azure OpenAI 的一手文档链接(概念、流程、可微调模型范围、连续微调、函数调用微调等主题)与次级资源(数据准备与分析、面向 RAG 的微调、QLoRA 微调小模型等),可支持自主深入学习:
- translations/bg/18-fine-tuning/RESOURCES.md(保加利亚语版资源页)
- 18-fine-tuning/RESOURCES.md(英文版资源页)
第 18 课也是该课程 v2 系列的最后一课。掌握微调之后,你便完整拥有了 generative-ai-for-beginners 课程覆盖的三层质量改进手段:改提示(提示工程)、改上下文(RAG)、改模型(微调)——三者分别对应"提示层、数据层、参数层",可以按成本与收益逐级递进选用。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00


