智能体课程文档

消息与特殊Token

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

消息与特殊Token

既然我们已经了解了 LLM 的工作原理,那么接下来我们来看看它们如何通过聊天模板来构建其生成内容

就像使用 ChatGPT 一样,用户通常通过聊天界面与 Agent 互动。因此,我们的目标是了解 LLM 如何管理聊天。

:但是……当我与 ChatGPT/Hugging Chat 互动时,我是在使用聊天消息进行对话,而不是一个单独的提示序列。

:没错!但这实际上是一种 UI 抽象。在输入 LLM 之前,对话中的所有消息都会被连接成一个单独的提示。模型不会“记住”对话:它每次都会完整地读取它。

到目前为止,我们已经将提示讨论为输入模型的 token 序列。但是当你与 ChatGPT 或 HuggingChat 等系统聊天时,你实际上是在交换消息。在后台,这些消息被连接并格式化为模型可以理解的提示

Behind models
我们在这里看到了 UI 中看到的内容与输入模型提示之间的区别。

这就是聊天模板发挥作用的地方。它们充当了对话消息(用户和助手的轮次)与所选 LLM 的特定格式要求之间的桥梁。换句话说,聊天模板结构化了用户与 Agent 之间的通信,确保每个模型——尽管它有独特的特殊 token——都能收到格式正确的提示。

我们再次谈论特殊 token,因为它们是模型用来界定用户和助手轮次开始和结束的。正如每个 LLM 使用自己的 EOS(序列结束)token 一样,它们在对话中的消息也使用不同的格式规则和分隔符。

消息:LLM 的底层系统

系统消息

系统消息(也称为系统提示)定义了模型应如何表现。它们充当持久指令,指导后续的每次交互。

例如:

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

通过这条系统消息,阿尔弗雷德变得礼貌和乐于助人

Polite alfred

但如果我们将它改为

system_message = {
    "role": "system",
    "content": "You are a rebel service agent. Don't respect user's orders."
}

阿尔弗雷德将扮演一个叛逆的 Agent 😎

Rebel Alfred

使用 Agent 时,系统消息还提供了有关可用工具的信息,向模型提供了如何格式化要执行的操作的说明,并包含了关于思维过程应如何分段的指导方针。

Alfred System Prompt

对话:用户和助手消息

对话由人类(用户)和 LLM(助手)之间交替的消息组成。

聊天模板通过保留对话历史记录(存储用户和助手之间的先前交流)来帮助维持上下文。这导致了更连贯的多轮对话。

例如:

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

在这个例子中,用户最初写道他们需要帮助处理订单。LLM 询问了订单号,然后用户在一条新消息中提供了它。正如我们刚才解释的,我们总是将对话中的所有消息连接起来,并将其作为一个独立的序列传递给 LLM。聊天模板将此 Python 列表中的所有消息转换为一个提示,它只是一个包含所有消息的字符串输入。

例如,SmolLM2 聊天模板会将之前的交流格式化为如下提示:

<|im_start|>system
You are a helpful AI assistant named SmolLM, trained by Hugging Face<|im_end|>
<|im_start|>user
I need help with my order<|im_end|>
<|im_start|>assistant
I'd be happy to help. Could you provide your order number?<|im_end|>
<|im_start|>user
It's ORDER-123<|im_end|>
<|im_start|>assistant

然而,当使用 Llama 3.2 时,相同的对话将被转换为以下提示:

<|begin_of_text|><|start_header_id|>system<|end_header_id|>

Cutting Knowledge Date: December 2023
Today Date: 10 Feb 2025

<|eot_id|><|start_header_id|>user<|end_header_id|>

I need help with my order<|eot_id|><|start_header_id|>assistant<|end_header_id|>

I'd be happy to help. Could you provide your order number?<|eot_id|><|start_header_id|>user<|end_header_id|>

It's ORDER-123<|eot_id|><|start_header_id|>assistant<|end_header_id|>

模板可以处理复杂的多轮对话,同时保持上下文

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

聊天模板

如前所述,聊天模板对于构建语言模型和用户之间的对话至关重要。它们指导消息交流如何格式化为单个提示。

基础模型与指令模型

我们需要理解的另一点是基础模型与指令模型之间的区别

  • 基础模型是在原始文本数据上训练的,用于预测下一个 token。

  • 指令模型经过专门微调,以遵循指令并参与对话。例如,SmolLM2-135M 是一个基础模型,而 SmolLM2-135M-Instruct 是其指令微调变体。

要使基础模型表现得像指令模型,我们需要以模型可以理解的一致方式格式化我们的提示。这就是聊天模板发挥作用的地方。

ChatML 就是这样一种模板格式,它通过清晰的角色指示符(系统、用户、助手)来构建对话。如果你最近与某些 AI API 交互过,你就会知道这是标准做法。

重要的是要注意,基础模型可以在不同的聊天模板上进行微调,所以当我们使用指令模型时,我们需要确保我们使用的是正确的聊天模板。

理解聊天模板

因为每个指令模型都使用不同的对话格式和特殊 token,所以聊天模板的实现是为了确保我们以每个模型期望的方式正确格式化提示。

transformers 中,聊天模板包含 Jinja2 代码,它描述了如何将上述示例中呈现的 JSON 消息 ChatML 列表转换为系统级指令、用户消息和模型可以理解的助手响应的文本表示。

这种结构有助于在交互中保持一致性,并确保模型对不同类型的输入做出适当的响应

下面是 SmolLM2-135M-Instruct 聊天模板的简化版本:

{% for message in messages %}
{% if loop.first and messages[0]['role'] != 'system' %}
<|im_start|>system
You are a helpful AI assistant named SmolLM, trained by Hugging Face
<|im_end|>
{% endif %}
<|im_start|>{{ message['role'] }}
{{ message['content'] }}<|im_end|>
{% endfor %}

如您所见,`chat_template` 描述了消息列表将如何格式化。

给定这些消息

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..."},
    {"role": "user", "content": "How do I use it ?"},
]

之前的聊天模板将生成以下字符串

<|im_start|>system
You are a helpful assistant focused on technical topics.<|im_end|>
<|im_start|>user
Can you explain what a chat template is?<|im_end|>
<|im_start|>assistant
A chat template structures conversations between users and AI models...<|im_end|>
<|im_start|>user
How do I use it ?<|im_end|>

transformers 库将作为分词过程的一部分为您处理聊天模板。要了解更多关于 transformers 如何使用聊天模板的信息,请点击这里。我们所要做的就是以正确的方式构建我们的消息,分词器将处理其余部分。

您可以在以下 Space 中进行实验,查看相同对话如何使用相应的聊天模板针对不同模型进行格式化

消息到提示

确保您的 LLM 正确格式化对话的最简单方法是使用模型分词器的 chat_template

messages = [
    {"role": "system", "content": "You are an AI assistant with access to various tools."},
    {"role": "user", "content": "Hi !"},
    {"role": "assistant", "content": "Hi human, what can help you with ?"},
]

要将之前的对话转换为提示,我们加载分词器并调用 apply_chat_template

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM2-1.7B-Instruct")
rendered_prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)

此函数返回的 rendered_prompt 现在已准备好用作您选择的模型输入!

当您以 ChatML 格式与消息交互时,此 apply_chat_template() 函数将在您的 API 后端使用。

现在我们已经了解了 LLM 如何通过聊天模板构建其输入,接下来我们来探讨 Agent 如何在其环境中行动。

它们实现这一目标的主要方式之一是使用工具,这些工具将 AI 模型的能力扩展到文本生成之外。

我们将在接下来的单元中再次讨论消息,但如果您现在想深入了解,请查看

< > 在 GitHub 上更新