
Claude API 비용 줄이는 법 — 프롬프트 캐싱부터 배치까지 6가지 정리
Claude API 비용의 진짜 범인은 매 요청 다시 실어 보내는 입력 토큰이다. 프롬프트 캐싱 손익분기(읽기 0.1배·쓰기 1.25배), 프리픽스 정확 일치 규칙과 캐시를 깨는 코드, 배치 API 50% 절감, 모델 티어와 effort까지 공식 문서 기준으로 정리했다.
매달 API 청구서를 열어보고 "이번 달은 왜 이렇게 나왔지" 싶은 순간이 있다. 사용량을 뜯어보면 범인은 대개 출력이 아니라 입력이다. 같은 시스템 프롬프트, 같은 도구 목록, 같은 문서 뭉치를 매 요청마다 통째로 다시 실어 보내고 있기 때문이다.
여기서 의외로 안 알려진 사실 하나. 그 반복되는 앞부분은 원래 입력 단가의 10분의 1로 처리할 수 있다.

캐시 읽기는 0.1배, 그런데 왜 내 캐시는 안 걸릴까
숫자부터. 프롬프트 캐싱을 켜면 캐시에 적중한 토큰은 기본 입력가의 0.1배로 계산된다. 대신 캐시를 새로 쓰는 요청은 5분 TTL이면 1.25배, 1시간 TTL이면 2배를 낸다.
손익분기가 여기서 갈린다.
- 5분 TTL: 1.25 + 0.1 = 1.35배 < 2배 → 같은 프리픽스를 2번만 재사용해도 이득
- 1시간 TTL: 2 + 0.2 = 2.2배 < 3배 → 3번은 써야 본전
1시간 TTL이 "오래 살아있으니 무조건 유리"가 아니라는 뜻이다. 쓰기 프리미엄이 두 배라, 재사용이 적으면 오히려 손해다. 요청이 띄엄띄엄 몰려 들어오는 서비스에서만 값을 한다.
그런데 현장에서 훨씬 자주 보는 상황은 따로 있다. 캐싱을 분명히 켰는데 usage.cache_read_input_tokens가 계속 0인 경우다.
프리픽스는 바이트 단위로 같아야 한다
캐싱은 유사도 매칭이 아니다. 프리픽스 정확 일치다. cache_control을 찍은 지점까지의 바이트가 100% 같아야 히트한다. 한 글자만 달라도 그 뒤는 전부 무효다.
렌더링 순서는 tools → system → messages이고, 무효화는 계단식으로 내려간다.
| 바뀐 것 | tools 캐시 | system 캐시 | messages 캐시 |
|---|---|---|---|
| 도구 정의(추가·삭제·순서) | 무효 | 무효 | 무효 |
| 모델 교체 | 무효 | 무효 | 무효 |
| 시스템 프롬프트 내용 | 유지 | 무효 | 무효 |
tool_choice·이미지·thinking 토글 | 유지 | 유지 | 무효 |
| 메시지 내용 | 유지 | 유지 | 무효 |
읽는 법은 간단하다. 위쪽 계층이 흔들리면 아래가 전부 날아간다. 도구를 하나 추가하는 순간 시스템 프롬프트와 대화 히스토리까지 통째로 다시 계산된다. 반대로 tool_choice를 요청마다 바꾸는 건 tools+system 캐시를 그대로 살려둔다. 이 부분은 생각보다 널널하다.
캐시를 조용히 깨먹는 단골 범인들:
- 시스템 프롬프트에
datetime.now()나 요청 UUID를 박아 넣기 — 매 요청 프리픽스가 달라진다 - JSON 직렬화 키 순서가 요청마다 뒤바뀌기(
sort_keys미지정,set순회) - 사용자마다 도구 세트를 다르게 조립하기 — 도구는 맨 앞에서 렌더링되므로 사용자 간 캐시 공유가 통째로 사라진다
- 조건부 시스템 섹션(
if flag: system += ...) — 플래그 조합 수만큼 서로 다른 프리픽스가 생긴다
배치 원칙은 여기서 저절로 따라 나온다. 고정된 것은 앞에, 변하는 것은 브레이크포인트 뒤에.
tools : 정렬된 고정 도구 목록
system : 얼어붙은 시스템 프롬프트 ← cache_control 여기
messages[0] : 큰 참조 문서 / 검색 결과
messages[-1] : 오늘 날짜, 사용자 질문, 요청 ID ← 여기부터는 캐시 밖
"현재 시각"이나 "사용자 이름"은 시스템 프롬프트에 끼워 넣지 말고 마지막 사용자 메시지로 내리면 된다. 5번째 턴에 들어간 문장은 5번째 턴 앞의 어떤 것도 무효화하지 않으니까.

최소 캐시 토큰은 모델마다 다르고, 세대순도 아니다
이건 진짜 조용한 함정이다. 프리픽스가 최소 토큰 수에 못 미치면 에러도 없이 캐시가 안 걸린다. cache_creation_input_tokens가 0으로 찍힐 뿐이다.
| 모델 | 최소 캐시 가능 토큰 |
|---|---|
| Opus 5 / Fable 5 / Mythos 5 | 512 |
| Opus 4.8 / Sonnet 5 / Sonnet 4.6 | 1024 |
| Opus 4.7 | 2048 |
| Opus 4.6 / Opus 4.5 / Haiku 4.5 | 4096 |
여기서 중요한 건 이 값이 세대순으로 단조롭게 내려가지 않는다는 점이다. 최신 모델은 512인데 Opus 4.6이나 Haiku 4.5는 4096이다. 3천 토큰짜리 프롬프트는 Opus 5에서는 캐시되고 Haiku 4.5에서는 안 된다. "저렴한 티어로 내려서 비용을 줄이자"고 모델을 바꿨다가 캐시가 통째로 풀려 오히려 더 나오는 시나리오가 정확히 여기서 나온다.
명시적 브레이크포인트는 요청당 최대 4개다. 세밀한 배치가 필요 없다면 최상위 cache_control 하나만 줘도 된다. 마지막 캐시 가능 블록에 자동으로 붙고, 대화가 길어지면 브레이크포인트도 따라 이동한다.
캐싱이 답이 아닌 경우
여기서 한 번 브레이크를 걸자. 캐싱은 만능이 아니다.
매 요청마다 완전히 다른 문서를 새로 분석하는 파이프라인 — 사용자가 올린 PDF를 한 번씩 요약해주는 서비스 같은 것 — 은 재사용할 프리픽스 자체가 없다. 여기에 cache_control을 달면 쓰기 프리미엄 1.25배만 꼬박꼬박 내고 읽기는 한 번도 못 한다. 순수한 손해다. 앞부분이 요청마다 다르면 그냥 끄는 게 맞다.
나머지 레버 네 개
배치 API. 최대 24시간 지연을 감수할 수 있는 작업이면 입력·출력 토큰 양쪽 다 50% 절감이다. 대량 분류, 오프라인 요약, 야간 리포트 생성이 여기 해당한다. 프롬프트 캐싱과 중첩 적용되므로 둘을 같이 쓰면 절감폭이 더 벌어진다. 물론 실시간 응답이 필요한 서비스에는 못 쓴다. 이건 트레이드오프라기보다 그냥 자격 요건이다.
모델 티어. 모든 Claude 모델에서 출력 토큰 단가는 입력의 5배다. 비율이 고정이라는 게 포인트다. 출력이 긴 작업일수록 모델 선택이 청구서를 좌우한다는 뜻이고, 뒤집으면 입력만 크고 출력이 짧은 작업(분류·추출)은 티어를 올려도 덜 아프다. 작업에 맞는 최저 티어를 기본으로 깔고 어려운 구간만 상위 모델로 넘기는 전략이 잘 먹힌다.
컨텍스트 관리. 긴 대화와 에이전트 루프는 턴이 돌 때마다 히스토리 전체를 다시 보낸다. 입력 토큰이 누적으로 쌓인다는 얘기다. context editing은 오래된 도구 결과나 thinking 블록을 삭제하고(요약이 아니라 삭제다), compaction은 한도 근처에서 이전 맥락을 요약한다. 이름이 비슷해 헷갈리지만 하는 일이 다르다.
effort. output_config.effort(low~max)로 사고 깊이와 토큰 지출을 조절한다. 낮추면 확실히 절감되지만 품질과의 트레이드오프라 감으로 정하면 안 된다. 실제 평가셋에 대고 스윕해본 뒤 라우트별로 값을 다르게 주는 게 맞다.
그 전에, tiktoken으로 Claude 토큰을 세지 마라
가장 기본이면서 가장 자주 틀리는 지점. 요청을 보내기 전 토큰 수는 count_tokens API로 파악해야 한다.
tiktoken은 OpenAI 토크나이저다. Claude 토큰을 여기에 물리면 일반 텍스트에서 15~20% 과소 계산되고, 코드나 비영어 텍스트에서는 오차가 더 벌어진다. 한국어 프롬프트를 주로 다루는 입장에선 남의 얘기가 아니다. 토큰화 방식은 모델마다 다르니, 추론에 쓸 모델 ID를 그대로 넣어서 세야 한다.
usage를 읽을 때 흔한 착각도 하나 짚고 가자. input_tokens는 캐시되지 않은 나머지만 센다. 전체 프롬프트 크기는 input_tokens + cache_creation_input_tokens + cache_read_input_tokens다. 에이전트를 몇 시간 돌렸는데 input_tokens가 4천으로 찍힌다면, 나머지는 캐시에서 읽어온 것이다. 한 필드만 보고 놀라지 말자.
순서대로 적용하는 체크리스트
count_tokens로 실측한다. 어디가 큰지 모르면 어떤 레버도 못 당긴다.- 반복되는 큰 컨텍스트가 있으면 캐싱부터. 절감폭이 가장 크다.
- 지연이 허용되면 배치 API(50%, 캐싱과 중첩 가능).
- 작업에 맞는 최저 모델 티어를 기본값으로.
- 긴 세션은 context editing / compaction으로 히스토리를 가볍게.
- effort 스윕으로 미세조정.
국내 실무 관점에서 이 순서는 조금 다르게 읽히기도 한다. 한국어는 같은 내용이라도 영어보다 토큰을 더 먹기 때문에, 전체 비용에서 입력이 차지하는 비중이 구조적으로 더 크다. 그만큼 캐싱 레버가 상대적으로 강하게 먹힌다는 뜻이다. 사내 규정집이나 약관, 제품 매뉴얼처럼 고정된 대형 문서를 매번 붙여 보내는 RAG 구성이라면 1번보다 2번이 먼저일 수도 있다.
그리고 개인적으로 가장 자주 목격한 함정은 따로 있다. 사내 챗봇에서 사용자 권한에 따라 도구 세트를 다르게 조립하는 구조다. 보안 관점에선 자연스러운 설계지만, 도구는 프롬프트 맨 앞에서 렌더링되기 때문에 이 순간 사용자 간 캐시 공유가 0이 된다. 권한 필터링을 도구 목록이 아니라 도구 실행 단에서 거는 것만으로 캐시 히트율이 확 올라가는 경우가 많다. 비용 최적화가 아키텍처 결정과 맞물린다는 건 이런 대목이다.
한 가지 더. 캐싱은 "설정"이 아니라 "코드 구조"에 가깝다. 마커를 어디 붙이느냐보다 프롬프트를 조립하는 함수가 요청마다 같은 바이트를 만들어내느냐가 훨씬 중요하다. 대시보드에서 절감률을 보기 전에, 두 요청의 렌더링된 프롬프트를 문자열로 덤프해서 diff부터 떠보는 게 빠르다.
정리하면 이렇다. 큰 레버는 캐싱과 배치이고 나머지는 미세조정이다. 다만 캐싱은 켜는 것보다 깨지지 않게 유지하는 것이 훨씬 어렵고, 그 실패는 에러 대신 청구서로 돌아온다.
여러분 서비스는 지금 cache_read_input_tokens가 얼마나 찍히고 있나요? 0에 가깝다면 위 범인 목록 중 어느 항목에 걸려 있을 것 같은지 궁금합니다.
📎 출처: 원문 보기
- platform.claude.comhttps://platform.claude.com/docs/en/build-with-claude/prompt-caching
댓글 0
댓글을 불러오는 중…







