
"단어 수에 1.3 곱하면 토큰 수 나오지 않나요?" 처음 GPT-4 API 비용을 예측할 때 저도 그렇게 생각했습니다. 그런데 실제로 tiktoken을 설치해서 돌려봤더니, 한국어가 섞인 프롬프트에서 그 수식은 완전히 빗나갔습니다. 토크나이저는 개발자가 대충 넘겨도 되는 부분이 아니라, API 비용과 컨텍스트 한도를 결정짓는 핵심 요소입니다.
tiktoken 직접 써보니 알게 된 것들
저는 GPT-4 API 비용을 사전에 계산하려는 목적으로 tiktoken을 처음 설치했습니다. 텍스트가 정수 리스트로 변환되는데, 그 리스트의 길이가 곧 토큰 수가 됩니다. 구조 자체는 직관적으로 이해됐지만, 실제 수치를 보고 나서는 좀 당황스러웠습니다.
BPE(Byte Pair Encoding)란 자주 등장하는 문자 조합을 하나의 토큰으로 합쳐 어휘 사전을 구성하는 방식입니다. 쉽게 말해 텍스트를 어절 단위도, 음절 단위도 아닌 "출현 빈도 기반의 조각"으로 쪼개는 알고리즘입니다. 이 방식은 영어 코퍼스를 중심으로 학습되었기 때문에, 영어 단어는 통째로 하나의 토큰이 되는 경우가 많은 반면, 한국어는 훨씬 잘게 분리됩니다.
제가 직접 비교해봤을 때 결과가 꽤 명확했습니다. "The weather is clear today"는 6토큰 내외였지만, 동일한 의미의 "오늘 날씨가 맑습니다"는 10~13토큰이 나왔습니다. 한국어는 교착어 특성상 조사와 어미가 어절에 붙어 있고, BPE 어휘 사전에 등록된 한국어 서브워드 조합이 상대적으로 적기 때문에 더 잘게 쪼개질 수밖에 없습니다. 같은 정보를 전달하는 데 한국어 사용자가 영어 사용자보다 토큰을 더 소비한다는 건, 구조적으로 더 많은 비용을 지불한다는 뜻이기도 합니다.
저는 이 사실이 단순히 기술적 특성으로 넘어가기에는 불편한 지점이 있다고 생각합니다. API 사용 비용이 언어에 따라 구조적으로 달라진다는 건, 비영어권 개발자들이 같은 작업에 더 많은 비용을 쓴다는 의미입니다. 모델 개발사들이 다국어 토크나이저 효율 개선에 더 적극적으로 나서야 한다고 생각합니다. 이게 단순한 기술 최적화 문제가 아니라 접근성과 형평성의 문제이기도 합니다.
코드 스니펫과 URL도 생각보다 토큰을 많이 먹습니다. 파이썬 코드의 들여쓰기 공백, 콜론, 괄호가 각각 별도 토큰으로 처리되는 경우가 있고, URL은 슬래시·점·하이픈이 분리되어 꽤 많은 토큰을 소비합니다. 짧아 보이는 코드 블록이 예상보다 훨씬 많은 토큰을 차지할 수 있다는 점은, 실제로 측정해보기 전까지는 실감하기 어렵습니다.
실무적으로 주의해야 할 포인트를 정리하면 다음과 같습니다. 한국어, 일본어, 아랍어 등 비영어 텍스트는 영어 대비 토큰 효율이 현저히 낮습니다. 코드, URL, 특수문자는 시각적 길이와 실제 토큰 수가 크게 다를 수 있습니다. "단어 수 × 1.3" 경험칙은 순수 영어 텍스트에나 어느 정도 유효합니다. 프롬프트에 여러 언어나 코드가 혼합되면 예측 오차가 급격히 커집니다.
어휘 사전(vocabulary) 크기도 중요한 변수입니다. cl100k_base는 약 10만 개의 서브워드를 포함하는데, 이 중 한국어 서브워드가 차지하는 비중은 영어에 비해 작을 수밖에 없습니다. BPE 논문을 쓴 Sennrich 등도 비영어권 언어에서의 토큰 비효율 문제를 인식했고, 이후 연구자들이 다국어 특화 토크나이저를 별도로 개발하는 계기가 됐습니다. 그런데 현재 시점에서도 주요 API의 기본 토크나이저는 여전히 영어 중심입니다. 개선 속도가 기대만큼 빠르지 않다고 느낍니다.
Claude API의 토큰 수가 tiktoken과 다른 이유
여기서 많은 개발자가 실수를 저지릅니다. Claude는 Anthropic의 자체 토크나이저를 사용하기 때문에, tiktoken으로 측정한 수치를 그대로 가져다 쓰면 안 됩니다. 저도 그걸 모르고 tiktoken 수치만 믿었다가 실제 API에서 context_length_exceeded 에러를 마주쳤습니다. 컨텍스트 한도 계산이 틀렸던 거였습니다.
컨텍스트 한도(context limit)란 모델이 한 번에 처리할 수 있는 최대 토큰 수를 말합니다. 이 한도를 넘긴 입력을 보내면 API가 에러를 반환하거나 앞부분 내용을 잘라냅니다. 모델마다 이 값이 다르고, 같은 텍스트라도 토크나이저에 따라 토큰 수가 달라지기 때문에 정확한 측정이 필요합니다.
Anthropic은 /v1/messages/count_tokens 엔드포인트를 공식적으로 제공합니다. 제가 직접 같은 프롬프트를 tiktoken과 이 엔드포인트로 각각 측정해봤더니, 동일 텍스트에서 5~15% 정도 차이가 발생했습니다. 한국어가 많이 섞인 텍스트일수록 그 격차가 커졌습니다. 이 수치를 모르고 넘어가면 비용 예측은 물론이고 컨텍스트 관리 전체가 흔들릴 수 있습니다.
Anthropic 공식 문서에서도 Claude 모델에 대해서는 tiktoken 대신 자체 API를 통한 토큰 카운팅을 권장하고 있습니다. 솔직히 이건 예상 밖이었습니다. 처음에는 "어차피 비슷하겠지"라고 생각했는데, 실제로 측정해보니 한국어 비중이 높은 프롬프트에서는 오차가 무시하기 어려운 수준이었습니다.
서브워드(subword)란 BPE가 만들어내는 단어보다 작은 언어 단위입니다. "맑습니다" 같은 한국어 어절이 "맑", "습", "니다"처럼 쪼개질 때 각각이 서브워드가 됩니다. 어떤 서브워드 조합을 어휘 사전에 포함하느냐는 각 모델 개발사가 학습 데이터와 정책에 따라 결정하기 때문에, tiktoken의 어휘 사전과 Anthropic의 어휘 사전은 엄연히 다릅니다. 이 차이가 5~15%의 토큰 수 격차로 이어집니다.
저는 이 부분에서 실용적인 조언을 하나 드리고 싶습니다. 모델을 바꿀 때마다 토큰 카운팅 도구도 같이 바꿔야 한다고 생각하는 게 맞습니다. "어차피 다 비슷하겠지"라는 생각으로 하나의 도구로 통일하면 반드시 한 번은 틀립니다. 복잡하게 느껴지더라도 각 모델의 공식 토큰 카운팅 방법을 쓰는 습관을 초반부터 잡아두는 게 낫습니다. 이게 번거롭게 느껴지는 건 이해하지만, 비용 예측 오차와 컨텍스트 초과 에러는 더 번거롭습니다.
경험칙이 아닌 직접 측정으로
비용 예측과 컨텍스트 관리를 안정적으로 하고 싶다면 원칙은 하나입니다. 사용하는 모델의 공식 토크나이저나 API를 직접 호출해서 측정하는 것, 그게 전부입니다. 경험칙에 기대는 건 영어 전용, 코드 없음, 특수문자 없음이라는 조건이 모두 성립할 때나 겨우 통합니다.
토크나이저 실습은 LLM을 다루는 개발자에게 선택이 아닙니다. 한국어와 코드가 섞인 실무 프롬프트에서 경험칙은 예상보다 훨씬 자주 빗나갑니다. 저처럼 에러를 먼저 만나고 나서 이걸 배우는 것보다, 지금 당장 각 모델의 공식 API로 직접 측정해보는 쪽이 낫습니다. 그리고 한 가지 더 — 모델이 업데이트될 때 토크나이저도 바뀔 수 있다는 점을 염두에 두고, 주기적으로 다시 확인하는 습관을 들이는 것도 필요합니다.
참고
- OpenAI. (2023). tiktoken. GitHub. https://github.com/openai/tiktoken
- Anthropic. (2024). Token counting. https://docs.anthropic.com/en/docs/build-with-claude/token-counting
- Sennrich, R., Haddow, B., & Birch, A. (2016). Neural Machine Translation of Rare Words with Subword Units. ACL 2016. https://aclanthology.org/P16-1162/