huggingface--transformers
e06fe8e8c6
Secret Leaks / trufflehog (push) Failing after 1s
Build documentation / build (push) Failing after 1s
Build documentation / build_other_lang (push) Failing after 0s
CodeQL Security Analysis / CodeQL Analysis (push) Failing after 0s
PR CI / pr-ci (push) Failing after 1s
Slow tests on important models (on Push - A10) / Get all modified files (push) Failing after 1s
Slow tests on important models (on Push - A10) / Model CI (push) Has been skipped
Self-hosted runner (benchmark) / Benchmark (aws-g5-4xlarge-cache) (push) Has been cancelled
New model PR merged notification / Notify new model (push) Has been cancelled
Update Transformers metadata / build_and_package (push) Has been cancelled
720 ่ก
42 KiB
Markdown
720 ่ก
42 KiB
Markdown
<!--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, 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` ํํฐ๋ฅผ ์ถ๊ฐํ๋ฉด ์ผ๊ด์ฑ์ ์ ์งํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค. |