Transformers 文件
模板編寫
並獲得增強的文件體驗
開始使用
模板編寫
聊天模板是一個儲存在分詞器 chat_template 屬性中的 Jinja 模板。Jinja 是一種模板語言,允許您編寫類似 Python 的程式碼和語法。聊天模板執行以下三個作用。
- 列印用
<|
和|>
包裹的角色(<|user|>
、<|assistant|>
等)。 - 列印訊息,後跟一個序列結束(
EOS
)標記。 - 如果 add_generation_prompt=True,則列印助手標記,以便模型生成助手響應。
一個示例如下所示。
{%- for message in messages %}
{{- '<|' + message['role'] + |>\n' }}
{{- message['content'] + eos_token }}
{%- endfor %}
{%- if add_generation_prompt %}
{{- '<|assistant|>\n' }}
{%- endif %}
該模板可以自定義以處理更復雜的用例。本指南將向您展示如何新增和編輯模板,幷包含模板編寫技巧。
建立模板
透過編寫 Jinja 模板,然後將其設定為分詞器中的聊天模板來建立模板。例如,以下模板向助手訊息新增 [ASST]
和 [/ASST]
標籤。
{%- for message in messages %}
{%- if message['role'] == 'user' %}
{{- bos_token + '[INST] ' + message['content'].strip() + ' [/INST]' }}
{%- elif message['role'] == 'system' %}
{{- '<<SYS>>\\n' + message['content'].strip() + '\\n<</SYS>>\\n\\n' }}
{%- elif message['role'] == 'assistant' %}
{{- '[ASST] ' + message['content'] + ' [/ASST]' + eos_token }}
{%- endif %}
{%- endfor %}
在分詞器中設定模板,下次使用 apply_chat_template() 時,將使用新模板。
template = tokenizer.chat_template
template = template.replace("SYS", "SYSTEM") # Change the system token
tokenizer.chat_template = template # Set the new template
該模板儲存在 tokenizer_config.json
檔案中。使用 push_to_hub() 將其上傳到 Hub,這樣您以後可以重複使用它,並確保每個人都為您的模型使用正確的模板。
tokenizer.push_to_hub("model_name")
模板編寫技巧
編寫 Jinja 模板最簡單的方法是參考現有模板。在任何聊天模型上使用 print(tokenizer.chat_template)
檢視其使用的模板。嘗試從不呼叫任何工具或不支援 RAG 的簡單模型開始。最後,檢視 Jinja 文件 以獲取有關格式和語法的更多詳細資訊。
本節整理了一些編寫清晰高效的 Jinja 模板的最佳實踐。
去除空白
Jinja 會列印文字塊之前或之後的任何空白。這對於聊天模板來說可能是一個問題,因為空白的使用應該是故意的。新增 -
以去除塊之前的任何空白。
{%- for message in messages %}
{{- message['role'] + message['content'] }}
{%- endfor %}
以下不正確的空白使用示例可能會在輸出中引入換行符和縮排。
{% for message in messages %}
{{ message['role'] + message['content'] }}
{% endfor %}
特殊變數
模板中有五個特殊變數可用。您可以將幾乎任何附加引數傳遞給 apply_chat_template(),它將在模板中作為變數可用。但是,您應該儘量將變數數量保持在以下五個,以便使用者無需編寫自定義程式碼即可使用聊天模型來處理模型特定的引數。
messages
包含聊天曆史記錄,作為訊息字典列表。tools
包含 JSON 模式格式的工具列表。documents
包含文件列表,格式為{"title": Title, "contents": "Contents"}
(專為 RAG 模型設計)。add_generation_prompt
是一個布林值,用於確定是否在對話結束時新增助手標題。bos_token
和eos_token
是從分詞器的special_tokens_map
中提取的特殊標記。
可呼叫函式
模板中有兩個可呼叫函式可用。
raise_exception(msg)
引發TemplateException
。這對於除錯或警告使用者模板使用不正確很有用。strftime_now(format_str)
檢索特定格式的當前日期和時間,這可能有助於包含在系統訊息中。它等同於 Python 中的 datetime.now().strftime(format_str)。
與非 Python Jinja 的相容性
Jinja 以多種語言實現,它們通常具有相同的語法。在 Python 中編寫模板允許您使用 Python 方法,例如字串上的 lower 或字典上的 items。但如果模板在非 Python 實現中使用,例如在使用 Javascript 或 Rust 部署時,這將不起作用。
進行以下更改以確保所有 Jinja 實現的相容性。
- 將 Python 方法替換為 Jinja 過濾器。例如,將
string.lower()
替換為string|lower
,或將dict.items()
替換為dict|dictitems
。大多數更改都遵循相同的模式,除了string.strip()
,它被替換為string|trim
。有關過濾器的完整列表,請參閱 內建過濾器 列表。 - 將
True
、False
和None
(這些是 Python 特有的)分別替換為true
、false
和none
。 - 直接渲染字典或列表可能會在其他實現中返回不同的結果。例如,字串條目可能會從單引號變為雙引號。為避免這種情況,請新增 tojson 過濾器以保持一致性。
大型模板
較新的模型或具有 工具呼叫 和 RAG 等功能的模型需要更大的模板,長度可能超過 100 行。在單獨的檔案中編寫大型模板可能更容易。單獨檔案中的行號與模板解析或執行錯誤中的行號完全對應,從而更容易除錯任何潛在問題。
將模板寫入單獨的檔案並將其提取到聊天模板中。
open("template.jinja", "w").write(tokenizer.chat_template)
您也可以將編輯過的模板重新載入到分詞器中。
tokenizer.chat_template = open("template.jinja").read()
工具模板
沒有編寫工具模板的特定格式,但最好遵循標準 API。這確保了模板在模型之間廣泛可用,而無需使用者編寫自定義程式碼來將工具與您的模型一起使用。
空白和特殊標記等格式是模型特定的。確保一切都與模型訓練時使用的格式完全匹配。
以下部分列出了用於編寫工具模板的標準 API 元素。
工具定義
Transformers 聊天模板方法允許使用者將工具作為 Python 函式或 JSON 模式傳遞。當傳遞函式時,會自動生成 JSON 模式並傳遞給模板。模板中的 tools
變數總是接受 JSON 模式列表。
特定的標記和工具描述應與您的模型訓練時使用的標記和工具描述相匹配。您的模型不需要理解 JSON 模式輸入,因為您的模板可以將 JSON 模式轉換為您的模型格式。例如,Command-R 是用 Python 函式頭定義的工具進行訓練的,但 Command-R 工具模板接受 JSON 模式。模板在內部轉換型別並將輸入工具渲染為 Python 頭。
{
"type": "function",
"function": {
"name": "multiply",
"description": "A function that multiplies two numbers",
"parameters": {
"type": "object",
"properties": {
"a": {
"type": "number",
"description": "The first number to multiply"
},
"b": {
"type": "number",
"description": "The second number to multiply"
}
},
"required": ["a", "b"]
}
}
}
下面顯示了一個在聊天模板中處理工具定義的示例。特定的標記和工具描述應更改為與模型訓練時使用的標記和工具描述相匹配。
{%- if tools %}
{%- for tool in tools %}
{{- '<tool>' + tool['function']['name'] + '\n' }}
{%- for argument in tool['function']['parameters']['properties'] %}
{{- argument + ': ' + tool['function']['parameters']['properties'][argument]['description'] + '\n' }}
{%- endfor %}
{{- '\n</tool>' }}
{%- endif %}
{%- endif %}
工具呼叫
工具呼叫(如果存在)是一個包含 "assistant"
角色的列表。這始終是一個列表,即使大多數工具呼叫模型僅支援單個工具呼叫,這意味著該列表通常只包含一個元素。
{
"role": "assistant",
"tool_calls": [
{
"type": "function",
"function": {
"name": "multiply",
"arguments": {
"a": 5,
"b": 6
}
}
}
]
}
下面顯示了處理工具呼叫的常見模式。
{%- if message['role'] == 'assistant' and 'tool_calls' in message %}
{%- for tool_call in message['tool_calls'] %}
{{- '<tool_call>' + tool_call['function']['name'] + '\n' + tool_call['function']['arguments']|tojson + '\n</tool_call>' }}
{%- endif %}
{%- endfor %}
{%- endif %}
工具響應
工具響應是一個帶有 role
、name
(函式名稱)和 content
(工具呼叫結果)鍵的訊息字典。
{
"role": "tool",
"name": "multiply",
"content": "30"
}
並非所有鍵都需要在工具響應中使用。例如,如果模型不期望函式名稱包含在工具響應中,那麼您只需包含 role
和 content
。
{%- if message['role'] == 'tool' %}
{{- "<tool_result>" + message['content'] + "</tool_result>" }}
{%- endif %}
貢獻
透過在分詞器中設定 chat_template
屬性並使用 apply_chat_template() 進行測試來新增聊天模板。如果它按預期工作,那麼您可以使用 push_to_hub() 將其上傳到 Hub。
即使您不是模型所有者,為具有空聊天模板或使用預設類模板的模型新增模板也很有幫助。在模型倉庫上開啟 拉取請求 以新增模板。
tokenizer.chat_template = template
tokenizer.push_to_hub("model_name")