☰
SmolLM 对话模板(Chat Templates)实战指南:从 ChatML 格式到 transformers 集成应用
2026/10/9 11:57:31 网站建设 项目流程
  • 教程
  • 人工智能
  • 大模型
  • NLP
  • 微调

【免费下载链接】smol-course

A course on aligning smol models.

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

对话模板(Chat Templates)是语言模型对齐(Alignment)流程的第一步,也是本仓库 smol-course 指令微调模块的核心前置知识。本文以 v1/ko/1_instruction_tuning/chat_templates.md 为主干,结合仓库内的实操 Notebook 源码,系统讲解对话模板的作用机制、ChatML 格式、系统消息与多轮对话的构造方法,以及如何借助transformers库的apply_chat_template与 TRL 的setup_chat_format快速落地。读完本文,你将能够正确构造任意 instruct 模型所需的对话格式,并为后续的监督微调(SFT)准备好训练数据。

为什么对话模板是对齐的第一步

基础模型与指令模型的分野

基础模型(Base Model)是在海量原始文本上训练、以预测下一个 token 为目标的模型;而指令模型(Instruct Model)则是在此基础上针对"遵循指令、展开对话"进行过专门微调的变体。本仓库反复使用的示例正好说明了这一区别:

  • HuggingFaceTB/SmolLM2-135M是基础模型;
  • HuggingFaceTB/SmolLM2-135M-Instruct是其指令微调(instruction-tuned)变体。

要让基础模型表现得像指令模型,关键不在于改模型结构,而在于把提示词(prompt)格式化成模型能够理解的、一致的形态——这正是对话模板的用武之地。ChatML 就是这类模板格式中的典型代表:它用清晰的角色指示符(system、user、assistant)把一段对话结构化。

需要特别强调的是:同一个基础模型可以被不同的对话模板微调成不同的指令模型。因此,使用某个 instruct 模型时,必须使用与该模型配套的对话模板,否则模型的角色理解与响应模式都会出现偏差。这也是为什么在仓库的 指令微调模块总览 中,对话模板被列为与监督微调并列的第一个主题。

对话模板在指令微调流程中的位置

从 v1/1_instruction_tuning/README.md 可以看到,本模块的完整链路是:先掌握对话模板(把交互结构化)→ 再通过 SFT 让模型在任务数据集上学会目标行为。SFT 训练数据的组织、推理时的输入构造,都依赖正确的对话模板,因此它是对齐流程中名副其实的"第一步"。

理解对话模板:ChatML 格式

对话模板的核心,是定义"与语言模型通信时,对话应以什么形式呈现"。模板中通常包含系统级指令、用户消息、助手回复,并把这些内容编排成模型可理解的结构化格式。这种结构保证了交互的一致性,也让模型能针对不同类型的输入给出恰当响应。

下面是一段典型的 ChatML 格式对话(来自原文档):

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

可以看到:每一条消息都以<|im_start|>加角色名开头,以<|im_end|>结尾;<|im_start|>assistant出现在最后,表示等待模型生成回复。

在transformers库中,对话模板与模型的 tokenizer 绑定管理:我们只需要把消息按正确结构组织好,剩下的格式化工序由 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..."} ]

对比前面的 ChatML 示例可以看到,这份messages列表里的每条消息(role 与 content 键值对)都会在应用模板后被映射成<|im_start|>role\ncontent<|im_end|>的形式——system、user、assistant三种角色依次展开,构成完整的对话上下文。

系统消息:定义模型的"行为基调"

系统消息(System Message)负责设定模型的基础行为方式,它是一条影响后续所有交互的持续性指令。典型用法如下(来自原文档):

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

在 ChatML 格式中,系统消息会被放置在对话的最前面(通常紧跟<|im_start|>system),从而在模型处理后续每一轮用户消息时都保持约束力。实际项目中,系统消息常用来声明角色身份、输出规范、知识截止日期等全局性要求——例如仓库新版练习 Notebook(notebooks/1/4.ipynb)中 SmolLM3 的系统消息就包含了 Knowledge Cutoff Date、Reasoning Mode 等元信息字段,可见系统消息是模板中承载全局配置的核心载体。

对话与多轮支持:用历史上下文维持一致性

对话模板通过维护对话历史(conversation history)来保持上下文:模型在回答当前问题时,会同时看到此前用户与助手之间的往来记录,从而实现更连贯的多轮对话。原文档给出了这样一个客服场景示例:

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"}, ]

模板可以处理复杂的多轮对话而不会丢失上下文,例如数学辅导场景:

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?"}, ]

注意这里的规律:消息列表中交替排列user与assistant消息,system消息置于最前。模板应用后,每一轮对话都会带上此前全部轮次的格式化文本,这就是多轮一致性的来源。

基于 transformers 的实现:apply_chat_template 详解

transformers库对对话模板提供了内建支持。原文档给出了核心用法:先加载模型对应的 tokenizer,再调用apply_chat_template:

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 )

apply_chat_template的三个关键参数及其影响如下:

参数取值作用
messages消息列表每条消息需含role(system/user/assistant)与content两个键,角色顺序需符合模板约定
tokenizeTrue/False为False时返回格式化后的字符串;为True时直接返回token id 列表,便于输入模型
add_generation_promptTrue/False为True时在末尾追加一条空的assistant角色起始标记,指示模型从此处开始生成回复;为False时仅输出已有对话的完整格式化文本

仓库韩语版实操 Notebook(v1/ko/1_instruction_tuning/notebooks/chat_templates_example.ipynb)对这三种模式给出了完整的对照实验,可作为验证:

  • 不 tokenize、不加生成提示:tokenizer.apply_chat_template(messages, tokenize=False)输出纯文本对话,其中每个角色由特殊 token(<|im_start|>、<|im_end|>)包裹;
  • tokenize 并加生成提示:tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True)返回 token id 序列,用tokenizer.decode(...)还原后可看到末尾多出一个<|im_start|>assistant\n的空助手角色标记,即模型即将开始续写的位置;
  • 纯 tokenize:tokenizer.apply_chat_template(messages, add_generation_prompt=True)直接得到形如[1, 4093, 198, 19556, ...]的整数列表,证明模板化后的对话(含特殊 token)已落入模型的词表空间。

这组实验也印证了原文档的结论:只要把消息结构组织正确,格式化的"脏活"完全由 tokenizer 承担——无论是纯文本展示、解码回看还是直接喂给模型生成,都只需调整参数即可。

自定义对话模板格式

除了使用模型自带的模板,你还可以按需定制不同消息类型的格式。例如为不同角色添加特殊 token 或调整排版(来自原文档):

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

在transformers中,tokenizer 的chat_template属性本身就是一个 Jinja 模板字符串,apply_chat_template底层就是对该 Jinja 模板的渲染。因此在自定义格式时,既可以像上面这样手工拼装(适合快速原型),也可以直接改写 tokenizer 的chat_template属性传入完整的 Jinja 模板(适合生产化部署)。需要留意的是:自定义模板必须与模型的微调格式严格一致——如果模型是用 ChatML 微调的,却喂给它<|system|>风格的模板,模型将无法正确理解角色。

此外,TRL 库提供了setup_chat_format(model, tokenizer)工具(见 v1/ko/1_instruction_tuning/notebooks/sft_finetuning_example.ipynb 中的用法),它会为模型与 tokenizer 一次性配置好对话格式与配套特殊 token,在微调场景下可以省去手动设置模板的步骤,是原文档自定义格式方案在生产流程中的便捷替代。

仓库实战:把数据集加工成 ChatML 训练样本

理解了模板原理后,下一步就是把原始数据集加工成符合 ChatML 格式的训练样本——这正是 v1/ko/1_instruction_tuning/notebooks/chat_templates_example.ipynb 的核心练习,也对应模块总览(v1/1_instruction_tuning/README.md)中列出的两个由易到难的实验任务:

  1. 🐢 入门练习:把HuggingFaceTB/smoltalk数据集(everyday-conversations配置)转换为 ChatML 格式。该数据集的样本本身已是消息结构,重点是调用tokenizer.apply_chat_template完成格式化;
  2. 🐕 进阶练习:把openai/gsm8k数据集转换为 ChatML 格式。该数据集样本是"问题-答案"的原始文本对,需要先手工构造含role、content的消息列表(例如把问题映射为user消息、把答案映射为assistant消息),再套用对话模板。

两个练习都通过datasets库的map操作逐样本处理。这一加工思路与后续 SFT 完全衔接:在 v1/ko/1_instruction_tuning/notebooks/sft_finetuning_example.ipynb 中,SFTTrainer会自动按模型的对话模板格式化输入消息——前提是数据已具备messages结构;若数据不是这种格式,就需要按上面练习中的方式先行转换,该 Notebook 也明确提示读者回到本模块(../chat_templates.md)补课。也就是说,对话模板不仅是推理时的输入规范,更是监督微调数据管线中不可或缺的一环。

小结与下一步

对话模板用统一的角色结构(system / user / assistant)把人与模型的交互格式化,是让基础模型"表现得像指令模型"的前提,也是整个对齐流程的起点。核心要点回顾:

  • 选对模板:instruct 模型必须配套其微调时使用的对话模板(如 ChatML),不可混用;
  • 正确组织消息:role+content的消息列表由tokenizer.apply_chat_template统一渲染,tokenize控制输出形式,add_generation_prompt控制是否追加生成起始标记;
  • 善用系统消息与多轮历史:系统消息设定全局行为基调,历史消息维持多轮上下文一致性;
  • 贯通微调流程:把原始数据集(如smoltalk、gsm8k)加工成 ChatML 格式,即可交由 TRL 的SFTTrainer开展监督微调。

下一步可以继续阅读仓库中的 监督微调指南,并动手运行两个实操 Notebook:对话模板练习 与 SFT 微调练习,在 SmolLM2 上完整体验"模板格式化 → 数据集转换 → 监督微调"的完整链路。

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

【免费下载链接】smol-course

A course on aligning smol models.

项目地址:https://gitcode.com/gh_mirrors/smo/smol-course
点击查看免费下载
上一篇:WorkshopDL终极指南:无需Steam客户端下载创意工坊模组
下一篇:OpenCore Legacy Patcher:为老款Mac注入新生的技术魔法

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

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

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

立即咨询