-
축약어는 토큰을 아끼지 못한다 — caveman의 규칙IT 2026. 7. 31. 22:00
AI 에이전트에 긴 프롬프트를 물릴 때마다 나는 습관처럼 단어를 줄였다. configuration은 cfg로, implementation은 impl로, request는 req로. 글자 수가 눈에 띄게 줄어드니 당연히 토큰도 줄었겠거니 했다. 토큰이 곧 비용이고 컨텍스트 한도니까, 짧게 쓰면 아낀다고 믿은 것이다.
그런데 막상 토크나이저에 문자열을 넣어 세어 보면 멈칫이 온다. cfg가 configuration보다 토큰을 더 많이 먹는 경우가 흔하다. 글자는 4분의 1로 줄였는데 토큰은 오히려 늘어난 것이다. 이 반직관의 정체를 파고들다 caveman이라는 도구가 이 현상을 아예 규칙으로 못 박아 둔 걸 발견했다. 이 글은 그 하나의 오해 — "짧아 보이는 문자열"과 "토큰이 적은 문자열"은 다르다 — 를 푼다.
한 가지 미리 밝혀 둘 게 있다. 이 오해는 입력과 출력 어느 쪽에나 똑같이 적용된다. 토크나이저는 텍스트가 내가 써 보낸 프롬프트인지 모델이 뱉은 답인지 가리지 않고, 그저 글자열을 덩어리로 쪼갤 뿐이기 때문이다. 그래서 이 글의 결론은 두 자리 모두에서 유효하다 — 모델에게 짧게 답하라고 시킬 때(출력)도, 에이전트가 매 세션 읽어 들이는 `CLAUDE.md` 같은 메모리 파일이나 MCP 도구 설명을 손으로 줄일 때(입력)도 똑같다. 뒤에 인용할 caveman의 ultra 모드 규칙은 출력에 거는 것이지만, 규칙이 딛고 선 원리 자체는 어느 쪽에도 그대로 선다.
토크나이저는 글자가 아니라 '자주 나오는 덩어리'로 쪼갠다
LLM은 텍스트를 글자 단위로 읽지 않는다. BPE(Byte Pair Encoding, 자주 함께 등장하는 글자 덩어리를 하나의 토큰으로 미리 묶어 두는 방식)라는 규칙으로 문자열을 토큰 조각으로 나눈다. 학습 말뭉치에서 자주 붙어 나온 글자열일수록 통째로 한 토큰이 되고, 드물게 나오는 글자열은 여러 조각으로 잘게 쪼개진다. 즉 토큰 수를 결정하는 건 글자 수가 아니라 그 글자열이 얼마나 흔한가다.
다이어그램 설명. 이 그림은 긴 단어가 오히려 적은 토큰이 되는 경우를 보여준다. "configuration"은 13글자로 길지만 프로그래밍 말뭉치에 워낙 자주 나오는 단어라, BPE가 이미 이 글자열을 한두 조각으로 통째로 묶어 두었다. 글자가 길다고 토큰이 많은 게 아니라, 흔한 단어일수록 통째로 묶여 토큰이 적어진다는 게 핵심이다. 여기서 정확한 토큰 개수는 모델마다 쓰는 토크나이저가 달라 조금씩 다르니, 숫자 자체보다 "흔하면 통째로 묶인다"는 원리로 읽는 게 맞다.
다이어그램 설명. 이 그림은 짧은 축약어가 왜 절감으로 이어지지 않는지를 보여준다. "cfg"는 3글자로 짧지만, 일상 텍스트에 통째로 자주 등장하는 글자열이 아니라 BPE가 이걸 하나로 묶어 둔 적이 없다. 그래서 오히려 c·f·g처럼 잘게 쪼개지거나, 흔한 온전한 단어와 같은 수의 토큰으로 나뉜다. 글자를 4분의 1로 줄여도 토큰은 그대로거나 늘어나는 이유가 여기 있다 — 줄인 건 글자 수일 뿐 토큰 수가 아니었다.
caveman은 출력 토큰을 줄이는 것이 목적인 도구인데도, ultra 모드 규칙에 이 점을 정확히 적어 두었다. 새 축약어(cfg·impl·req·res·fn)를 만들지 말라는 것이다. 근거를 그대로 옮기면 "tokenizer split them same as full word: zero token saved, reader still decode. Full word cheaper AND clearer" — 토크나이저가 축약어를 온전한 단어와 똑같이 쪼개니 절감은 0인데, 읽는 쪽은 여전히 cfg가 무슨 뜻인지 머릿속에서 풀어야 한다. 절약은 없고 가독성만 손해라는 뜻이다.
화살표 →도 마찬가지 — 짧다고 공짜가 아니다
같은 오해가 기호에도 적용된다. 인과를 나타내려고 원인 → 결과처럼 화살표를 쓰면 "because" 같은 단어보다 짧으니 아낀다고 느낀다. 하지만 caveman은 ultra 규칙에서 화살표 →도 금지한다. 이 기호가 그 자체로 독립된 한 토큰을 차지하기 때문이다. 화면에서 좁은 한 글자로 보여도 토큰 예산에서는 온전한 한 자리를 먹는다. 짧게 보이는 것과 토큰이 적은 것은 다르다는 원리가 여기서도 똑같이 반복된다.
진짜 토큰을 줄이는 축은 '글자'가 아니라 '단어(개념)'다
그렇다면 무엇을 줄여야 실제로 토큰이 줄어드는가. 답은 글자 수가 아니라 단어 수, 즉 개념의 수다. 흔한 단어 하나는 이미 최소 토큰이라 철자를 비틀어 봐야 이득이 없다. 반면 문장에서 개념 하나를 통째로 덜어 내면 그 개념이 차지하던 토큰이 전부 사라진다.
다이어그램 설명. 이 그림은 토큰을 줄이는 두 가지 시도가 전혀 다른 결과에 이르는 것을 대비한다. "글자 수 줄이기" 갈래는 축약어로 철자를 비트는 방식인데, 흔한 단어는 이미 통째로 묶여 있어 "토큰 절감 거의 0, 가독성만 손해"로 끝난다. "단어·개념 수 줄이기" 갈래는 필요 없는 수식어나 인사말 같은 개념 자체를 덜어 내는 방식이라, "토큰이 실제로 줄고 뜻은 그대로" 남는다. caveman이 관사(a/an/the)·군더더기(just·really·basically)·상투어(sure·certainly)를 걷어 내는 것도 바로 이 오른쪽 갈래 — 글자를 비트는 게 아니라 개념 단위로 덜어 내는 접근이다.
정리하면, caveman이 실제로 65% 토큰을 줄인다고 말할 때 그 절감은 configuration을 cfg로 바꿔서 나온 게 아니다. 불필요한 개념 — 인사, 완충어, 중복 설명 — 을 통째로 들어내서 나온 것이다. 철자 압축은 절감이 아니라 착시였다.
caveman의 판단 규칙 — 축약할지 말지 어떻게 정하나
이 원리를 도구가 어떻게 규칙으로 굳혔는지 보면 응용법이 분명해진다. caveman은 어떤 축약어를 쓸지 말지를 "토크나이저가 이걸 온전한 단어와 같게 쪼개는가"라는 한 가지 질문으로 가른다.
다이어그램 설명. 이 그림은 caveman이 축약 여부를 정하는 판단 흐름이다. "축약 후보"가 들어오면 "토크나이저가 온전한 단어와 같게 쪼개나?"를 묻는다. 그렇다는 쪽 — cfg·impl·req처럼 새로 지어낸 약어 — 은 절감이 없으니 "풀어쓴다"로 간다. 아니라는 쪽 — DB·API·HTTP처럼 말뭉치에 이미 흔해 통째로 한 토큰이 된 표준 약어 — 은 "그대로 쓴다"로 간다. 같은 "약어"라도 결정 기준이 글자 길이가 아니라 토크나이저가 그걸 어떻게 다루는가라는 점이 이 규칙의 핵심이다. 흔히 하는 오해는 "짧으면 무조건 이득"이라 여겨 새 약어를 남발하는 것인데, 이 흐름은 그 지점에서 정확히 걸러 낸다.
정리 — 줄여야 할 건 철자가 아니라 개념이다
토큰을 아끼려고 단어를 축약하는 건 대개 헛수고다. 흔한 단어는 이미 최소 토큰이고, 지어낸 약어는 오히려 잘게 쪼개져 절감이 0이면서 읽는 사람에게 해독 부담만 지운다. 화살표 같은 기호도 짧아 보일 뿐 독립 토큰을 먹는다. 진짜 줄이는 축은 글자가 아니라 개념의 수 — 문장에서 없어도 되는 뜻 한 덩어리를 통째로 덜어 낼 때 토큰이 실제로 사라진다.
그래서 나는 프롬프트를 다듬을 때 이제 철자를 비틀지 않는다. 대신 "이 문장에서 통째로 지워도 뜻이 남는 개념이 있나"를 묻는다. 축약할지 고민되는 단어가 있으면 토크나이저에 한 번 넣어 세어 보면 된다 — 온전한 단어와 토큰 수가 같으면, 풀어쓰는 쪽이 더 싸고 더 맑다.
그리고 이 기준은 내가 손으로 다듬는 입력 파일에도 똑같이 걸린다. 에이전트가 매 세션 읽는 `CLAUDE.md`를 줄이겠다고 configuration을 cfg로 바꿔 봐야 토큰은 그대로고 나중에 읽을 나만 고생한다. 줄여야 할 것은 거기서도 철자가 아니라 개념 — 없어도 되는 문장 한 덩어리다.
참고한 공개 자료:
- caveman skill (JuliusBrussee/caveman): https://github.com/JuliusBrussee/caveman
- OpenAI Tokenizer (BPE 동작 확인용): https://platform.openai.com/tokenizer
- Byte Pair Encoding — Hugging Face NLP Course: https://huggingface.co/learn/nlp-course/chapter6/5
- Let's build the GPT Tokenizer — Andrej Karpathy: https://www.youtube.com/watch?v=zduSFxRajkE
이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.
'IT' 카테고리의 다른 글
에이전트는 서로를 어떻게 찾는가 — 발견, 그리고 에이전트의 '명함' (0) 2026.08.02 AI 에이전트의 두 개의 축 — 도구를 붙이는 일과 동료를 부르는 일은 다르다 (0) 2026.08.02 서브에이전트 출력 압축 — 토큰 절약의 잊힌 세 번째 축, 메인 컨텍스트 예산 (0) 2026.08.01 상주 컨텍스트를 한 번만 압축하면 — 매 세션 영구히 아끼는 입력 토큰 (0) 2026.08.01 산문은 손실 압축, 코드는 무손실 — 무엇을 지킬 수 있는지는 '중요도'가 아니라 '식별 가능성'이 정한다 (0) 2026.07.31 AI 코딩 에이전트의 토큰 절약 — 뇌가 아니라 입을 줄인다 (0) 2026.07.31 자율 에이전트인가, 통제된 하네스인가 — LLM을 부리는 두 가지 모델 (0) 2026.07.30 AI 시스템 테스트, 무엇을 가짜로 두고 무엇을 진짜로 돌릴까 — mock 경계 원칙 (0) 2026.07.29 채점자도 AI라면 — LLM-as-judge로 답변 품질을 자동 평가할 때 빠지는 함정 (0) 2026.07.29 스킬이 50개 넘으니 엉뚱한 게 불렸다 — 겹침을 임베딩으로 자동 탐지하기 (0) 2026.07.29