logo
aillmtokenizer

토큰과 토크나이저 - LLM이 글자를 읽는 방식

LLM API를 써보면 "토큰"이라는 단위를 자주 만납니다. 요금도 토큰으로 매기고, 컨텍스트 한도도 토큰으로 표시됩니다. 그런데 토큰은 우리가 생각하는 "단어"나 "글자"와 정확히 일치하지 않습니다. LLM은 사람처럼 글자를 읽는 게 아니라, 자기만의 방식으로 텍스트를 조각내서 읽기 때문입니다.

이 글에서는 토큰이 무엇이고, 토크나이저가 어떻게 동작하며, 이게 비용·성능·특히 한국어에 어떤 영향을 주는지 정리합니다.


1. 토큰이란 무엇인가

토큰(token) 은 LLM이 텍스트를 처리하는 최소 단위입니다. 사람은 문장을 단어로 나눠 읽지만, LLM은 서브워드(subword), 즉 단어보다 잘거나 큰 조각으로 나눠 읽습니다.

영어 예시를 보면 감이 옵니다.

"unbelievable" → ["un", "believ", "able"] (3 토큰) "cat" → ["cat"] (1 토큰) "tokenization" → ["token", "ization"] (2 토큰)
  • 자주 쓰이는 단어(cat)는 통째로 1토큰
  • 드물거나 긴 단어는 여러 조각으로 분해

"자주 등장하는 덩어리는 크게, 드문 것은 잘게" 나누는 게 핵심 원리입니다. 대략적인 감각으로 영어는 1토큰 ≈ 4글자 ≈ 0.75단어 정도입니다.


2. 왜 단어도, 글자도 아닌 서브워드인가

토큰 단위를 정하는 데는 트레이드오프가 있습니다.

단위장점단점
글자(character)어휘가 아주 작음, 모르는 단어 없음시퀀스가 너무 길어짐, 의미 단위 약함
단어(word)의미 단위가 명확어휘 폭발, 신조어·오타 처리 불가
서브워드(subword)어휘 크기와 표현력의 균형(그 중간이라 대부분 채택)

단어 단위로 하면 "어휘 사전"이 수백만 개로 불어나고, 처음 보는 신조어("킹받다")를 아예 처리 못 합니다. 글자 단위로 하면 어휘는 작아지지만 문장 하나가 수백 토큰이 되어 비효율적입니다.

서브워드는 그 사이의 절충안입니다. 알려진 조각을 조합해 어떤 단어든(심지어 오타나 신조어도) 표현할 수 있고, 어휘 크기도 5만~15만 개 수준으로 관리됩니다.


3. BPE - 서브워드를 만드는 대표 알고리즘

가장 널리 쓰이는 방식이 BPE(Byte Pair Encoding) 입니다. 아이디어는 단순합니다.

"가장 자주 붙어 나오는 글자 쌍을 계속 하나로 합쳐라."

동작을 개념적으로 보면 이렇습니다.

초기: l o w l o w e r n e w e s t 1단계: 'e s'가 가장 자주 등장 → 'es'로 병합 2단계: 'es t'가 자주 등장 → 'est'로 병합 3단계: 'l o'가 자주 등장 → 'lo'로 병합 ... 반복하면 자주 쓰는 덩어리(low, est ...)가 하나의 토큰이 됨

이 병합을 수만 번 반복해 어휘 사전(vocabulary) 을 완성합니다. 실제 텍스트를 토큰화할 때는 이 사전을 보고 긴 조각부터 매칭합니다.

이렇게 만든 사전을 쓰는 게 토크나이저(tokenizer) 입니다. 토크나이저는 학습된 모델마다 다릅니다. GPT 계열은 tiktoken, 다른 모델은 SentencePiece 등 각자의 토크나이저를 씁니다. 같은 문장도 모델마다 토큰 수가 다르다는 뜻입니다.

요즘은 순수 문자가 아니라 바이트 단위 BPE를 많이 씁니다. 텍스트를 UTF-8 바이트로 본 뒤 병합하기 때문에, 어떤 언어·이모지·특수문자도 "모르는 글자" 없이 표현할 수 있습니다.


4. 한국어가 토큰을 많이 먹는 이유

실무에서 체감하는 문제입니다. 같은 의미라도 한국어가 영어보다 토큰을 훨씬 많이 씁니다.

"Hello, how are you?" → 약 6 토큰 "안녕하세요, 어떻게 지내세요?" → 약 15~20 토큰 (모델마다 다름)

왜 이럴까요?

  1. 학습 데이터 편중: 토크나이저는 대부분 영어 위주 코퍼스로 학습됩니다. 영어 단어는 통째로 1토큰이 되는 경우가 많지만, 한국어는 자주 등장하지 못해 큰 덩어리로 병합될 기회가 적습니다.
  2. 바이트 단위 분해: 한글 한 글자는 UTF-8에서 3바이트입니다. 사전에 없는 조합이면 글자 하나가 여러 토큰으로 쪼개지기도 합니다.
  3. 교착어 특성: 한국어는 조사·어미가 붙는 교착어라 형태가 다양합니다("먹다/먹었다/먹으니까/먹겠습니다"). 각 변형이 별도 조각으로 흩어지기 쉽습니다.

결과적으로 한국어는 영어 대비 2~3배 토큰을 쓰는 경우가 흔합니다. 이게 왜 중요한지는 다음 절에서 이어집니다. (최근 모델들은 한국어 토크나이징이 많이 개선됐지만, 여전히 영어보다 불리한 건 사실입니다.)


5. 토큰이 비용·컨텍스트·성능에 미치는 영향

토큰은 단순한 내부 개념이 아니라 돈과 성능에 직결됩니다.

5-1. 비용

LLM API는 입력 토큰 + 출력 토큰 개수로 과금합니다. 한국어가 토큰을 2배 쓴다면, 같은 작업에 요금도 약 2배 나온다는 뜻입니다. 대량 처리 서비스라면 무시 못 할 차이입니다.

5-2. 컨텍스트 한도

모델이 한 번에 볼 수 있는 창(컨텍스트 윈도우)은 토큰으로 정해집니다. 예를 들어 128K 토큰 모델이라도, 한국어 문서는 영어 문서보다 더 적은 분량밖에 못 넣습니다. RAG에서 청크를 몇 개 넣을 수 있는지에도 영향을 줍니다.

5-3. 성능·속도

출력은 토큰을 하나씩 생성하므로, 출력 토큰이 많을수록 응답이 느리고 비쌉니다. "간결하게 답하라"는 지시가 속도·비용 최적화에도 도움이 되는 이유입니다.


6. 실무 팁

토큰을 이해하면 아낄 수 있는 지점들이 보입니다.

  • 토큰 수를 미리 재라. 요청 전에 토크나이저 라이브러리로 토큰 수를 계산하면, 컨텍스트 초과와 비용 폭탄을 예방할 수 있습니다.
# OpenAI 계열 예시 (tiktoken) import tiktoken enc = tiktoken.encoding_for_model("gpt-4o") tokens = enc.encode("안녕하세요, 반갑습니다") print(len(tokens)) # 실제 토큰 수 확인
  • 불필요한 반복을 줄여라. 프롬프트에 매번 붙는 긴 시스템 지침, 중복 설명은 토큰을 잡아먹습니다. 공통 부분은 프롬프트 캐싱으로 처리하면 비용을 크게 줄일 수 있습니다.
  • JSON 응답은 키를 짧게. 대량 구조화 출력에서 긴 키 이름은 매 응답마다 토큰을 씁니다.
  • 한국어 요약·번역 파이프라인에서는 토큰 폭증을 감안해 청크 크기와 컨텍스트 예산을 잡으세요. "글자 수"가 아니라 "토큰 수" 기준으로 설계해야 합니다.
  • 잘림(truncation) 주의. 입력이 컨텍스트를 넘으면 앞이나 뒤가 잘려나갈 수 있습니다. 중요한 지시는 잘리지 않을 위치에 배치하세요.

마무리

토큰은 LLM을 다룰 때 계속 마주치는 기본 화폐 단위입니다.

정리하면 이렇습니다.

  1. LLM은 글자나 단어가 아니라 서브워드 토큰으로 텍스트를 읽는다.
  2. BPE 로 "자주 쓰는 덩어리는 크게, 드문 것은 잘게" 사전을 만든다.
  3. 한국어는 여러 이유로 토큰을 많이 먹어 비용·컨텍스트에서 불리하다.
  4. 토큰은 곧 비용·컨텍스트 한도·속도다. 설계할 때 "글자 수"가 아니라 "토큰 수"로 생각하자.

토큰 감각이 생기면 프롬프트를 왜 다이어트해야 하는지, 왜 캐싱이 중요한지가 자연스럽게 이해됩니다.

me

강경원

Backend Developer

성능과 안정성으로 신뢰받는 백엔드 개발자 · 요즘은 AI/LLM을 서비스에 접목합니다

이력서 보기