AI 서비스가 글을 세는 단위는 글자가 아니라 토큰이에요. 토큰은 모델이 글을 잘라 다루는 최소 조각을 말해요. 그런데 이 조각이 몇 글자짜리인지는 언어마다 달라요.
이 단위를 몰라도 대화창에 글을 넣는 데는 아무 지장이 없어요. 문제는 긴 문서를 통째로 넣거나, 프로그램에서 API를 불러 쓰거나, 한 번에 들어가는 분량을 미리 가늠해야 할 때예요. 그때 글자 수로 어림하면 어긋나요. 어림이 얼마나 어긋나는지는 재 보기 전에는 알 수 없고요.
먼저 이 글의 범위를 밝힐게요. 이 글이 잰 것은 Gemini API 계열이에요. 다른 회사 모델은 재지 못했어요. 그러니 여기 나오는 숫자를 다른 서비스에 그대로 옮기면 안 돼요. 그리고 이 글은 어느 도구가 낫다는 이야기를 하지 않아요. 값을 재는 자리와 그 값이 어디에서 갈리는지만 봐요.
아래 숫자는 2026년 8월 17일에 Gemini API의 countTokens 엔드포인트를 파이썬으로 직접 호출해 받은 응답값이에요. 공식 문서 문장은 같은 날 ai.google.dev/gemini-api/docs/tokens 페이지를 받아 원문에서 확인했어요. 문서에서 옮긴 문장과 제가 잰 값은 아래에서 매번 갈라 적을게요. 둘을 섞으면 어느 쪽이 확인된 것인지 알 수 없게 되거든요.

공식 countTokens API로 같은 문장을 직접 세어 봤어요
토큰 수를 어림하는 계산기는 많아요. 글자 수를 넣으면 대충 몇 토큰이라고 알려 주는 웹 페이지도 있고요. 그런데 그런 값은 어림이에요. 실제로 그 서비스가 몇으로 세는지를 확정해 주는 것은 서비스가 직접 여는 엔드포인트뿐이에요. Gemini API에는 그 자리가 따로 있어요.
POST https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:countTokens
본문에는 재고 싶은 글을 담아 보내요. 응답은 이렇게 와요.
{"totalTokens":15,"promptTokensDetails":[{"modality":"TEXT","tokenCount":15}]}
totalTokens가 전체 값이고, promptTokensDetails가 종류별로 나눠 적어 줘요. 글자만 보냈으니 modality가 TEXT 하나예요. 이미지를 함께 넣으면 여기에 줄이 하나 더 붙는데, 그 이야기는 뒤에서 따로 할게요.
이 응답이 어림이 아니라는 점이 중요해요. 모델이 실제로 쓰는 조각내기 규칙을 그대로 적용해 센 값이라, 같은 글을 같은 모델에 보내면 같은 값이 나와요. 제가 같은 문장을 반복해서 넣어 봤을 때도 값이 흔들리지 않았어요.
이 자리에 같은 뜻의 한국어와 영어를 넣어 봤어요. 뜻이 같아야 비교가 되니, 회의록을 요약하고 할 일을 뽑아 달라는 같은 요청을 두 언어로 적었어요.
| 보낸 글 | 문자 수 | totalTokens | 1토큰당 문자 수 |
|---|
| 오늘 회의록을 요약해 주세요 그리고 할 일을 뽑아 주세요 | 31 | 15 | 약 2.1자 |
| Please summarize today's meeting notes and extract the action items. | 68 | 13 | 약 5.2자 |
두 문장은 뜻이 거의 같아요. 그런데 글자 수가 두 배 넘게 많은 영어 쪽이 토큰은 오히려 적게 나왔어요. 오른쪽 칸은 제가 앞의 두 숫자를 나눠 붙인 것이고, 응답에 그렇게 적혀 있는 것은 아니에요.
문단으로 늘려도 방향은 같았어요.
| 보낸 글 | 문자 수 | totalTokens |
|---|
| 한국어 문단 하나 | 119 | 59 |
| 같은 문장을 열 번 이은 한국어 문단 | 270 | 161 |
| 안녕하세요 | 5 | 1 |
| 가나다라마바사아자차 | 10 | 9 |
| abcde | 5 | 2 |
| abcdefghij | 10 | 3 |
여기서 눈에 걸리는 줄이 두 개 있어요. 안녕하세요는 다섯 자인데 1토큰이에요. 자주 쓰이는 덩어리는 통째로 한 조각이 되는 셈이에요. 반대로 가나다라마바사아자차는 열 자에 9토큰이에요. 뜻을 이루지 않는 글자를 늘어놓으면 거의 글자마다 한 조각이 돼요.
이 두 줄이 말해 주는 것이 하나 있어요. 한글이라서 몇 자에 1토큰이라는 고정 비율은 성립하지 않아요. 같은 한국어여도 어떤 낱말이 들어 있느냐로 갈려요. 인사말이나 자주 쓰는 표현이 많은 글은 값이 낮게 나오고, 고유명사나 낯선 조합이 많은 글은 값이 높게 나와요. 그러니 남이 재 준 비율을 가져다 쓰는 것보다 자기 글을 한 번 재 보는 편이 훨씬 정확해요.
문단 두 줄을 견줘 보면 그 폭이 보여요. 119자 문단은 문자 하나당 약 0.50토큰이고, 270자 문단은 약 0.60토큰이에요. 같은 한국어 산문인데도 이만큼 벌어져요. 이 두 값도 제가 앞의 숫자를 나눠 붙인 것이고 응답에 적혀 있는 값은 아니에요.
제가 넣어 본 이름들 사이에서는 글자 쪽 값이 흔들리지 않았어요. 같은 31자 문장을 이름에 preview가 붙지 않은 모델 열여덟 개에 각각 넣어 봤는데 전부 15가 나왔어요. 제가 넣은 이름을 그대로 적을게요. gemini-2.5-flash, gemini-2.5-flash-image, gemini-2.5-flash-lite, gemini-2.5-flash-native-audio-latest, gemini-2.5-pro, gemini-3-pro-image, gemini-3.1-flash-image, gemini-3.1-flash-lite, gemini-3.1-flash-lite-image, gemini-3.5-flash, gemini-3.5-flash-lite, gemini-3.6-flash, gemini-3.7-flash, gemini-flash-latest, gemini-flash-lite-latest, gemini-pro-latest, gemma-4-31b-it, gemma-4-26b-a4b-it 예요. 열여덟이라는 숫자는 이 목록을 제가 직접 센 것이에요.
모델 이름은 같은 날 모델 목록 엔드포인트를 불러 살아 있는 것만 골랐어요. 목록이 돌려준 이름은 쉰세 개였고, 그중 countTokens를 지원한다고 표시된 이름이 마흔세 개였어요. 여기서 이름에 preview가 붙은 것을 빼면 스무 개가 남고, 거기서 다시 embedding 계열 둘을 빼면 위 열여덟이 돼요. 이 이름들은 조회한 날 기준이라, 나중에 목록이 바뀔 수 있어요.
뺀 embedding 계열도 값은 재 두었어요. 같은 31자 문장을 gemini-embedding-001과 gemini-embedding-2에 넣어 봤더니 둘 다 20이 나왔어요. 위 열여덟이 전부 15였던 것과 다른 값이에요. 그러니 값이 같았다는 말은 제가 고른 위 열여덟에 한정한 이야기이고, 목록에 있는 이름 어디에 넣어도 같다는 뜻이 아니에요.
문서의 '약 4자에 1토큰'과 한국어 실측값이 갈리는 자리
공식 문서 첫 문단에 어림값이 적혀 있어요. 원문 그대로 옮길게요.
For Gemini models, a token is equivalent to about 4 characters. 100 tokens is equal to about 60-80 English words.
앞 문장은 약 4자에 1토큰, 뒤 문장은 100토큰이 영어 단어 60개에서 80개쯤이라고 적어요. 뒤 문장에는 English words라고 언어가 밝혀져 있고, 앞 문장에는 언어가 적혀 있지 않아요.
이 어림을 제 실측값과 나란히 놓으면 이래요.
| 보낸 글 | 문자 수 | 문서 어림(문자 수 ÷ 4) | 실측 totalTokens |
|---|
| 한국어 31자 문장 | 31 | 약 8 | 15 |
| 영어 68자 문장 | 68 | 약 17 | 13 |
| 한국어 119자 문단 | 119 | 약 30 | 59 |
| 한국어 270자 문단 | 270 | 약 68 | 161 |
가운데 칸은 제가 문서의 어림을 그대로 적용해 나눈 값이고, 문서에 이 표가 있는 것은 아니에요. 방향을 보면 한국어는 어림보다 위로 갈리고 영어는 아래로 갈려요.
왜 갈리는지는 이 글이 단정하지 않을게요. 문서가 앞 문장에서 언어를 밝히지 않았고, 저는 실측값만 가지고 있어서 원인을 말할 근거가 없어요. 확인된 것은 여기까지예요. 문서의 어림값을 한국어에 그대로 쓰면 실제보다 적게 잡힌다는 사실이에요.
글자 종류를 섞으면 어떻게 되는지도 재 봤어요.
| 보낸 글 | 문자 수 | totalTokens |
|---|
| 회의록 summary 를 2026-08-17 까지 정리해 주세요 | 35 | 19 |
| 회의 잘했어요 👍👍👍 | 11 | 6 |
| 會議錄 要約 | 6 | 4 |
한글과 영문과 숫자가 섞인 줄이 35자에 19토큰이에요. 1토큰당 약 1.8자예요. 앞의 순한글 31자 문장이 1토큰당 약 2.1자였으니, 섞인 쪽이 오히려 글자당 값은 높아요. 뒤에서 볼 숫자 쪽 결과와 같은 방향이에요. 이모지가 든 줄과 한자가 든 줄도 각각 재 두었어요. 이 세 줄은 제가 고른 문자열 하나씩이라, 같은 종류라도 다른 문자열이면 값이 달라질 수 있어요.

자모가 분리된 한글은 토큰 수가 통째로 달라져요
여기가 이 글에서 가장 크게 벌어진 자리예요. 먼저 낱말을 정의하고 갈게요.
한글 가는 저장하는 방법이 둘이에요. 하나는 완성된 글자 하나로 저장하는 방식이고, 다른 하나는 자음 ㄱ과 모음 ㅏ를 따로 저장해 화면에서만 합쳐 보이게 하는 방식이에요. 뒤쪽을 이 글에서는 자모가 분리된 상태라고 부를게요. 눈으로는 똑같이 보이지만 프로그램이 세는 문자 수가 달라져요.
같은 문장을 두 형태로 보내 봤어요.
| 보낸 글 | 문자 수 | totalTokens |
|---|
| 31자 문장(완성된 글자로 저장) | 31 | 15 |
| 같은 문장(자모가 분리된 상태) | 62 | 62 |
| 119자 문단(완성된 글자로 저장) | 119 | 59 |
| 같은 문단(자모가 분리된 상태) | 242 | 244 |
한 문장에서 15가 62가 됐어요. 네 배가 넘어요. 문단에서는 59가 244가 됐고요. 그리고 뒤쪽 두 줄은 문자 수와 토큰 수가 거의 같아요. 자모가 하나씩 조각이 돼 버린 셈이에요.
조건을 분명히 붙일게요. 이 결과는 자모가 분리된 상태로 저장된 텍스트를 보냈을 때의 값이에요. 제가 그 상태를 만든 방법은 파이썬의 문자 정규화 기능을 써서 완성된 글자를 자모 단위로 풀어 놓은 것이에요. 어떤 프로그램에서 복사하면 반드시 그렇게 된다는 이야기는 이 글이 확인하지 않았어요. 그러니 그런 단정은 쓰지 않을게요.
대신 확인하는 방법만 적어 둘게요. 눈으로 세는 글자 수와 프로그램이 돌려주는 문자 수가 크게 어긋나면 그 상태를 의심해 볼 수 있어요. 위 표에서 31자 문장이 62로 잡혔던 것이 그 신호예요. 값을 미리 재는 습관이 있다면 이 어긋남이 먼저 눈에 들어와요.
왜 이 자리를 따로 떼어 적느냐면, 화면만 봐서는 전혀 티가 나지 않기 때문이에요. 두 문장을 나란히 붙여 놓아도 눈으로는 구분되지 않아요. 글자 모양도 같고 줄 길이도 같아요. 그런데 보내면 값이 네 배가 돼요. 긴 문서를 통째로 넣는 상황이라면 들어갈 줄 알았던 분량이 안 들어가는 일이 생겨요. 그때 원인을 글 내용에서 찾으면 계속 헛돌아요.
이 갈림도 모델과 무관했어요. 앞에서 든 열여덟 모델 전부에서 자모가 분리된 31자 문장은 62로 같았어요. 그러니 모델을 바꿔서 피할 수 있는 문제가 아니에요. 입력 쪽에서 형태를 맞춰 놓는 수밖에 없어요.
한 가지 더 짚고 갈게요. 문단 쪽 값을 보면 242자가 244토큰이에요. 토큰 수가 문자 수보다 오히려 조금 많아요. 자모 하나가 한 조각이 되는 데서 그치지 않고, 어떤 자리에서는 조각이 더 쪼개졌다는 뜻이에요. 그래서 자모가 분리된 텍스트에서는 문자 수를 세어 토큰 수를 어림하는 것도 잘 맞지 않아요.
숫자·전화번호는 글자 수만큼 세지고, 줄바꿈은 뭉쳐서 세져요
글자가 아닌 문자들도 재 봤어요.
| 보낸 글 | 문자 수 | totalTokens |
|---|
| 20260817 | 8 | 8 |
| 010-1234-5678 | 13 | 13 |
| 줄바꿈만 열 개 | 10 | 1 |
| 공백만 열 개 | 10 | 1 |
| 빈 문자열 | 0 | 응답에 totalTokens 키 없음 |
숫자 여덟 자리가 8토큰이에요. 문자 수와 토큰 수가 같아요. 전화번호 모양의 열세 자도 13이었어요. 앞에서 영문 열 자가 3토큰이었던 것과 견주면 차이가 커요. 그러니 숫자가 빽빽한 글은 같은 길이의 영문보다 값이 커질 수 있어요. 날짜와 번호가 잔뜩 든 표를 통째로 넣는 경우가 여기 해당해요.
반대쪽이 줄바꿈과 공백이에요. 열 개를 이어 보내도 1토큰이었어요. 같은 문자가 이어지면 뭉쳐서 한 조각이 되는 셈이에요.
여기서 조건을 붙일게요. 이 두 줄은 줄바꿈만, 공백만 들어 있는 입력을 잰 값이에요. 글 사이사이에 흩어져 있는 줄바꿈이 어떻게 세지는지는 이 값으로 알 수 없어요. 그건 앞뒤 글자와 함께 잘리기 때문에 따로 재야 해요.
빈 문자열은 응답이 조금 특이했어요. 오류가 나지 않고 응답 자체는 왔는데, 그 응답 안에 totalTokens 키가 아예 없었어요. 값이 0으로 적혀 오는 것이 아니라 키가 빠져 있어요. 프로그램에서 이 값을 꺼내 쓴다면 키가 없는 경우를 따로 처리해야 해요.
이 절의 값들이 왜 쓸모가 있는지 짚어 볼게요. 한국어 문서를 그대로 넣는 상황에서는 앞 절의 비율만 알면 되는데, 실제로 넣는 자료는 순한 산문인 경우가 드물어요. 주문 번호와 날짜가 줄줄이 붙은 표, 좌표나 코드가 섞인 목록, 사람 이름과 전화번호가 나열된 명단 같은 것들이 섞여 들어가요. 위 표를 보면 그런 자료는 같은 길이의 산문보다 값이 크게 나올 수 있다는 것을 알 수 있어요. 숫자 여덟 자리가 8토큰이었으니까요.
반대로 서식 때문에 늘어난 빈 줄이나 들여쓰기 공백은 걱정만큼 값을 밀어 올리지 않았어요. 열 개를 이어 보냈을 때 1토큰이었어요. 그러니 보기 좋게 줄을 띄운 것 때문에 값이 커졌다고 짐작하기 전에, 숫자와 기호가 몇 줄이나 들어갔는지를 먼저 세어 보는 편이 맞아요.
글자가 아닌 입력에도 토큰이 붙어요 — 이미지·오디오·영상의 고정 값
문서는 글자 말고 다른 입력에도 값을 매긴다고 적어요. Key points about tokenization이라는 한 목록 안에 세 줄로 들어 있어요. 원문 그대로 옮길게요.
Images ≤384 pixels in both dimensions count as 258 tokens. Larger images are tiled into 768x768 pixel tiles, each counting as 258 tokens.
Video: 263 tokens per second
Audio: 32 tokens per second
정리하면 가로세로 모두 384픽셀 이하인 이미지는 258토큰, 그보다 크면 768x768 조각으로 나뉘어 조각마다 258토큰, 영상은 초당 263토큰, 오디오는 초당 32토큰이라고 적혀 있어요.
이미지 쪽은 직접 재 봤어요. 단색이 아닌 무늬 이미지를 크기별로 만들어 보냈고, 두 모델에 같은 이미지를 넣었어요.
| 이미지 크기 | gemini-2.5-flash | gemini-3.6-flash |
|---|
| 200x200 | 258 | 1089 |
| 384x384 | 258 | 1089 |
| 512x512 | 258 | 1089 |
| 768x768 | 258 | 1089 |
| 1024x1024 | 258 | 1089 |
| 1792x1024 | 258 | 1100 |
| 2048x2048 | 258 | 1089 |
왼쪽 칸은 문서의 258과 맞아떨어져요. 다만 크기를 아무리 올려도 258이 그대로였어요. 문서가 적은 조각내기가 값에 반영된 자리는 제가 잰 범위에서 나오지 않았어요. 3000x3000까지 올려도 258이었어요.
오른쪽 칸은 아예 다른 값이에요. 같은 이미지가 1089나 1100으로 나와요. 같은 1792x1024 이미지를 네 모델에 넣어 봤더니 gemini-2.5-pro는 258, gemini-3.5-flash와 gemini-3.6-flash와 gemini-3.7-flash는 1100이었어요.
여기서 앞 절과의 대조가 선명해져요. 글자는 제가 잰 열여덟 모델에서 값이 같았는데, 이미지는 그 안에서도 모델에 따라 갈렸어요. 왜 갈리는지는 이 글이 단정하지 않을게요. 제가 가진 것은 응답값뿐이에요.
이 대조가 실무에서 어떻게 걸리는지만 짚어 둘게요. 글자만 다루던 흐름을 그대로 두고 모델 이름만 새 것으로 바꾸는 경우가 흔한데, 글자 쪽은 값이 같으니 아무 일도 안 일어난 것처럼 보여요. 그런데 같은 흐름에 이미지가 섞여 있으면 입력 토큰이 네 배 가까이 뛸 수 있어요. 제가 잰 범위에서는 258이 1089나 1100이 됐어요. 그러니 모델을 바꾼 뒤에는 글자만 재 보고 넘어가지 말고 이미지가 든 요청도 한 번 재 보는 편이 맞아요.
그리고 오른쪽 칸 안에서도 값이 완전히 고정은 아니었어요. 정사각형 이미지들은 크기와 무관하게 1089였는데 1792x1024 한 줄만 1100이었어요. 이 차이가 가로세로 비율 때문인지는 이 글이 말하지 않을게요. 제가 그 칸으로 잰 것은 위 표에 있는 일곱 가지 크기까지예요. 앞에서 적은 3000x3000은 왼쪽 칸에서만 재 본 값이에요.
이미지와 글자를 함께 보내면 응답이 종류별로 나눠 적어 줘요. 300x300 이미지에 31자 문장을 붙였더니 이렇게 왔어요.
{"totalTokens":273,"promptTokensDetails":[{"modality":"TEXT","tokenCount":15},{"modality":"IMAGE","tokenCount":258}]}
273은 15와 258을 더한 값이에요. 그러니 이미지가 든 요청을 다룰 때는 promptTokensDetails를 열어 종류별로 보는 편이 정확해요.
오디오와 영상은 이 글이 재지 않았어요. 위 두 줄은 문서에 적힌 값을 옮긴 것까지예요.

미리 센 값과 실제 호출의 사용량이 갈리는 자리
미리 재는 것만으로 실제 요청의 총합을 알 수 있다고 생각하기 쉬운데, 그렇지 않았어요. 같은 31자 문장을 generateContent로 실제 호출해 응답의 usageMetadata를 열어 봤어요.
| 필드 | 값 |
|---|
| promptTokenCount | 15 |
| candidatesTokenCount | 83 |
| thoughtsTokenCount | 967 |
| totalTokenCount | 1065 |
promptTokenCount가 15로 나왔어요. 앞에서 countTokens로 잰 값과 같아요. 그러니 미리 센 값이 맞아떨어지는 것은 입력분까지예요.
그런데 같은 응답에 thoughtsTokenCount가 967로 붙어 있어요. 이 값은 미리 셀 수 없어요. 요청을 보내기 전에는 모델이 얼마나 생각할지 알 수 없으니까요. 총합인 totalTokenCount도 1065라 입력분 15와는 자릿수가 달라요.
문서도 미리 세는 쪽과 사후에 받는 쪽을 나눠 적어요. 미리 세는 쪽은 요청의 입력만 세서 총 토큰 수를 돌려준다고 적고, 사후에 받는 쪽은 입력과 출력과 생각과 캐시된 내용과 도구 사용분까지 필드를 나눠 돌려준다고 적어요. 문서가 든 필드 이름은 total_input_tokens, total_output_tokens, total_thought_tokens, total_cached_tokens, total_tool_use_tokens, total_tokens 예요.
문서가 한 줄 더 적어 둔 것도 봐야 해요. 시스템 지시는 입력 토큰의 일부로 세진다고 적고, 함수와 코드 실행과 구글 검색 같은 도구도 함께 세진다고 적어요. 그러니 본문만 미리 재고 그 값을 그대로 실제 입력분이라고 읽으면 어긋나요. 붙여 보내는 지시문과 도구 정의가 있으면 그것도 입력에 들어가요.
정리하면 미리 세는 값은 이렇게 읽어야 해요. 내가 보내는 글이 몇 조각으로 잘리는지까지는 정확해요. 반면 응답이 얼마나 길어질지, 모델이 중간에 얼마나 생각할지, 도구를 몇 번 부를지는 미리 알 수 없어요. 그래서 미리 센 값은 상한을 넘기는지 확인하는 데 쓰고, 응답 뒤에 오는 사용량 값은 실제로 얼마가 들었는지 확인하는 데 쓰는 식으로 자리를 갈라 두는 편이 좋아요.
한 가지 더 눈여겨볼 것이 있어요. 제가 받은 응답에서 입력분은 15인데 생각 몫이 967이었어요. 입력보다 예순 배 넘게 큰 값이에요. 이 숫자는 제가 한 번 호출해서 받은 값 하나일 뿐이고 매번 같지 않아요. 다만 입력을 짧게 적었다고 해서 응답 전체가 작아지는 것은 아니라는 점은 이 한 줄에서도 보여요.
입력 상한과 나란히 놓아야 값이 쓸모 있어요
토큰 수를 재는 이유 중 하나는 한 번에 얼마나 넣을 수 있는지를 가늠하기 위해서예요. 모델마다 다룰 수 있는 토큰 수가 정해져 있거든요. 문서는 이 값을 컨텍스트 창이라고 부르고, 입력과 출력을 합친 상한이라고 적어요.
다만 목록 엔드포인트는 이걸 한 덩어리로 주지 않아요. 입력 상한과 출력 상한을 따로 두 필드로 돌려줘요. 제가 같은 날 받은 값을 옮기면 이래요. 가운데 칸은 합친 값이 아니라 입력 쪽 상한이에요.
| 모델 | 입력 토큰 상한 | 출력 토큰 상한 |
|---|
| gemini-2.5-flash | 1,048,576 | 65,536 |
| gemini-3.5-flash | 1,048,576 | 65,536 |
| gemini-3.6-flash | 1,048,576 | 65,536 |
| gemini-3.7-flash | 1,048,576 | 65,536 |
| gemma-4-31b-it | 262,144 | 32,768 |
여기서 앞의 실측값을 붙여 보면 감이 잡혀요. 제가 잰 한국어 문단이 문자 하나당 약 0.50에서 0.60토큰이었으니, 입력 상한이 1,048,576인 모델이라면 한국어로 대략 백만 자 후반에서 이백만 자 초반쯤이 들어가는 셈이에요. 이 환산은 제가 앞의 두 숫자로 나눠 본 것이고, 문서나 응답에 이렇게 적혀 있는 것은 아니에요. 그리고 앞에서 본 대로 글마다 비율이 달라지니 경계에 가까운 분량이라면 반드시 직접 재야 해요.
같은 계산을 자모가 분리된 상태에 대입하면 자리가 확 달라져요. 그쪽은 눈에 보이는 글자 하나가 문자 둘로 늘고, 그 문자마다 거의 한 조각이 돼요. 제가 잰 31자 문장이 62토큰이었으니 눈에 보이는 글자 하나당 2토큰인 셈이에요. 상한이 1,048,576인 모델이라면 오십만 자 남짓밖에 안 들어가요. 바로 위에서 센 백만 자 후반에서 이백만 자 초반과 견주면 4분의 1에서 3할 사이예요. 눈에 보이는 글은 똑같은데 들어가는 양이 이만큼 달라지는 거예요.
직접 재 보려면 요청 하나면 돼요
이 글의 값을 그대로 믿지 말고 자기 글로 재 보는 편이 좋아요. 필요한 것은 세 가지예요.
| 준비물 | 설명 |
|---|
| API 키 | AI 스튜디오에서 발급받은 키 하나 |
| 모델 이름 | 목록 엔드포인트에서 확인한 살아 있는 이름 |
| 잴 글 | 평소에 자주 넣는 문장이나 문서 앞부분 |
순서는 이래요. 먼저 모델 목록을 한 번 불러 이름이 살아 있는지 확인해요. 이름이 바뀐 줄 모르고 옛 이름으로 부르면 오류만 보게 되거든요. 그다음 countTokens 주소에 모델 이름을 끼워 넣고, 본문에 잴 글을 담아 보내요. 응답에서 totalTokens를 꺼내면 끝이에요.
한 가지만 더 챙기면 좋아요. 같은 글을 파일에서 읽어 보낼 때와 화면에서 붙여 넣어 보낼 때의 문자 수를 함께 찍어 보세요. 두 값이 다르면 앞에서 본 자모 분리 문제일 수 있어요. 토큰 수만 보면 그냥 값이 크다고 넘어가게 되는데, 문자 수를 같이 찍으면 어디서 벌어졌는지가 바로 보여요.
응답을 다룰 때 하나 조심할 것이 있어요. 앞에서 본 대로 빈 문자열을 보내면 totalTokens 키가 아예 없어요. 여러 문장을 반복해서 재는 프로그램을 짠다면 빈 줄이 섞였을 때 키가 없어서 멈출 수 있어요. 값을 꺼낼 때 기본값을 정해 두는 편이 안전해요.
이 글에서 확인하지 못한 것
솔직하게 남길게요.
첫째, 다른 회사 모델이에요. 이 글이 잰 것은 Gemini API 계열뿐이에요. 다른 서비스는 토큰을 나누는 방식이 다를 수 있고, 이 글은 그쪽을 재지 못했어요. 여기 나온 숫자를 다른 서비스에 옮겨 쓰면 안 돼요.
둘째, 오디오와 영상의 실측값이에요. 초당 263토큰과 초당 32토큰은 문서에 적힌 값을 옮긴 것이고, 제가 파일을 넣어 재 본 것이 아니에요.
셋째, 문서의 조각내기 문장과 실측이 갈린 이유예요. 문서는 큰 이미지가 768x768 조각으로 나뉜다고 적는데, 제가 잰 gemini-2.5-flash에서는 크기를 올려도 258이 유지됐어요. 그 차이가 어디서 오는지는 이 글이 말하지 않을게요.
넷째, 자모가 분리된 상태가 언제 생기는가예요. 저는 파이썬으로 그 상태를 만들어 넣었을 뿐이에요. 어떤 기기나 프로그램에서 복사하면 그렇게 되는지는 확인하지 않았어요.
다섯째, countTokens 호출 자체의 과금이에요. 제가 연 문서에 그 문장이 없었어요. 그래서 무료라고도 유료라고도 쓰지 않을게요. 계정 사용량 화면과 대조해 보지도 않았어요.
여섯째, 모델 목록의 수명이에요. 위 열여덟 이름은 2026년 8월 17일에 목록을 불러 확인한 것이에요. 이름은 자주 바뀌니 쓰기 전에 다시 부르는 편이 안전해요.
일곱째, 긴 글에서의 비율이에요. 제가 잰 가장 긴 한국어는 270자예요. 수천 자짜리 문서에서도 같은 비율이 유지되는지는 재지 않았어요.
정리
- 토큰 수를 확정해 주는 자리는 어림 계산기가 아니라 서비스가 여는
countTokens 엔드포인트예요. 응답은 totalTokens와 종류별 내역인 promptTokensDetails로 와요.
- 같은 뜻의 문장에서 한국어 31자가 15토큰, 영어 68자가 13토큰이었어요. 글자 수가 두 배 넘는 영어 쪽이 토큰은 더 적었어요.
- 문서의 어림은 약 4자에 1토큰이에요. 한국어 실측은 그보다 위로, 영어 실측은 아래로 갈렸어요. 원인은 이 글이 단정하지 않아요.
- 한글이라고 고정 비율이 있는 것도 아니에요. 안녕하세요는 다섯 자에 1토큰인데 가나다라마바사아자차는 열 자에 9토큰이었어요.
- 자모가 분리된 상태로 저장된 텍스트를 보내면 값이 통째로 달라져요. 31자 문장이 15에서 62로, 119자 문단이 59에서 244로 늘었어요.
- 숫자 여덟 자리는 8토큰, 전화번호 모양 열세 자는 13토큰이에요. 반대로 줄바꿈 열 개와 공백 열 개는 각각 1토큰이었어요.
- 빈 문자열을 보내면 응답에
totalTokens 키 자체가 없어요. 0이 들어오는 것이 아니에요.
- 글자 값은 제가 잰 열여덟 모델에서 모두 같았어요. 다만 목록에 함께 있던 embedding 계열 둘은 같은 문장을 20으로 셌어요. 반면 같은 이미지가 gemini-2.5-flash에서는 258, gemini-3.6-flash에서는 1089이나 1100으로 갈렸어요.
- 미리 센 값이 맞아떨어지는 것은 입력분까지예요. 실제 호출 응답에는
thoughtsTokenCount 같은 값이 따로 붙어요.
지금 할 수 있는 가장 짧은 확인은 두 가지예요. 평소에 자주 넣는 한국어 문장 하나를 countTokens에 넣어 자기 기준값을 만들어 두는 것, 그리고 그 문장의 문자 수와 눈으로 세는 글자 수가 맞는지 보는 것이에요. 이 두 자리만 보면 몇 자에 1토큰이더라 대신 내 글은 얼마더라를 말할 수 있게 돼요.
함께 보면 좋은 글
확인한 자료: Gemini API countTokens 엔드포인트 실호출(generativelanguage.googleapis.com/v1beta/models/<모델>:countTokens), 같은 API의 모델 목록 엔드포인트와 generateContent 응답의 usageMetadata, 그리고 공식 문서 Understand and count tokens(ai.google.dev/gemini-api/docs/tokens). 모두 2026년 8월 17일에 파이썬으로 직접 호출하거나 페이지를 받아 원문에서 확인했어요.