토큰 카운팅을 제대로 하는 방법: Claude에 tiktoken 사용을 중단하세요
요약
Claude 모델의 토큰 수를 계산할 때 OpenAI의 tiktoken을 사용하면 비용과 컨텍스트 예산에서 큰 오차가 발생합니다. Anthropic에서 제공하는 전용 count_tokens 엔드포인트를 사용하여 모델별로 정확한 토큰 수를 계산해야 합니다.
핵심 포인트
- tiktoken은 OpenAI 전용으로 Claude 계산 시 15~20% 오차 발생
- 정확한 계산을 위해 Anthropic SDK의 count_tokens 엔드포인트 사용 권장
- 모델 버전 간에도 토큰 계산 방식이 다르므로 토큰 수 캐싱 주의
- 비용 추정 시 실제 사용 중인 모델의 토크나이저를 반드시 반영
저에게는 20%나 오차가 발생하는 비용 추정기가 있었는데, 그 이유는 당혹스럽게도 OpenAI의 토크나이저(tokenizer)인 tiktoken으로 Claude 토큰을 계산하고 있었기 때문입니다. 모델이 다르면 토크나이저도 다르고, 계산 결과도 다릅니다. 만약 다른 모델의 토크나이저를 빌려와서 Claude의 비용이나 컨텍스트 예산(context budgets)을 추정하고 있다면, 당신의 수치는 허구입니다. 어떻게 올바르게 계산하는지, 그리고 잘못된 방식이 어떤 문제를 일으키는지 알려드리겠습니다.
왜 Claude에 tiktoken이 틀린 방법인가
tiktoken은 OpenAI 모델을 위해 토큰화(tokenize)를 수행합니다. Claude는 다른 토크나이저를 사용합니다. 두 방식은 텍스트가 토큰으로 분할되는 방식에 대해 일치하지 않습니다. 일반적인 영어 산문(prose)의 경우, tiktoken은 Claude 토큰을 약 15~20% 정도 적게 계산합니다. 코드나 비영어 텍스트의 경우 그 격차는 더 심해지는데, 이는 토크나이저가 각자 최적화되지 않은 입력값에 대해 가장 크게 갈라지기 때문입니다.
따라서 tiktoken을 기반으로 구축된 "비용 추정"이나 "이것이 컨텍스트에 들어갈 것인가"에 대한 확인은 체계적으로 어긋나게 됩니다. 저에게는 프롬프트가 8,000 토큰이라고 알려주었지만, Claude는 9,500 토큰에 가까운 수치로 인식했습니다. 바쁜 하루 동안 이 차이를 곱해본다면 예산 전망은 의미 있는 수준으로 틀리게 됩니다.
올바른 방법: count_tokens 엔드포인트
Claude에는 이를 위한 전용 엔드포인트(endpoint)가 있으며, SDK가 이를 감싸고 있습니다. 카운트는 모델별로 다르므로, 추론(inference)에 사용할 것과 동일한 모델을 전달해야 합니다:
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
...
이것이 실제 모델에 대한, 실제 토크나이저를 통한, 실제 카운트입니다. 근사치가 아닙니다.
비용 추정 계산하기
실제 입력 카운트를 확보했다면, 비용 계산은 간단합니다. 100만 입력 토큰당 5달러인 Opus 4.8의 경우:
const tokens = result.input_tokens;
const inputCost = (tokens / 1_000_000) * 5; // Opus 4.8 입력에 대해 $5/M
console.log(`Estimated input cost: $${inputCost.toFixed(4)}`);
만약 티어(tiers) 사이에서 고민 중이라면, 2026년에 중요한 100만 토큰당 요율은 다음과 같습니다:
| 모델 | 입력 $/M | 출력 $/M |
|---|---|---|
| Haiku 4.5 | 1 | 5 |
| ... |
토큰 수는 입력 측에서만 모델별로 동일합니다. 생성 작업이 많은 작업에서는 출력 토큰 (output tokens)이 비용의 대부분을 차지하며, 요청을 실행하기 전까지는 그 수를 알 수 없다는 점을 기억하세요.
모델별 드리프트 (model-specific drift) 주의
저를 놀라게 했던 미묘한 차이 중 하나는 Claude 모델 버전 간에 토큰 수가 변경된다는 점입니다. 동일한 입력 텍스트라도 Opus 4.7에서는 Opus 4.6보다 더 높은 토큰 수를 생성하는데, 이는 두 모델의 계산 방식이 다르기 때문입니다. 따라서 이전 모델의 토큰 수를 캐싱(cache)하여 재사용한다면, tiktoken을 사용할 때보다는 덜 틀리겠지만 여전히 틀린 결과가 될 것입니다.
해결책은 모델이 변경될 때 토큰 수를 절대 캐싱하지 않는 것입니다. 실제로 사용 중인 모델에 대해 countTokens를 다시 실행하세요. 모델 간 변환을 위해 일괄적인 배수(multiplier)를 적용하지 마세요. 그 차이는 균일하지 않습니다.
버전 간 파일 차이 비교 (Diffing)
"이 변경 사항으로 인해 토큰이 얼마나 추가되었는가"를 확인하기 위한 유용한 패턴은 두 버전을 모두 계산한 뒤 차이를 구하는 것입니다. 엔드포인트(endpoint)는 상태를 유지하지 않으므로(stateless), 각각을 계산하고 차이(diff)를 구하기만 하면 됩니다:
import { execSync } from "node:child_process";
import fs from "node:fs";
...
저는 이를 시스템 프롬프트(system-prompt)의 비대화를 감시하는 데 사용합니다. 프롬프트가 수천 토큰씩 늘어나면, 캐시 미스(cached-miss)가 발생하는 모든 요청마다 실제 비용이 발생하며, 차이 비교(diff)를 통해 이를 가시화할 수 있습니다.
요점 (The takeaway)
토크나이저(tokenizer)는 모델의 일부입니다. 토큰 수를 추정하기 위해 다른 모델의 토크나이저를 빌려 쓰는 것은, 잘못된 단위를 사용하여 측정하면서 오차가 상쇄되기를 바라는 것과 같습니다. 오차는 상쇄되지 않고 오히려 누적됩니다. 정확한 모델에 대해 countTokens를 사용하고, 모델 버전 간에 토큰 수를 재사용하지 마세요. 그리고 출력 토큰은 생성 비용을 지배하는 미지의 변수라는 점을 기억하세요. 이는 단 한 번의 API 호출이며, 비용도 들지 않습니다. 또한 신뢰할 수 있는 예산 추정치와 20%나 차이 나는 추정치를 가르는 결정적인 차이입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기