localaiforum
로그인
가이드 › 기초

토큰과 토크나이저

모델은 단어나 글자를 결코 보지 못합니다. 모델이 보는 것은 토큰 ID입니다. 바이트 페어 인코딩(BPE) 또는 그 근접 변종으로 만들어진, 서브워드 조각들의 고정된 어휘를 가리키는 정수입니다. 토큰화는 모든 것이 지나가는 관문입니다. 프롬프트, 응답, 컨텍스트 창, 초당 토큰 계기, API 청구서. 토큰으로 생각하기 시작하면 LLM 동작에 대한 속설의 절반이 녹아 사라집니다.

어휘는 어떻게 만들어지는가

BPE는 원시 바이트에서 시작해, 가장 빈번한 인접 쌍을 어휘가 예산에 도달할 때까지 반복적으로 병합합니다. 결과: 자주 쓰는 단어는 단일 토큰이 되고, 드문 단어는 2–5개 조각이 되며, 표현 불가능한 것은 없습니다. 바이트 폴백이 오탈자와 이모지를 포함한 모든 문자열을 커버합니다. 어휘는 ~30k 항목(구형 모델)에서 ~250k(현대 다국어 모델)까지입니다:

토크나이저 어휘 크기 비고
GPT-2 ~50k 영어/웹 편중
Llama 2 ~32k 한국어는 뼈아프게 분할
Llama 3 ~128k 대형 다국어 업그레이드
Qwen 2 / 2.5 / 3 ~151k 강력한 CJK 병합
Gemma ~256k 가장 큰 일반 어휘

주로 영어로 학습된 토크나이저는 영어 조각을 공격적으로 병합합니다. 한국어 음절 쌍은 쓸 만한 병합을 훨씬 덜 받습니다. 모델 자체의 한국어 실력이 좋든 나쁘든, 한국어 세금은 그 전에 어휘가 결정합니다.

실습 예제: 영어

"Tokenization turns text into pieces."

→ ["Token", "ization", " turns", " text", " into", " pieces", "."]
→ 37자 → 7 토큰 ≈ 5.3자/토큰

디테일에 주목하세요. 흔한 단어 "Token"은 한 조각이고, 접미사는 자기 몫을 따로 받으며, 앞의 공백은 다음 토큰에 속합니다("turns"가 아니라 " turns"). 그래서 "hello", " hello", "Hello"는 서로 다른 토큰입니다. 공백 하나, 대문자 하나 차이로 토큰화 결과가 달라집니다.

실습 예제: 한국어

같은 문장, 더 나쁜 경제학. 한글은 음절 단위로 쓰이고, 영어 편중 어휘에서는 한국어 병합이 드뭅니다(아래 분할은 그럴듯한 예시이지 정확한 값은 아닙니다):

"안녕하세요, 만나서 반가워요."        # 17자

강한 다국어 어휘(~150k 항목):
["안녕", "하세요", ",", " 만나", "서", " 반", "가", "워", "요", "."]
→ ~10 토큰 ≈ 1.7자/토큰

약한 어휘(~32k 항목, 자모 단위 분할):
["안", "녕", "하", "세", "요", ",", " 만", "나", "서", ...]
→ 15+ 토큰 ≈ 1.1자/토큰

영어는 평균 ~4자/토큰입니다. 한국어는 보통 1–1.5에 머뭅니다. 같은 의미에 토큰은 3–4배. 그래서:

  • CJK 프롬프트는 컨텍스트 창을 놀랄 만큼 빨리 소모합니다. 8k 토큰 창은 한국어보다 영어를 대략 3–4배 더 담습니다.
  • 동일한 tok/s에서도 한국어는 더 느리게 "느껴집니다". 문장당 토큰이 더 많고, 토큰당 텍스트가 더 적습니다.
  • 토큰당 과금 API에서 한국어는 더 비싸고, 한국어로 쓰인 추론 트레이스도 같은 방식으로 예산을 태웁니다.

글자 세기 질문이 실패하는 이유

"strawberry에 r이 몇 개냐"고 물으면 큰 모델도 헤둥댑니다. 이유: 모델은 글자를 본 적이 없습니다. "strawberry"는 대략 ["straw", "berry"] — 정수 두 개로 도착합니다. 정수 안에 글자 수는 없습니다. 페이지 번호가 그 페이지의 철자를 알려주지 않는 것과 같습니다. 모델은 암기한 철자를 읊거나 한 단계씩 추론할 수 있고, 둘 다 불안정합니다. 꼭 필요하다면: 모델에게 먼저 단어를 한 줄에 한 글자씩 쓰게 하고, 줄 수를 세게 하세요.

어휘는 모델과 함께 배포됩니다

  • 토크나이저 파일(어휘, 병합)은 릴리스의 일부입니다. GGUF에는 내장되어 있고, safetensors 저장소에는 가중치 옆에 함께 있습니다.
  • 엔진(llama.cpp, LM Studio, vLLM, ...)은 올바른 토크나이저를 자동으로 로드합니다. 직접 고르는 일은 없습니다.
  • 토큰 수는 모델 상대적입니다. 같은 텍스트가 한 패밀리 어휘에서는 1,000 토큰, 다른 어휘에서는 1,150 토큰일 수 있습니다. 모델을 넘어 토큰 예산을 하드코딩하지 마세요.
  • 어휘 품질과 모델 품질은 별개의 축입니다. 32k 어휘 모델도 한국어를 다룰 수 있습니다(자기 토큰을 이해하니까). 문장당 토큰을 더 쓸 뿐입니다.

모든 것은 토큰으로 값이 매겨집니다

관심 대상 측정 단위
컨텍스트 창 (4k → 128k+) 입력 토큰 + 출력 토큰 합산
생성 속도 초당 토큰
KV 캐시 메모리 컨텍스트의 토큰마다 증가 (KV 캐시)
API 가격 백만 토큰당
출력 길이 제한 최대 출력 토큰
추론/thinking 예산 답하기 전에 모델이 쓸 수 있는 토큰
RAG용 문서 임베딩 청크로 나눠 백만 토큰당 계수

특수 토큰과 챗 템플릿

텍스트 조각 외에 어휘는 제어용 ID를 예약해 둡니다. 시퀀스 시작, 시퀀스 끝, 역할 마커입니다. 챗 UI가 메시지를 보낼 때 날것 텍스트를 보내는 것이 아닙니다. <|im_start|>user ... <|im_end|> 같은 특수 토큰을 당신의 말들 사이에 끼워 넣는 챗 템플릿을 채워 보냅니다. 이 감싸기가, 엔진이 보고하는 토큰 수가 항상 메시지 텍스트 단독보다 조금 더 큰 이유이고, 서로 다른 패밀리의 템플릿을 섞으면 모델이 혼란스러워지는 이유입니다.

추정 규칙: 영어는 글자 수 ÷ 4. 한국어는 글자 수 ÷ 1.0–1.5. 최악을 가정하세요. 시뮬레이터는 ~4자/토큰 근사를 사용하며 영어 기준으로 보정되어 있습니다. 한국어는 머릿속에서 부풀리세요.

직접 토큰 세기

pip install tiktoken
python -c "import tiktoken as t; e = t.get_encoding('o200k_base'); print(len(e.encode('hello world')))"
  • tiktoken(https://github.com/openai/tiktoken)은 OpenAI 계열 인코딩을 다룹니다. 다른 계열은 다르지만 영어는 대략 ±15% 안에 들어옵니다.
  • Hugging Face 모델 페이지에는 토크나이저 뷰어가 있고, 토크나이저 플레이그라운드에서는 텍스트를 붙여넣고 분할을 실시간으로 볼 수 있습니다.
  • 로컬 엔진은 로그에 프롬프트 토큰 수를 찍습니다. 실제 프롬프트로 한 번 확인한 뒤에는 비율로 추정하세요.

관련: transformer 내부 · 프리필 대 디코드 · KV 캐시