☰
smol-course 指令微调实战:从 ChatML 对话模板到 TRL 监督微调(SFT)全流程指南
2026/10/9 1:04:20 网站建设 项目流程
  • 教程
  • 人工智能
  • 大模型
  • NLP
  • 微调

【免费下载链接】smol-course

A course on aligning smol models.

项目地址:https://gitcode.com/gh_mirrors/smo/smol-course
点击查看免费下载

本文是 smol-course 项目「指令微调(Instruction Tuning)」模块的技术指南,系统讲解两条核心技术主线:以 ChatML 为代表的对话模板(Chat Templates)与基于 TRLSFTTrainer的监督微调(Supervised Fine-Tuning)。读完本文,你将掌握如何把基础模型(如SmolLM2-135M)格式化为可对话的指令模型、如何将任意数据集转换为 ChatML 格式,以及如何配置SFTConfig完成一次完整的微调、评估与发布流程。

模块概览:指令微调在 smol-course 中的位置

指令微调(Instruction Tuning)是指:为了把预训练模型适配到特定任务,使用与该任务相关的数据集对模型进行额外训练的过程,从而让模型在目标任务上取得更优表现。smol-course 的韩文版模块(v1/ko/1_instruction_tuning/README.md)将这一主题拆分为两大核心内容:

  1. 对话模板(Chat Templates)——结构化用户与 AI 模型之间的交互,保证响应的一致性与上下文相关性,核心组件包括系统提示词与基于角色的消息;
  2. 监督微调(SFT)——使用带标签的任务数据对预训练语言模型进行适配,是让模型真正"学会干活"的关键步骤。

模块同时提供了两张实战练习表(v1/ko/1_instruction_tuning/README.md):

标题说明实战内容仓库链接
Chat Templates使用 SmolLM2 掌握对话模板,并将数据集转换为 ChatML 格式🐢 将HuggingFaceTB/smoltalk数据集转为 chatml 格式;🐕 将openai/gsm8k数据集转为 chatml 格式chat_templates_example.ipynb
Supervised Fine-Tuning使用SFTTrainer对 SmolLM2 进行微调🐢 使用HuggingFaceTB/smoltalk数据集;🐕 使用bigcode/the-stack-smol数据集;🦁 为真实使用场景挑选数据集sft_finetuning_example.ipynb

注:本模块的完整理论文档为 v1/ko/1_instruction_tuning/chat_templates.md 与 v1/ko/1_instruction_tuning/supervised_fine_tuning.md,以下章节分别展开。

一、对话模板(Chat Templates)

1.1 基础模型 vs 指令模型:为什么需要模板

**基础模型(Base Model)**在大量原始文本上以"预测下一个 token"为目标进行训练;**指令模型(Instruct Model)**则是专门经过微调、能够遵循指令并参与对话的变体。以仓库实战使用的模型为例:HuggingFaceTB/SmolLM2-135M是基础模型,而SmolLM2-135M-Instruct是其指令微调版本。

要让基础模型表现得像指令模型,必须以模型能理解的方式一致地格式化提示词——这正是对话模板的用武之地。ChatML是其中一种被广泛使用的模板格式,通过明确的角色指示符(system、user、assistant)来结构化对话:

<|im_start|>user 안녕하세요!<|im_end|> <|im_start|>assistant 만나서 반갑습니다!<|im_end|> <|im_start|>user 질문을 해도 될까요?<|im_end|> <|im_start|>assistant

关键事实:基础模型可能在不同的对话模板上被微调过,因此使用指令模型时,必须使用与之一致(匹配)的对话模板,否则模型无法正确解析角色与消息边界。从源码结构看,模板的核心作用就是定义"与语言模型通信时对话应以何种格式呈现"——包括系统级指令、用户消息、助手响应三部分,从而在交互中维持格式一致性并引导模型对不同输入做出恰当响应。

1.2 消息结构:role 与 content

transformers库会根据模型的 tokenizer 自动处理对话模板。我们只需把消息结构化为包含role与content键的字典列表,剩下的格式化工作交给 tokenizer:

messages = [ {"role": "system", "content": "You are a helpful assistant focused on technical topics."}, {"role": "user", "content": "Can you explain what a chat template is?"}, {"role": "assistant", "content": "A chat template structures conversations between users and AI models..."} ]

其中**系统消息(System Message)**奠定模型的基础行为方式,是影响后续所有交互的持久指令。例如:

system_message = { "role": "system", "content": "You are a professional customer service agent. Always be polite, clear, and helpful." }

而**对话历史(Conversation)**则让模板通过记录用户与助手之间的多轮往来维持上下文,从而实现更连贯的多轮对话:

conversation = [ {"role": "user", "content": "I need help with my order"}, {"role": "assistant", "content": "I'd be happy to help. Could you provide your order number?"}, {"role": "user", "content": "It's ORDER-123"}, ]

1.3 Transformers 实现:apply_chat_template 的核心用法

transformers库为对话模板提供了内建支持,核心 API 是AutoTokenizer.apply_chat_template。仓库文档 v1/ko/1_instruction_tuning/chat_templates.md 给出的标准用法如下:

from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM2-135M-Instruct") messages = [ {"role": "system", "content": "You are a helpful coding assistant."}, {"role": "user", "content": "Write a Python function to sort a list"}, ] # 应用对话模板 formatted_chat = tokenizer.apply_chat_template( messages, tokenize=False, add_generation_prompt=True )

三个关键参数说明:

  • tokenize=False:返回纯文本字符串(而非 token id),便于直接查看模板化后的对话内容;
  • tokenize=True(默认):返回 token id 列表,可直接喂给模型;
  • add_generation_prompt=True:在末尾追加assistant角色的起始标记(如<|im_start|>assistant),提示模型开始生成响应,这在推理/生成场景中尤其重要。

1.4 自定义格式与多轮支持

不同消息类型可以定制不同的格式,例如按角色追加特殊 token 或自定义排版:

template = """ <|system|>{system_message} <|user|>{user_message} <|assistant|>{assistant_message} """.lstrip()

模板同样能处理复杂多轮对话并在其中维持上下文,例如下面这个数学辅导场景:

messages = [ {"role": "system", "content": "You are a math tutor."}, {"role": "user", "content": "What is calculus?"}, {"role": "assistant", "content": "Calculus is a branch of mathematics..."}, {"role": "user", "content": "Can you give me an example?"}, ]

1.5 实战:从 notebook 看模板的完整调用链

chat_templates_example.ipynb 给出了可复现的完整链路,首先动态选择设备并加载模型:

from transformers import AutoModelForCausalLM, AutoTokenizer from trl import setup_chat_format import torch device = ( "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu" ) model_name = "HuggingFaceTB/SmolLM2-135M" model = AutoModelForCausalLM.from_pretrained(pretrained_model_name_or_path=model_name).to(device) tokenizer = AutoTokenizer.from_pretrained(pretrained_model_name_or_path=model_name) model, tokenizer = setup_chat_format(model=model, tokenizer=tokenizer)

这里的trl.setup_chat_format会为没有内建对话模板的基础模型自动装配一套 ChatML 模板并补充对应的特殊 token,是"把基础模型变成可对话模型"的关键一步(这也解释了为何后续apply_chat_template能直接输出<|im_start|>系列标记)。

随后定义一条简单对话并观察三种输出形态(对应 notebook 中的三组实验):

messages = [ {"role": "user", "content": "Hello, how are you?"}, {"role": "assistant", "content": "I'm doing well, thank you! How can I assist you today?"}, ] # 1) 不 tokenize,直接查看模板化后的对话字符串 input_text = tokenizer.apply_chat_template(messages, tokenize=False) print("Conversation with template:", input_text) # => <|im_start|>user\nHello, how are you?<|im_end|>\n<|im_start|>assistant\n... # 2) tokenize 并添加生成提示,解码后可见末尾多出 assistant 引导标记 input_text = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True) print("Conversation decoded:", tokenizer.decode(token_ids=input_text)) # 3) 默认 tokenize,得到与模型词表对应的 token id 序列 input_text = tokenizer.apply_chat_template(messages, add_generation_prompt=True) print("Conversation tokenized:", input_text)

三组实验分别验证了:模板如何插入特殊 token 形成结构化文本、生成提示(generation prompt)如何在结尾追加assistant引导、以及整个对话+特殊 token 如何被映射为模型词表中的 id 序列。notebook 还提供了两档练习题:

  • 🐢 使用datasets.load_dataset("HuggingFaceTB/smoltalk", "everyday-conversations")加载对话数据,通过ds.map(process_dataset)将每条样本转换为包含role/content的消息列表并应用对话模板;
  • 🐕 将openai/gsm8k(数学推理数据集,含question与answer字段)转换为 ChatML 格式,需要自行构造用户消息与助手消息再套用模板。

这两项练习的意义在于:虽然 TRL 在训练时会自动套用模型对话模板,但理解内部格式转换机制(特别是不同字段如何映射为 role/content)对排查数据问题、适配自定义数据集至关重要。

二、监督微调(Supervised Fine-Tuning)

2.1 什么是 SFT:原理与适用场景

监督微调(SFT)是让预训练模型适配特定任务或领域的关键过程。预训练模型虽有出色的通用能力,但往往需要针对具体使用场景做定制。SFT 通过在人验证过的、精心筛选的数据集上继续训练来弥合这一差距。

其核心机制是:通过带标签的 token 示例教会预训练模型执行特定任务——向模型展示大量期望的"输入-输出"行为样例,使其学习到针对你的使用场景的特定模式。SFT 之所以有效,是因为它既利用了预训练阶段获得的基础知识,又能把模型行为调整到符合你的具体需求。

是否使用 SFT,主要取决于"模型当前能力"与"具体需求"之间的差距。以下场景尤其适合:

  • 需要精细控制模型输出时,例如开发客户服务应用,希望模型始终遵循公司准则、以标准化方式处理技术咨询;
  • 专业领域(如医疗、法律)中,准确性与领域术语遵循至关重要;
  • 在以上情形中,SFT 能帮助模型响应符合专业标准并贴合领域知识。

2.2 微调流程:数据、训练与持续评估

SFT 的过程包含三个环节:

  1. 数据准备:选择或构建能代表目标任务的数据集,应覆盖模型将遇到的各种场景。数据质量至关重要——每条样本都要清晰示范你期望模型产出的输出类型;
  2. 实际训练:使用 Hugging Face 的transformers与trl等框架,基于数据集训练模型权重;
  3. 持续评估:全过程都要用验证集监控模型性能,确保模型学到期望行为的同时不损失通用能力。关于如何评估模型,将在本仓库的模块 4(Evaluation)中展开。

2.3 SFT 在偏好对齐中的角色

SFT 是让语言模型与人类偏好对齐的基础环节:**基于人类反馈的强化学习(RLHF)与直接偏好优化(DPO)**等技术,都先依靠 SFT 建立基础层面的任务理解,再进一步把模型响应与期望结果对齐。预训练模型尽管语言能力普遍,却不一定总能产出符合人类偏好的输出;SFT 通过引入领域数据与指令来填补这一差距,使模型生成更贴近人类期望的响应。这也是本仓库后续偏好对齐模块(如 v1/ko/2_preference_alignment)的地基。

2.4 核心工具:TRL 与 SFTTrainer

监督微调的关键软件包是Transformer Reinforcement Learning(TRL)——一套用强化学习(RL)训练 transformer 语言模型的工具包。它构建于 Hugging Face Transformers 之上,允许直接加载预训练语言模型,支持大部分 decoder 与 encoder-decoder 架构,并覆盖语言建模中的主要 RL 流程:SFT、奖励建模(RM)、近端策略优化(PPO)、直接偏好优化(DPO)。仓库的多个模块都会使用 TRL。

2.5 实战:SFTConfig 关键参数逐项解析

sft_finetuning_example.ipynb 展示了用SFTTrainer微调HuggingFaceTB/SmolLM2-135M的完整流程。数据准备阶段强调一个要点:TRL 会根据模型对话模板自动格式化输入消息,因此数据只需以含role/content键的字典列表形式组织:

from transformers import AutoModelForCausalLM, AutoTokenizer from datasets import load_dataset from trl import SFTConfig, SFTTrainer, setup_chat_format import torch device = ( "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu" ) model_name = "HuggingFaceTB/SmolLM2-135M" model = AutoModelForCausalLM.from_pretrained(pretrained_model_name_or_path=model_name).to(device) tokenizer = AutoTokenizer.from_pretrained(pretrained_model_name_or_path=model_name) model, tokenizer = setup_chat_format(model=model, tokenizer=tokenizer) finetune_name = "SmolLM2-FT-MyDataset" finetune_tags = ["smol-course", "module_1"] # 加载对话数据集(path 与 name 分别指定数据集与子集配置) ds = load_dataset(path="HuggingFaceTB/smoltalk", name="everyday-conversations")

随后通过SFTConfig配置训练过程。该配置控制训练步数、批大小、学习率、评估方式等,notebook 中的核心参数及含义如下:

参数示例值作用说明
output_dir"./sft_output"训练输出(checkpoint、日志等)保存目录
max_steps1000最大训练步数,按期望训练时长与数据集规模调整
per_device_train_batch_size4每设备训练批大小,受 GPU 显存容量约束
learning_rate5e-5学习率,微调场景的常用取值
logging_steps10训练指标(loss 等)的日志记录频率
save_steps100模型 checkpoint 的保存频率
evaluation_strategy"steps"周期性评估设置(按步数评估)
eval_steps50评估频率(步数间隔)
use_mps_devicedevice == "mps"是否在 Apple MPS 上启用(混合精度训练相关)
hub_model_idfinetune_name上传 Hugging Face Hub 时使用的模型名称
sft_config = SFTConfig( output_dir="./sft_output", max_steps=1000, per_device_train_batch_size=4, learning_rate=5e-5, logging_steps=10, save_steps=100, evaluation_strategy="steps", eval_steps=50, use_mps_device=(True if device == "mps" else False), hub_model_id=finetune_name, ) trainer = SFTTrainer( model=model, args=sft_config, train_dataset=ds["train"], eval_dataset=ds["test"], )

实战提示(notebook 标注):若改用bigcode/the-stack-smol这类代码数据集,需通过参数指定content列(字段名与对话数据集不同);若数据集本身不是 TRL 可直接转换的对话格式,则需先按 chat_templates.md 的方法自行预处理。

2.6 训练、保存与发布:一次完整的微调闭环

配置完成即可启动训练并保存、发布模型(对应 notebook 三连):

# 训练:反复遍历数据集、计算损失并通过反向传播更新参数以最小化损失 trainer.train() # 保存模型到本地目录 trainer.save_model(f"./{finetune_name}") # 上传到 Hugging Face Hub(需先 login 并配置 hub_model_id) trainer.push_to_hub(tags=finetune_tags)

训练前后对比是验证微调效果的标准做法:notebook 在训练前先用同一 prompt 测试基础模型——

prompt = "Write a haiku about programming" messages = [{"role": "user", "content": prompt}] formatted_prompt = tokenizer.apply_chat_template(messages, tokenize=False) inputs = tokenizer(formatted_prompt, return_tensors="pt").to(device) outputs = model.generate(**inputs, max_new_tokens=100) print("Before training:") print(tokenizer.decode(outputs[0], skip_special_tokens=True))

训练完成后,用相同 prompt 对微调后模型再次生成(使用save_model保存的权重),对比输出质量即可直观看到 SFT 带来的行为改变。完整的微调流程是:加载基础模型 →setup_chat_format装配对话模板 → 加载/预处理数据集 → 配置SFTConfig→ 初始化SFTTrainer→train()→save_model/push_to_hub→ 训练前后生成对比。

三、下一步学习路径

完成本模块后,建议按以下路径继续深入(均位于本仓库内):

  1. 动手跑通两个 notebook:chat_templates_example.ipynb(先掌握模板与数据集转换)、sft_finetuning_example.ipynb(完成一次完整微调),可尝试升级难度(如代码数据集、自选真实场景数据集);
  2. 进阶偏好对齐:在 SFT 打底后,进入模块 2 偏好对齐了解 DPO 等后续对齐技术(本模块 SFT 正是其基础);
  3. 评估闭环:微调效果需要通过模块 4 评估中的验证集与评估工具来客观衡量,防止灾难性遗忘与过拟合。

掌握对话模板的格式化规则与SFTTrainer的参数语义,是后续所有对齐类微调(DPO、PPO 等)的共同地基——这也是 smol-course 将本模块置于课程起点、并在各语言版本(如 v1/1_instruction_tuning/README.md)中保持一致编排的原因。

  • 教程
  • 人工智能
  • 大模型
  • NLP
  • 微调

【免费下载链接】smol-course

A course on aligning smol models.

项目地址:https://gitcode.com/gh_mirrors/smo/smol-course
点击查看免费下载
上一篇:2 行代码接入 Font Awesome CDN:图标引入、国内源与排错实操
下一篇:WPF界面开发困境与终极解决方案:Extended WPF Toolkit完全指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询