DrDavis's picture
Upload folder using huggingface_hub
17c6d62 verified
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
โš ๏ธ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
rendered properly in your Markdown viewer.
-->
# ์ฑ„ํŒ… ๋ชจ๋ธ์„ ์œ„ํ•œ ํ…œํ”Œ๋ฆฟ[[templates-for-chat-models]]
## ์†Œ๊ฐœ[[introduction]]
์š”์ฆ˜ LLM์˜ ๊ฐ€์žฅ ํ”ํ•œ ํ™œ์šฉ ์‚ฌ๋ก€ ์ค‘ ํ•˜๋‚˜๋Š” **์ฑ„ํŒ…**์ž…๋‹ˆ๋‹ค. ์ฑ„ํŒ…์€ ์ผ๋ฐ˜์ ์ธ ์–ธ์–ด ๋ชจ๋ธ์ฒ˜๋Ÿผ ๋‹จ์ผ ๋ฌธ์ž์—ด์„ ์ด์–ด๊ฐ€๋Š” ๋Œ€์‹  ์—ฌ๋Ÿฌ ๊ฐœ์˜ **๋ฉ”์‹œ์ง€**๋กœ ๊ตฌ์„ฑ๋œ ๋Œ€ํ™”๋ฅผ ์ด์–ด๊ฐ‘๋‹ˆ๋‹ค. ์ด ๋Œ€ํ™”์—๋Š” "์‚ฌ์šฉ์ž"๋‚˜ "์–ด์‹œ์Šคํ„ดํŠธ"์™€ ๊ฐ™์€ **์—ญํ• **๊ณผ ๋ฉ”์‹œ์ง€ ํ…์ŠคํŠธ๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.
ํ† ํฐํ™”์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ๋‹ค์–‘ํ•œ ๋ชจ๋ธ์€ ์ฑ„ํŒ…์— ๋Œ€ํ•ด ๋งค์šฐ ๋‹ค๋ฅธ ์ž…๋ ฅ ํ˜•์‹์„ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ **์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ**์„ ๊ธฐ๋Šฅ์œผ๋กœ ์ถ”๊ฐ€ํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค. ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์€ ํ† ํฌ๋‚˜์ด์ €์˜ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค. ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์€ ๋Œ€ํ™” ๋ชฉ๋ก์„ ๋ชจ๋ธ์ด ๊ธฐ๋Œ€ํ•˜๋Š” ํ˜•์‹์ธ '๋‹จ์ผ ํ† ํฐํ™”๊ฐ€ ๊ฐ€๋Šฅํ•œ ๋ฌธ์ž์—ด'๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
`BlenderBot` ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•œ ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ์ด๋ฅผ ๊ตฌ์ฒด์ ์œผ๋กœ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. BlenderBot์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋งค์šฐ ๊ฐ„๋‹จํ•œ ํ…œํ”Œ๋ฆฟ์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ, ์ฃผ๋กœ ๋Œ€ํ™” ๋ผ์šด๋“œ ์‚ฌ์ด์— ๊ณต๋ฐฑ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค:
```python
>>> from transformers import AutoTokenizer
>>> tokenizer = AutoTokenizer.from_pretrained("facebook/blenderbot-400M-distill")
>>> chat = [
... {"role": "user", "content": "Hello, how are you?"},
... {"role": "assistant", "content": "I'm doing great. How can I help you today?"},
... {"role": "user", "content": "I'd like to show off how chat templating works!"},
... ]
>>> tokenizer.apply_chat_template(chat, tokenize=False)
" Hello, how are you? I'm doing great. How can I help you today? I'd like to show off how chat templating works!</s>"
```
์ „์ฒด ์ฑ„ํŒ…์ด ํ•˜๋‚˜์˜ ๋ฌธ์ž์—ด๋กœ ์••์ถ•๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ์„ค์ •์ธ `tokenize=True`๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ๊ทธ ๋ฌธ์ž์—ด๋„ ํ† ํฐํ™”๋ฉ๋‹ˆ๋‹ค. ๋” ๋ณต์žกํ•œ ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด `mistralai/Mistral-7B-Instruct-v0.1` ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
```python
>>> from transformers import AutoTokenizer
>>> tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-Instruct-v0.1")
>>> chat = [
... {"role": "user", "content": "Hello, how are you?"},
... {"role": "assistant", "content": "I'm doing great. How can I help you today?"},
... {"role": "user", "content": "I'd like to show off how chat templating works!"},
... ]
>>> tokenizer.apply_chat_template(chat, tokenize=False)
"<s>[INST] Hello, how are you? [/INST]I'm doing great. How can I help you today?</s> [INST] I'd like to show off how chat templating works! [/INST]"
```
์ด๋ฒˆ์—๋Š” ํ† ํฌ๋‚˜์ด์ €๊ฐ€ [INST]์™€ [/INST] ์ œ์–ด ํ† ํฐ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์‚ฌ์šฉ์ž ๋ฉ”์‹œ์ง€์˜ ์‹œ์ž‘๊ณผ ๋์„ ํ‘œ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค(์–ด์‹œ์Šคํ„ดํŠธ ๋ฉ”์‹œ์ง€ ์ œ์™ธ). Mistral-instruct๋Š” ์ด๋Ÿฌํ•œ ํ† ํฐ์œผ๋กœ ํ›ˆ๋ จ๋˜์—ˆ์ง€๋งŒ, BlenderBot์€ ๊ทธ๋ ‡์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
## ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋‚˜์š”?[[how-do-i-use-chat-templates]]
์œ„์˜ ์˜ˆ์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์€ ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. `role`๊ณผ `content` ํ‚ค๊ฐ€ ํฌํ•จ๋œ ๋ฉ”์‹œ์ง€ ๋ชฉ๋ก์„ ์ž‘์„ฑํ•œ ๋‹ค์Œ, [`~PreTrainedTokenizer.apply_chat_template`] ๋ฉ”์„œ๋“œ์— ์ „๋‹ฌํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ถœ๋ ฅ์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค! ๋ชจ๋ธ ์ƒ์„ฑ์˜ ์ž…๋ ฅ์œผ๋กœ ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•  ๋•Œ, `add_generation_prompt=True`๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ [์ƒ์„ฑ ํ”„๋กฌํ”„ํŠธ](#what-are-generation-prompts)๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
๋‹ค์Œ์€ `Zephyr` ์–ด์‹œ์Šคํ„ดํŠธ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜์—ฌ `model.generate()`์˜ ์ž…๋ ฅ์„ ์ค€๋น„ํ•˜๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค:
```python
from transformers import AutoModelForCausalLM, AutoTokenizer
checkpoint = "HuggingFaceH4/zephyr-7b-beta"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForCausalLM.from_pretrained(checkpoint) # ์—ฌ๊ธฐ์„œ bfloat16 ์‚ฌ์šฉ ๋ฐ/๋˜๋Š” GPU๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
messages = [
{
"role": "system",
"content": "You are a friendly chatbot who always responds in the style of a pirate",
},
{"role": "user", "content": "How many helicopters can a human eat in one sitting?"},
]
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt")
print(tokenizer.decode(tokenized_chat[0]))
```
์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Zephyr๊ฐ€ ๊ธฐ๋Œ€ํ•˜๋Š” ์ž…๋ ฅ ํ˜•์‹์˜ ๋ฌธ์ž์—ด์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
```text
<|system|>
You are a friendly chatbot who always responds in the style of a pirate</s>
<|user|>
How many helicopters can a human eat in one sitting?</s>
<|assistant|>
```
์ด์ œ ์ž…๋ ฅ์ด Zephyr์— ๋งž๊ฒŒ ํ˜•์‹์ด ์ง€์ •๋˜์—ˆ์œผ๋ฏ€๋กœ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์— ๋Œ€ํ•œ ์‘๋‹ต์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:
```python
outputs = model.generate(tokenized_chat, max_new_tokens=128)
print(tokenizer.decode(outputs[0]))
```
์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ต๋‹ˆ๋‹ค:
```text
<|system|>
You are a friendly chatbot who always responds in the style of a pirate</s>
<|user|>
How many helicopters can a human eat in one sitting?</s>
<|assistant|>
Matey, I'm afraid I must inform ye that humans cannot eat helicopters. Helicopters are not food, they are flying machines. Food is meant to be eaten, like a hearty plate o' grog, a savory bowl o' stew, or a delicious loaf o' bread. But helicopters, they be for transportin' and movin' around, not for eatin'. So, I'd say none, me hearties. None at all.
```
์ด์ œ ์‰ฌ์›Œ์กŒ์ฃ !
## ์ฑ„ํŒ…์„ ์œ„ํ•œ ์ž๋™ํ™”๋œ ํŒŒ์ดํ”„๋ผ์ธ์ด ์žˆ๋‚˜์š”?[[is-there-an-automated-pipeline-for-chat]]
๋„ค, ์žˆ์Šต๋‹ˆ๋‹ค! ์šฐ๋ฆฌ์˜ ํ…์ŠคํŠธ ์ƒ์„ฑ ํŒŒ์ดํ”„๋ผ์ธ์€ ์ฑ„ํŒ… ์ž…๋ ฅ์„ ์ง€์›ํ•˜์—ฌ ์ฑ„ํŒ… ๋ชจ๋ธ์„ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ „์—๋Š” "ConversationalPipeline" ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ, ์ด์ œ๋Š” ์ด ๊ธฐ๋Šฅ์ด [`TextGenerationPipeline`]์— ํ†ตํ•ฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ์—๋Š” ํŒŒ์ดํ”„๋ผ์ธ์„ ์‚ฌ์šฉํ•˜์—ฌ `Zephyr` ์˜ˆ์ œ๋ฅผ ๋‹ค์‹œ ์‹œ๋„ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:
```python
from transformers import pipeline
pipe = pipeline("text-generation", "HuggingFaceH4/zephyr-7b-beta")
messages = [
{
"role": "system",
"content": "You are a friendly chatbot who always responds in the style of a pirate",
},
{"role": "user", "content": "How many helicopters can a human eat in one sitting?"},
]
print(pipe(messages, max_new_tokens=128)[0]['generated_text'][-1]) # ์–ด์‹œ์Šคํ„ดํŠธ์˜ ์‘๋‹ต์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.
```
```text
{'role': 'assistant', 'content': "Matey, I'm afraid I must inform ye that humans cannot eat helicopters. Helicopters are not food, they are flying machines. Food is meant to be eaten, like a hearty plate o' grog, a savory bowl o' stew, or a delicious loaf o' bread. But helicopters, they be for transportin' and movin' around, not for eatin'. So, I'd say none, me hearties. None at all."}
```
ํŒŒ์ดํ”„๋ผ์ธ์€ ํ† ํฐํ™”์™€ `apply_chat_template` ํ˜ธ์ถœ ์˜ ์„ธ๋ถ€ ์‚ฌํ•ญ์„ ๋ชจ๋‘ ์ฒ˜๋ฆฌํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์—, ๋ชจ๋ธ์— ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์ด ์žˆ์œผ๋ฉด ํŒŒ์ดํ”„๋ผ์ธ์„ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ๋ฉ”์‹œ์ง€ ๋ชฉ๋ก์„ ์ „๋‹ฌํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค!
## "์ƒ์„ฑ ํ”„๋กฌํ”„ํŠธ"๋ž€ ๋ฌด์—‡์ธ๊ฐ€์š”?[[what-are-generation-prompts]]
`apply_chat_template` ๋ฉ”์„œ๋“œ์—๋Š” `add_generation_prompt` ์ธ์ˆ˜๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ˆˆ์น˜์ฑ˜์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ์ธ์ˆ˜๋Š” ํ…œํ”Œ๋ฆฟ์— ๋ด‡ ์‘๋‹ต์˜ ์‹œ์ž‘์„ ๋‚˜ํƒ€๋‚ด๋Š” ํ† ํฐ์„ ์ถ”๊ฐ€ํ•˜๋„๋ก ์ง€์‹œํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฑ„ํŒ…์„ ๊ณ ๋ คํ•ด ๋ณด์„ธ์š”:
```python
messages = [
{"role": "user", "content": "Hi there!"},
{"role": "assistant", "content": "Nice to meet you!"},
{"role": "user", "content": "Can I ask a question?"}
]
```
Zephyr ์˜ˆ์ œ์—์„œ ๋ณด์•˜๋˜ ๊ฒƒ๊ณผ ๊ฐ™์ด, ์ƒ์„ฑ ํ”„๋กฌํ”„ํŠธ ์—†์ด ChatML ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณด์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค:
```python
tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=False)
"""<|im_start|>user
Hi there!<|im_end|>
<|im_start|>assistant
Nice to meet you!<|im_end|>
<|im_start|>user
Can I ask a question?<|im_end|>
"""
```
์ƒ์„ฑ ํ”„๋กฌํ”„ํŠธ๊ฐ€ **์žˆ๋Š”** ๊ฒฝ์šฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
```python
tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
"""<|im_start|>user
Hi there!<|im_end|>
<|im_start|>assistant
Nice to meet you!<|im_end|>
<|im_start|>user
Can I ask a question?<|im_end|>
<|im_start|>assistant
"""
```
์ด๋ฒˆ์—๋Š” ๋ด‡ ์‘๋‹ต์˜ ์‹œ์ž‘์„ ๋‚˜ํƒ€๋‚ด๋Š” ํ† ํฐ์„ ์ถ”๊ฐ€ํ•œ ๊ฒƒ์„ ์ฃผ๋ชฉํ•˜์„ธ์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ชจ๋ธ์ด ํ…์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์‚ฌ์šฉ์ž์˜ ๋ฉ”์‹œ์ง€๋ฅผ ๊ณ„์†ํ•˜๋Š” ๋Œ€์‹  ๋ด‡ ์‘๋‹ต์„ ์ž‘์„ฑํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ธฐ์–ตํ•˜์„ธ์š”, ์ฑ„ํŒ… ๋ชจ๋ธ์€ ์—ฌ์ „ํžˆ ์–ธ์–ด ๋ชจ๋ธ์ผ ๋ฟ์ด๋ฉฐ, ๊ทธ๋“ค์—๊ฒŒ ์ฑ„ํŒ…์€ ํŠน๋ณ„ํ•œ ์ข…๋ฅ˜์˜ ํ…์ŠคํŠธ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค! ์ ์ ˆํ•œ ์ œ์–ด ํ† ํฐ์œผ๋กœ ์•ˆ๋‚ดํ•ด์•ผ ์ฑ„ํŒ… ๋ชจ๋ธ์ด ๋ฌด์—‡์„ ํ•ด์•ผ ํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋ชจ๋“  ๋ชจ๋ธ์ด ์ƒ์„ฑ ํ”„๋กฌํ”„ํŠธ๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. BlenderBot๊ณผ LLaMA ๊ฐ™์€ ์ผ๋ถ€ ๋ชจ๋ธ์€ ๋ด‡ ์‘๋‹ต ์ „์— ํŠน๋ณ„ํ•œ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ `add_generation_prompt` ์ธ์ˆ˜๋Š” ํšจ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. `add_generation_prompt`์˜ ์ •ํ™•ํ•œ ํšจ๊ณผ๋Š” ์‚ฌ์šฉ ์ค‘์ธ ํ…œํ”Œ๋ฆฟ์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.
## ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ํ›ˆ๋ จ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‚˜์š”?[[can-i-use-chat-templates-in-training]]
๋„ค! ์ด ๋ฐฉ๋ฒ•์€ ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ๋ชจ๋ธ์ด ํ›ˆ๋ จ ์ค‘์— ๋ณด๋Š” ํ† ํฐ๊ณผ ์ผ์น˜ํ•˜๋„๋ก ํ•˜๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ ์„ธํŠธ์— ๋Œ€ํ•œ ์ „์ฒ˜๋ฆฌ ๋‹จ๊ณ„๋กœ ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ ํ›„์—๋Š” ๋‹ค๋ฅธ ์–ธ์–ด ๋ชจ๋ธ ํ›ˆ๋ จ ์ž‘์—…๊ณผ ๊ฐ™์ด ๊ณ„์†ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ›ˆ๋ จํ•  ๋•Œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ `add_generation_prompt=False`๋กœ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์–ด์‹œ์Šคํ„ดํŠธ ์‘๋‹ต์„ ํ”„๋กฌํ”„ํŠธํ•˜๋Š” ์ถ”๊ฐ€ ํ† ํฐ์€ ํ›ˆ๋ จ ์ค‘์—๋Š” ๋„์›€์ด ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์˜ˆ์ œ๋ฅผ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:
```python
from transformers import AutoTokenizer
from datasets import Dataset
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta")
chat1 = [
{"role": "user", "content": "Which is bigger, the moon or the sun?"},
{"role": "assistant", "content": "The sun."}
]
chat2 = [
{"role": "user", "content": "Which is bigger, a virus or a bacterium?"},
{"role": "assistant", "content": "A bacterium."}
]
dataset = Dataset.from_dict({"chat": [chat1, chat2]})
dataset = dataset.map(lambda x: {"formatted_chat": tokenizer.apply_chat_template(x["chat"], tokenize=False, add_generation_prompt=False)})
print(dataset['formatted_chat'][0])
```
๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:
```text
<|user|>
Which is bigger, the moon or the sun?</s>
<|assistant|>
The sun.</s>
```
์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ๋Š” ์ผ๋ฐ˜์ ์ธ ์–ธ์–ด ๋ชจ๋ธ ์ž‘์—…๊ณผ ๊ฐ™์ด `formatted_chat` ์—ด์„ ์‚ฌ์šฉํ•˜์—ฌ ํ›ˆ๋ จ์„ ๊ณ„์†ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
<Tip>
`apply_chat_template(tokenize=False)`๋กœ ํ…์ŠคํŠธ๋ฅผ ํ˜•์‹ํ™”ํ•œ ๋‹ค์Œ ๋ณ„๋„์˜ ๋‹จ๊ณ„์—์„œ ํ† ํฐํ™”ํ•˜๋Š” ๊ฒฝ์šฐ, `add_special_tokens=False` ์ธ์ˆ˜๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. `apply_chat_template(tokenize=True)`๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์ด ๋ฌธ์ œ๋ฅผ ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค!
๊ธฐ๋ณธ์ ์œผ๋กœ ์ผ๋ถ€ ํ† ํฌ๋‚˜์ด์ €๋Š” ํ† ํฐํ™”ํ•  ๋•Œ `<bos>` ๋ฐ `<eos>`์™€ ๊ฐ™์€ ํŠน๋ณ„ ํ† ํฐ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์€ ํ•ญ์ƒ ํ•„์š”ํ•œ ๋ชจ๋“  ํŠน๋ณ„ ํ† ํฐ์„ ํฌํ•จํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ๊ธฐ๋ณธ `add_special_tokens=True`๋กœ ์ถ”๊ฐ€์ ์ธ ํŠน๋ณ„ ํ† ํฐ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ์ž˜๋ชป๋˜๊ฑฐ๋‚˜ ์ค‘๋ณต๋˜๋Š” ํŠน๋ณ„ ํ† ํฐ์„ ์ƒ์„ฑํ•˜์—ฌ ๋ชจ๋ธ ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
</Tip>
## ๊ณ ๊ธ‰: ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์— ์ถ”๊ฐ€ ์ž…๋ ฅ ์‚ฌ์šฉ[[advanced-extra-inputs-to-chat-templates]]
`apply_chat_template`๊ฐ€ ํ•„์š”ํ•œ ์œ ์ผํ•œ ์ธ์ˆ˜๋Š” `messages`์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ `apply_chat_template`์— ํ‚ค์›Œ๋“œ ์ธ์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ํ…œํ”Œ๋ฆฟ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ๋‹ค์–‘ํ•œ ์šฉ๋„๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ž์œ ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ธ์ˆ˜์˜ ์ด๋ฆ„์ด๋‚˜ ํ˜•์‹์—๋Š” ์ œํ•œ์ด ์—†์–ด ๋ฌธ์ž์—ด, ๋ฆฌ์ŠคํŠธ, ๋”•์…”๋„ˆ๋ฆฌ ๋“ฑ์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ ‡๊ธด ํ•˜์ง€๋งŒ, ์ด๋Ÿฌํ•œ ์ถ”๊ฐ€ ์ธ์ˆ˜์˜ ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ ์‚ฌ๋ก€๋กœ 'ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ์œ„ํ•œ ๋„๊ตฌ'๋‚˜ '๊ฒ€์ƒ‰ ์ฆ๊ฐ• ์ƒ์„ฑ์„ ์œ„ํ•œ ๋ฌธ์„œ'๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ์— ๋Œ€ํ•ด ์ธ์ˆ˜์˜ ์ด๋ฆ„๊ณผ ํ˜•์‹์— ๋Œ€ํ•œ ๋ช‡ ๊ฐ€์ง€ ๊ถŒ์žฅ ์‚ฌํ•ญ์ด ์žˆ์œผ๋ฉฐ, ์ด๋Š” ์•„๋ž˜ ์„น์…˜์— ์„ค๋ช…๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋ชจ๋ธ ์ž‘์„ฑ์ž์—๊ฒŒ ๋„๊ตฌ ํ˜ธ์ถœ ์ฝ”๋“œ๋ฅผ ๋ชจ๋ธ ๊ฐ„์— ์‰ฝ๊ฒŒ ์ „์†กํ•  ์ˆ˜ ์žˆ๋„๋ก ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ์ด ํ˜•์‹๊ณผ ํ˜ธํ™˜๋˜๋„๋ก ๋งŒ๋“ค ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.
## ๊ณ ๊ธ‰: ๋„๊ตฌ ์‚ฌ์šฉ / ํ•จ์ˆ˜ ํ˜ธ์ถœ[[advanced-tool-use--function-calling]]
"๋„๊ตฌ ์‚ฌ์šฉ" LLM์€ ๋‹ต๋ณ€์„ ์ƒ์„ฑํ•˜๊ธฐ ์ „์— ์™ธ๋ถ€ ๋„๊ตฌ๋กœ์„œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋„๊ตฌ ์‚ฌ์šฉ ๋ชจ๋ธ์— ๋„๊ตฌ๋ฅผ ์ „๋‹ฌํ•  ๋•Œ๋Š” ๋‹จ์ˆœํžˆ ํ•จ์ˆ˜ ๋ชฉ๋ก์„ `tools` ์ธ์ˆ˜๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:
```python
import datetime
def current_time():
"""ํ˜„์žฌ ํ˜„์ง€ ์‹œ๊ฐ„์„ ๋ฌธ์ž์—ด๋กœ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค."""
return str(datetime.now())
def multiply(a: float, b: float):
"""
๋‘ ์ˆซ์ž๋ฅผ ๊ณฑํ•˜๋Š” ํ•จ์ˆ˜
์ธ์ˆ˜:
a: ๊ณฑํ•  ์ฒซ ๋ฒˆ์งธ ์ˆซ์ž
b: ๊ณฑํ•  ๋‘ ๋ฒˆ์งธ ์ˆซ์ž
"""
return a * b
tools = [current_time, multiply]
model_input = tokenizer.apply_chat_template(
messages,
tools=tools
)
```
์ด๊ฒƒ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋ ค๋ฉด ํ•จ์ˆ˜๋ฅผ ์œ„ ํ˜•์‹์œผ๋กœ ์ž‘์„ฑํ•ด์•ผ ๋„๊ตฌ๋กœ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌ๋ฌธ ๋ถ„์„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ตฌ์ฒด์ ์œผ๋กœ ๋‹ค์Œ ๊ทœ์น™์„ ๋”ฐ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค:
- ํ•จ์ˆ˜๋Š” ์„ค๋ช…์ ์ธ ์ด๋ฆ„์„ ๊ฐ€์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
- ๋ชจ๋“  ์ธ์ˆ˜์—๋Š” ํƒ€์ž… ํžŒํŠธ๊ฐ€ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
- ํ•จ์ˆ˜์—๋Š” ํ‘œ์ค€ Google ์Šคํƒ€์ผ์˜ ๋„ํฌ์ŠคํŠธ๋ง์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(์ฆ‰, ์ดˆ๊ธฐ ํ•จ์ˆ˜ ์„ค๋ช… ๋‹ค์Œ์— ์ธ์ˆ˜๋ฅผ ์„ค๋ช…ํ•˜๋Š” `Args:` ๋ธ”๋ก์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค).
- `Args:` ๋ธ”๋ก์—๋Š” ํƒ€์ž…์„ ํฌํ•จํ•˜์ง€ ๋งˆ์„ธ์š”. ์ฆ‰, `a (int): The first number to multiply` ๋Œ€์‹  `a: The first number to multiply`๋ผ๊ณ  ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํƒ€์ž… ํžŒํŠธ๋Š” ํ•จ์ˆ˜ ํ—ค๋”์— ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
- ํ•จ์ˆ˜์—๋Š” ๋ฐ˜ํ™˜ ํƒ€์ž…๊ณผ ๋„ํฌ์ŠคํŠธ๋ง์— `Returns:` ๋ธ”๋ก์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋Œ€๋ถ€๋ถ„์˜ ๋„๊ตฌ ์‚ฌ์šฉ ๋ชจ๋ธ์€ ์ด๋ฅผ ๋ฌด์‹œํ•˜๋ฏ€๋กœ ์ด๋Š” ์„ ํƒ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.
### ๋„๊ตฌ ๊ฒฐ๊ณผ๋ฅผ ๋ชจ๋ธ์— ์ „๋‹ฌํ•˜๊ธฐ[[passing-tool-results-to-the-model]]
์œ„์˜ ์˜ˆ์ œ ์ฝ”๋“œ๋Š” ๋ชจ๋ธ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋„๊ตฌ๋ฅผ ๋‚˜์—ดํ•˜๋Š” ๋ฐ ์ถฉ๋ถ„ํ•˜์ง€๋งŒ, ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”? ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ์—๋Š” ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:
1. ๋ชจ๋ธ์˜ ์ถœ๋ ฅ์„ ํŒŒ์‹ฑํ•˜์—ฌ ๋„๊ตฌ ์ด๋ฆ„๊ณผ ์ธ์ˆ˜๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
2. ๋ชจ๋ธ์˜ ๋„๊ตฌ ํ˜ธ์ถœ์„ ๋Œ€ํ™”์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
3. ํ•ด๋‹น ์ธ์ˆ˜์— ๋Œ€์‘ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
4. ๊ฒฐ๊ณผ๋ฅผ ๋Œ€ํ™”์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
### ๋„๊ตฌ ์‚ฌ์šฉ ์˜ˆ์ œ[[a-complete-tool-use-example]]
๋„๊ตฌ ์‚ฌ์šฉ ์˜ˆ์ œ๋ฅผ ๋‹จ๊ณ„๋ณ„๋กœ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š” ๋„๊ตฌ ์‚ฌ์šฉ ๋ชจ๋ธ ์ค‘์—์„œ ์„ฑ๋Šฅ์ด ๊ฐ€์žฅ ์šฐ์ˆ˜ํ•œ 8B `Hermes-2-Pro` ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ถฉ๋ถ„ํ•˜๋‹ค๋ฉด, ๋” ํฐ ๋ชจ๋ธ์ธ [Command-R](https://huggingface.co/CohereForAI/c4ai-command-r-v01) ๋˜๋Š” [Mixtral-8x22B](https://huggingface.co/mistralai/Mixtral-8x22B-Instruct-v0.1)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋‘ ๋ชจ๋ธ ๋ชจ๋‘ ๋„๊ตฌ ์‚ฌ์šฉ์„ ์ง€์›ํ•˜๋ฉฐ ๋” ๊ฐ•๋ ฅํ•œ ์„ฑ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
๋จผ์ € ๋ชจ๋ธ๊ณผ ํ† ํฌ๋‚˜์ด์ €๋ฅผ ๋กœ๋“œํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:
```python
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
checkpoint = "NousResearch/Hermes-2-Pro-Llama-3-8B"
tokenizer = AutoTokenizer.from_pretrained(checkpoint, revision="pr/13")
model = AutoModelForCausalLM.from_pretrained(checkpoint, torch_dtype=torch.bfloat16, device_map="auto")
```
๋‹ค์Œ์œผ๋กœ, ๋„๊ตฌ ๋ชฉ๋ก์„ ์ •์˜ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:
```python
def get_current_temperature(location: str, unit: str) -> float:
"""
ํŠน์ • ์œ„์น˜์˜ ํ˜„์žฌ ์˜จ๋„๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
์ธ์ˆ˜:
์œ„์น˜: ์˜จ๋„๋ฅผ ๊ฐ€์ ธ์˜ฌ ์œ„์น˜, "๋„์‹œ, ๊ตญ๊ฐ€" ํ˜•์‹
๋‹จ์œ„: ์˜จ๋„ ๋‹จ์œ„ (์„ ํƒ์ง€: ["celsius", "fahrenheit"])
๋ฐ˜ํ™˜๊ฐ’:
์ง€์ •๋œ ์œ„์น˜์˜ ํ˜„์žฌ ์˜จ๋„๋ฅผ ์ง€์ •๋œ ๋‹จ์œ„๋กœ ๋ฐ˜ํ™˜, float ํ˜•์‹.
"""
return 22. # ์ด ํ•จ์ˆ˜๋Š” ์‹ค์ œ๋กœ ์˜จ๋„๋ฅผ ๊ฐ€์ ธ์™€์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค!
def get_current_wind_speed(location: str) -> float:
"""
์ฃผ์–ด์ง„ ์œ„์น˜์˜ ํ˜„์žฌ ํ’์†์„ km/h ๋‹จ์œ„๋กœ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
์ธ์ˆ˜:
์œ„์น˜(location): ํ’์†์„ ๊ฐ€์ ธ์˜ฌ ์œ„์น˜, "๋„์‹œ, ๊ตญ๊ฐ€" ํ˜•์‹
๋ฐ˜ํ™˜๊ฐ’:
์ฃผ์–ด์ง„ ์œ„์น˜์˜ ํ˜„์žฌ ํ’์†์„ km/h ๋‹จ์œ„๋กœ ๋ฐ˜ํ™˜, float ํ˜•์‹.
"""
return 6. # ์ด ํ•จ์ˆ˜๋Š” ์‹ค์ œ๋กœ ํ’์†์„ ๊ฐ€์ ธ์™€์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค!
tools = [get_current_temperature, get_current_wind_speed]
```
์ด์ œ ๋ด‡์„ ์œ„ํ•œ ๋Œ€ํ™”๋ฅผ ์„ค์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:
```python
messages = [
{"role": "system", "content": "You are a bot that responds to weather queries. You should reply with the unit used in the queried location."},
{"role": "user", "content": "Hey, what's the temperature in Paris right now?"}
]
```
์ด์ œ ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ์ ์šฉํ•˜๊ณ  ์‘๋‹ต์„ ์ƒ์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:
```python
inputs = tokenizer.apply_chat_template(messages, chat_template="tool_use", tools=tools, add_generation_prompt=True, return_dict=True, return_tensors="pt")
inputs = {k: v.to(model.device) for k, v in inputs.items()}
out = model.generate(**inputs, max_new_tokens=128)
print(tokenizer.decode(out[0][len(inputs["input_ids"][0]):]))
```
๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
```text
<tool_call>
{"arguments": {"location": "Paris, France", "unit": "celsius"}, "name": "get_current_temperature"}
</tool_call><|im_end|>
```
๋ชจ๋ธ์ด ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ์œ ํšจํ•œ ์ธ์ˆ˜๋กœ ์ˆ˜ํ–‰ํ–ˆ์œผ๋ฉฐ, ํ•จ์ˆ˜ ๋„ํฌ์ŠคํŠธ๋ง์— ์š”์ฒญ๋œ ํ˜•์‹์œผ๋กœ ํ˜ธ์ถœํ–ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋ธ์€ ์šฐ๋ฆฌ๊ฐ€ ํ”„๋ž‘์Šค์˜ ํŒŒ๋ฆฌ๋ฅผ ์ง€์นญํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ถ”๋ก ํ–ˆ๊ณ , ํ”„๋ž‘์Šค๊ฐ€ SI ๋‹จ์œ„์˜ ๋ณธ๊ณ ์žฅ์ž„์„ ๊ธฐ์–ตํ•˜์—ฌ ์˜จ๋„๋ฅผ ์„ญ์”จ๋กœ ํ‘œ์‹œํ•ด์•ผ ํ•œ๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค.
๋ชจ๋ธ์˜ ๋„๊ตฌ ํ˜ธ์ถœ์„ ๋Œ€ํ™”์— ์ถ”๊ฐ€ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ž„์˜์˜ `tool_call_id`๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ID๋Š” ๋ชจ๋“  ๋ชจ๋ธ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ, ์—ฌ๋Ÿฌ ๋„๊ตฌ ํ˜ธ์ถœ์„ ํ•œ ๋ฒˆ์— ๋ฐœํ–‰ํ•˜๊ณ  ๊ฐ ์‘๋‹ต์ด ์–ด๋А ํ˜ธ์ถœ์— ํ•ด๋‹นํ•˜๋Š”์ง€ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. ์ด ID๋Š” ๋Œ€ํ™” ๋‚ด์—์„œ ๊ณ ์œ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
```python
tool_call_id = "vAHdf3" # ์ž„์˜์˜ ID, ๊ฐ ๋„๊ตฌ ํ˜ธ์ถœ๋งˆ๋‹ค ๊ณ ์œ ํ•ด์•ผ ํ•จ
tool_call = {"name": "get_current_temperature", "arguments": {"location": "Paris, France", "unit": "celsius"}}
messages.append({"role": "assistant", "tool_calls": [{"id": tool_call_id, "type": "function", "function": tool_call}]})
```
์ด์ œ ๋„๊ตฌ ํ˜ธ์ถœ์„ ๋Œ€ํ™”์— ์ถ”๊ฐ€ํ–ˆ์œผ๋ฏ€๋กœ, ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋Œ€ํ™”์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š” ํ•ญ์ƒ 22.0์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋”๋ฏธ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ, ๊ฒฐ๊ณผ๋ฅผ ์ง์ ‘ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋‹ค์‹œ ํ•œ ๋ฒˆ, `tool_call_id`๋Š” ๋„๊ตฌ ํ˜ธ์ถœ์— ์‚ฌ์šฉํ–ˆ๋˜ ID์™€ ์ผ์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
```python
messages.append({"role": "tool", "tool_call_id": tool_call_id, "name": "get_current_temperature", "content": "22.0"})
```
๋งˆ์ง€๋ง‰์œผ๋กœ, ์–ด์‹œ์Šคํ„ดํŠธ๊ฐ€ ํ•จ์ˆ˜ ์ถœ๋ ฅ์„ ์ฝ๊ณ  ์‚ฌ์šฉ์ž์™€ ๊ณ„์† ๋Œ€ํ™”ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค:
```python
inputs = tokenizer.apply_chat_template(messages, chat_template="tool_use", tools=tools, add_generation_prompt=True, return_dict=True, return_tensors="pt")
inputs = {k: v.to(model.device) for k, v in inputs.items()}
out = model.generate(**inputs, max_new_tokens=128)
print(tokenizer.decode(out[0][len(inputs["input_ids"][0]):]))
```
๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
```text
The current temperature in Paris, France is 22.0 ยฐ Celsius.<|im_end|>
```
์ด๊ฒƒ์€ ๋”๋ฏธ ๋„๊ตฌ์™€ ๋‹จ์ผ ํ˜ธ์ถœ์„ ์‚ฌ์šฉํ•œ ๊ฐ„๋‹จํ•œ ๋ฐ๋ชจ์˜€์ง€๋งŒ, ๋™์ผํ•œ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ์‹ค์ œ ๋„๊ตฌ์™€ ๋” ๊ธด ๋Œ€ํ™”๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‹ค์‹œ๊ฐ„ ์ •๋ณด, ๊ณ„์‚ฐ ๋„๊ตฌ ๋˜๋Š” ๋Œ€๊ทœ๋ชจ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผํ•˜์—ฌ ๋Œ€ํ™”ํ˜• ์—์ด์ „ํŠธ์˜ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
<Tip>
์œ„์—์„œ ๋ณด์—ฌ์ค€ ๋„๊ตฌ ํ˜ธ์ถœ ๊ธฐ๋Šฅ์€ ๋ชจ๋“  ๋ชจ๋ธ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ์ผ๋ถ€ ๋ชจ๋ธ์€ ๋„๊ตฌ ํ˜ธ์ถœ ID๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ์ผ๋ถ€๋Š” ํ•จ์ˆ˜ ์ด๋ฆ„๋งŒ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒฐ๊ณผ์™€ ๋„๊ตฌ ํ˜ธ์ถœ์„ ์ˆœ์„œ์— ๋”ฐ๋ผ ๋งค์นญํ•˜๋ฉฐ, ํ˜ผ๋™์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ๋„๊ตฌ ํ˜ธ์ถœ๋งŒ ๋ฐœํ–‰ํ•˜๋Š” ๋ชจ๋ธ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€๋Šฅํ•œ ๋งŽ์€ ๋ชจ๋ธ๊ณผ ํ˜ธํ™˜๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์›ํ•œ๋‹ค๋ฉด, ์—ฌ๊ธฐ์— ๋ณด์—ฌ์ค€ ๊ฒƒ์ฒ˜๋Ÿผ ๋„๊ตฌ ํ˜ธ์ถœ์„ ๊ตฌ์„ฑํ•˜๊ณ , ๋ชจ๋ธ์ด ๋ฐœํ–‰ํ•œ ์ˆœ์„œ๋Œ€๋กœ ๋„๊ตฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ๋ชจ๋ธ์˜ ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์ด ๋‚˜๋จธ์ง€ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
</Tip>
### ๋„๊ตฌ ์Šคํ‚ค๋งˆ ์ดํ•ดํ•˜๊ธฐ[[understanding-tool-schemas]]
`apply_chat_template`์˜ `tools` ์ธ์ˆ˜์— ์ „๋‹ฌํ•˜๋Š” ๊ฐ ํ•จ์ˆ˜๋Š” [JSON ์Šคํ‚ค๋งˆ](https://json-schema.org/learn/getting-started-step-by-step)๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์Šคํ‚ค๋งˆ๋Š” ๋ชจ๋ธ ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์— ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค. ์ฆ‰, ๋„๊ตฌ ์‚ฌ์šฉ ๋ชจ๋ธ์€ ํ•จ์ˆ˜ ์ž์ฒด๋ฅผ ์ง์ ‘ ๋ณด์ง€ ์•Š์œผ๋ฉฐ, ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ๋ณด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋„๊ตฌ ์‚ฌ์šฉ ๋ชจ๋ธ์ด ๊ด€์‹ฌ์„ ๊ฐ€์ง€๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ **์ •์˜**์™€ **์ธ์ˆ˜**์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ๋ฌด์—‡์„ ํ•˜๊ณ  ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€์— ๊ด€์‹ฌ์ด ์žˆ์„ ๋ฟ, ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค! ๋ชจ๋ธ์˜ ์ถœ๋ ฅ์„ ์ฝ๊ณ  ๋ชจ๋ธ์ด ๋„๊ตฌ ์‚ฌ์šฉ์„ ์š”์ฒญํ–ˆ๋Š”์ง€ ๊ฐ์ง€ํ•˜์—ฌ, ์ธ์ˆ˜๋ฅผ ๋„๊ตฌ ํ•จ์ˆ˜์— ์ „๋‹ฌํ•˜๊ณ  ์ฑ„ํŒ…์—์„œ ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์€ ์—ฌ๋Ÿฌ๋ถ„์˜ ๋ชซ์ž…๋‹ˆ๋‹ค.
์œ„์˜ ๊ทœ๊ฒฉ์„ ๋”ฐ๋ฅธ๋‹ค๋ฉด, ํ…œํ”Œ๋ฆฟ์— ์ „๋‹ฌํ•  JSON ์Šคํ‚ค๋งˆ ์ƒ์„ฑ์„ ์ž๋™ํ™”ํ•˜๊ณ  ๋ณด์ด์ง€ ์•Š๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜ ๋ณ€ํ™˜์„ ๋” ์ œ์–ดํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ˆ˜๋™์œผ๋กœ ๋ณ€ํ™˜์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ์ˆ˜๋™ ์Šคํ‚ค๋งˆ ๋ณ€ํ™˜ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.
```python
from transformers.utils import get_json_schema
def multiply(a: float, b: float):
"""
๋‘ ์ˆซ์ž๋ฅผ ๊ณฑํ•˜๋Š” ํ•จ์ˆ˜
์ธ์ˆ˜:
a: ๊ณฑํ•  ์ฒซ ๋ฒˆ์งธ ์ˆซ์ž
b: ๊ณฑํ•  ๋‘ ๋ฒˆ์งธ ์ˆซ์ž
"""
return a * b
schema = get_json_schema(multiply)
print(schema)
```
์ด ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
```json
{
"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"]
}
}
}
```
์›ํ•œ๋‹ค๋ฉด ์ด๋Ÿฌํ•œ ์Šคํ‚ค๋งˆ๋ฅผ ํŽธ์ง‘ํ•˜๊ฑฐ๋‚˜ `get_json_schema`๋ฅผ ์ „ํ˜€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์ฒ˜์Œ๋ถ€ํ„ฐ ์ง์ ‘ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. JSON ์Šคํ‚ค๋งˆ๋Š” `apply_chat_template`์˜ `tools` ์ธ์ˆ˜์— ์ง์ ‘ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋” ๋ณต์žกํ•œ ํ•จ์ˆ˜์— ๋Œ€ํ•œ ์ •๋ฐ€ํ•œ ์Šคํ‚ค๋งˆ๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์Šคํ‚ค๋งˆ๊ฐ€ ๋ณต์žกํ• ์ˆ˜๋ก ๋ชจ๋ธ์ด ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ํ˜ผ๋ž€์„ ๊ฒช์„ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์•„์ง‘๋‹ˆ๋‹ค! ๊ฐ€๋Šฅํ•œ ํ•œ ๊ฐ„๋‹จํ•œ ํ•จ์ˆ˜ ์„œ๋ช…์„ ์œ ์ง€ํ•˜๊ณ , ์ธ์ˆ˜(ํŠนํžˆ ๋ณต์žกํ•˜๊ณ  ์ค‘์ฒฉ๋œ ์ธ์ˆ˜)๋ฅผ ์ตœ์†Œํ™”ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.
์—ฌ๊ธฐ ์ง์ ‘ ์Šคํ‚ค๋งˆ๋ฅผ ์ •์˜ํ•˜๊ณ  ์ด๋ฅผ `apply_chat_template`์— ์ „๋‹ฌํ•˜๋Š” ์˜ˆ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค:
```python
# ์ธ์ˆ˜๋ฅผ ๋ฐ›์ง€ ์•Š๋Š” ๊ฐ„๋‹จํ•œ ํ•จ์ˆ˜
current_time = {
"type": "function",
"function": {
"name": "current_time",
"description": "Get the current local time as a string.",
"parameters": {
'type': 'object',
'properties': {}
}
}
}
# ๋‘ ๊ฐœ์˜ ์ˆซ์ž ์ธ์ˆ˜๋ฅผ ๋ฐ›๋Š” ๋” ์™„์ „ํ•œ ํ•จ์ˆ˜
multiply = {
'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']
}
}
}
model_input = tokenizer.apply_chat_template(
messages,
tools = [current_time, multiply]
)
```
## ๊ณ ๊ธ‰: ๊ฒ€์ƒ‰ ์ฆ๊ฐ• ์ƒ์„ฑ[[advanced-retrieval-augmented-generation]]
"๊ฒ€์ƒ‰ ์ฆ๊ฐ• ์ƒ์„ฑ" ๋˜๋Š” "RAG" LLM์€ ์ฟผ๋ฆฌ์— ์‘๋‹ตํ•˜๊ธฐ ์ „์— ๋ฌธ์„œ์˜ ์ฝ”ํผ์Šค๋ฅผ ๊ฒ€์ƒ‰ํ•˜์—ฌ ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ชจ๋ธ์€ ์ œํ•œ๋œ ์ปจํ…์ŠคํŠธ ํฌ๊ธฐ ์ด์ƒ์œผ๋กœ ์ง€์‹ ๊ธฐ๋ฐ˜์„ ํฌ๊ฒŒ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. RAG ๋ชจ๋ธ์— ๋Œ€ํ•œ ์šฐ๋ฆฌ์˜ ๊ถŒ์žฅ ์‚ฌํ•ญ์€ ํ…œํ”Œ๋ฆฟ์ด `documents` ์ธ์ˆ˜๋ฅผ ํ—ˆ์šฉํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ์ธ์ˆ˜๋Š” ๊ฐ "๋ฌธ์„œ"๊ฐ€ `title`๊ณผ `contents` ํ‚ค๋ฅผ ๊ฐ€์ง€๋Š” ๋‹จ์ผ dict์ธ ๋ฌธ์„œ ๋ชฉ๋ก์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ˜•์‹์€ ๋„๊ตฌ์— ์‚ฌ์šฉ๋˜๋Š” JSON ์Šคํ‚ค๋งˆ๋ณด๋‹ค ํ›จ์”ฌ ๊ฐ„๋‹จํ•˜๋ฏ€๋กœ ๋ณ„๋„์˜ ๋„์šฐ๋ฏธ ํ•จ์ˆ˜๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋‹ค์Œ์€ RAG ํ…œํ”Œ๋ฆฟ์ด ์ž‘๋™ํ•˜๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค:
```python
document1 = {
"title": "The Moon: Our Age-Old Foe",
"contents": "Man has always dreamed of destroying the moon. In this essay, I shall..."
}
document2 = {
"title": "The Sun: Our Age-Old Friend",
"contents": "Although often underappreciated, the sun provides several notable benefits..."
}
model_input = tokenizer.apply_chat_template(
messages,
documents=[document1, document2]
)
```
## ๊ณ ๊ธ‰: ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋‚˜์š”?[[advanced-how-do-chat-templates-work]]
๋ชจ๋ธ์˜ ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์€ `tokenizer.chat_template` ์†์„ฑ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์ด ์„ค์ •๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ํ•ด๋‹น ๋ชจ๋ธ ํด๋ž˜์Šค์˜ ๊ธฐ๋ณธ ํ…œํ”Œ๋ฆฟ์ด ๋Œ€์‹  ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. `BlenderBot`์˜ ํ…œํ”Œ๋ฆฟ์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:
```python
>>> from transformers import AutoTokenizer
>>> tokenizer = AutoTokenizer.from_pretrained("facebook/blenderbot-400M-distill")
>>> tokenizer.chat_template
"{% for message in messages %}{% if message['role'] == 'user' %}{{ ' ' }}{% endif %}{{ message['content'] }}{% if not loop.last %}{{ ' ' }}{% endif %}{% endfor %}{{ eos_token }}"
```
์•ฝ๊ฐ„ ๋ณต์žกํ•ด ๋ณด์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ๊ธฐ ์‰ฝ๊ฒŒ ์ •๋ฆฌํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์—์„œ ์ถ”๊ฐ€ํ•˜๋Š” ์ค„๋ฐ”๊ฟˆ๊ณผ ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ํ…œํ”Œ๋ฆฟ ์ถœ๋ ฅ์— ํฌํ•จ๋˜์ง€ ์•Š๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” [๊ณต๋ฐฑ์„ ์ œ๊ฑฐํ•˜๋Š”](#trimming-whitespace) ํŒ์ž…๋‹ˆ๋‹ค:
```
{%- for message in messages %}
{%- if message['role'] == 'user' %}
{{- ' ' }}
{%- endif %}
{{- message['content'] }}
{%- if not loop.last %}
{{- ' ' }}
{%- endif %}
{%- endfor %}
{{- eos_token }}
```
๋งŒ์•ฝ ์ด์™€ ๊ฐ™์€ ํ˜•์‹์„ ์ฒ˜์Œ ๋ณธ๋‹ค๋ฉด, ์ด๊ฒƒ์€ [Jinja ํ…œํ”Œ๋ฆฟ](https://jinja.palletsprojects.com/en/3.1.x/templates/)์ž…๋‹ˆ๋‹ค.
Jinja๋Š” ํ…์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ํ…œํ”Œ๋ฆฟ ์–ธ์–ด์ž…๋‹ˆ๋‹ค. ๋งŽ์€ ๋ฉด์—์„œ ์ฝ”๋“œ์™€ ๊ตฌ๋ฌธ์ด ํŒŒ์ด์ฌ๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ˆœ์ˆ˜ ํŒŒ์ด์ฌ์—์„œ๋Š” ์ด ํ…œํ”Œ๋ฆฟ์ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณด์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค:
```python
for idx, message in enumerate(messages):
if message['role'] == 'user':
print(' ')
print(message['content'])
if not idx == len(messages) - 1: # Check for the last message in the conversation
print(' ')
print(eos_token)
```
์ด ํ…œํ”Œ๋ฆฟ์€ ์„ธ ๊ฐ€์ง€ ์ผ์„ ํ•ฉ๋‹ˆ๋‹ค:
1. ๊ฐ ๋ฉ”์‹œ์ง€์— ๋Œ€ํ•ด, ๋ฉ”์‹œ์ง€๊ฐ€ ์‚ฌ์šฉ์ž ๋ฉ”์‹œ์ง€์ธ ๊ฒฝ์šฐ ๊ณต๋ฐฑ์„ ์ถ”๊ฐ€ํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์•„๋ฌด๊ฒƒ๋„ ์ถœ๋ ฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
2. ๋ฉ”์‹œ์ง€ ๋‚ด์šฉ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
3. ๋ฉ”์‹œ์ง€๊ฐ€ ๋งˆ์ง€๋ง‰ ๋ฉ”์‹œ์ง€๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ ๋‘ ๊ฐœ์˜ ๊ณต๋ฐฑ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰ ๋ฉ”์‹œ์ง€ ํ›„์—๋Š” EOS ํ† ํฐ์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.
์ด๊ฒƒ์€ ๋งค์šฐ ๊ฐ„๋‹จํ•œ ํ…œํ”Œ๋ฆฟ์ž…๋‹ˆ๋‹ค. ์ œ์–ด ํ† ํฐ์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์œผ๋ฉฐ, ์ดํ›„ ๋Œ€ํ™”์—์„œ ๋ชจ๋ธ์ด ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•ด์•ผ ํ•˜๋Š”์ง€ ์ง€์‹œํ•˜๋Š” "์‹œ์Šคํ…œ" ๋ฉ”์‹œ์ง€๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ Jinja๋Š” ์ด๋Ÿฌํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๋งŽ์€ ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค! LLaMA๊ฐ€ ์ž…๋ ฅ์„ ํ˜•์‹ํ™”ํ•˜๋Š” ๋ฐฉ์‹๊ณผ ์œ ์‚ฌํ•œ ํ˜•์‹์˜ Jinja ํ…œํ”Œ๋ฆฟ์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค(์‹ค์ œ LLaMA ํ…œํ”Œ๋ฆฟ์€ ๊ธฐ๋ณธ ์‹œ์Šคํ…œ ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ์™€ ์ผ๋ฐ˜์ ์ธ ์‹œ์Šคํ…œ ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค - ์‹ค์ œ ์ฝ”๋“œ์—์„œ๋Š” ์ด ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์„ธ์š”!).
```
{%- for message in messages %}
{%- if message['role'] == 'user' %}
{{- bos_token + '[INST] ' + message['content'] + ' [/INST]' }}
{%- elif message['role'] == 'system' %}
{{- '<<SYS>>\\n' + message['content'] + '\\n<</SYS>>\\n\\n' }}
{%- elif message['role'] == 'assistant' %}
{{- ' ' + message['content'] + ' ' + eos_token }}
{%- endif %}
{%- endfor %}
```
์ด ํ…œํ”Œ๋ฆฟ์„ ์ž ์‹œ ์‚ดํŽด๋ณด๋ฉด ๋ฌด์—‡์„ ํ•˜๋Š”์ง€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋จผ์ €, ๊ฐ ๋ฉ”์‹œ์ง€์˜ "role"์— ๋”ฐ๋ผ ํŠน์ • ํ† ํฐ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ˆ„๊ฐ€ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋ƒˆ๋Š”์ง€ ๋ชจ๋ธ์—๊ฒŒ ๋ช…ํ™•ํ•˜๊ฒŒ ์•Œ๋ ค์ค๋‹ˆ๋‹ค. ๋˜ํ•œ ์‚ฌ์šฉ์ž, ์–ด์‹œ์Šคํ„ดํŠธ ๋ฐ ์‹œ์Šคํ…œ ๋ฉ”์‹œ์ง€๋Š” ๊ฐ๊ฐ ๊ณ ์œ ํ•œ ํ† ํฐ์œผ๋กœ ๋ž˜ํ•‘๋˜์–ด ๋ชจ๋ธ์ด ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
## ๊ณ ๊ธ‰: ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ ์ถ”๊ฐ€ ๋ฐ ํŽธ์ง‘[[advanced-adding-and-editing-chat-templates]]
### ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‚˜์š”?[[how-do-i-create-a-chat-template]]
๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. Jinja ํ…œํ”Œ๋ฆฟ์„ ์ž‘์„ฑํ•˜๊ณ  `tokenizer.chat_template`์— ์„ค์ •ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๋ชจ๋ธ์˜ ๊ธฐ์กด ํ…œํ”Œ๋ฆฟ์„ ์‹œ์ž‘์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ํ•„์š”์— ๋งž๊ฒŒ ํŽธ์ง‘ํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฌ์šธ ๊ฒƒ ์ž…๋‹ˆ๋‹ค! ์˜ˆ๋ฅผ ๋“ค์–ด, ์œ„์˜ LLaMA ํ…œํ”Œ๋ฆฟ์„ ๊ฐ€์ ธ์™€ ์–ด์‹œ์Šคํ„ดํŠธ ๋ฉ”์‹œ์ง€์— "[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 %}
```
์ด์ œ `tokenizer.chat_template` ์†์„ฑ์„ ์„ค์ •ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋‹ค์Œ์— [`~PreTrainedTokenizer.apply_chat_template`]๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ƒˆ๋กญ๊ฒŒ ์„ค์ •ํ•œ ํ…œํ”Œ๋ฆฟ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค! ์ด ์†์„ฑ์€ `tokenizer_config.json` ํŒŒ์ผ์— ์ €์žฅ๋˜๋ฏ€๋กœ, [`~utils.PushToHubMixin.push_to_hub`]๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒˆ ํ…œํ”Œ๋ฆฟ์„ ํ—ˆ๋ธŒ์— ์—…๋กœ๋“œํ•˜๊ณ  ๋ชจ๋“  ์‚ฌ์šฉ์ž๊ฐ€ ๋ชจ๋ธ์— ๋งž๋Š” ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!
```python
template = tokenizer.chat_template
template = template.replace("SYS", "SYSTEM") # ์‹œ์Šคํ…œ ํ† ํฐ ๋ณ€๊ฒฝ
tokenizer.chat_template = template # ์ƒˆ ํ…œํ”Œ๋ฆฟ ์„ค์ •
tokenizer.push_to_hub("model_name") # ์ƒˆ ํ…œํ”Œ๋ฆฟ์„ ํ—ˆ๋ธŒ์— ์—…๋กœ๋“œ!
```
์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜๋Š” [`~PreTrainedTokenizer.apply_chat_template`] ๋ฉ”์†Œ๋“œ๋Š” [`TextGenerationPipeline`] ํด๋ž˜์Šค์—์„œ ํ˜ธ์ถœ๋˜๋ฏ€๋กœ, ์˜ฌ๋ฐ”๋ฅธ ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ์„ค์ •ํ•˜๋ฉด ๋ชจ๋ธ์ด ์ž๋™์œผ๋กœ [`TextGenerationPipeline`]๊ณผ ํ˜ธํ™˜๋ฉ๋‹ˆ๋‹ค.
<Tip>
๋ชจ๋ธ์„ ์ฑ„ํŒ… ์šฉ๋„๋กœ ๋ฏธ์„ธ ์กฐ์ •ํ•˜๋Š” ๊ฒฝ์šฐ, ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ ์™ธ์—๋„ ์ƒˆ ์ฑ„ํŒ… ์ œ์–ด ํ† ํฐ์„ ํ† ํฌ๋‚˜์ด์ €์— ํŠน๋ณ„ ํ† ํฐ์œผ๋กœ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ํŠน๋ณ„ ํ† ํฐ์€ ์ ˆ๋Œ€๋กœ ๋ถ„ํ• ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ, ์ œ์–ด ํ† ํฐ์ด ์—ฌ๋Ÿฌ ์กฐ๊ฐ์œผ๋กœ ํ† ํฐํ™”๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, ํ…œํ”Œ๋ฆฟ์—์„œ ์–ด์‹œ์Šคํ„ดํŠธ ์ƒ์„ฑ์˜ ๋์„ ๋‚˜ํƒ€๋‚ด๋Š” ํ† ํฐ์œผ๋กœ ํ† ํฌ๋‚˜์ด์ €์˜ `eos_token` ์†์„ฑ์„ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํ…์ŠคํŠธ ์ƒ์„ฑ ๋„๊ตฌ๊ฐ€ ํ…์ŠคํŠธ ์ƒ์„ฑ์„ ์–ธ์ œ ์ค‘์ง€ํ•ด์•ผ ํ• ์ง€ ์ •ํ™•ํžˆ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
</Tip>
### ์™œ ์ผ๋ถ€ ๋ชจ๋ธ์€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ…œํ”Œ๋ฆฟ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‚˜์š”?[[why-do-some-models-have-multiple-templates]]
์ผ๋ถ€ ๋ชจ๋ธ์€ ๋‹ค๋ฅธ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•ด ๋‹ค๋ฅธ ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ผ๋ฐ˜ ์ฑ„ํŒ…์„ ์œ„ํ•œ ํ…œํ”Œ๋ฆฟ๊ณผ ๋„๊ตฌ ์‚ฌ์šฉ ๋˜๋Š” ๊ฒ€์ƒ‰ ์ฆ๊ฐ• ์ƒ์„ฑ์— ๋Œ€ํ•œ ํ…œํ”Œ๋ฆฟ์„ ๋ณ„๋„๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ `tokenizer.chat_template`๋Š” ๋”•์…”๋„ˆ๋ฆฌ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์•ฝ๊ฐ„์˜ ํ˜ผ๋ž€์„ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ฐ€๋Šฅํ•œ ํ•œ ๋ชจ๋“  ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•ด ๋‹จ์ผ ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. `if tools is defined`์™€ ๊ฐ™์€ Jinja ๋ฌธ์žฅ๊ณผ `{% macro %}` ์ •์˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ์ฝ”๋“œ ๊ฒฝ๋กœ๋ฅผ ๋‹จ์ผ ํ…œํ”Œ๋ฆฟ์— ์‰ฝ๊ฒŒ ๋ž˜ํ•‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ํ† ํฌ๋‚˜์ด์ €์— ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ…œํ”Œ๋ฆฟ์ด ์žˆ๋Š” ๊ฒฝ์šฐ, `tokenizer.chat_template`๋Š” ํ…œํ”Œ๋ฆฟ ์ด๋ฆ„์ด ํ‚ค์ธ `๋”•์…”๋„ˆ๋ฆฌ`์ž…๋‹ˆ๋‹ค. `apply_chat_template` ๋ฉ”์†Œ๋“œ๋Š” ํŠน์ • ํ…œํ”Œ๋ฆฟ ์ด๋ฆ„์— ๋Œ€ํ•œ ํŠน๋ณ„ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ•ฉ๋‹ˆ๋‹ค: ์ผ๋ฐ˜์ ์œผ๋กœ `default`๋ผ๋Š” ํ…œํ”Œ๋ฆฟ์„ ์ฐพ๊ณ , ์ฐพ์„ ์ˆ˜ ์—†์œผ๋ฉด ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‚ฌ์šฉ์ž๊ฐ€ `tools` ์ธ์ˆ˜๋ฅผ ์ „๋‹ฌํ•  ๋•Œ `tool_use`๋ผ๋Š” ํ…œํ”Œ๋ฆฟ์ด ์กด์žฌํ•˜๋ฉด ๋Œ€์‹  ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ด๋ฆ„์˜ ํ…œํ”Œ๋ฆฟ์— ์ ‘๊ทผํ•˜๋ ค๋ฉด `apply_chat_template()`์˜ `chat_template` ์ธ์ˆ˜์— ์›ํ•˜๋Š” ํ…œํ”Œ๋ฆฟ ์ด๋ฆ„์„ ์ „๋‹ฌํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
์‚ฌ์šฉ์ž์—๊ฒŒ ์•ฝ๊ฐ„์˜ ํ˜ผ๋ž€์„ ์ค„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ํ…œํ”Œ๋ฆฟ์„ ์ง์ ‘ ์ž‘์„ฑํ•˜๋Š” ๊ฒฝ์šฐ ๊ฐ€๋Šฅํ•œ ํ•œ ๋‹จ์ผ ํ…œํ”Œ๋ฆฟ์— ๋ชจ๋“  ๊ฒƒ์„ ๋„ฃ๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค!
### ์–ด๋–ค ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋‚˜์š”?[[what-template-should-i-use]]
์ด๋ฏธ ์ฑ„ํŒ…์šฉ์œผ๋กœ ํ›ˆ๋ จ๋œ ๋ชจ๋ธ์— ํ…œํ”Œ๋ฆฟ์„ ์„ค์ •ํ•  ๋•Œ๋Š” ํ…œํ”Œ๋ฆฟ์ด ํ›ˆ๋ จ ์ค‘ ๋ชจ๋ธ์ด ๋ณธ ๋ฉ”์‹œ์ง€ ํ˜•์‹๊ณผ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์„ฑ๋Šฅ ์ €ํ•˜๋ฅผ ๊ฒฝํ—˜ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ํฝ๋‹ˆ๋‹ค. ์ด๋Š” ๋ชจ๋ธ์„ ์ถ”๊ฐ€๋กœ ํ›ˆ๋ จํ•  ๋•Œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ์ฑ„ํŒ… ํ† ํฐ์„ ์ผ์ •ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ตœ์ƒ์˜ ์„ฑ๋Šฅ์„ ์–ป๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ด๋Š” ํ† ํฐํ™”์™€ ๋งค์šฐ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ํ›ˆ๋ จ ์ค‘์— ์‚ฌ์šฉ๋œ ํ† ํฐํ™”๋ฅผ ์ •ํ™•ํžˆ ์ผ์น˜์‹œํ‚ฌ ๋•Œ ์ถ”๋ก ์ด๋‚˜ ๋ฏธ์„ธ ์กฐ์ •์—์„œ ์ตœ๊ณ ์˜ ์„ฑ๋Šฅ์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋ฐ˜๋ฉด์— ์ฒ˜์Œ๋ถ€ํ„ฐ ๋ชจ๋ธ์„ ํ›ˆ๋ จ์‹œํ‚ค๊ฑฐ๋‚˜ ์ฑ„ํŒ…์šฉ์œผ๋กœ ๊ธฐ๋ณธ ์–ธ์–ด ๋ชจ๋ธ์„ ๋ฏธ์„ธ ์กฐ์ •ํ•˜๋Š” ๊ฒฝ์šฐ, ์ ์ ˆํ•œ ํ…œํ”Œ๋ฆฟ์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ๋งŽ์€ ์ž์œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. LLM์€ ๋‹ค์–‘ํ•œ ์ž…๋ ฅ ํ˜•์‹์„ ์ฒ˜๋ฆฌํ•  ๋งŒํผ ์ถฉ๋ถ„ํžˆ ๋˜‘๋˜‘ํ•ฉ๋‹ˆ๋‹ค. ์ธ๊ธฐ ์žˆ๋Š” ์„ ํƒ ์ค‘ ํ•˜๋‚˜๋Š” `ChatML` ํ˜•์‹์ด๋ฉฐ, ์ด๋Š” ๋งŽ์€ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ์œ ์—ฐํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ข‹์€ ์„ ํƒ์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
```
{%- for message in messages %}
{{- '<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n' }}
{%- endfor %}
```
์ด ํ…œํ”Œ๋ฆฟ์ด ๋งˆ์Œ์— ๋“ ๋‹ค๋ฉด, ์ฝ”๋“œ์— ๋ฐ”๋กœ ๋ณต์‚ฌํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ•œ ์ค„ ๋ฒ„์ „์„ ์ œ๊ณตํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ํ•œ ์ค„ ๋ฒ„์ „์€ [์ƒ์„ฑ ํ”„๋กฌํ”„ํŠธ](#what-are-generation-prompts)์— ๋Œ€ํ•œ ํŽธ๋ฆฌํ•œ ์ง€์›๋„ ํฌํ•จํ•˜๊ณ  ์žˆ์ง€๋งŒ, BOS๋‚˜ EOS ํ† ํฐ์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š”! ๋ชจ๋ธ์ด ํ•ด๋‹น ํ† ํฐ์„ ๊ธฐ๋Œ€ํ•˜๋”๋ผ๋„, `apply_chat_template`์— ์˜ํ•ด ์ž๋™์œผ๋กœ ์ถ”๊ฐ€๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฆ‰, ํ…์ŠคํŠธ๋Š” `add_special_tokens=False`์— ์˜ํ•ด ํ† ํฐํ™”๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ…œํ”Œ๋ฆฟ๊ณผ `add_special_tokens` ๋…ผ๋ฆฌ ๊ฐ„์˜ ์ž ์žฌ์ ์ธ ์ถฉ๋Œ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•จ์ž…๋‹ˆ๋‹ค. ๋ชจ๋ธ์ด ํŠน๋ณ„ ํ† ํฐ์„ ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฒฝ์šฐ, ํ…œํ”Œ๋ฆฟ์— ์ง์ ‘ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค!
```python
tokenizer.chat_template = "{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% for message in messages %}{{'<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n'}}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant\n' }}{% endif %}"
```
์ด ํ…œํ”Œ๋ฆฟ์€ ๊ฐ ๋ฉ”์‹œ์ง€๋ฅผ `<|im_start|>` ์™€ `<|im_end|>`ํ† ํฐ์œผ๋กœ ๊ฐ์‹ธ๊ณ , ์—ญํ• ์„ ๋ฌธ์ž์—ด๋กœ ์ž‘์„ฑํ•˜์—ฌ ํ›ˆ๋ จ ์‹œ ์‚ฌ์šฉํ•˜๋Š” ์—ญํ• ์— ๋Œ€ํ•œ ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
```text
<|im_start|>system
You are a helpful chatbot that will do its best not to say anything so stupid that people tweet about it.<|im_end|>
<|im_start|>user
How are you?<|im_end|>
<|im_start|>assistant
I'm doing great!<|im_end|>
```
"์‚ฌ์šฉ์ž", "์‹œ์Šคํ…œ" ๋ฐ "์–ด์‹œ์Šคํ„ดํŠธ" ์—ญํ• ์€ ์ฑ„ํŒ…์˜ ํ‘œ์ค€์ด๋ฉฐ, ๊ฐ€๋Šฅํ•  ๋•Œ ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ๋ชจ๋ธ์ด [`TextGenerationPipeline`]๊ณผ ์ž˜ ์ž‘๋™ํ•˜๋„๋ก ํ•˜๋ ค๋ฉด ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿฌํ•œ ์—ญํ• ์—๋งŒ ๊ตญํ•œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ…œํ”Œ๋ฆฟ์€ ๋งค์šฐ ์œ ์—ฐํ•˜๋ฉฐ, ์–ด๋–ค ๋ฌธ์ž์—ด์ด๋“  ์—ญํ• ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
### ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค! ์–ด๋–ป๊ฒŒ ์‹œ์ž‘ํ•ด์•ผ ํ•˜๋‚˜์š”?[[i-want-to-add-some-chat-templates-how-should-i-get-started]]
์ฑ„ํŒ… ๋ชจ๋ธ์ด ์žˆ๋Š” ๊ฒฝ์šฐ, ํ•ด๋‹น ๋ชจ๋ธ์˜ `tokenizer.chat_template` ์†์„ฑ์„ ์„ค์ •ํ•˜๊ณ  [`~PreTrainedTokenizer.apply_chat_template`]๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•œ ๋‹ค์Œ ์—…๋ฐ์ดํŠธ๋œ ํ† ํฌ๋‚˜์ด์ €๋ฅผ ํ—ˆ๋ธŒ์— ํ‘ธ์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ชจ๋ธ ์†Œ์œ ์ž๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ์—๋„ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋นˆ ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋ธ์ด๋‚˜ ์—ฌ์ „ํžˆ ๊ธฐ๋ณธ ํด๋ž˜์Šค ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, [ํ’€ ๋ฆฌํ€˜์ŠคํŠธ](https://huggingface.co/docs/hub/repositories-pull-requests-discussions)๋ฅผ ๋ชจ๋ธ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— ์—ด์–ด ์ด ์†์„ฑ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์„ธ์š”!
์†์„ฑ์„ ์„ค์ •ํ•˜๋ฉด ๋์ž…๋‹ˆ๋‹ค! `tokenizer.apply_chat_template`๊ฐ€ ์ด์ œ ํ•ด๋‹น ๋ชจ๋ธ์— ๋Œ€ํ•ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋ฏ€๋กœ, `TextGenerationPipeline`๊ณผ ๊ฐ™์€ ๊ณณ์—์„œ๋„ ์ž๋™์œผ๋กœ ์ง€์›๋ฉ๋‹ˆ๋‹ค!
๋ชจ๋ธ์— ์ด ์†์„ฑ์„ ์„ค์ •ํ•จ์œผ๋กœ์จ, ์˜คํ”ˆ ์†Œ์Šค ๋ชจ๋ธ์˜ ์ „์ฒด ๊ธฐ๋Šฅ์„ ์ปค๋ฎค๋‹ˆํ‹ฐ๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ˜•์‹ ๋ถˆ์ผ์น˜๋Š” ์ด ๋ถ„์•ผ์—์„œ ์˜ค๋žซ๋™์•ˆ ์„ฑ๋Šฅ์„ ์ €ํ•˜์‹œํ‚ค๋Š” ๋ฌธ์ œ์˜€์œผ๋ฏ€๋กœ, ์ด์ œ ์ด๋ฅผ ๋๋‚ผ ๋•Œ์ž…๋‹ˆ๋‹ค!
## ๊ณ ๊ธ‰: ํ…œํ”Œ๋ฆฟ ์ž‘์„ฑ ํŒ[[advanced-template-writing-tips]]
Jinja์— ์ต์ˆ™ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ, ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ์ž‘์„ฑํ•˜๋Š” ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ ๋จผ์ € ๋ฉ”์‹œ์ง€๋ฅผ ์›ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ˜•์‹ํ™”ํ•˜๋Š” ์งง์€ ํŒŒ์ด์ฌ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ž‘์„ฑํ•œ ๋‹ค์Œ, ํ•ด๋‹น ์Šคํฌ๋ฆฝํŠธ๋ฅผ ํ…œํ”Œ๋ฆฟ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
ํ…œํ”Œ๋ฆฟ ํ•ธ๋“ค๋Ÿฌ๋Š” `messages`๋ผ๋Š” ๋ณ€์ˆ˜๋กœ ๋Œ€ํ™” ๊ธฐ๋ก์„ ๋ฐ›์Šต๋‹ˆ๋‹ค. ํŒŒ์ด์ฌ์—์„œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ…œํ”Œ๋ฆฟ ๋‚ด์˜ `messages`์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, `{% for message in messages %}`๋กœ ๋ฐ˜๋ณตํ•˜๊ฑฐ๋‚˜ `{{ messages[0] }}`์™€ ๊ฐ™์ด ๊ฐœ๋ณ„ ๋ฉ”์‹œ์ง€์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋‹ค์Œ ํŒ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ Jinja๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค:
### ๊ณต๋ฐฑ ์ œ๊ฑฐ[[trimming-whitespace]]
๊ธฐ๋ณธ์ ์œผ๋กœ Jinja๋Š” ๋ธ”๋ก ์ „ํ›„์˜ ๊ณต๋ฐฑ์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๊ณต๋ฐฑ์„ ๋งค์šฐ ์ •ํ™•ํ•˜๊ฒŒ ๋‹ค๋ฃจ๊ณ ์ž ํ•˜๋Š” ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์—์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค! ์ด๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ํ…œํ”Œ๋ฆฟ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค:
```
{%- for message in messages %}
{{- message['role'] + message['content'] }}
{%- endfor %}
```
์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•˜์ง€ ๋งˆ์„ธ์š”:
```
{% for message in messages %}
{{ message['role'] + message['content'] }}
{% endfor %}
```
`-`๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ธ”๋ก ์ „ํ›„์˜ ๊ณต๋ฐฑ์ด ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ ์˜ˆ์ œ๋Š” ๋ฌดํ•ดํ•ด ๋ณด์ด์ง€๋งŒ, ์ค„๋ฐ”๊ฟˆ๊ณผ ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ์ถœ๋ ฅ์— ํฌํ•จ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ์›ํ•˜์ง€ ์•Š๋Š” ๊ฒฐ๊ณผ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!
### ๋ฐ˜๋ณต๋ฌธ[[for-loops]]
Jinja์—์„œ ๋ฐ˜๋ณต๋ฌธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
```
{%- for message in messages %}
{{- message['content'] }}
{%- endfor %}
```
{{ ํ‘œํ˜„์‹ ๋ธ”๋ก }} ๋‚ด๋ถ€์— ์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ์ด ์ถœ๋ ฅ์œผ๋กœ ์ธ์‡„๋ฉ๋‹ˆ๋‹ค. `+`์™€ ๊ฐ™์€ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ‘œํ˜„์‹ ๋ธ”๋ก ๋‚ด๋ถ€์—์„œ ๋ฌธ์ž์—ด์„ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
### ์กฐ๊ฑด๋ฌธ[[if-statements]]
Jinja์—์„œ ์กฐ๊ฑด๋ฌธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
```
{%- if message['role'] == 'user' %}
{{- message['content'] }}
{%- endif %}
```
ํŒŒ์ด์ฌ์ด ๊ณต๋ฐฑ์„ ์‚ฌ์šฉํ•˜์—ฌ `for` ๋ฐ `if` ๋ธ”๋ก์˜ ์‹œ์ž‘๊ณผ ๋์„ ํ‘œ์‹œํ•˜๋Š” ๋ฐ˜๋ฉด, Jinja๋Š” `{% endfor %}` ๋ฐ `{% endif %}`๋กœ ๋ช…์‹œ์ ์œผ๋กœ ๋์„ ํ‘œ์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
### ํŠน์ˆ˜ ๋ณ€์ˆ˜[[special-variables]]
ํ…œํ”Œ๋ฆฟ ๋‚ด๋ถ€์—์„œ๋Š” `messages` ๋ชฉ๋ก์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์„ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์—ฌ๋Ÿฌ ๋‹ค๋ฅธ ํŠน์ˆ˜ ๋ณ€์ˆ˜์—๋„ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” `bos_token` ๋ฐ `eos_token`๊ณผ ๊ฐ™์€ ํŠน๋ณ„ ํ† ํฐ๊ณผ ์•ž์„œ ๋…ผ์˜ํ•œ `add_generation_prompt` ๋ณ€์ˆ˜๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ `loop` ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ˜„์žฌ ๋ฐ˜๋ณต์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์˜ˆ๋ฅผ ๋“ค์–ด `{% if loop.last %}`๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ˜„์žฌ ๋ฉ”์‹œ์ง€๊ฐ€ ๋Œ€ํ™”์˜ ๋งˆ์ง€๋ง‰ ๋ฉ”์‹œ์ง€์ธ์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. `add_generation_prompt`๊ฐ€ `True`์ธ ๊ฒฝ์šฐ ๋Œ€ํ™” ๋์— ์ƒ์„ฑ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์˜ˆ์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
```
{%- if loop.last and add_generation_prompt %}
{{- bos_token + 'Assistant:\n' }}
{%- endif %}
```
### ๋น„ํŒŒ์ด์ฌ Jinja์™€์˜ ํ˜ธํ™˜์„ฑ[[compatibility-with-non-python-jinja]]
Jinja์˜ ์—ฌ๋Ÿฌ ๊ตฌํ˜„์€ ๋‹ค์–‘ํ•œ ์–ธ์–ด๋กœ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ๋™์ผํ•œ ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ์ฃผ์š” ์ฐจ์ด์ ์€ ํŒŒ์ด์ฌ์—์„œ ํ…œํ”Œ๋ฆฟ์„ ์ž‘์„ฑํ•  ๋•Œ ํŒŒ์ด์ฌ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ฌธ์ž์—ด์— `.lower()`๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๋”•์…”๋„ˆ๋ฆฌ์— `.items()`๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๋น„ํŒŒ์ด์ฌ Jinja ๊ตฌํ˜„์—์„œ ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•  ๋•Œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ JS์™€ Rust๊ฐ€ ์ธ๊ธฐ ์žˆ๋Š” ๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ๋Š” ๋น„ํŒŒ์ด์ฌ ๊ตฌํ˜„์ด ํ”ํ•ฉ๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ ๊ฑฑ์ •ํ•˜์ง€ ๋งˆ์„ธ์š”! ๋ชจ๋“  Jinja ๊ตฌํ˜„์—์„œ ํ˜ธํ™˜์„ฑ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ํ…œํ”Œ๋ฆฟ์„ ์‰ฝ๊ฒŒ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค:
- ํŒŒ์ด์ฌ ๋ฉ”์†Œ๋“œ๋ฅผ Jinja ํ•„ํ„ฐ๋กœ ๋Œ€์ฒดํ•˜์„ธ์š”. ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐ™์€ ์ด๋ฆ„์„ ๊ฐ€์ง€๋ฉฐ, ์˜ˆ๋ฅผ ๋“ค์–ด `string.lower()`๋Š” `string|lower`๋กœ, `dict.items()`๋Š” `dict|items`๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฃผ๋ชฉํ•  ๋งŒํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ `string.strip()`์ด `string|trim`์œผ๋กœ ๋ฐ”๋€Œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ Jinja ๋ฌธ์„œ์˜ [๋‚ด์žฅ ํ•„ํ„ฐ ๋ชฉ๋ก](https://jinja.palletsprojects.com/en/3.1.x/templates/#builtin-filters)์„ ์ฐธ์กฐํ•˜์„ธ์š”.
- ํŒŒ์ด์ฌ์— ํŠนํ™”๋œ `True`, `False`, `None`์„ ๊ฐ๊ฐ `true`, `false`, `none`์œผ๋กœ ๋Œ€์ฒดํ•˜์„ธ์š”.
- ๋”•์…”๋„ˆ๋ฆฌ๋‚˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ง์ ‘ ๋ Œ๋”๋งํ•  ๋•Œ ๋‹ค๋ฅธ ๊ตฌํ˜„์—์„œ๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: ๋ฌธ์ž์—ด ํ•ญ๋ชฉ์ด ๋‹จ์ผ ๋”ฐ์˜ดํ‘œ์—์„œ ์ด์ค‘ ๋”ฐ์˜ดํ‘œ๋กœ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค). `tojson` ํ•„ํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.