为什么需要 Chat Template? 大语言模型本质上是文本续写器 (text continuation model)。它们并不天然理解”对话”这个概念,只能处理纯文本。因此,我们需要一种标准化的方式来告诉模型:
哪段文本是系统提示(system prompt)
哪段文本是用户输入(user input)
哪段文本是助手回复(assistant response)
如何处理工具调用(tool calls)
Chat Template 就像是对话的格式说明书 ,确保训练和推理时使用完全一致的格式。
Chat Template 的结构 让我们看一个来自 Qwen3-4B-Instruct 模型的真实例子:
1 2 3 4 5 6 7 { "chat_template" : "{%- if tools %}\n {{- '<|im_start|>system\\n' }}..." , "eos_token" : "<|im_end|>" , "pad_token" : "<|endoftext|>" , "tokenizer_class" : "Qwen2Tokenizer" , "model_max_length" : 1010000 }
核心组件 1. chat_template 字段
这是一个 Jinja2 模板 (Jinja2 template),包含了完整的格式化逻辑。它使用特殊标记(special tokens)来分隔不同的消息部分。
2. 特殊标记 (Special Tokens)
从 added_tokens_decoder 中可以看到模型定义的特殊标记:
1 2 3 4 5 6 { "151644" : { "content" : "<|im_start|>" } , "151645" : { "content" : "<|im_end|>" } , "151657" : { "content" : "<tool_call>" } , "151658" : { "content" : "</tool_call>" } }
这些标记在训练时就被模型学习,用于识别消息边界和特殊语义。
3. 视觉和多模态标记
Qwen3 还支持多模态输入,因此包含了视觉相关的特殊标记:
1 2 3 4 5 6 { "151652" : { "content" : "<|vision_start|>" } , "151653" : { "content" : "<|vision_end|>" } , "151655" : { "content" : "<|image_pad|>" } , "151656" : { "content" : "<|video_pad|>" } }
Chat Template 的工作原理 示例 1: 简单对话 输入的结构化数据:
1 2 3 4 5 messages = [ {"role" : "system" , "content" : "你是一个有帮助的AI助手" }, {"role" : "user" , "content" : "什么是机器学习?" }, {"role" : "assistant" , "content" : "机器学习是人工智能的一个分支..." } ]
经过 Chat Template 处理后:
1 2 3 4 5 6 <|im_start|>system 你是一个有帮助的AI助手<|im_end|> <|im_start|>user 什么是机器学习?<|im_end|> <|im_start|>assistant 机器学习是人工智能的一个分支...<|im_end|>
模型看到 <|im_start|>user 就知道”接下来是用户的输入”,看到 <|im_end|> 就知道”这段消息结束了”。
示例 2: 带工具调用的对话 当模型需要调用外部工具(如搜索、计算器)时,Chat Template 会生成更复杂的格式:
输入数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 tools = [ { "name" : "get_weather" , "description" : "获取指定城市的天气" , "parameters" : { "city" : {"type" : "string" , "description" : "城市名称" } } } ] messages = [ {"role" : "user" , "content" : "上海今天天气如何?" }, { "role" : "assistant" , "content" : "让我帮你查询" , "tool_calls" : [ {"name" : "get_weather" , "arguments" : {"city" : "上海" }} ] } ]
处理后的格式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <|im_start|>system # Tools You may call one or more functions to assist with the user query. You are provided with function signatures within <tools></tools> XML tags: <tools> {"name": "get_weather", "description": "获取指定城市的天气", ...} </tools> For each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags: <tool_call> {"name": <function-name>, "arguments": <args-json-object>} </tool_call><|im_end|> <|im_start|>user 上海今天天气如何?<|im_end|> <|im_start|>assistant 让我帮你查询 <tool_call> {"name": "get_weather", "arguments": {"city": "上海"}} </tool_call><|im_end|>
注意模板自动在系统消息中注入了工具使用说明,这让模型知道如何正确地调用工具。
Chat Template 的关键作用 1. 训练与推理一致性 (Training-Inference Consistency) 模型在训练时看到的格式和推理时必须完全一致。如果训练时使用 <|im_start|>,推理时用别的格式,模型性能会大幅下降。
2. 多轮对话的上下文管理 (Context Management) Chat Template 确保整个对话历史以正确的格式拼接:
1 2 3 4 5 6 7 <|im_start|>user 第一个问题<|im_end|> <|im_start|>assistant 第一个回答<|im_end|> <|im_start|>user 第二个问题<|im_end|> <|im_start|>assistant
模型可以清晰地看到对话的边界和顺序。
3. 功能扩展性 (Extensibility) 通过添加新的特殊标记,可以支持新功能而不改变模型架构:
代码补全 : <|fim_prefix|>, <|fim_middle|>, <|fim_suffix|> (FIM = Fill In the Middle)
思维链 : <think>...</think> 标记模型的内部推理过程
多模态 : <|vision_start|>, <|image_pad|> 处理图像输入
实战: 如何使用 Chat Template 使用 HuggingFace Transformers 库时,Chat Template 是自动应用的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from transformers import AutoTokenizertokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-4B-Instruct" ) messages = [ {"role" : "system" , "content" : "你是一个有帮助的AI助手" }, {"role" : "user" , "content" : "你好!" } ] formatted_text = tokenizer.apply_chat_template( messages, tokenize=False , add_generation_prompt=True ) print (formatted_text)
输出:
1 2 3 4 5 <|im_start|>system 你是一个有帮助的AI助手<|im_end|> <|im_start|>user 你好!<|im_end|> <|im_start|>assistant
模型会从最后的 <|im_start|>assistant\n 开始生成回复。
不同模型的 Chat Template 差异 不同模型家族使用不同的格式约定:
模型
格式风格
特殊标记
Qwen
ChatML 风格
`<
Llama 3
特殊标记
`<
Mistral
Instruct 格式
[INST], [/INST]
GPT-4
OpenAI 格式
无特殊标记(API 层面处理)
这就是为什么你不能随意混用不同模型的 tokenizer —— 它们的 Chat Template 完全不兼容!
参考 https://kq4b3vgg5b.feishu.cn/wiki/MLxWwTt2Bim4FwkdgIRcSkU0nZf