비용 얘기가 나오면 다들 모델부터 바꾼다
"AI API 비용이 너무 나와요" 소리가 나오면 보통 이런 순서로 간다.
- 더 싼 모델로 내린다
max_tokens를 줄인다- 프롬프트를 짧게 깎는다
전부 품질을 깎는 트레이드오프다. 품질을 안 건드리고 먼저 할 수 있는 게 프롬프트 캐싱이다. 시스템 프롬프트, 문서 컨텍스트, 도구 정의처럼 매 요청 반복되는 앞부분을 캐시에서 읽으면 그 토큰은 정가의 약 1/10 값이다. RAG나 에이전트처럼 긴 컨텍스트를 매번 실어 보내는 워크로드면 체감 절감폭이 크다.
문제는, 캐싱은 켜기만 하면 되는 게 아니라 조용히 안 먹는다는 점이다.
캐싱은 "프리픽스 매칭"이다
이것만 이해하면 절반은 끝이다.
요청은 tools → system → messages 순서로 이어붙여진다. 캐시는 이 이어붙인 바이트열의 앞에서부터 일치하는 구간만 재사용한다. 앞부분 어디든 1바이트라도 바뀌면, 그 지점 이후는 전부 캐시 미스다.
[tools][system][messages...]
↑ 여기서 한 글자 바뀌면
↑ 이 뒤로 전부 다시 full price
그래서 설계 원칙은 하나로 정리된다.
안 변하는 걸 앞에, 매 요청 바뀌는 걸 뒤에.
- 앞: 고정된 시스템 프롬프트, 항상 같은 순서의 도구 목록, 큰 문서 컨텍스트
- 뒤: 타임스탬프, 요청 ID, 사용자 질문, 세션별 값
캐시 중단점(cache_control)은 "여기까지 캐시해줘" 표시다. 그 뒤에 변동 요소를 두면 된다.
캐시가 조용히 깨지는 5가지 이유
로그에 에러가 안 뜬다. 그냥 비용이 안 줄어들 뿐이다.
1. 시스템 프롬프트에 현재 시각을 넣는다
// 캐시 절대 안 먹음 — 매 요청 system 프리픽스가 달라진다
system: `너는 어시스턴트다. 현재 시각: ${new Date().toISOString()}`
시각이 필요하면 시스템 프롬프트 맨 앞이 아니라, 캐시 중단점 뒤쪽 메시지에 넣는다.
2. JSON을 직렬화할 때 키 순서가 들쭉날쭉
도구 정의나 컨텍스트를 객체에서 JSON.stringify로 만들면, 키 순서가 요청마다 다를 수 있다. 바이트열이 달라지면 캐시 미스다. 직렬화는 키를 정렬해서 결정적으로.
3. 도구 목록이 요청마다 바뀐다
조건에 따라 도구를 넣었다 뺐다 하면 tools 블록이 흔들리고, 그 뒤 system·messages까지 전부 캐시가 날아간다. 도구 세트는 고정하고, 쓸 수 없는 도구는 프롬프트로 통제하는 게 낫다.
4. 대화 중간에 시스템 프롬프트를 수정한다
멀티턴에서 "이제 간결 모드" 같은 지시를 top-level system에 덧붙이면 캐시된 프리픽스가 통째로 무효화된다. 최신 모델은 이런 운영 지시를 messages 배열에 {role: "system"}으로 뒤에 붙일 수 있다 — 캐시된 앞부분을 안 건드린다.
5. effort나 모델을 중간에 바꾼다
캐시는 모델 단위로 잡힌다. 대화 도중 모델을 갈아타면 캐시 재사용이 안 된다. "싼 모델 → 비싼 모델 캐스케이드"가 캐시 관점에선 손해일 수 있는 이유다. 대체로 한 모델에서 effort를 조절하는 게 캐시도 지키고 관리도 단순하다.
확인: cache_read 토큰을 봐라
응답 usage에 세 값이 있다.
response.usage.cache_creation_input_tokens // 캐시에 쓴 토큰 (정가 약 1.25배)
response.usage.cache_read_input_tokens // 캐시에서 읽은 토큰 (정가 약 0.1배)
response.usage.input_tokens // 캐시 못 탄 토큰 (정가)
같은 프리픽스로 요청을 반복하는데 cache_read_input_tokens가 계속 0이면, 위 5가지 중 하나가 작동 중이다. 로그에 이 값을 찍어두고 몇 요청만 관찰하면 바로 보인다.
순서: 공짜 레버부터
비용 최적화는 이 순서로 간다.
- 캐싱 (품질 영향 0)
- 입력 토큰 위생 — 안 쓰는 컨텍스트 안 싣기, 히스토리 정리
- 출력 토큰 위생 — 장황한 응답 줄이는 프롬프트
- 배치 API — 실시간 아니어도 되는 작업은 50% 할인
- 그 다음에야 effort 조절, 모델 선택 같은 트레이드오프
캐싱으로 얼마 빠지는지 측정하기 전에 모델부터 내리는 건 순서가 틀렸다.
정리
LLM API 비용의 첫 레버는 프롬프트 캐싱이고, 핵심은 "프리픽스 매칭 — 앞부분이 안 변해야 한다"는 것 하나다. 시각·요청 ID·가변 도구 목록을 프리픽스에 넣지 말고, cache_read_input_tokens로 실제로 먹는지 확인하라.
AI·LLM 기능을 서비스에 붙이거나 비용 구조를 잡는 작업이 필요하면 AI & Agentic Solution을 참고하면 된다. 프롬프트 엔지니어링과 LLM API 연동 기초는 AI 교육 섹션에 정리해뒀다.