개발자들은 Claude의 프롬프트 캐싱(prompt-caching)이 캐시된 토큰을 전혀 반환하지 않으면서도 프리미엄 요금을 청구하는 방식으로 조용히 실패할 수 있다는 사실을 발견했습니다. WhatsApp 핸들러에 대해 일주일간 로그를 실행한 결과, 캐시 읽기가 전혀 발생하지 않았음에도 불구하고 API는 캐싱 기능에 대해 비용을 청구하며 월 비용을 $1,890에서 $406로 낮추었습니다.
이 문제가 중요한 이유
프롬프트 캐싱은 프롬프트의 정적 부분(prefix)을 재사용하여 비용을 절감하고 응답 속도를 높이기 위한 것입니다. 캐싱이 제대로 작동하면 트래픽이 많은 앱은 월간 청구 금액에서 수백 달러를 절감할 수 있습니다. 하지만 캐싱이 작동하지 않으면 개발자는 실제로 사용하지도 않은 기능에 대해 비용을 지불하게 되며, 이러한 조용한 실패는 문제의 징후를 알리는 오류나 경고를 전혀 제공하지 않습니다.
버그가 나타나는 방식
API는 cache-control 플래그와 prefix를 수락한 다음, 캐시에서 읽은 토큰 수를 보고합니다. 관찰된 사례에서는 모든 요청의 캐시 읽기 횟수가 0으로 반환되었습니다. 호출은 성공했고 예외도 발생하지 않았지만, 청구 내역에는 프리미엄 캐시 비용이 반영되었습니다. 캐시 읽기 횟수를 명시적으로 로그에 남기지 않는 한 이 실패는 눈에 보이지 않습니다.
캐시가 깨지는 일반적인 원인
- Prefix가 너무 짧음 – 각 Claude 모델은 캐싱 가능한 prefix에 대해 최소 토큰 길이를 정의합니다. Haiku 4.5는 최소 4,096 토큰이 필요하며, Sonnet 4.6은 1,024 토큰만 필요합니다. 이보다 짧은 prefix를 보내면 요청 형식은 충족되지만 서비스는 캐시 지침을 무시합니다.
- 가변적인 바이트의 이동 – 캐싱을 위해서는 바이트 단위의 정확한 일치가 필요합니다. 시스템 프롬프트의 맨 앞에 타임스탬프,
new Date(), 또는 사용자 이메일과 같은 동적 요소를 추가하면 바이트 시퀀스가 변경되어 모든 요청이 캐시되지 않은 새로운 쓰기 작업으로 처리됩니다. - 도구(Tool) 목록 순서 변경 – 도구는 프롬프트 앞에 추가됩니다. 만약 도구 배열이 객체 키(object keys)를 기반으로 생성된다면, 호출마다 반복 순서가 달라질 수 있어 바이트 레이아웃이 바뀌고 캐시가 깨지게 됩니다.
오늘 바로 적용할 수 있는 해결책
- Prefix 길이 검증 – 요청을 보내기 전에 모델의 최소 요구 사항과 비교하여 prefix의 토큰 수를 추정하십시오. 기준에 미달하면 prefix를 거부하거나 패딩(padding)을 추가하십시오.
- 모든 호출에서 캐시 읽기 로그 기록 – "cache read tokens" 필드를 기록하십시오. 0이 연속해서 나타난다면 캐시가 작동하지 않고 있다는 명확한 신호입니다.
- 프롬프트의 앞부분 바이트 고정 – 캐시 세그먼트에서 동적 데이터를 제외하십시오. 사용자별 정보를 반드시 포함해야 한다면, 캐시된 prefix 뒤에 배치하십시오.
- 모델 식별자 동기화 – 라우팅에 사용되는 모델 ID가 캐시 테이블에 저장된 ID와 일치하는지 확인하십시오. ID가 일치하지 않으면 캐시 조회를 할 수 없습니다.
비용 측면
매일 수천 건의 호출을 수행하는 앱의 경우, 캐시 미사용에서 사용으로 전환하면 월간 비용을 극적으로 낮출 수 있습니다. 보고된 사례에서는 약 $1,890에서 $406로 감소했습니다. 트래픽이 적더라도 눈에 띄는 절감 효과를 볼 수 있으며, 대규모 정적 프롬프트를 재사용함으로써 얻는 성능 향상은 지연 시간(latency)을 줄여줄 수 있습니다.
반론
하지만 실패가 조용히 일어난다는 특성 때문에, 과다 지불을 하지 않고 있는지 확인할 수 있는 유일한 방법은 읽기 횟수를 확인하는 것뿐이며, 많은 이들이 이 점을 간과합니다.
향후 주의 깊게 살펴볼 사항
- 메트릭 대시보드 – 요청량과 함께 캐시 읽기 토큰을 확인할 수 있는 게이지를 추가하십시오.
- 도구 순서의 안정성 – 동적으로 생성된 도구 목록에 의존하는 경우, 프롬프트에 삽입하기 전에 결정론적(deterministic)으로 정렬하는 것을 고려하십시오.
핵심 요약: Claude의 프롬프트 캐싱은 요청을 조용히 무시할 때 에러를 발생시키지 않습니다. 읽기 토큰을 로그로 남겨 캐시 효율성을 검증하고, 적절한 prefix 길이를 강제하며, 프롬프트의 앞부분 바이트를 불변(immutable) 상태로 유지하십시오. 그래야만 약속된 비용 및 속도 이점을 누릴 수 있습니다.
