프롬프트 캐싱으로 API 비용 줄이는 법
LLM API를 어느 정도 진지하게 쓰기 시작하면 청구서가 가장 먼저 비명을 지르는 자리가 두 군데다. 하나는 길어지는 시스템 프롬프트, 또 하나는 멀티턴 대화의 누적된 히스토리다. 두 경우 모두 같은 텍스트를 매 요청마다 다시 보내고 있는데, 모델 입장에서도 매번 처음 보는 토큰처럼 attention을 다시 계산한다. 사용자도 비싸고 제공사도 비싼 구조가 한동안 그대로 굴러갔다.
프롬프트 캐싱은 이 비효율을 정공법으로 푸는 기능이다. Anthropic이 2024년 8월에 베타로 도입했고, OpenAI는 같은 해 10월에 자동 캐싱 형태로 따라왔으며, Google Gemini는 명시적 캐시 객체를 만드는 방식으로 같은 시기에 합류했다. 2025년 들어서는 캐시 사용이 LLM 애플리케이션 비용 구조의 기본 전제가 되었고, Claude Code CLI도 사용자가 별도 설정을 하지 않아도 내부적으로 캐싱을 적극적으로 활용한다. 이 글에서는 프롬프트 캐싱이 무엇이고, Claude Code에서 어떻게 적용되며, 캐시 효율을 끌어올리려면 어떤 점을 신경 써야 하는지를 정리한다.
프롬프트 캐싱이 풀어주는 문제
LLM 추론에서 입력 토큰 처리는 보통 두 단계로 나뉜다. prefill 단계에서 입력 전체에 대해 attention을 한 번 계산하고, decode 단계에서 한 토큰씩 출력을 낸다. prefill 단계가 입력 길이에 비례해서 비용과 지연시간을 차지한다. 입력 100K 토큰짜리 프롬프트는 출력이 짧아도 prefill 비용이 거의 그대로 들어간다.
문제는 같은 prefix를 반복해서 보내는 패턴이 LLM 워크로드에서 흔하다는 점이다. 코드 에이전트는 같은 시스템 프롬프트와 도구 정의를 모든 요청에 붙이고, RAG 시스템은 같은 매뉴얼을 매 질문마다 다시 보내며, 멀티턴 챗봇은 이전 턴 전체를 다음 요청에 포함시킨다. 1만 토큰짜리 시스템 프롬프트로 하루 1,000번 호출하면 그것만으로 1,000만 토큰을 처리한 비용이 청구된다.
프롬프트 캐싱은 이 prefix 부분의 KV 캐시를 제공사 서버 측에 잠시 보관해 두고, 같은 prefix가 다시 들어오면 prefill을 다시 돌리지 않고 재사용한다. 모델 입장에서는 동일한 attention 계산을 다시 할 이유가 없으니 비용도 떨어지고 첫 토큰까지의 지연시간도 줄어든다.
Anthropic 캐싱이 동작하는 방식
Anthropic의 프롬프트 캐싱은 명시적이다. 요청 본문 안에 cache_control 마커를 박아 어디까지가 캐시 대상인지 직접 지정한다. 마커는 한 요청에 최대 4개까지 둘 수 있고, 각 마커 위치에 도달했을 때까지의 prefix가 하나의 캐시 블록으로 잡힌다.
messages = [
{
"role": "system",
"content": [
{"type": "text", "text": LARGE_SYSTEM_PROMPT,
"cache_control": {"type": "ephemeral"}}
]
},
{"role": "user", "content": "이번 턴 질문"}
]
가격 구조는 캐시 쓰기와 읽기가 다르다. 2025년 11월 기준 Claude Sonnet 4.5의 base 입력가가 100만 토큰당 $3인데, 캐시 쓰기는 5분 TTL일 때 $3.75, 1시간 TTL일 때 $6, 캐시 읽기는 $0.30이다. 즉 처음 한 번은 25%~100% 비싸게 쓰고, 두 번째 호출부터는 base의 10% 가격으로 읽는다. 캐시가 한 번이라도 재사용되면 손익분기를 넘고, 두 번째 호출부터는 거의 무료에 가깝다.
TTL은 기본 5분이다. 같은 prefix가 5분 안에 다시 들어오면 캐시 적중, 그렇지 않으면 캐시는 만료되고 다시 써야 한다. 1시간 TTL은 옵션이고, 가격이 두 배지만 사용 빈도가 낮은 prefix를 길게 살려둘 수 있다. 사내 챗봇처럼 사용자 트래픽이 띄엄띄엄 들어오는 워크로드에는 1시간 TTL이 어울리고, 코딩 에이전트처럼 같은 세션 안에서 연속으로 호출이 일어나는 경우에는 5분으로도 충분하다.
캐시 대상이 되려면 최소 길이를 넘어야 한다. Claude Sonnet과 Opus는 1,024 토큰 이상, Haiku는 2,048 토큰 이상부터 캐시 가능하다. 짧은 시스템 프롬프트는 굳이 마커를 박아도 캐싱이 적용되지 않는다는 뜻이다. 마커가 prefix의 어디에 위치하든 캐시는 메시지의 처음부터 그 마커까지의 누적 prefix를 기준으로 잡힌다는 점도 함께 기억해 둘 만하다.
Claude Code CLI에서의 캐싱
Claude Code CLI는 프롬프트 캐싱을 내부적으로 적극적으로 활용한다. 사용자가 직접 cache_control을 넣을 일은 없고, 대신 CLI가 어떤 토큰까지를 캐시 가능한 prefix로 묶을지를 자동으로 판단한다.
크게 세 영역이 캐시 대상이다. 첫째는 시스템 프롬프트와 도구 정의 묶음이다. Claude Code의 시스템 프롬프트는 작업 지침, 환경 정보, 등록된 도구 스키마를 합쳐 보통 1만~2만 토큰을 넘는다. 여기에 MCP 서버 한두 개가 붙으면 도구 정의가 더 늘어난다. 이 prefix는 세션 동안 거의 변하지 않으므로 매 요청마다 캐시 적중이 일어난다.
둘째는 CLAUDE.md와 그 하위 메모리 파일이다. 프로젝트 루트, 사용자 홈 디렉토리, 부모 디렉토리에서 자동 로드되는 이 파일들은 시스템 프롬프트 영역에 합쳐져 들어가므로 같은 캐시 라인 안에서 처리된다. 이 자리에 RAG처럼 자주 바뀌는 컨텍스트를 끼워 넣으면 매 호출마다 캐시가 깨진다는 점을 의식해 둘 필요가 있다.
셋째는 대화 히스토리다. Claude Code는 멀티턴이 진행될수록 이전 턴들을 prefix로 누적해 보내는데, 누적된 prefix의 끝부분 가까이에 캐시 마커를 갱신해 가며 진행한다. 이전 턴에서 읽은 큰 파일이나 grep 결과 같은 무거운 컨텍스트가 다음 턴에서도 입력 비용 없이 재활용되는 이유가 여기에 있다.
캐시 사용량은 /cost 명령으로 확인할 수 있다. cache creation, cache read 토큰이 각각 따로 표시되고, 정상적인 코딩 세션이라면 누적 토큰 중 80% 이상이 cache read 자리에서 잡힌다. 이 비율이 낮게 나온다면 prefix가 자주 바뀌는 패턴이 어딘가에 끼어 있다는 신호다. /context 명령은 입력 토큰의 구성 비율을 보여주므로 어느 영역이 컨텍스트를 차지하고 있는지 함께 점검할 수 있다.
캐시 효율을 떨어뜨리는 패턴들
캐시는 prefix 일치를 전제로 동작하기 때문에, 매 요청마다 prefix 앞쪽이 조금씩 달라지는 구성에서는 캐시 적중률이 빠르게 무너진다. 실전에서 자주 나오는 실수는 비슷한 형태를 띤다.
첫 번째는 시스템 프롬프트나 CLAUDE.md 안에 현재 시각, 랜덤 ID, 사용자 식별자처럼 매번 바뀌는 값을 넣어 두는 경우다. 변동값이 prefix의 위쪽에 있으면 그 아래의 모든 토큰이 캐시 대상에서 빠진다. 변동값은 가능한 한 prefix의 끝쪽, 사용자 메시지 직전에 두는 편이 안전하다. 정말 필요한 경우라면 시간 정보를 분 단위가 아니라 시간 단위 또는 일 단위로 둥글려 prefix 안정성을 회복시키는 식으로 절충할 수도 있다.
두 번째는 RAG 결과를 시스템 프롬프트 영역에 끼워 넣는 패턴이다. retrieval 결과는 매 질문마다 달라지므로 캐시 적중을 매번 깨뜨린다. retrieval로 받아온 문서는 사용자 메시지 쪽에 붙여 시스템 prefix를 안정시키는 편이 비용 면에서 유리하다. 또는 retrieval 자체를 도구 호출로 빼서, 도구 결과가 대화 히스토리의 뒤쪽에 자연스럽게 누적되도록 두는 구성도 자주 쓰인다.
세 번째는 /clear를 자주 누르는 습관이다. /clear는 현재 컨텍스트를 비우고 새 세션을 시작하는데, 이 시점에서 5분 TTL 캐시는 사실상 의미를 잃는다. 작업이 정말 끊어진 게 아니라면 같은 세션 안에서 계속 진행하고, 컨텍스트가 너무 커졌다고 느껴질 때만 /compact로 요약하는 편이 캐시를 유지하면서 비용을 관리하기에 낫다. /compact 자체는 캐시를 깨지만, 그 다음부터는 줄어든 prefix 위에서 새 캐시 라인이 형성된다.
네 번째는 멀티 에이전트 구성에서 sub-agent의 시스템 프롬프트를 매번 다르게 만드는 경우다. sub-agent는 매번 새로운 컨텍스트로 호출되기 때문에, 그쪽 시스템 프롬프트가 안정적이지 않으면 캐시 적중이 거의 일어나지 않는다. 자주 호출되는 sub-agent라면 같은 프롬프트 템플릿을 고정해 두고 변동값만 user 메시지로 넘기는 형태가 합리적이다.
정리
프롬프트 캐싱은 LLM 비용 구조에서 가장 단순하면서 효과가 큰 최적화 수단이다. 같은 prefix를 반복해서 보내는 거의 모든 워크로드에서 호출당 비용이 한 자릿수 분의 1로 떨어진다. Claude Code CLI 사용자라면 별도의 코드 작업 없이도 캐싱의 혜택을 받고 있을 가능성이 높지만, prefix 안정성을 의식하지 않으면 그 혜택의 상당 부분이 빠져나갈 수 있다.
실제로 챙길 점은, 1. 시스템 프롬프트와 CLAUDE.md에는 자주 바뀌는 값을 넣지 말 것, 2.변동 정보는 prefix의 끝쪽 또는 사용자 메시지에 둘 것, 3. 같은 세션을 가능한 한 길게 유지할 것, 4. 비용 점검은 /cost와 /context로 정기적으로 들여다볼 것 정도로 정리할 수 있겠다.