Mistral의 Instruct 토크나이제이션 & 채팅 템플릿 해부
Mistral의 Instruct 토크나이제이션 & 채팅 템플릿 해부 (Demystifying Mistral's Instruct Tokenization & Chat Templates)
Mistral 토크나이저가 버전별로 instruct 토크나이제이션과 채팅 템플릿을 어떻게 다루는지, 그 이야기와 올바른 사용법을 자세히 풀어내는 문서예요.
출처: 문서
본문
[!IMPORTANT] 이 문서는 지원 중단(deprecated)되었어요. 완전하고 심층적인 문서는 여기를 확인해 주세요.
원래 토크나이저 V1부터 최신 V3와 Tekken 토크나이저까지, Mistral의 토크나이저들은 instruct 모델을 위해 토크나이즈하는 방식에서 미묘한 변화를 겪어 왔어요. 최적의 접근 방식을 찾기 위해 최적화와 연구를 오래 진행해 왔답니다. 오늘은 이 토크나이저들을 깊이 들여다보고, 논쟁의 원인을 해소하며, 어떻게 동작하는지, 각각에 맞는 올바른 채팅 템플릿은 무엇인지, 그리고 커뮤니티에서의 이야기를 살펴볼 거예요.
이 글에서는 주로 간단한 지시 따르기(instruction following)를 위한 instruct 토크나이제이션과 채팅 템플릿을 다룰게요. 함수 호출(function calling)이나 fill in the middle은 다루지 않아요.
여기에 있는 모든 정보의 기준(ground truth)은 Hugging Face와 GitHub의 리포지토리, 특히 mistral_common에서 찾을 수 있어요.
Tokenizer V1:
"<s> [INST] user message [/INST] assistant message</s> [INST] new user message [/INST]"
mistral-common에서는 기본적으로 시스템 프롬프트가 첫 번째 사용자 메시지 앞에 붙어요. (자유롭게 커스터마이즈할 수 있어요.)
Tokenizer V2:
"<s>[INST] user message[/INST] assistant message</s>[INST] new user message[/INST]"
mistral-common에서는 기본적으로 시스템 프롬프트가 마지막 사용자 메시지 앞에 붙어요. (자유롭게 커스터마이즈할 수 있어요.)
FIM
"<s>[SUFFIX]suffix[PREFIX] prefix"
Tokenizer V3:
"<s>[INST] user message[/INST] assistant message</s>[INST] new user message[/INST]"
V3는 V2와 매우 비슷해요. 유일한 차이는 function calling에 관한 거예요.
FIM
"<s>[SUFFIX]suffix[PREFIX] prefix"
Tokenizer V3 - Tekken (Nemo):
"<s>[INST]user message[/INST]assistant message</s>[INST]new user message[/INST]"
mistral-common에서는 기본적으로 시스템 프롬프트가 마지막 사용자 메시지 앞에 붙어요. (자유롭게 커스터마이즈할 수 있어요.)
EDIT: 자세한 새 문서는 cookbooks에서 확인할 수 있어요.
Tokenizer V1
최초의 릴리스인 Mistral 7B V1, V2 그리고 Mixtral 8x7B V1은 커뮤니티로부터 많은 감사와 사랑을 받았어요. 하지만 그렇다고 해서 instruct 토크나이저에 대한 올바른 채팅 템플릿을 둘러싼 커뮤니티 내부의 불일치와 논쟁을 막을 수는 없었어요. 오늘날에는 mistral_common을 토크나이제이션 과정의 기준으로 안정적으로 신뢰할 수 있지만, 그 당시 대부분의 커뮤니티는 사용 가능한 Jinja 채팅 템플릿에 의존했어요!
커뮤니티는 토크나이저와 채팅 템플릿의 불일치를 아주 빨리 알아차렸고, 특수 문자열 주변의 공백을 조정한 커스텀 버전으로 더 나은 결과를 얻었어요. 커뮤니티가 모델과 관련된 문제와 버그를 발견하는 데 정말 빠르고 유용하다는 게 놀라워요!
이 첫 릴리스에 사용된 토크나이저는 sentencepiece에 기반하며, 옛 Llama 모델과 비슷한 템플릿을 사용해요. 이 토크나이저는 instruct 메시지를 다음과 같이 다뤄요:
Instruct 채팅 템플릿 (Instruct Chat Template)
앞서 언급했듯이 채팅 템플릿은 첫 Llama 템플릿과 매우 비슷하며, 다음과 같은 문자열로 이어져요.
<s> [INST] user message [/INST] assistant message</s> [INST] new user message [/INST]
여기서 유일한 특수 문자열은 사용자 메시지를 시작하는 [INST]와 사용자 메시지를 끝내는 [/INST]였어요. 이로써 assistant의 응답 자리가 마련되죠. BOS(beginning of string)는 지금도 <s>로 표현되고, EOS(end of string)는 </s>로 표현되며, 각 완성(completion)의 끝에 사용되어 assistant 메시지를 종료해요.
공백(whitespace)은 극도로 중요해요.
<s>와 </s>는 실제 문자열이라기보다 BOS와 EOS를 나타내는 표현에 가깝다는 점을 기억하세요. 그에 해당하는 ID는 각각 1과 2예요.
⚠️ 이 템플릿은 항상 모델이 공백으로 시작하는 토큰(항상 앞에 공백이 있는)을 출력하게 해요. 추론 엔진에 따라 그 공백을 기본적으로 제거할 수도 있고 아닐 수도 있어요. 따라서 템플릿을 사용할 때 각 assistant 응답 뒤에 공백(정확히 하나)이 있는지 확인하는 게 필수적이에요.
이런 문자열에 대한 HuggingFace transformers의 Jinja 템플릿은 다음과 같을 수 있어요:
{{ bos_token }}{% for message in messages %}{% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}{{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}{% endif %}{% if message['role'] == 'user' %}{{ ' [INST] ' + message['content'] + ' [/INST]' }}{% elif message['role'] == 'assistant' %}{{ ' ' + message['content'] + eos_token}}{% else %}{{ raise_exception('Only user and assistant roles are supported!') }}{% endif %}{% endfor %}
현재 기본적으로 사용되고 있는 것은 tokenizer_config.json에서 확인할 수 있어요.
읽기 쉽게 포맷하면, 어떻게 동작하는지 이해하기 더 쉬워져요:
{{ bos_token }}
{% for message in messages %}
{% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}
{{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}
{% endif %}
{% if message['role'] == 'user' %}
{{ ' [INST] ' + message['content'] + ' [/INST]' }}
{% elif message['role'] == 'assistant' %}
{{ ' ' + message['content'] + eos_token }}
{% else %}
{{ raise_exception('Only user and assistant roles are supported!') }}
{% endif %}
{% endfor %}
⚠️ 보시다시피 각
message['content']는 항상 공백으로 시작해요. 이는message['content']의 첫 공백을 여러분이나 추론 라이브러리가 수동으로 제거했다고 가정해요.
템플릿을 직접 수동으로 적용하고 싶다면 Python에서 이렇게 할 수 있어요:
from jinja2 import Template, Environment, exceptions
JINJA_TEMPLATE = "{{ bos_token }}{% for message in messages %}{% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}{{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}{% endif %}{% if message['role'] == 'user' %}{{ ' [INST] ' + message['content'] + ' [/INST]' }}{% elif message['role'] == 'assistant' %}{{ ' ' + message['content'] + eos_token}}{% else %}{{ raise_exception('Only user and assistant roles are supported!') }}{% endif %}{% endfor %}"
def raise_exception(message):
raise ValueError(message)
def apply_jinja_template(messages, bos_token='<s>', eos_token='</s>'):
template_str = JINJA_TEMPLATE
env = Environment()
env.globals['raise_exception'] = raise_exception
template = env.from_string(template_str)
try:
result = template.render(messages=messages, bos_token=bos_token, eos_token=eos_token)
return result
except exceptions.TemplateError as e:
raise ValueError(f"Template rendering error: {e}")
print(apply_jinja_template(messages))
Instruct 토크나이제이션 로직 (Instruct Tokenization Logic)
이제 mistral_common에서 볼 수 있는 토크나이제이션 과정의 원래 로직을 살펴볼게요. 여러분은 종종 토크나이저에 텍스트를 그대로 넘기고 전체 문자열을 있는 그대로 인코딩하지 않아요. mistral-common은 실제로 request -> int로 바로 가는 반면, transformers가 사용하는 방식 같은 다른 접근 방식은 request -> str -> int에 더 가까워요. 토크나이제이션 과정에서 실제로 하는 방식은 다음 로직에 더 가까워요:
-
각 메시지를 토크나이즈:
사용자 메시지와 assistant 메시지가 있을 거예요. 각각을 특수 문자열로 감싼 개별 문자열로 따로 가져와서 인코딩해요. 앞선 예시에서 이렇게 될 거예요:
encode("[INST] user message [/INST]"),encode("assistant message"), 그리고encode("[INST] new user message [/INST]"), 계속해서... -
연결 (Concatenate):
각 메시지가 토크나이즈되고 인코딩되면 모두 연결하고, 앞에 BOS ID를 붙이고 쌍으로 EOS ID로 구분해요:
BOS_ID + encode("[INST] user message [/INST]") + encode("assistant message") + EOS_ID + encode("[INST] new user message [/INST]")
단계별로 따르면 이것이 실제로 다음과 같이 공백이 추가된 문자열과 일치한다는 걸 눈치챌 수 있어요:
<s>[INST]_user message_[/INST]_assistant message</s>[INST]_new user message_[/INST]
"_"는 특수 문자열로 감쌀 때 추가되는 공백을 나타내요.
위에서 언급한 채팅 템플릿과 비교하면 BOS와 EOS 뒤에 일부 공백이 빠져 있어요. 그럼 그것들은 어디서 오는 걸까요? 그것들은 인코딩할 때 sentencepiece에서 와요. sentencepiece는 기본적으로 앞에 공백으로 시작해요. 그래서 우리가 encode할 때마다 앞 공백을 추가하는 거예요. 그렇기 때문에:
encode("[INST] user message [/INST]")는 실제로encode(" [INST] user message [/INST]")를 인코딩하는 거예요.
이게 앞 공백들을 추가해서 최종 문자열이 이렇게 더 보이게 해요:
<s>_[INST] user message [/INST] assistant message</s>_[INST] new user message [/INST]
"_"는 sentencepiece가 새로 추가한 공백을 나타내요.
마지막으로 토큰별로 보면 다음과 같이 돼요.
"_"는 어떤 공백이든 나타내요.
시스템 프롬프트 (System Prompt)
첫 릴리스에는 시스템 프롬프트에 대한 특정 방법론이 없었어요. 기본적으로 보통 시스템 프롬프트를 첫 번째 사용자 메시지 앞에 붙이고, 두 개의 새 줄이 따라와요:
<s> [INST] system prompt
user message [/INST] assistant message</s> [INST] new user message [/INST]
Tokenizer V2
앞선 토크나이저를 따르고 주로 독점(proprietary) 모델에 사용되는 두 번째 버전의 토크나이저는, 지금은 옛 모델이 된 Mistral Small 2402와 Mistral Large 2402와 같은 모델들을 구동했어요. 이 새 토크나이저는 컨트롤 토큰을 도입했는데, 특히 이전의 특수 문자열 [INST]와 [/INST]가 해당 ID 3과 4를 가진 컨트롤 토큰이 되었고, function calling을 위한 새 컨트롤 토큰들도 도입했어요.
Instruct 채팅 템플릿 (Instruct Chat Template)
컨트롤 토큰의 도입 덕분에, 일부 공백이 없어지면서 채팅 템플릿이 약간 바뀌었어요.
<s>[INST] user message[/INST] assistant message</s>[INST] new user message[/INST]
비교를 위해, 이전 토크나이저의 이전 채팅 템플릿 문자열은 이렇습니다:
<s> [INST] user message [/INST] assistant message</s> [INST] new user message [/INST]
⚠️ 이 템플릿은 항상 모델이 공백으로 시작하는 토큰(항상 앞에 공백이 있는)을 출력하게 해요. 추론 엔진에 따라 그 공백을 기본적으로 제거할 수도 있고 아닐 수도 있어요. 따라서 템플릿을 사용할 때 각 assistant 응답 뒤에 공백(정확히 하나)이 있는지 확인하는 게 필수적이에요.
이런 문자열에 대한 HuggingFace transformers의 Jinja 템플릿은 다음과 같을 수 있어요:
{{ bos_token }}{% for message in messages %}{% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}{{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}{% endif %}{% if message['role'] == 'user' %}{{ '[INST] ' + message['content'] + '[/INST]' }}{% elif message['role'] == 'assistant' %}{{ ' ' + message['content'] + eos_token}}{% else %}{{ raise_exception('Only user and assistant roles are supported!') }}{% endif %}{% endfor %}
읽기 쉽게 포맷하면:
{{ bos_token }}
{% for message in messages %}
{% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}
{{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}
{% endif %}
{% if message['role'] == 'user' %}
{{ '[INST] ' + message['content'] + '[/INST]' }}
{% elif message['role'] == 'assistant' %}
{{ ' ' + message['content'] + eos_token }}
{% else %}
{{ raise_exception('Only user and assistant roles are supported!') }}
{% endif %}
{% endfor %}
⚠️ 보시다시피 각
message['content']는 항상 공백으로 시작해요. 이는message['content']의 첫 공백을 여러분이나 추론 라이브러리가 수동으로 제거했다고 가정해요.
템플릿을 직접 수동으로 적용하고 싶다면 Python에서 이렇게 할 수 있어요:
from jinja2 import Template, Environment, exceptions
JINJA_TEMPLATE = "{{ bos_token }}{% for message in messages %}{% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}{{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}{% endif %}{% if message['role'] == 'user' %}{{ '[INST] ' + message['content'] + '[/INST]' }}{% elif message['role'] == 'assistant' %}{{ ' ' + message['content'] + eos_token}}{% else %}{{ raise_exception('Only user and assistant roles are supported!') }}{% endif %}{% endfor %}"
def raise_exception(message):
raise ValueError(message)
def apply_jinja_template(messages, bos_token='<s>', eos_token='</s>'):
template_str = JINJA_TEMPLATE
env = Environment()
env.globals['raise_exception'] = raise_exception
template = env.from_string(template_str)
try:
result = template.render(messages=messages, bos_token=bos_token, eos_token=eos_token)
return result
except exceptions.TemplateError as e:
raise ValueError(f"Template rendering error: {e}")
print(apply_jinja_template(messages))
FIM
FIM을 위한 템플릿은 다음과 같아요:
<s>[SUFFIX]suffix[PREFIX] prefix
Instruct 토크나이제이션 로직 (Instruct Tokenization Logic)
이제 컨트롤 토큰이 생겼으니, 토크나이즈하는 과정이 약간 바뀌었어요. 채팅 템플릿 뒤에 있는 새 로직은 이래요:
-
각 메시지를 토크나이즈:
사용자 메시지와 assistant 메시지가 있어요. 각각을 개별 문자열로 따로 가져와서 인코딩해요:
encode(user_message),encode(assistant_message), 그리고encode(new_user_message), 계속해서... -
연결 (Concatenate):
각 메시지가 토크나이즈되고 인코딩되면 모두 연결하고, 앞에 BOS ID를 붙이고 쌍으로 EOS ID로 구분하면서, 사용자 메시지를 컨트롤 토큰, 특히
[INST]ID와[/INST]ID로 감싸요:BOS_ID + INST_ID + encode("user message") + /INST_ID + encode("assistant message") + EOS_ID + INST_ID + encode("new user message") + /INST_ID
이에 따라 문자열은 이렇게 될 거예요:
<s>[INST]user message[/INST]assistant message</s>[INST]new user message[/INST]
하지만 다시 한번, 이번에는 컨트롤 토큰 뒤에 일부 공백이 빠져 있어요. 그것들은 이전과 같은 곳, 즉 sentencepiece에서 와요:
encode("user message")는 실제로encode(" user message")를 인코딩해요.encode("assistant message")는 실제로encode(" assistant message")를 인코딩해요.encode("new user message")는 실제로encode(" new user message")를 인코딩해요.
이게 빠진 공백을 추가해서 최종 문자열이 이렇게 더 보이게 해요:
<s>[INST]_user message[/INST]_assistant message</s>[INST]_new user message[/INST]
"_"는 sentencepiece가 새로 추가한 공백을 나타내요.
마지막으로 토큰별로 보면 다음과 같이 돼요.
시스템 프롬프트 (System Prompt)
두 번째 버전의 토크나이저는 약간 다른 시스템 프롬프트 방식을 구현해요. 기본적으로 마지막 사용자 메시지 앞에 붙여요:
<s>[INST] user message[/INST] assistant message</s>[INST] system prompt
new user message[/INST]
⚠️ 이것은
mistral_common과 템플릿이 시스템 프롬프트를 구현하는 방식이에요. 하지만 쉽게 커스터마이즈할 수 있어요. 시스템 프롬프트를 마지막에서 두 번째, 또는 예전처럼 첫 번째 사용자 메시지처럼 다른 위치에 사용해도 괜찮아요.
Tokenizer V3
이 토크나이저는 Mixtral 8x22B, Codestral 22B, Mathstral 7B, Mamba Codestral 7B, Small 2409, Large 2(Large 2407) 같은 모델들을 구동해요. 두 번째 버전과 매우 비슷하며, tool 사용만 약간 달라요.
기본 instruct를 위한 채팅 템플릿, 토크나이제이션, 시스템 프롬프트는 이전 버전과 동일해요.
Tekken
Tekken은 V3 토크나이저의 다른 버전으로, Mistral Nemo 12B와 Pixtral 12B를 구동해요. 원래 버전과 이전 토크나이저들이 sentencepiece에 기반한 반면, Tekken은 tiktoken에 기반해요. 상당히 더 큰 어휘 크기를 가지며 인코딩도 다르게 처리해요. 채팅 템플릿의 주요 차이는 sentencepiece처럼 공백을 앞에 붙이지 않는다는 거예요.
그 결과 더 단순한 채팅 템플릿과 더 직관적인 토크나이제이션으로 이어져요.
Tekken Instruct 채팅 템플릿 (Tekken Instruct Chat Template)
더 적은 방해적인 공백으로, 새 템플릿은 다음과 같이 단순해요:
<s>[INST]user message[/INST]assistant message</s>[INST]new user message[/INST]
비교를 위해, 이전 토크나이저의 채팅 템플릿은 이렇습니다:
<s>[INST] user message[/INST] assistant message</s>[INST] new user message[/INST]
이런 문자열에 대한 HuggingFace transformers의 Jinja 템플릿은 다음과 같을 수 있어요:
{{ bos_token }}{% for message in messages %}{% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}{{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}{% endif %}{% if message['role'] == 'user' %}{{ '[INST]' + message['content'] + '[/INST]' }}{% elif message['role'] == 'assistant' %}{{ message['content'] + eos_token}}{% else %}{{ raise_exception('Only user and assistant roles are supported!') }}{% endif %}{% endfor %}
읽기 쉽게 포맷하면:
{{ bos_token }}
{% for message in messages %}
{% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}
{{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}
{% endif %}
{% if message['role'] == 'user' %}
{{ '[INST]' + message['content'] + '[/INST]' }}
{% elif message['role'] == 'assistant' %}
{{ message['content'] + eos_token }}
{% else %}
{{ raise_exception('Only user and assistant roles are supported!') }}
{% endif %}
{% endfor %}
템플릿을 직접 수동으로 적용하고 싶다면 Python에서 이렇게 할 수 있어요:
from jinja2 import Template, Environment, exceptions
JINJA_TEMPLATE = "{{ bos_token }}{% for message in messages %}{% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}{{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}{% endif %}{% if message['role'] == 'user' %}{{ '[INST]' + message['content'] + '[/INST]' }}{% elif message['role'] == 'assistant' %}{{ message['content'] + eos_token}}{% else %}{{ raise_exception('Only user and assistant roles are supported!') }}{% endif %}{% endfor %}"
def raise_exception(message):
raise ValueError(message)
def apply_jinja_template(messages, bos_token='<s>', eos_token='</s>'):
template_str = JINJA_TEMPLATE
env = Environment()
env.globals['raise_exception'] = raise_exception
template = env.from_string(template_str)
try:
result = template.render(messages=messages, bos_token=bos_token, eos_token=eos_token)
return result
except exceptions.TemplateError as e:
raise ValueError(f"Template rendering error: {e}")
print(apply_jinja_template(messages))
Tekken Instruct 토크나이제이션 로직 (Tekken Instruct Tokenization Logic)
토크나이제이션 로직은 이전과 여전히 같아요:
-
각 메시지를 토크나이즈:
사용자 메시지와 assistant 메시지가 있어요. 각각을 개별 문자열로 따로 가져와서 인코딩해요:
encode(user_message),encode(assistant_message), 그리고encode(new_user_message), 계속해서... -
연결 (Concatenate):
각 메시지가 토크나이즈되고 인코딩되면 모두 연결하고, 앞에 BOS ID를 붙이고 쌍으로 EOS ID로 구분하면서, 사용자 메시지를 컨트롤 토큰, 특히
[INST]ID와[/INST]ID로 감싸요:BOS_ID + INST_ID + encode("user message") + /INST_ID + encode("assistant message") + EOS_ID + INST_ID + encode("new user message") + /INST_ID
그리고 그게 전부예요. 결과 문자열은 더 직관적이고, sentencepiece와는 다른 동작 덕분에 추가 공백이 없어서 최종 문자열은 다음과 같아요:
<s>[INST]user message[/INST]assistant message</s>[INST]new user message[/INST]
토큰별로 보면:
시스템 프롬프트 (System Prompt)
기본적으로 시스템 프롬프트는 이전 버전들과 비슷하게 처리돼요:
<s>[INST]user message[/INST]assistant message</s>[INST]system prompt
new user message[/INST]
결론 (Conclusion)
토크나이저들은 V1에서 V3, 그리고 Tekken 변형까지 크게 진화했어요. 각 반복은 개선과 변화를 가져왔고, 때로는 커뮤니티에서 논쟁과 이슈로 이어지기도 했어요. 이 토크나이저들의 미묘함을 이해하는 것은 다양한 애플리케이션에서 Mistral 모델의 성능을 최적화하고 제대로 파인튜닝하는 데 중요해요.
핵심 요약 (Key Takeaways):
- Tokenizer V1:
sentencepiece와 Llama 모델과 비슷한 템플릿을 사용했어요.- 공백 처리가 있는 특수 문자열
[INST]와[/INST]. - 시스템 프롬프트를 두 개의 새 줄과 함께 첫 번째 사용자 메시지 앞에 붙여요.
- Tokenizer V2:
[INST]와[/INST]및 다른 컨트롤 토큰을 위한 컨트롤 토큰을 도입했어요.- 일부 공백이 없어지며 채팅 템플릿이 약간 조정됐어요.
- 시스템 프롬프트를 마지막 사용자 메시지에 붙여요.
- Tokenizer V3:
- V2와 비슷하지만 tool 사용이 개선됐어요.
- V2와 같은 채팅 템플릿, 토크나이제이션, 시스템 프롬프트 방식을 사용해요.
- Tokenizer V3 - Tekken:
- 더 큰 어휘를 가진
tiktoken에 기반해요. - 앞 공백이 없는 더 단순한 채팅 템플릿.
- 더 큰 어휘를 가진
모범 사례 (Best Practices):
- 공백 처리 (Whitespace Handling): 특히
sentencepiece기반 토크나이저는 앞 공백을 붙이므로 공백 처리에 세심한 주의를 기울이세요. - 컨트롤 토큰 (Control Tokens): V2와 V3 토크나이저에서 컨트롤 토큰을 올바르게 사용해서 사용자 메시지가 제대로 감싸지도록 하세요.
- 시스템 프롬프트 (System Prompts): 필요에 따라 시스템 프롬프트를 커스터마이즈하되, 각 토크나이저 버전의 기본 위치를 인지하세요.
커뮤니티와 리소스 (Community and Resources):
- 커뮤니티 기여 (Community Contributions): 커뮤니티는 불일치와 버그를 식별하고 해결하는 데 결정적인 역할을 해왔으며, 오픈소스 개발의 협업적 특성을 보여줘요. Mistral의 discord 서버에 참여해서 커뮤니티 멤버들과 교류해 보세요!
- 기준 (Ground Truth): 가장 정확하고 최신 정보를 원한다면 GitHub의 mistral_common 리포지토리와 문서를 참고하세요.