목록으로
3 분 소요

Claude Code API 비용을 90% 줄이는 캐시 설계 원칙

프로덕션에서 캐시가 깨지니 API 비용이 10배로 뛰었다. 같은 날 Anthropic 엔지니어들이 그 이유를 정확히 설명해줬다.

어제 급한 프로덕션 작업이 있었다. 작업 중간에 프롬프트 캐시가 깨졌다. 그 한 시간 동안 나간 API 비용이 지난 3일치를 합친 것보다 많았다.

타이밍이 묘했다. 같은 날 저녁, Claude Code를 만든 Anthropic의 Thariq과 Lance Martin이 나란히 프롬프트 캐싱 설계에 대한 글을 올렸다. 읽어보니 내 캐시가 우연히 깨진 게 아니었다. 설계부터 깨지기 쉬운 구조였다.

두 글에서 뽑아낸 내용을, 당일 겪은 프로덕션 사고의 경험과 함께 정리한다.

접두사 매칭이라 순서가 전부다

Anthropic API의 프롬프트 캐싱은 요청 시작 지점부터 토큰 단위로 순서대로 매칭한다. 캐시된 버전과 한 글자라도 달라지는 순간, 그 뒤는 전부 캐시 미스가 된다. 부분 매칭도 없고, 건너뛰기도 없다.

Claude Code 팀은 프롬프트 순서를 인프라처럼 다룬다. 정적 시스템 프롬프트가 맨 앞에 오고, 그 다음이 CLAUDE.md, 세션 컨텍스트 순이다. 대화 메시지는 매 턴마다 바뀌기 때문에 맨 뒤에 놓는다. 이 순서 덕분에 비용이 큰 고정 접두사가 세션 내내 캐시되어 재사용된다.

캐시된 토큰은 일반 입력 토큰 비용의 10%만 청구된다. 이 차이가 캐시 깨짐이 곧 10배 비용 폭증인 이유다.

내 실수는 시스템 프롬프트에 타임스탬프를 넣은 것이었다. 매 요청마다 타임스탬프가 새로 생성되니 맨 첫 토큰부터 달라졌다. 그 뒤의 어떤 것도 캐시를 탈 수 없었다. 디버그 로그 하나를 잘못된 위치에 넣은 대가로, 매 요청 10만 토큰 이상을 전액 결제하고 있었다.

Claude Code 팀도 도구 정의의 순서가 비결정적으로 바뀌면 캐시 미스가 발생한다고 밝혔다. 도구 자체는 달라진 게 없어도, 직렬화 순서만 바뀌면 그 지점에서 캐시가 끊긴다.

시스템 프롬프트를 고치지 말고 메시지로 업데이트하라

세션 중에 컨텍스트가 바뀔 때(파일 수정, 시간 변경, 모드 전환) 시스템 프롬프트를 직접 고치고 싶은 충동이 든다. 하지 마라. 시스템 프롬프트를 한 글자라도 고치면 캐시 접두사 전체가 무효화된다.

Claude Code는 첫 요청 이후 시스템 프롬프트를 건드리지 않는다. 바뀐 컨텍스트는 다음 사용자 메시지에 system-reminder 태그로 감싸서 전달한다. 모델은 동일하게 읽지만, 캐시 접두사는 그대로 유지된다.

Plan Mode가 좋은 예다. Plan Mode로 전환하려면 도구 정의를 교체해야 할 것 같지만, 그러면 캐시가 깨진다. 대신 Claude Code는 Plan Mode를 EnterPlanMode라는 도구 호출로 구현했다. 모델이 어려운 문제를 감지하면 스스로 Plan Mode에 진입할 수 있다. 도구 세트는 처음부터 끝까지 바뀌지 않는다.

모델 전환도 같은 논리다. 대화 중간에 모델을 바꾸면 캐시가 통째로 깨진다. Claude Code는 다른 모델을 별도 컨텍스트의 서브에이전트로 실행해서, 부모 대화의 캐시를 보호한다.

도구가 많으면 빼지 말고 숨겨라

MCP 서버가 수십 개의 도구를 로딩할 수 있다. 매 요청에 전부 포함시키면 비용이 크다. 하지만 요청 사이에 도구를 빼면 캐시가 깨진다. 도구 정의도 캐시 접두사의 일부이기 때문이다.

Claude Code 팀이 찾은 해법은 defer_loading이다. 전체 도구 스키마 대신, 도구 이름과 defer_loading: true 플래그만 담은 가벼운 스텁을 넣는다. 스텁은 항상 같은 순서로 유지되어 캐시 접두사를 동일하게 보존한다. 모델이 실제로 도구의 전체 스키마가 필요할 때는 ToolSearch 도구를 호출해서 그때그때 불러온다.

이 패턴은 현재 Anthropic API에서 직접 사용할 수 있다. 자체 에이전트에 같은 스텁-앤-서치 방식을 구현하면 된다.

Manus의 peakji는 캐시 히트율을 프로덕션 에이전트에서 가장 결정적인 지표라고 말했다. 어제 이후로 동의한다.

컨텍스트 압축에도 캐시 함정이 있다

대화가 컨텍스트 윈도우를 가득 채우면 압축이 필요하다. 히스토리를 요약하고 줄인 형태로 이어가는 것이다. 보통은 요약 프롬프트로 API를 호출하려 한다. 하지만 그 요약 호출이 다른 시스템 프롬프트나 다른 도구 정의를 사용하면, 기존 캐시와 전혀 매칭되지 않는다. 비용이 가장 높은 순간에, 10만 토큰 이상의 전체 대화를 캐시 혜택 없이 처리하게 된다.

Claude Code는 압축 호출에도 부모 대화의 시스템 프롬프트와 도구 정의를 그대로 재사용한다. 바뀌는 것은 마지막 사용자 메시지뿐이다(압축 지시문으로). 부모 대화의 캐시 접두사가 여전히 매칭되므로, 새 메시지와 요약 출력분만 전액 결제하면 된다.

Anthropic은 이 패턴을 API에 컴팩션 기능으로 내장했다. 여기에 auto-caching도 출시해서, 요청 본문에 cache_control을 한 번만 설정하면 캐시 브레이크포인트가 자동 적용된다.

캐시 히트율은 운영 지표다

Claude Code 팀은 캐시 히트율을 서버 가동률처럼 모니터링한다. 수치가 떨어지면 장애로 선언한다.

이 관점이 프롬프트 설계에 대한 내 생각을 바꿨다. 시스템 프롬프트 수정, 도구 순서 변경, 세션 중 모델 전환, 모두 잠재적 장애 요인이다. 가장 저렴한 토큰은 캐시를 타는 토큰이고, 어제 나는 그 반대가 얼마나 비싼지 정확히 배웠다.

뉴스레터 구독하기

최신 프로젝트, 아티클, AI와 웹 개발 실험에 대한 소식을 받아보세요.