토크나이저와 한국어 토큰 비용: 같은 내용이 왜 더 비쌀까?
아래 두 문장은 같은 말입니다. 직접 지어낸 예문이고, 앞은 한국어로 49자, 뒤는 영어로 100자입니다.
배포하기 전에 데이터베이스를 백업하고, 마이그레이션이 실패하면 이전 버전으로 되돌립니다.
Back up the database before deploying, and roll back to the previous version if the migration fails.GPT-4o 계열이 쓰는 o200k_base 토크나이저로 세면 한국어 문장은 28토큰, 영어 문장은 19토큰입니다. 글자는 절반인데 토큰은 1.5배 가까이 많습니다. GPT-4 시절의 cl100k_base로 세면 차이가 더 벌어져서 45토큰 대 19토큰이 됩니다. 요금은 토큰으로 매기니, 같은 내용을 한국어로 보내면 이만큼 더 냅니다.
요금표의 단위는 글자가 아니라 토큰
흔히 LLM API 요금을 글자 수에 비례하는 것으로 이해합니다. 한국어든 영어든 같은 내용이면 비슷한 값이 나오고, 토큰은 대략 단어 하나쯤이라고 생각합니다. 이렇게 이해하면 위의 결과가 설명되지 않습니다. 한국어 문장은 글자도 적고 어절도 9개로 영어 단어 17개의 절반인데, 토큰은 영어보다 많기 때문입니다.
요금표가 실제로 세는 것은 토크나이저가 잘라 낸 조각의 개수입니다. 그 조각을 정하는 규칙은 모델을 학습하기 전에 대량의 텍스트로 미리 만들어 두고, 이 텍스트가 어떤 언어로 얼마나 채워졌는지에 따라 조각의 모양이 달라집니다. 같은 내용의 토큰 수가 언어마다 다른 것은 그래서입니다. 그리고 그 비율은 고정된 상수가 아니라 토크나이저마다, 모델 세대마다 다릅니다.
Anthropic의 요금 문서도 이 점을 FAQ에 적어 두었습니다. 요금 페이지는 영어에서 1토큰이 대략 4글자 또는 0.75단어라고 어림한 뒤, 정확한 수는 언어와 내용에 따라 달라진다고 덧붙입니다. 「1토큰 ≈ 4글자」는 처음부터 영어에 대한 어림이었습니다.
BPE가 자주 나오는 조각부터 묶는 방식
오늘날 대부분의 모델이 쓰는 토크나이저의 뿌리는 Sennrich 등(2016)의 BPE입니다. 원래 기계 번역에서 처음 보는 단어를 다루려고 가져온 방법으로, 글자 단위에서 시작해 학습 텍스트에 가장 자주 붙어 나오는 쌍을 하나로 합치는 일을 정해진 어휘 크기에 이를 때까지 되풀이합니다. 자주 나오는 단어는 통째로 한 토큰이 되고, 드문 단어는 여러 조각으로 쪼개집니다.
여기서 이미 언어 간 차이가 생깁니다. 학습 텍스트에 영어가 많으면 database, migration 같은 영어 단어가 통째로 어휘에 들어갑니다. 한국어가 적으면 데이터베이스는 몇 조각으로 남습니다. 합치기 횟수(어휘 크기)는 한정돼 있어서, 어떤 언어에 그 자리를 얼마나 내주느냐가 곧 그 언어의 토큰 수를 정합니다.
GPT-2는 이 BPE를 글자가 아니라 바이트 위에서 돌렸습니다(공개 코드). 바이트 단위로 시작하면 어떤 문자열이든 최소한 바이트 조각으로는 표현되므로 「모르는 글자」가 사라집니다. 이 글에서 재는 tiktoken 계열과 Qwen, EXAONE의 토크나이저가 이 바이트 수준 BPE입니다.
또 다른 방식은 SentencePiece(Kudo & Richardson, 2018)입니다. 공백으로 미리 단어를 나누지 않고 원문을 그대로 받아 공백까지 ▁ 기호로 다루며, BPE와 unigram 언어 모델 두 방식을 지원합니다. Mistral 7B 같은 모델은 이 계열의 어휘에 바이트 폴백(byte fallback)을 붙였습니다. 어휘에 없는 글자를 만나면 그 글자의 UTF-8 바이트를 하나씩 토큰으로 내는 장치입니다.
한글 한 음절이 UTF-8 3바이트라는 사실
한글 완성형 음절은 유니코드에 11,172개가 있고(U+AC00부터 U+D7A3까지), UTF-8로 쓰면 한 음절이 3바이트입니다. 영어 알파벳은 1바이트입니다. 그래서 바이트 수준 BPE에서 한국어는 출발선부터 불리합니다. 합치기를 한 번도 거치지 않은 상태라면 음절 하나가 토큰 셋입니다.
실제로 어휘에 없는 음절을 넣어 보면 이 출발선이 보입니다. 거의 쓰이지 않는 음절 뷁을 세면 다음과 같습니다.
| 토크나이저 | 뷁의 토큰 수 |
잘린 모양 |
|---|---|---|
tiktoken cl100k_base |
3 | 바이트 EB · B7 · 81 하나씩 |
tiktoken o200k_base |
2 | EB B7 · 81 |
| Qwen3-8B | 1 | 음절 하나가 통째로 어휘에 있음 |
| Mistral-7B-Instruct-v0.3 | 4 | ▁ · <0xEB> · <0xB7> · <0x81> |
Mistral의 마지막 줄이 바이트 폴백입니다. <0xEB> 같은 토큰은 그 바이트 하나를 뜻하고, 앞의 ▁는 SentencePiece가 문장 머리에 붙이는 공백 표시입니다. 같은 토크나이저로 데이터베이스를 세면 9토큰이 나오는데, 데·이·터는 음절 토큰으로 있고 베만 어휘에 없어 바이트 셋으로 흩어집니다. 흔한 단어 안에서도 한 음절이 빠지면 그 자리에서 토큰이 세 배로 늘어납니다.
음절 하나를 따로 넣었을 때 토큰 하나로 끝나는 음절이 11,172개 중 몇 개인지도 셀 수 있습니다. cl100k_base는 129개, o200k_base는 677개, Qwen3는 2,512개, EXAONE은 1,399개입니다. Mistral v0.3은 어휘에 음절 그대로(또는 앞에 ▁가 붙은 형태로) 들어 있는 것이 346개입니다. 다만 이 숫자가 곧 한국어 효율은 아닙니다. 아래 표에서 보듯 음절을 가장 많이 가진 Qwen3보다 EXAONE이 한국어를 더 적은 토큰으로 셉니다. EXAONE은 데이터베이스를 2토큰으로 자르는데, 음절보다 긴 단위를 어휘에 넣었기 때문입니다.
같은 뜻 세 쌍을 여섯 토크나이저로 센 결과
이 절의 숫자는 누구나 다시 낼 수 있는 계산입니다. 예문 세 쌍은 제가 지어낸 것이고, 개발 문서와 시스템 프롬프트에 흔한 문장 모양을 골랐습니다.
1 배포하기 전에 데이터베이스를 백업하고, 마이그레이션이 실패하면 이전 버전으로 되돌립니다.
Back up the database before deploying, and roll back to the previous version if the migration fails.
2 이 함수는 사용자의 주문 목록을 날짜순으로 정렬한 뒤 최근 10건만 돌려줍니다.
This function sorts the user's orders by date and returns only the 10 most recent.
3 답변은 세 문장 이내로 하고, 존댓말을 쓰며, 확실하지 않은 내용은 모른다고 말하세요.
Keep answers to three sentences or fewer, use a polite tone, and say you don't know when you are unsure.세는 조건은 이렇습니다. OpenAI 쪽은 tiktoken 0.14.0의 두 인코딩을 쓰고, 오픈 모델은 Hugging Face 허브에서 로그인 없이 받을 수 있는 tokenizer.json(2026년 10월 9일 기준 main 리비전)을 tokenizers 0.22.2로 읽습니다. 특수 토큰은 붙이지 않고, 어휘 크기는 추가 토큰까지 포함한 값입니다. 칸마다 「한국어/영어」 토큰 수입니다.
| 토크나이저 (어휘 크기) | 1 | 2 | 3 | 합계 | 한/영 배율 |
|---|---|---|---|---|---|
tiktoken cl100k_base (100,277) |
45/19 | 43/18 | 47/24 | 135/61 | 2.21 |
tiktoken o200k_base (200,019) |
28/19 | 26/17 | 30/23 | 84/59 | 1.42 |
| Qwen/Qwen3-8B (151,669) | 34/19 | 32/19 | 32/24 | 98/62 | 1.58 |
| kakaocorp/kanana-1.5-8b-instruct-2505 (128,259) | 29/19 | 26/18 | 30/24 | 85/61 | 1.39 |
| LGAI-EXAONE/EXAONE-4.0-1.2B (102,400) | 22/19 | 23/20 | 25/25 | 70/64 | 1.09 |
| mistralai/Mistral-7B-Instruct-v0.3 (32,768) | 52/20 | 49/20 | 51/26 | 152/66 | 2.30 |
몇 가지를 덧붙입니다. openai/gpt-oss-20b의 토크나이저는 o200k_base와 같은 수를 냈고, EXAONE 3.5(2.4B Instruct)는 4.0과 같은 수를, upstage/SOLAR-10.7B-Instruct-v1.0(어휘 32,000)은 Mistral과 같은 수를 냈습니다. google/gemma-3, meta-llama/Llama-3.1, HyperCLOVA X SEED는 허브에서 이용 동의를 먼저 요구하는 저장소라 표에 없습니다.
표에서 제가 중요하게 보는 것은 두 가지입니다. 첫째, 같은 회사의 토크나이저도 세대가 바뀌면 한국어 배율이 2.21에서 1.42로 줄었습니다. 저는 어휘를 두 배로 늘리면서 늘어난 자리의 상당 부분이 비영어권 언어에 돌아간 결과로 읽습니다. 둘째, 한국어 배율이 가장 낮은 EXAONE은 영어 문장을 오히려 가장 많이 셉니다(64토큰). 어휘의 자리는 한정돼 있어서 한쪽을 늘리면 다른 쪽이 조금 줄어듭니다.
이 표의 한계도 분명합니다. 문장 셋, 토큰 몇백 개짜리 표본입니다. 코드나 숫자가 섞인 글, 구어체, 고유명사가 많은 글은 배율이 다르게 나옵니다. 영어 번역을 어떻게 하느냐에 따라서도 분모가 바뀝니다. 이 표는 「배율이 1이 아니고 토크나이저마다 다르다」를 보이는 데까지만 씁니다.
연구가 말하는 언어 간 격차
큰 표본으로 같은 질문을 던진 연구가 Petrov 등의 「Language Model Tokenizers Introduce Unfairness Between Languages」(NeurIPS 2023)입니다. 200개 언어로 번역된 같은 문장 모음인 FLORES-200에서 각 언어의 토큰 수를 영어 토큰 수로 나눈 값을 「프리미엄」이라 부르고, 초록에서 언어에 따라 그 차이가 최대 15배에 이른다고 적었습니다.
이 논문의 부록 표(v2)에 한국어 줄이 있습니다. GPT-2 토크나이저는 5.07, LLaMA(1세대)는 3.18, cl100k_base는 2.38입니다. 위 표의 cl100k_base 배율 2.21과 크게 다르지 않습니다. 다국어용으로 만든 XLM-RoBERTa는 1.16, NLLB는 1.03까지 내려갑니다. 한국어가 특별히 불리한 언어는 아닙니다. 같은 표에서 미얀마어는 GPT-2 기준 16.89입니다.
같은 표에서 바이트 단위로 바로 읽는 ByT5의 한국어 프리미엄은 1.20입니다. 위 예문 세 쌍도 UTF-8로 재면 한국어 349바이트, 영어 286바이트로 1.22배입니다. 한국어는 바이트로 보면 영어보다 조금 길 뿐입니다. 토큰이 두 배씩 차이 나는 것은 한국어라는 언어가 장황해서가 아니라, 어휘가 한국어 바이트 묶음을 충분히 합쳐 두지 않았기 때문입니다.
OpenAI의 GPT-4o 발표 글(openai.com/index/hello-gpt-4o)에도 비영어권 언어의 토큰 수에 관한 내용이 있다고 인용되곤 합니다. 이 글을 쓰는 시점에 그 페이지가 열리지 않아 원문을 대조할 수 없었으므로, 거기 실렸다는 한국어 수치는 옮기지 않습니다.
비용·컨텍스트·출력 속도에 함께 붙는 배율
토큰 배율은 요금에서 끝나지 않습니다. 토큰으로 매겨지는 모든 것에 같은 배율이 붙습니다.
비용은 단가 × 토큰 수입니다. OpenAI 요금 페이지는 2026년 10월 9일 기준 gpt-4o를 입력 100만 토큰당 2.50달러, 출력 100만 토큰당 10달러로 적고 있고, tiktoken은 gpt-4o를 o200k_base로 셉니다. 영어로 한 달에 입력 1,000만 토큰, 출력 100만 토큰이 드는 일을 위 표의 배율 1.42대로 한국어로 돌린다고 계산하면, 입력은 25달러에서 35.50달러로, 출력은 10달러에서 14.20달러로 늘어납니다. cl100k_base 시절 배율 2.21이었다면 같은 일이 두 배 넘게 나왔을 것입니다. 이 계산은 표본 세 쌍의 배율을 그대로 곱한 것이라 어림 이상은 아닙니다. 공급자별 단가 자체를 나란히 놓은 글은 테스트용 LLM API 비용 비교: 로컬 모델에서 Gemini·Groq·Claude까지에 정리돼 있습니다.
컨텍스트 창도 토큰으로 잽니다. 예문 세 쌍 기준으로 o200k_base는 영어를 토큰당 4.85자, 한국어를 토큰당 1.68자로 담았습니다. 같은 창에 넣을 수 있는 한국어 문서의 분량은 그만큼 짧아지고, 긴 대화가 요약이나 잘림에 걸리는 시점도 빨라집니다.
출력 속도는 보통 초당 토큰 수로 말합니다. 모델이 1초에 같은 수의 토큰을 낸다면, 같은 내용의 답을 한국어로 받는 데 걸리는 시간은 토큰 배율만큼 늘어납니다. 배율 1.42라면 영어로 10초 걸릴 답이 14초쯤 걸리는 셈입니다. 사용자가 체감하는 것은 이쪽인 경우가 많습니다.
요청 제한도 토큰으로 겁니다. Anthropic의 요청 제한 문서는 Messages API의 제한을 분당 요청 수(RPM), 분당 입력 토큰(ITPM), 분당 출력 토큰(OTPM)으로 잰다고 적고 있습니다. 같은 사용자 수를 받아도 한국어 서비스는 ITPM과 OTPM 한도에 먼저 닿습니다.
「1토큰 ≈ 4글자」를 한국어에 쓰면 생기는 오차
위 예문의 한국어 세 문장은 공백과 문장부호까지 합쳐 141자입니다. 영어 어림대로 4로 나누면 35토큰쯤이 나옵니다. 실제로는 o200k_base로 84토큰, cl100k_base로 135토큰입니다. 어림이 실제의 절반에도 못 미칩니다. 「한국어는 1글자가 1토큰쯤」이라는 반대쪽 어림도 토크나이저마다 틀립니다. cl100k_base에서는 거의 맞고(토큰당 1.04자), EXAONE에서는 두 배 가깝게 틀립니다(토큰당 2.01자).
그래서 저는 한국어 비용을 글자 수에 상수를 곱해 어림하지 않는 쪽을 권합니다. 쓰려는 모델의 토크나이저로 실제 프롬프트와 실제 답변 표본을 세는 것이 가장 짧은 길입니다. OpenAI 계열은 tiktoken이 모델 이름을 인코딩에 연결해 두었고(0.14.0 기준 gpt-4o, gpt-4.1, gpt-5, o3가 o200k_base), 오픈 모델은 허브의 tokenizer.json을 그대로 읽으면 됩니다.
Claude는 토크나이저 파일이 공개돼 있지 않습니다. 대신 토큰 세기 API(POST /v1/messages/count_tokens)가 있고, 메시지 생성과 같은 입력을 받아 입력 토큰 수를 돌려줍니다. 문서는 이 값이 추정치이고 실제 사용량과 조금 다를 수 있으며, 호출 자체는 무료이고 요청 수 제한만 따로 있다고 적고 있습니다. 같은 문서에는 Claude Opus 4.7부터 새 토크나이저를 써서 같은 텍스트가 이전 모델보다 대략 30% 많은 토큰이 된다는 안내도 있습니다. 모델을 바꾸면 예전 모델로 잰 토큰 수를 다시 쓰지 말고 새로 세라는 뜻입니다. 이 30%가 한국어에서도 같은 비율인지는 문서가 말하지 않습니다.
출력 쪽은 세기가 더 어렵습니다. 입력은 보내기 전에 셀 수 있지만 출력은 모델이 정합니다. 저라면 실제 질문 수십 개를 돌려 응답의 usage에 찍힌 출력 토큰 수를 모으고, 그 평균으로 비용을 잡겠습니다. 한국어 답변이 같은 내용의 영어 답변보다 길게 나오는지는 모델의 습관에도 달려 있어서, 토크나이저 배율만으로는 알 수 없습니다.
한국어 특화 토크나이저가 의미 있는 조건
표에서 EXAONE의 배율 1.09는 눈에 띕니다. 한국어 특화 모델을 고를 이유로 보이기도 합니다. 저는 이 숫자가 의미를 갖는 조건이 꽤 좁다고 봅니다.
토큰 효율은 같은 단가일 때만 그대로 비용 차이가 됩니다. 단가가 다른 두 모델이라면 토큰 수 × 단가를 직접 곱해 봐야 하고, 토큰이 30% 적어도 단가가 두 배면 의미가 없습니다. 자체 GPU에서 오픈 모델을 돌리는 경우에는 사정이 다릅니다. 이때는 토큰당 계산량이 거의 정해져 있으니, 같은 한국어 문서를 더 적은 토큰으로 처리하는 토크나이저가 처리량과 컨텍스트 여유를 바로 늘려 줍니다.
또 하나는 품질입니다. 토큰을 적게 쓰는 것과 한국어를 잘 이해하는 것은 별개의 성질입니다. 토큰이 적으면 같은 창에 더 많은 맥락이 들어가고 바이트 조각이 덜 흩어지니 도움이 될 여지는 있습니다. 하지만 이 글의 측정은 그 연결을 보여 주지 않습니다. 모델 선택은 토큰 수가 아니라 실제 과제로 평가한 결과로 해야 한다고 저는 봅니다.
시스템 프롬프트 언어를 고르는 기준
비용 이야기가 나오면 시스템 프롬프트를 영어로 쓰자는 제안이 자주 따라옵니다. 위 예문 3번이 그런 지시문입니다. o200k_base로 한국어 30토큰, 영어 23토큰이고, EXAONE에서는 25토큰 대 25토큰으로 같습니다. 같은 지시를 영어로 쓰면 앞의 경우 매 요청 7토큰을 아끼고, 뒤의 경우에는 아무것도 아끼지 않습니다.
이 차이가 의미 있으려면 프롬프트가 길고 요청이 많아야 합니다. 수천 토큰짜리 시스템 프롬프트를 하루 수십만 번 보낸다면 배율 1.4는 무시할 수 없습니다. 다만 그런 경우에는 프롬프트 캐시가 먼저입니다. Anthropic 요금 페이지에 따르면 캐시에서 읽은 입력은 기본 입력 단가의 0.1배이고(일부 최신 모델은 0.05배나 0.025배), 앞의 요청 제한 문서에 따르면 대부분 모델에서 ITPM에도 들어가지 않습니다. 고정된 시스템 프롬프트라면 언어를 바꾸는 것보다 캐시 쪽이 줄이는 폭이 훨씬 큽니다.
반대쪽 비용도 있습니다. 영어 지시에 한국어 답을 요구하면 「존댓말」, 「~습니다체」처럼 영어로 옮기기 어려운 지시가 흐려집니다. 프롬프트를 고치는 사람이 한국어 화자라면 유지보수 비용도 따라옵니다. 저라면 사용자에게 보이는 말투와 형식에 관한 지시는 한국어로 두고, 길고 기계적인 부분(도구 설명, 출력 스키마, 규칙 목록)은 영어로 써서 토큰을 줄이는 쪽을 먼저 시도하겠습니다. 어느 쪽이 답의 품질을 떨어뜨리는지는 모델마다 달라서 직접 비교해 봐야 합니다.
여기서부터 확신할 수 없는 부분
토크나이저의 배율은 확실하게 잴 수 있습니다. 공개된 파일이 있으면 같은 입력은 언제나 같은 수를 냅니다. 이 글에서 확실한 것은 거기까지입니다.
공개되지 않은 토크나이저는 API가 돌려주는 수를 믿는 수밖에 없고, Claude의 토큰 세기 API는 스스로 추정치라고 밝힙니다. tiktoken에 이름이 올라 있지 않은 최신 OpenAI 모델은 어떤 인코딩을 쓰는지 밖에서 알 수 없으니, 응답의 usage에 찍힌 수로 확인해야 합니다. 출력 토큰은 토크나이저보다 모델의 말버릇이 더 크게 좌우합니다. 그리고 토큰을 덜 쓰는 언어로 바꿨을 때 답의 질이 어떻게 변하는지는 토큰 수로는 전혀 알 수 없습니다.
함께 읽기
- 프롬프트 캐싱: 긴 시스템 프롬프트를 10분의 1 가격으로 읽히는 순서 설계시스템 프롬프트가 2만 토큰인 챗봇이 있다고 해 보겠습니다. 제품 설명서, 응대 규칙, 예시 대화가 들어 있습니다. 사용자가 "배송 언제 와요?"라고 한 줄을 물어도 모델은 매번 2만 토큰을 처음부터 다시 읽고, API는 그만큼 과금합니다.
- 한국어 RAG에서 벡터만 쓰면 안 되는 이유: 하이브리드 검색 설계처음 RAG를 짤 때는 벡터 검색만 썼습니다. 코사인 유사도 하나로 충분할 줄 알았죠. 그런데 한국어 질문에서 이상한 일이 잦았습니다. 분명 문서에 있는 단어를 물었는데 검색이 안 됩니다. 비슷한 의미의 다른 문서만 계속 위에 뜹니다. 원인을 찾다 보니, 벡터 검색이 "의미가 비슷한가"는 잘 재는데 "그 단어가 실제로 …
- Expo 앱 다국어: 사전의 키를 한국어 원문으로 둔 이유성경 지도 앱에 언어 다섯 개를 더했습니다. 영어, 일본어, 중국어 간체와 번체, 스페인어입니다. 화면이 하나뿐이고 서버도 없는 앱이라 붙이는 일 자체는 간단할 줄 알았는데, 번역문을 어디에 둘지에서 막혔습니다.
- LLM 토큰 스트리밍은 응답을 빠르게 만들까?같은 모델에 같은 질문을 두 번 보낸다고 해 보겠습니다. 한 번은 stream: false, 한 번은 stream: true 입니다. 스트리밍 쪽이 훨씬 빠르게 느껴집니다. 그런데 마지막 글자가 도착하는 시각은 두 쪽이 거의 같습니다. 모델은 어느 쪽이든 토큰을 하나씩 순서대로 만들고, 스트리밍은 그 순서를 바꾸지 않기…
- 컨텍스트 100만 토큰 시대에도 RAG가 필요할까?사내 문서 300개를 합치면 80만 토큰쯤 됩니다. 컨텍스트 창이 100만 토큰인 모델이라면 전부 한 번에 넣을 수 있습니다. 그러면 문서를 잘게 자르고, 임베딩을 만들고, 벡터 DB를 운영하고, 검색 품질을 튜닝하던 RAG 파이프라인이 통째로 필요 없어지는 것처럼 보입니다.