Prompt Caching과 KV 캐시
KV 캐시의 원리
섹션 제목: “KV 캐시의 원리”트랜스포머 모델은 입력 시퀀스의 각 토큰에 대해 키(Key)와 값(Value) 행렬을 계산한다. 이것이 어텐션 메커니즘의 KV 행렬이다. 동일한 토큰 시퀀스에 대해 이 행렬을 매번 재계산하는 것은 낭비다. **KV 캐시(KV cache)**는 이 행렬을 저장해 두고, 다음 요청에서 같은 프리픽스(prefix)가 등장하면 재계산 없이 재사용한다.
핵심 조건이 있다. 프리픽스가 완전히 동일해야 한다. 프리픽스의 첫 토큰부터 마지막 토큰까지 이전 요청과 정확히 일치해야만 캐시가 히트한다. 중간에 토큰 하나라도 다르면 그 위치부터 캐시가 무효화된다.
에이전트 루프에서 이것은 중요한 설계 원칙을 시사한다. 변하지 않는 내용(시스템 프롬프트, 도구 정의)은 항상 앞에, 변하는 내용(대화 히스토리, 도구 결과)은 뒤에 배치해야 한다.
Anthropic 프롬프트 캐싱 비용 구조
섹션 제목: “Anthropic 프롬프트 캐싱 비용 구조”Anthropic은 프롬프트 캐싱을 명시적인 API 기능으로 제공한다. 비용 구조는 다음과 같다.
| 캐시 상태 | 가격 |
|---|---|
| 캐시 쓰기(cache write) | 기본 입력 토큰 가격의 약 25% 프리미엄 |
| 캐시 읽기(cache hit) | 기본 입력 토큰 가격의 약 10% (90% 할인) |
| 캐시 미스(cache miss) | 기본 입력 토큰 가격 100% |
첫 번째 요청에서는 캐시 쓰기 프리미엄이 붙는다. 두 번째 요청부터 캐시 히트 가격(10%)이 적용된다. 따라서 2회 이상 히트하면 손익분기를 넘어 비용 절감이 시작된다. 루프에서 시스템 프롬프트가 매 이터레이션마다 재사용된다면 — 10번 루프면 10번 히트 — 시스템 프롬프트 비용이 사실상 거의 사라진다.
구체적으로 계산하면: 시스템 프롬프트 2000 토큰, 기본 입력가 P라 할 때, 쓰기 비용 = 2000 × 1.25P, 2회부터 히트 비용 = 2000 × 0.1P. 3번째 요청부터 누적 절감이 시작되고, 루프가 길수록 절감폭이 커진다.
루프 내 캐시 히트율 최적화
섹션 제목: “루프 내 캐시 히트율 최적화”┌─────────────────────────────────────────────────────────────────┐│ 캐시 히트율을 높이는 프롬프트 구조 │├───────────────────┬─────────────────────────────────────────────┤│ 안정적 (앞에 배치) │ 변동적 (뒤에 배치) │├───────────────────┼─────────────────────────────────────────────┤│ 시스템 프롬프트 │ 현재 대화 메시지 ││ 도구 정의 목록 │ 도구 실행 결과 ││ 코드베이스 파일 │ 에이전트 내부 추론 (scratchpad) ││ 기준 명세(spec) │ 이터레이션별 관찰 내용 │└───────────────────┴─────────────────────────────────────────────┘Anthropic의 cache_control 마커를 사용하면 어디까지 캐시할지 명시적으로 지정할 수 있다.
개념 이해용 의사 코드이며 실제 API와 다를 수 있습니다.
def build_cached_messages( system_prompt: str, tools: list[dict], conversation_history: list[dict],) -> tuple[list[dict], list[dict]]: """캐시 가능한 정적 부분과 동적 부분을 분리해 메시지를 구성한다."""
# 시스템 프롬프트: 캐시 마커 적용 system = [ { "type": "text", "text": system_prompt, "cache_control": {"type": "ephemeral"}, # 프리픽스 캐시 포인트 } ]
# 도구 정의: 정적이므로 시스템 뒤에 두되 변경 없이 유지 # (도구 목록이 바뀌면 이 지점 이후 캐시 무효화됨)
# 대화 히스토리: 동적, 캐시 마커 없음 messages = conversation_history # 매 이터레이션마다 추가됨
return system, messages캐시 무효화의 위험
섹션 제목: “캐시 무효화의 위험”캐시 히트율을 망가뜨리는 흔한 실수들이 있다.
도구 목록 변경: 이터레이션 중에 도구를 동적으로 추가하거나 제거하면 도구 정의 이후의 모든 캐시가 무효화된다. 루프 시작 전 도구 목록을 고정하고, 루프 중에는 변경하지 않아야 한다.
MCP 서버 재연결: MCP(모델 컨텍스트 프로토콜) 서버가 루프 중에 새로운 도구를 노출하면 도구 정의가 바뀌어 캐시가 깨진다. MCP 세션을 루프 전에 초기화하고 고정하는 패턴이 권장된다.
타임스탬프 삽입: 시스템 프롬프트에 현재 시각을 동적으로 넣으면 매 요청마다 프리픽스가 달라져 캐시가 영구히 미스된다. 동적 정보는 시스템 프롬프트가 아닌 대화 메시지에 포함시켜야 한다.
모델 버전 변경: 다른 모델로 요청을 보내면 그 모델의 KV 캐시는 비어 있다. 루프 전체에서 동일한 모델을 사용해야 한다.
Codex 루프의 캐싱 패턴
섹션 제목: “Codex 루프의 캐싱 패턴”OpenAI의 Codex 루프 구현에서 유사한 원칙이 적용된다. 코드베이스의 주요 파일을 시스템 프롬프트 앞부분에 배치하고 이 부분은 루프 내내 변경하지 않는다. 대화 히스토리와 테스트 출력은 뒤쪽에 누적한다. 이 패턴으로 코드 편집 루프의 비용을 의미 있게 절감할 수 있다. 초기 파일 로딩 비용이 사실상 한 번으로 줄어들기 때문이다.
캐싱과 컨팩션의 상호작용
섹션 제목: “캐싱과 컨팩션의 상호작용”캐싱과 5-3 챕터에서 다룬 컨팩션(context compaction)은 상충되는 측면이 있다. 컨팩션은 컨텍스트를 요약해 교체하는데, 이 과정에서 캐시된 프리픽스가 달라질 수 있다. 실용적인 접근은 시스템 프롬프트와 도구 정의는 캐싱으로 보호하고, 대화 히스토리만 컨팩션 대상으로 삼는 것이다. 이렇게 하면 두 기술의 이점을 모두 유지할 수 있다.
다음 챕터에서는 비용 절감의 또 다른 차원인 **모델 라우팅(model routing)**을 다룬다. 내부 루프의 단순한 작업에 값비싼 프런티어 모델을 쓰지 않고, 작업 복잡도에 따라 모델을 선택하는 방법을 살펴본다.
참고 자료
- Anthropic — Prompt caching — 접속 2026-06-30
- OpenAI — Unrolling the Codex agent loop — 접속 2026-06-30