์ฑํ ๋ชจ๋ธ์ ์ํ ํ ํ๋ฆฟ[[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 ์ด์ ์ฌ์ฉํ์ฌ ํ๋ จ์ ๊ณ์ํ๋ฉด ๋ฉ๋๋ค.
๊ณ ๊ธ: ์ฑํ ํ ํ๋ฆฟ์ ์ถ๊ฐ ์ ๋ ฅ ์ฌ์ฉ[[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]]
์์ ์์ ์ฝ๋๋ ๋ชจ๋ธ์ ์ฌ์ฉํ ์ ์๋ ๋๊ตฌ๋ฅผ ๋์ดํ๋ ๋ฐ ์ถฉ๋ถํ์ง๋ง, ์ค์ ๋ก ์ฌ์ฉํ๊ณ ์ ํ๋ ๊ฒฝ์ฐ๋ ์ด๋ป๊ฒ ํด์ผ ํ ๊น์? ์ด๋ฌํ ๊ฒฝ์ฐ์๋ ๋ค์์ ์ํํด์ผ ํฉ๋๋ค:
- ๋ชจ๋ธ์ ์ถ๋ ฅ์ ํ์ฑํ์ฌ ๋๊ตฌ ์ด๋ฆ๊ณผ ์ธ์๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
- ๋ชจ๋ธ์ ๋๊ตฌ ํธ์ถ์ ๋ํ์ ์ถ๊ฐํฉ๋๋ค.
- ํด๋น ์ธ์์ ๋์ํ๋ ํจ์๋ฅผ ํธ์ถํฉ๋๋ค.
- ๊ฒฐ๊ณผ๋ฅผ ๋ํ์ ์ถ๊ฐํฉ๋๋ค.
๋๊ตฌ ์ฌ์ฉ ์์ [[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)
์ด ํ ํ๋ฆฟ์ ์ธ ๊ฐ์ง ์ผ์ ํฉ๋๋ค:
- ๊ฐ ๋ฉ์์ง์ ๋ํด, ๋ฉ์์ง๊ฐ ์ฌ์ฉ์ ๋ฉ์์ง์ธ ๊ฒฝ์ฐ ๊ณต๋ฐฑ์ ์ถ๊ฐํ๊ณ , ๊ทธ๋ ์ง ์์ผ๋ฉด ์๋ฌด๊ฒ๋ ์ถ๋ ฅํ์ง ์์ต๋๋ค.
- ๋ฉ์์ง ๋ด์ฉ์ ์ถ๊ฐํฉ๋๋ค.
- ๋ฉ์์ง๊ฐ ๋ง์ง๋ง ๋ฉ์์ง๊ฐ ์๋ ๊ฒฝ์ฐ ๋ ๊ฐ์ ๊ณต๋ฐฑ์ ์ถ๊ฐํฉ๋๋ค. ๋ง์ง๋ง ๋ฉ์์ง ํ์๋ 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]๊ณผ ํธํ๋ฉ๋๋ค.
์ ์ผ๋ถ ๋ชจ๋ธ์ ์ฌ๋ฌ ๊ฐ์ ํ ํ๋ฆฟ์ ๊ฐ์ง๊ณ ์๋์?[[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ํํฐ๋ฅผ ์ถ๊ฐํ๋ฉด ์ผ๊ด์ฑ์ ์ ์งํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.