DrDavis's picture
Upload folder using huggingface_hub
17c6d62 verified

์ฑ„ํŒ… ๋ชจ๋ธ์„ ์œ„ํ•œ ํ…œํ”Œ๋ฆฟ[[templates-for-chat-models]]

์†Œ๊ฐœ[[introduction]]

์š”์ฆ˜ LLM์˜ ๊ฐ€์žฅ ํ”ํ•œ ํ™œ์šฉ ์‚ฌ๋ก€ ์ค‘ ํ•˜๋‚˜๋Š” ์ฑ„ํŒ…์ž…๋‹ˆ๋‹ค. ์ฑ„ํŒ…์€ ์ผ๋ฐ˜์ ์ธ ์–ธ์–ด ๋ชจ๋ธ์ฒ˜๋Ÿผ ๋‹จ์ผ ๋ฌธ์ž์—ด์„ ์ด์–ด๊ฐ€๋Š” ๋Œ€์‹  ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฉ”์‹œ์ง€๋กœ ๊ตฌ์„ฑ๋œ ๋Œ€ํ™”๋ฅผ ์ด์–ด๊ฐ‘๋‹ˆ๋‹ค. ์ด ๋Œ€ํ™”์—๋Š” "์‚ฌ์šฉ์ž"๋‚˜ "์–ด์‹œ์Šคํ„ดํŠธ"์™€ ๊ฐ™์€ ์—ญํ• ๊ณผ ๋ฉ”์‹œ์ง€ ํ…์ŠคํŠธ๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

ํ† ํฐํ™”์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ๋‹ค์–‘ํ•œ ๋ชจ๋ธ์€ ์ฑ„ํŒ…์— ๋Œ€ํ•ด ๋งค์šฐ ๋‹ค๋ฅธ ์ž…๋ ฅ ํ˜•์‹์„ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ๊ธฐ๋Šฅ์œผ๋กœ ์ถ”๊ฐ€ํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค. ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์€ ํ† ํฌ๋‚˜์ด์ €์˜ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค. ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์€ ๋Œ€ํ™” ๋ชฉ๋ก์„ ๋ชจ๋ธ์ด ๊ธฐ๋Œ€ํ•˜๋Š” ํ˜•์‹์ธ '๋‹จ์ผ ํ† ํฐํ™”๊ฐ€ ๊ฐ€๋Šฅํ•œ ๋ฌธ์ž์—ด'๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

BlenderBot ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•œ ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ์ด๋ฅผ ๊ตฌ์ฒด์ ์œผ๋กœ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. BlenderBot์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋งค์šฐ ๊ฐ„๋‹จํ•œ ํ…œํ”Œ๋ฆฟ์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ, ์ฃผ๋กœ ๋Œ€ํ™” ๋ผ์šด๋“œ ์‚ฌ์ด์— ๊ณต๋ฐฑ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค:

>>> 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 ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

>>> 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๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์„ฑ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ์€ Zephyr ์–ด์‹œ์Šคํ„ดํŠธ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜์—ฌ model.generate()์˜ ์ž…๋ ฅ์„ ์ค€๋น„ํ•˜๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค:

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๊ฐ€ ๊ธฐ๋Œ€ํ•˜๋Š” ์ž…๋ ฅ ํ˜•์‹์˜ ๋ฌธ์ž์—ด์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

<|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์— ๋งž๊ฒŒ ํ˜•์‹์ด ์ง€์ •๋˜์—ˆ์œผ๋ฏ€๋กœ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์— ๋Œ€ํ•œ ์‘๋‹ต์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

outputs = model.generate(tokenized_chat, max_new_tokens=128) 
print(tokenizer.decode(outputs[0]))

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ต๋‹ˆ๋‹ค:

<|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 ์˜ˆ์ œ๋ฅผ ๋‹ค์‹œ ์‹œ๋„ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:

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])  # ์–ด์‹œ์Šคํ„ดํŠธ์˜ ์‘๋‹ต์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.
{'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 ์ธ์ˆ˜๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ˆˆ์น˜์ฑ˜์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ์ธ์ˆ˜๋Š” ํ…œํ”Œ๋ฆฟ์— ๋ด‡ ์‘๋‹ต์˜ ์‹œ์ž‘์„ ๋‚˜ํƒ€๋‚ด๋Š” ํ† ํฐ์„ ์ถ”๊ฐ€ํ•˜๋„๋ก ์ง€์‹œํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฑ„ํŒ…์„ ๊ณ ๋ คํ•ด ๋ณด์„ธ์š”:

messages = [
    {"role": "user", "content": "Hi there!"},
    {"role": "assistant", "content": "Nice to meet you!"},
    {"role": "user", "content": "Can I ask a question?"}
]

Zephyr ์˜ˆ์ œ์—์„œ ๋ณด์•˜๋˜ ๊ฒƒ๊ณผ ๊ฐ™์ด, ์ƒ์„ฑ ํ”„๋กฌํ”„ํŠธ ์—†์ด ChatML ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณด์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค:

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|>
"""

์ƒ์„ฑ ํ”„๋กฌํ”„ํŠธ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

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๋กœ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์–ด์‹œ์Šคํ„ดํŠธ ์‘๋‹ต์„ ํ”„๋กฌํ”„ํŠธํ•˜๋Š” ์ถ”๊ฐ€ ํ† ํฐ์€ ํ›ˆ๋ จ ์ค‘์—๋Š” ๋„์›€์ด ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์˜ˆ์ œ๋ฅผ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:

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])

๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

<|user|>
Which is bigger, the moon or the sun?</s>
<|assistant|>
The sun.</s>

์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ๋Š” ์ผ๋ฐ˜์ ์ธ ์–ธ์–ด ๋ชจ๋ธ ์ž‘์—…๊ณผ ๊ฐ™์ด formatted_chat ์—ด์„ ์‚ฌ์šฉํ•˜์—ฌ ํ›ˆ๋ จ์„ ๊ณ„์†ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

`apply_chat_template(tokenize=False)`๋กœ ํ…์ŠคํŠธ๋ฅผ ํ˜•์‹ํ™”ํ•œ ๋‹ค์Œ ๋ณ„๋„์˜ ๋‹จ๊ณ„์—์„œ ํ† ํฐํ™”ํ•˜๋Š” ๊ฒฝ์šฐ, `add_special_tokens=False` ์ธ์ˆ˜๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. `apply_chat_template(tokenize=True)`๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์ด ๋ฌธ์ œ๋ฅผ ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค! ๊ธฐ๋ณธ์ ์œผ๋กœ ์ผ๋ถ€ ํ† ํฌ๋‚˜์ด์ €๋Š” ํ† ํฐํ™”ํ•  ๋•Œ `` ๋ฐ ``์™€ ๊ฐ™์€ ํŠน๋ณ„ ํ† ํฐ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์€ ํ•ญ์ƒ ํ•„์š”ํ•œ ๋ชจ๋“  ํŠน๋ณ„ ํ† ํฐ์„ ํฌํ•จํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ๊ธฐ๋ณธ `add_special_tokens=True`๋กœ ์ถ”๊ฐ€์ ์ธ ํŠน๋ณ„ ํ† ํฐ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ์ž˜๋ชป๋˜๊ฑฐ๋‚˜ ์ค‘๋ณต๋˜๋Š” ํŠน๋ณ„ ํ† ํฐ์„ ์ƒ์„ฑํ•˜์—ฌ ๋ชจ๋ธ ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณ ๊ธ‰: ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์— ์ถ”๊ฐ€ ์ž…๋ ฅ ์‚ฌ์šฉ[[advanced-extra-inputs-to-chat-templates]]

apply_chat_template๊ฐ€ ํ•„์š”ํ•œ ์œ ์ผํ•œ ์ธ์ˆ˜๋Š” messages์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ apply_chat_template์— ํ‚ค์›Œ๋“œ ์ธ์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ํ…œํ”Œ๋ฆฟ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ๋‹ค์–‘ํ•œ ์šฉ๋„๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ž์œ ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ธ์ˆ˜์˜ ์ด๋ฆ„์ด๋‚˜ ํ˜•์‹์—๋Š” ์ œํ•œ์ด ์—†์–ด ๋ฌธ์ž์—ด, ๋ฆฌ์ŠคํŠธ, ๋”•์…”๋„ˆ๋ฆฌ ๋“ฑ์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ ‡๊ธด ํ•˜์ง€๋งŒ, ์ด๋Ÿฌํ•œ ์ถ”๊ฐ€ ์ธ์ˆ˜์˜ ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ ์‚ฌ๋ก€๋กœ 'ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ์œ„ํ•œ ๋„๊ตฌ'๋‚˜ '๊ฒ€์ƒ‰ ์ฆ๊ฐ• ์ƒ์„ฑ์„ ์œ„ํ•œ ๋ฌธ์„œ'๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ์— ๋Œ€ํ•ด ์ธ์ˆ˜์˜ ์ด๋ฆ„๊ณผ ํ˜•์‹์— ๋Œ€ํ•œ ๋ช‡ ๊ฐ€์ง€ ๊ถŒ์žฅ ์‚ฌํ•ญ์ด ์žˆ์œผ๋ฉฐ, ์ด๋Š” ์•„๋ž˜ ์„น์…˜์— ์„ค๋ช…๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋ชจ๋ธ ์ž‘์„ฑ์ž์—๊ฒŒ ๋„๊ตฌ ํ˜ธ์ถœ ์ฝ”๋“œ๋ฅผ ๋ชจ๋ธ ๊ฐ„์— ์‰ฝ๊ฒŒ ์ „์†กํ•  ์ˆ˜ ์žˆ๋„๋ก ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ์ด ํ˜•์‹๊ณผ ํ˜ธํ™˜๋˜๋„๋ก ๋งŒ๋“ค ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

๊ณ ๊ธ‰: ๋„๊ตฌ ์‚ฌ์šฉ / ํ•จ์ˆ˜ ํ˜ธ์ถœ[[advanced-tool-use--function-calling]]

"๋„๊ตฌ ์‚ฌ์šฉ" LLM์€ ๋‹ต๋ณ€์„ ์ƒ์„ฑํ•˜๊ธฐ ์ „์— ์™ธ๋ถ€ ๋„๊ตฌ๋กœ์„œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋„๊ตฌ ์‚ฌ์šฉ ๋ชจ๋ธ์— ๋„๊ตฌ๋ฅผ ์ „๋‹ฌํ•  ๋•Œ๋Š” ๋‹จ์ˆœํžˆ ํ•จ์ˆ˜ ๋ชฉ๋ก์„ tools ์ธ์ˆ˜๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

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 ๋˜๋Š” Mixtral-8x22B๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋‘ ๋ชจ๋ธ ๋ชจ๋‘ ๋„๊ตฌ ์‚ฌ์šฉ์„ ์ง€์›ํ•˜๋ฉฐ ๋” ๊ฐ•๋ ฅํ•œ ์„ฑ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋จผ์ € ๋ชจ๋ธ๊ณผ ํ† ํฌ๋‚˜์ด์ €๋ฅผ ๋กœ๋“œํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:

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")

๋‹ค์Œ์œผ๋กœ, ๋„๊ตฌ ๋ชฉ๋ก์„ ์ •์˜ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:

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]

์ด์ œ ๋ด‡์„ ์œ„ํ•œ ๋Œ€ํ™”๋ฅผ ์„ค์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:

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

์ด์ œ ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ์ ์šฉํ•˜๊ณ  ์‘๋‹ต์„ ์ƒ์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:

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]):]))

๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

<tool_call>
{"arguments": {"location": "Paris, France", "unit": "celsius"}, "name": "get_current_temperature"}
</tool_call><|im_end|>

๋ชจ๋ธ์ด ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ์œ ํšจํ•œ ์ธ์ˆ˜๋กœ ์ˆ˜ํ–‰ํ–ˆ์œผ๋ฉฐ, ํ•จ์ˆ˜ ๋„ํฌ์ŠคํŠธ๋ง์— ์š”์ฒญ๋œ ํ˜•์‹์œผ๋กœ ํ˜ธ์ถœํ–ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋ธ์€ ์šฐ๋ฆฌ๊ฐ€ ํ”„๋ž‘์Šค์˜ ํŒŒ๋ฆฌ๋ฅผ ์ง€์นญํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ถ”๋ก ํ–ˆ๊ณ , ํ”„๋ž‘์Šค๊ฐ€ SI ๋‹จ์œ„์˜ ๋ณธ๊ณ ์žฅ์ž„์„ ๊ธฐ์–ตํ•˜์—ฌ ์˜จ๋„๋ฅผ ์„ญ์”จ๋กœ ํ‘œ์‹œํ•ด์•ผ ํ•œ๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋ธ์˜ ๋„๊ตฌ ํ˜ธ์ถœ์„ ๋Œ€ํ™”์— ์ถ”๊ฐ€ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ž„์˜์˜ tool_call_id๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ID๋Š” ๋ชจ๋“  ๋ชจ๋ธ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ, ์—ฌ๋Ÿฌ ๋„๊ตฌ ํ˜ธ์ถœ์„ ํ•œ ๋ฒˆ์— ๋ฐœํ–‰ํ•˜๊ณ  ๊ฐ ์‘๋‹ต์ด ์–ด๋А ํ˜ธ์ถœ์— ํ•ด๋‹นํ•˜๋Š”์ง€ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. ์ด ID๋Š” ๋Œ€ํ™” ๋‚ด์—์„œ ๊ณ ์œ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

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์™€ ์ผ์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

messages.append({"role": "tool", "tool_call_id": tool_call_id, "name": "get_current_temperature", "content": "22.0"})

๋งˆ์ง€๋ง‰์œผ๋กœ, ์–ด์‹œ์Šคํ„ดํŠธ๊ฐ€ ํ•จ์ˆ˜ ์ถœ๋ ฅ์„ ์ฝ๊ณ  ์‚ฌ์šฉ์ž์™€ ๊ณ„์† ๋Œ€ํ™”ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค:

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]):]))

๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

The current temperature in Paris, France is 22.0 ยฐ Celsius.<|im_end|>

์ด๊ฒƒ์€ ๋”๋ฏธ ๋„๊ตฌ์™€ ๋‹จ์ผ ํ˜ธ์ถœ์„ ์‚ฌ์šฉํ•œ ๊ฐ„๋‹จํ•œ ๋ฐ๋ชจ์˜€์ง€๋งŒ, ๋™์ผํ•œ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ์‹ค์ œ ๋„๊ตฌ์™€ ๋” ๊ธด ๋Œ€ํ™”๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‹ค์‹œ๊ฐ„ ์ •๋ณด, ๊ณ„์‚ฐ ๋„๊ตฌ ๋˜๋Š” ๋Œ€๊ทœ๋ชจ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผํ•˜์—ฌ ๋Œ€ํ™”ํ˜• ์—์ด์ „ํŠธ์˜ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„์—์„œ ๋ณด์—ฌ์ค€ ๋„๊ตฌ ํ˜ธ์ถœ ๊ธฐ๋Šฅ์€ ๋ชจ๋“  ๋ชจ๋ธ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ์ผ๋ถ€ ๋ชจ๋ธ์€ ๋„๊ตฌ ํ˜ธ์ถœ ID๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ์ผ๋ถ€๋Š” ํ•จ์ˆ˜ ์ด๋ฆ„๋งŒ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒฐ๊ณผ์™€ ๋„๊ตฌ ํ˜ธ์ถœ์„ ์ˆœ์„œ์— ๋”ฐ๋ผ ๋งค์นญํ•˜๋ฉฐ, ํ˜ผ๋™์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ๋„๊ตฌ ํ˜ธ์ถœ๋งŒ ๋ฐœํ–‰ํ•˜๋Š” ๋ชจ๋ธ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€๋Šฅํ•œ ๋งŽ์€ ๋ชจ๋ธ๊ณผ ํ˜ธํ™˜๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์›ํ•œ๋‹ค๋ฉด, ์—ฌ๊ธฐ์— ๋ณด์—ฌ์ค€ ๊ฒƒ์ฒ˜๋Ÿผ ๋„๊ตฌ ํ˜ธ์ถœ์„ ๊ตฌ์„ฑํ•˜๊ณ , ๋ชจ๋ธ์ด ๋ฐœํ–‰ํ•œ ์ˆœ์„œ๋Œ€๋กœ ๋„๊ตฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ๋ชจ๋ธ์˜ ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์ด ๋‚˜๋จธ์ง€ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋„๊ตฌ ์Šคํ‚ค๋งˆ ์ดํ•ดํ•˜๊ธฐ[[understanding-tool-schemas]]

apply_chat_template์˜ tools ์ธ์ˆ˜์— ์ „๋‹ฌํ•˜๋Š” ๊ฐ ํ•จ์ˆ˜๋Š” JSON ์Šคํ‚ค๋งˆ๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์Šคํ‚ค๋งˆ๋Š” ๋ชจ๋ธ ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์— ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค. ์ฆ‰, ๋„๊ตฌ ์‚ฌ์šฉ ๋ชจ๋ธ์€ ํ•จ์ˆ˜ ์ž์ฒด๋ฅผ ์ง์ ‘ ๋ณด์ง€ ์•Š์œผ๋ฉฐ, ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ๋ณด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋„๊ตฌ ์‚ฌ์šฉ ๋ชจ๋ธ์ด ๊ด€์‹ฌ์„ ๊ฐ€์ง€๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ ์ •์˜์™€ ์ธ์ˆ˜์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ๋ฌด์—‡์„ ํ•˜๊ณ  ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€์— ๊ด€์‹ฌ์ด ์žˆ์„ ๋ฟ, ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค! ๋ชจ๋ธ์˜ ์ถœ๋ ฅ์„ ์ฝ๊ณ  ๋ชจ๋ธ์ด ๋„๊ตฌ ์‚ฌ์šฉ์„ ์š”์ฒญํ–ˆ๋Š”์ง€ ๊ฐ์ง€ํ•˜์—ฌ, ์ธ์ˆ˜๋ฅผ ๋„๊ตฌ ํ•จ์ˆ˜์— ์ „๋‹ฌํ•˜๊ณ  ์ฑ„ํŒ…์—์„œ ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์€ ์—ฌ๋Ÿฌ๋ถ„์˜ ๋ชซ์ž…๋‹ˆ๋‹ค.

์œ„์˜ ๊ทœ๊ฒฉ์„ ๋”ฐ๋ฅธ๋‹ค๋ฉด, ํ…œํ”Œ๋ฆฟ์— ์ „๋‹ฌํ•  JSON ์Šคํ‚ค๋งˆ ์ƒ์„ฑ์„ ์ž๋™ํ™”ํ•˜๊ณ  ๋ณด์ด์ง€ ์•Š๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜ ๋ณ€ํ™˜์„ ๋” ์ œ์–ดํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ˆ˜๋™์œผ๋กœ ๋ณ€ํ™˜์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ์ˆ˜๋™ ์Šคํ‚ค๋งˆ ๋ณ€ํ™˜ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

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)

์ด ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

{
  "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์— ์ „๋‹ฌํ•˜๋Š” ์˜ˆ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค:

# ์ธ์ˆ˜๋ฅผ ๋ฐ›์ง€ ์•Š๋Š” ๊ฐ„๋‹จํ•œ ํ•จ์ˆ˜
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 ํ…œํ”Œ๋ฆฟ์ด ์ž‘๋™ํ•˜๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค:

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์˜ ํ…œํ”Œ๋ฆฟ์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:


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

์•ฝ๊ฐ„ ๋ณต์žกํ•ด ๋ณด์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ๊ธฐ ์‰ฝ๊ฒŒ ์ •๋ฆฌํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์—์„œ ์ถ”๊ฐ€ํ•˜๋Š” ์ค„๋ฐ”๊ฟˆ๊ณผ ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ํ…œํ”Œ๋ฆฟ ์ถœ๋ ฅ์— ํฌํ•จ๋˜์ง€ ์•Š๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ๊ณต๋ฐฑ์„ ์ œ๊ฑฐํ•˜๋Š” ํŒ์ž…๋‹ˆ๋‹ค:

{%- for message in messages %}
    {%- if message['role'] == 'user' %}
        {{- ' ' }}
    {%- endif %}
    {{- message['content'] }}
    {%- if not loop.last %}
        {{- '  ' }}
    {%- endif %}
{%- endfor %}
{{- eos_token }}

๋งŒ์•ฝ ์ด์™€ ๊ฐ™์€ ํ˜•์‹์„ ์ฒ˜์Œ ๋ณธ๋‹ค๋ฉด, ์ด๊ฒƒ์€ Jinja ํ…œํ”Œ๋ฆฟ์ž…๋‹ˆ๋‹ค. Jinja๋Š” ํ…์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ํ…œํ”Œ๋ฆฟ ์–ธ์–ด์ž…๋‹ˆ๋‹ค. ๋งŽ์€ ๋ฉด์—์„œ ์ฝ”๋“œ์™€ ๊ตฌ๋ฌธ์ด ํŒŒ์ด์ฌ๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ˆœ์ˆ˜ ํŒŒ์ด์ฌ์—์„œ๋Š” ์ด ํ…œํ”Œ๋ฆฟ์ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณด์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค:

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]๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒˆ ํ…œํ”Œ๋ฆฟ์„ ํ—ˆ๋ธŒ์— ์—…๋กœ๋“œํ•˜๊ณ  ๋ชจ๋“  ์‚ฌ์šฉ์ž๊ฐ€ ๋ชจ๋ธ์— ๋งž๋Š” ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

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]๊ณผ ํ˜ธํ™˜๋ฉ๋‹ˆ๋‹ค.

๋ชจ๋ธ์„ ์ฑ„ํŒ… ์šฉ๋„๋กœ ๋ฏธ์„ธ ์กฐ์ •ํ•˜๋Š” ๊ฒฝ์šฐ, ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ ์™ธ์—๋„ ์ƒˆ ์ฑ„ํŒ… ์ œ์–ด ํ† ํฐ์„ ํ† ํฌ๋‚˜์ด์ €์— ํŠน๋ณ„ ํ† ํฐ์œผ๋กœ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ํŠน๋ณ„ ํ† ํฐ์€ ์ ˆ๋Œ€๋กœ ๋ถ„ํ• ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ, ์ œ์–ด ํ† ํฐ์ด ์—ฌ๋Ÿฌ ์กฐ๊ฐ์œผ๋กœ ํ† ํฐํ™”๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, ํ…œํ”Œ๋ฆฟ์—์„œ ์–ด์‹œ์Šคํ„ดํŠธ ์ƒ์„ฑ์˜ ๋์„ ๋‚˜ํƒ€๋‚ด๋Š” ํ† ํฐ์œผ๋กœ ํ† ํฌ๋‚˜์ด์ €์˜ `eos_token` ์†์„ฑ์„ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํ…์ŠคํŠธ ์ƒ์„ฑ ๋„๊ตฌ๊ฐ€ ํ…์ŠคํŠธ ์ƒ์„ฑ์„ ์–ธ์ œ ์ค‘์ง€ํ•ด์•ผ ํ• ์ง€ ์ •ํ™•ํžˆ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์™œ ์ผ๋ถ€ ๋ชจ๋ธ์€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ…œํ”Œ๋ฆฟ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‚˜์š”?[[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 %}

์ด ํ…œํ”Œ๋ฆฟ์ด ๋งˆ์Œ์— ๋“ ๋‹ค๋ฉด, ์ฝ”๋“œ์— ๋ฐ”๋กœ ๋ณต์‚ฌํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ•œ ์ค„ ๋ฒ„์ „์„ ์ œ๊ณตํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ํ•œ ์ค„ ๋ฒ„์ „์€ ์ƒ์„ฑ ํ”„๋กฌํ”„ํŠธ์— ๋Œ€ํ•œ ํŽธ๋ฆฌํ•œ ์ง€์›๋„ ํฌํ•จํ•˜๊ณ  ์žˆ์ง€๋งŒ, BOS๋‚˜ EOS ํ† ํฐ์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š”! ๋ชจ๋ธ์ด ํ•ด๋‹น ํ† ํฐ์„ ๊ธฐ๋Œ€ํ•˜๋”๋ผ๋„, apply_chat_template์— ์˜ํ•ด ์ž๋™์œผ๋กœ ์ถ”๊ฐ€๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฆ‰, ํ…์ŠคํŠธ๋Š” add_special_tokens=False์— ์˜ํ•ด ํ† ํฐํ™”๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ…œํ”Œ๋ฆฟ๊ณผ add_special_tokens ๋…ผ๋ฆฌ ๊ฐ„์˜ ์ž ์žฌ์ ์ธ ์ถฉ๋Œ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•จ์ž…๋‹ˆ๋‹ค. ๋ชจ๋ธ์ด ํŠน๋ณ„ ํ† ํฐ์„ ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฒฝ์šฐ, ํ…œํ”Œ๋ฆฟ์— ์ง์ ‘ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค!

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|>ํ† ํฐ์œผ๋กœ ๊ฐ์‹ธ๊ณ , ์—ญํ• ์„ ๋ฌธ์ž์—ด๋กœ ์ž‘์„ฑํ•˜์—ฌ ํ›ˆ๋ จ ์‹œ ์‚ฌ์šฉํ•˜๋Š” ์—ญํ• ์— ๋Œ€ํ•œ ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

<|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]๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•œ ๋‹ค์Œ ์—…๋ฐ์ดํŠธ๋œ ํ† ํฌ๋‚˜์ด์ €๋ฅผ ํ—ˆ๋ธŒ์— ํ‘ธ์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ชจ๋ธ ์†Œ์œ ์ž๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ์—๋„ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋นˆ ์ฑ„ํŒ… ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋ธ์ด๋‚˜ ์—ฌ์ „ํžˆ ๊ธฐ๋ณธ ํด๋ž˜์Šค ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ํ’€ ๋ฆฌํ€˜์ŠคํŠธ๋ฅผ ๋ชจ๋ธ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— ์—ด์–ด ์ด ์†์„ฑ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์„ธ์š”!

์†์„ฑ์„ ์„ค์ •ํ•˜๋ฉด ๋์ž…๋‹ˆ๋‹ค! 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 ๋ฌธ์„œ์˜ ๋‚ด์žฅ ํ•„ํ„ฐ ๋ชฉ๋ก์„ ์ฐธ์กฐํ•˜์„ธ์š”.
  • ํŒŒ์ด์ฌ์— ํŠนํ™”๋œ True, False, None์„ ๊ฐ๊ฐ true, false, none์œผ๋กœ ๋Œ€์ฒดํ•˜์„ธ์š”.
  • ๋”•์…”๋„ˆ๋ฆฌ๋‚˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ง์ ‘ ๋ Œ๋”๋งํ•  ๋•Œ ๋‹ค๋ฅธ ๊ตฌํ˜„์—์„œ๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: ๋ฌธ์ž์—ด ํ•ญ๋ชฉ์ด ๋‹จ์ผ ๋”ฐ์˜ดํ‘œ์—์„œ ์ด์ค‘ ๋”ฐ์˜ดํ‘œ๋กœ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค). tojson ํ•„ํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.