LLM 프롬프트 토큰 줄이기, 측정·캐싱·압축으로 접근하기
LLM 프롬프트 토큰은 tiktoken으로 먼저 측정하고, 반복되는 시스템 프롬프트는 프롬프트 캐싱으로 재사용하며, 컨텍스트는 압축·요약으로 줄인다. Anthropic·OpenAI 공식 캐싱 방식과 손대는 순서까지 짚었다.
목차
LLM 프롬프트 토큰을 줄이는 길은 크게 세 갈래다. 먼저 tiktoken 같은 토크나이저로 어느 요청의 어느 구간이 토큰을 많이 먹는지 측정하고, 매 요청마다 똑같이 들어가는 시스템 프롬프트와 툴 정의는 프롬프트 캐싱으로 재사용하며, 컨텍스트 자체는 압축하거나 요약해 넣는다. Anthropic 공식 문서에 따르면 2026년 7월 기준 캐시에서 읽는 토큰은 기본 입력가의 약 10%만 청구돼, 반복되는 컨텍스트가 큰 서비스일수록 절감 폭이 크다. 이 글은 API로 LLM을 호출하는 개발자를 대상으로 유료 API의 입력 토큰 비용을 줄이는 방법을 다룬다. 모델을 직접 파인튜닝하거나 자체 호스팅해 추론하는 경우는 범위 밖이다.
토큰이 어디서 새는지 어떻게 확인하나
줄이기 전에 재는 게 먼저다. 어느 부분이 토큰을 많이 먹는지 모르면 엉뚱한 곳을 손대게 된다. OpenAI 모델은 OpenAI가 공개한 오픈소스 토크나이저 tiktoken으로 토큰 수를 정확히 셀 수 있다. GPT-4와 GPT-3.5-turbo는 cl100k_base, GPT-4o 계열은 o200k_base 인코딩을 쓰고, o200k_base의 어휘 크기는 20만이다. 사용법은 인코딩을 불러와 텍스트를 인코딩한 뒤 길이를 재는 게 전부다.
import tiktoken
enc = tiktoken.get_encoding("o200k_base") # GPT-4o 계열
tokens = enc.encode("측정할 프롬프트 전체 텍스트")
print(len(tokens))Claude를 쓴다면 Anthropic 공식 토큰 카운팅 API가 있다. Anthropic 공식 문서에 따르면 POST /v1/messages/count_tokens 엔드포인트는 무료이고, 메시지 생성과 분당 요청 제한(rate limit)이 따로 매겨진다. 실제 호출과 똑같이 system·tools·messages를 넣으면 input_tokens 값을 돌려준다.
count = client.messages.count_tokens(
model="claude-opus-4-8",
system="시스템 프롬프트",
messages=[{"role": "user", "content": "질문 내용"}],
)
print(count.input_tokens)측정할 때는 프롬프트를 구간별로 쪼개 각각 세보는 게 요령이다. 시스템 프롬프트, 툴 정의, few-shot 예시(형식을 보여주려고 넣는 예시 몇 개), 검색해 붙인 컨텍스트, 사용자 입력을 나눠서 재면 어느 구간이 비대한지 바로 드러난다. 명령줄 도구로 확인하고 싶다면 Claude Code에서 토큰 사용량을 확인하는 세 방법을 비교한 글이 참고가 된다.
반복되는 프롬프트는 캐싱으로 재사용한다
매 요청마다 글자 하나 안 바뀌고 들어가는 시스템 프롬프트, 툴 정의, 긴 지침은 프롬프트 캐싱으로 재계산을 건너뛸 수 있다. 캐싱은 프롬프트 앞부분(프리픽스)을 한 번 처리해 두고, 다음 요청에서 같은 프리픽스가 오면 그 부분을 다시 계산하지 않고 싼값에 재사용하는 기능이다.
Anthropic 공식 문서에 따르면 캐시에서 읽는 토큰은 기본 입력가의 약 10%로 청구되고, 캐시를 처음 쓸 때는 기본 입력가보다 25% 더 든다. 기본 캐시 유지 시간은 5분이며 1시간 옵션은 추가 과금 대상이다. OpenAI 공식 문서에 따르면 프롬프트 캐싱은 자동으로 적용돼 코드를 고칠 필요가 없고, 1,024토큰을 넘는 프롬프트의 공통 프리픽스를 캐시한 뒤 128토큰 단위로 캐시 범위를 늘린다. 응답 usage의 cached_tokens 값으로 얼마가 캐시로 처리됐는지 확인할 수 있다.
| 구분 | Anthropic Claude | OpenAI |
|---|---|---|
| 적용 방식 | 캐시할 구간을 직접 지정 | 자동 적용, 코드 변경 불필요 |
| 캐시 대상 | 지정한 시스템 프롬프트·툴 정의 등 | 1,024토큰 넘는 공통 프리픽스 |
| 캐시 읽기 비용 | 기본 입력가의 약 10% | 캐시분 할인, 공식 요금 참조 |
| 기본 유지 시간 | 5분(1시간 옵션 추가 과금) | 자동 관리 |
캐시 적중률을 높이는 실무 원칙은 하나다. 고정된 콘텐츠를 앞에, 매번 바뀌는 사용자 입력을 뒤에 배치한다. 프리픽스 중간에서 한 글자라도 달라지면 그 뒤로는 캐시가 깨져 다시 계산되기 때문이다. 다만 캐시가 유지되는 5분 안에 같은 프리픽스로 여러 번 호출되는 워크로드(챗봇, 에이전트 루프)라야 이득이 난다. 어쩌다 한 번 부르는 요청이라면 캐시 쓰기에 붙는 추가 비용만 물고 재사용 이득은 못 볼 수 있으니, 호출 패턴을 보고 판단한다. 각 서비스의 캐싱 방식은 Anthropic 프롬프트 캐싱 문서와 OpenAI 프롬프트 캐싱 가이드에 정리돼 있다.
프롬프트 자체를 압축하려면?
정보량은 지키고 글자 수만 줄이는 게 핵심이다. 실무에서 손대는 지점은 세 곳이다. 중복 지시 걷어내기, few-shot 예시 개수 줄이기, 자동 압축 도구 쓰기.
- 중복과 군더더기: 같은 규칙을 두 번 적지 않는다. "당신은 매우 전문적이고 뛰어난" 같은 수식은 성능에 기여하지 않으면서 토큰만 먹으니 덜어낸다. 출력 형식을 JSON 스키마로 지정할 때도 실제로 쓰는 필드만 남긴다.
- few-shot 예시: 예시를 5개 넣었다면 3개, 2개로 줄여 보며 품질이 유지되는 최소 개수를 앞 섹션의 측정 도구로 찾는다. 예시 한 개가 수백 토큰인 경우가 흔하다.
- 자동 압축: Microsoft Research가 공개한 LLMLingua는 작은 모델로 각 토큰의 예측 가능성(perplexity, 다음에 올 확률이 높아 뻔한 정도)을 계산해, 뻔한 토큰은 버리고 정보 밀도가 높은 토큰만 남긴다. Microsoft Research에 따르면 지시형 프롬프트는 2~5배, 검색해 붙인 컨텍스트는 최대 20배까지 압축한다. 초판 LLMLingua는 2023년, 개선판 LLMLingua-2는 2024년에 나왔다.
압축은 공짜가 아니라 품질 저하 위험을 안고 간다. 그러니 압축 전과 후를 같은 평가셋으로 돌려 답의 정확도가 얼마나 떨어지는지 확인한 뒤 도입한다. 자세한 동작 원리는 Microsoft Research의 LLMLingua 프로젝트 페이지에서 볼 수 있다.
덜어낼수록 좋아진다 — OpenAI의 GPT-5.6 실측
압축이 늘 품질을 깎는 것은 아니다. OpenAI는 GPT-5.6 프롬프팅 안내 문서에서, 시스템 프롬프트의 군더더기를 걷어낸 구성이 내부 평가 점수를 약 10~15% 끌어올리면서 총 토큰을 41~66%까지 줄였다고 밝힌다. 지시가 서로 겹치거나 모델이 이미 잘하는 일을 재차 설명하는 대목이 오히려 방해가 됐다는 것이다. OpenAI가 권하는 방법은 단순하다.
- 지시·예시·도구를 한 번에 한 묶음씩 덜어내며 평가 점수가 어떻게 변하는지 본다.
- 같은 지시는 한 번만 적는다. 여러 곳에 반복해 두지 않는다.
- 예시와 스타일 규칙은 그것이 제품 요구사항을 담고 있을 때만 남긴다.
길이는 프롬프트만이 아니라 출력에서도 조절한다. OpenAI는 GPT-5.6의 응답 상세도를 text.verbosity 값(low·medium·high)으로, 추론에 쓰는 토큰을 reasoning.effort(none부터 max까지)로 지정하라고 안내한다. 짧은 답을 원할 때는 모델이 반드시 남겨야 할 정보와 생략해도 되는 세부를 구분해 지시하라고 덧붙인다. 자세한 지침은 OpenAI의 최신 모델 안내 문서에 정리돼 있다.

컨텍스트와 대화 히스토리를 다이어트한다
토큰을 가장 많이 잡아먹는 범인은 대개 프롬프트에 통째로 밀어 넣은 문서와 대화 기록이다. 여기부터 줄이면 효과가 크다.
- RAG(검색으로 찾은 문서를 프롬프트에 넣어 답하게 하는 방식) 컨텍스트: 문서 전체가 아니라 질문과 관련된 조각만 상위 몇 개(top-k)로 좁혀 넣는다. k를 3~5에서 시작해 답 품질을 보며 조정하면, 검색 정확도만 받쳐 줄 경우 넣는 토큰을 크게 줄일 수 있다.
- 대화 히스토리: 전체 대화를 매 요청마다 붙이는 대신, 오래된 대화는 짧은 요약본으로 접고 최근 몇 턴만 그대로 유지하는 슬라이딩 윈도우 방식을 쓴다.
- 출력도 토큰이다: max_tokens로 응답 길이 상한을 걸고, "핵심만 세 문장으로" 같은 형식 지시로 장황한 출력을 억제한다. 입력만 신경 쓰다 출력 토큰을 놓치는 경우가 많다.
토큰을 줄이는 것과 결이 다른 축으로, 애초에 싼 모델로 보내도 되는 쉬운 요청을 골라 값싼 모델로 넘기는 방법도 있다. 이 접근은 쉬운 요청을 싼 모델로 보내는 라우팅을 다룬 글에서 이어 보면 좋다.
무엇부터 손대야 하나
순서가 중요하다. 측정으로 병목 구간을 먼저 찾고, 반복되는 구간을 캐싱으로 묶는다. 캐싱은 코드 변경이 적으면서 반복 호출 워크로드에서 효과가 크니 우선순위가 높다. 그다음 컨텍스트와 대화 히스토리를 정리하고, 그래도 프롬프트가 크면 압축 도구를 검토한다. 측정을 건너뛰고 압축부터 손대면 품질만 깎이고 실제 절감은 작을 수 있다. 무엇을 줄이든 바꾸기 전후의 토큰 수와 답 품질을 함께 재는 습관이 결국 비용을 좌우한다.
