프리픽스 캐싱(Prefix Caching): LLM 추론 비용을 절반으로 줄이는 KV 캐시 재사용의 원리와 운영
왜 같은 프롬프트를 매번 다시 처리해야 하는가
프로덕션 LLM 서비스를 운영하다 보면 비슷한 패턴이 반복된다. 수천 개의 요청이 거의 동일한 앞부분 — 시스템 프롬프트, 소수의 예시 문서, few-shot 예제 — 을 공유한다. 그런데 기본 설정에서는 이 긴 공통 구간을 요청마다 다시 프리필(prefill)한다.
이 낭비가 상당하다. 1만 토큰짜리 공통 프리픽스를 초당 100개의 요청이 처리한다면, 매초 100만 토큰의 프리필이 반복된다. 토큰 하나를 프리필하는 비용은 디코드의 10~20배에 달한다. 여기서 프리픽스 캐싱이 등장한다.
프리픽스 캐싱(Prefix Caching) 은 이미 계산된 KV 활성화(Attention Key-Value 행렬)를 GPU 메모리나 CPU DRAM에 보관해 두고, 동일한 토큰 프리픽스가 다시 들어오면 재계산 없이 재사용하는 기술이다.
KV 캐시와 프리필의 비용 구조
트랜스포머의 두 가지 연산
트랜스포머 모델은 요청을 처리할 때 두 단계로 분리된다.
| 단계 | 목적 | 비용 특성 |
|---|---|---|
| 프리필(Prefill) | 입력 토큰 전체를 처음 처리해 KV 행렬 생성 | 컴퓨트 집약형 (FLOP 지배) |
| 디코드(Decode) | 토큰 하나씩 생성 | 메모리 대역폭 집약형 |
프리필에서 계산된 KV 행렬(Key-Value Cache)은 디코드 전체 과정에서 재사용된다. 이 구조 덕분에 "공통 프리픽스의 KV 행렬을 저장해 두면 다음 요청의 프리필 일부를 건너뛸 수 있다"는 아이디어가 자연스럽게 도출된다.
프리필 비용의 실제 규모
Llama-3-70B(FP8)를 H100 한 대에서 돌릴 때, 4096 토큰의 프리필은 약 750ms가 걸린다. 같은 길이를 디코드로 하면 5초 이상이다. 그러나 중요한 것은 프리필이 모든 토큰을 병렬로 처리하므로 절대 시간은 짧더라도 GPU 메모리 대역폭과 컴퓨트를 순간적으로 포화시킨다.
공통 프리픽스 2000 토큰이 있고, 각 요청의 고유 부분이 평균 500 토큰이라면, 캐시 히트 시 80% 프리필 절약이 가능하다.
프리픽스 캐싱의 동작 원리
트리 기반 매칭의 핵심
프리픽스 캐싱은 단순한 "키-값 저장"이 아니다. 토큰 시퀀스를 기수 트리(Radix Tree)로 인덱싱해 최장 공통 프리픽스를 O(L) 시간에 찾는다. 여기서 L은 입력 토큰 수다.
새 요청이 들어오면 서빙 엔진은 트리를 순회해 공유된 접두사의 길이를 확인한다. 매칭된 길이만큼 KV 행렬을 그대로 가져오고, 나머지만 실제로 프리필한다.
블록 경계 조건: 실제 구현에서 KV 캐시는 고정 크기 블록(예: 16 또는 32 토큰)으로 관리된다. 최장 공통 프리픽스는 가장 가까운 블록 경계에서 잘린다. 정확히 같은 토큰이라도 블록 경계 바깥 부분은 캐시 미스로 처리된다.
API 레벨 캐싱
클라우드 LLM API는 각자의 방식으로 프리픽스 캐싱을 노출한다.
Anthropic Prompt Caching
Anthropic은 명시적 캐시 제어를 제공한다. 프롬프트의 특정 구간 끝에 cache_control: {"type": "ephemeral"} 마커를 붙이면 해당 지점까지의 KV가 서버 측에 보관된다.
최소 캐시 블록 크기: 1,024 토큰
최대 캐시 중단점(breakpoint): 4개
캐시 수명: 마지막 히트로부터 5분 (beta: 1시간)
캐시 읽기 비용: 원래 입력 토큰 가격의 0.1× (90% 절감)
캐시 쓰기 비용: 원래 입력 토큰 가격의 1.25×캐시 쓰기는 처음 한 번 비싸게 지불하고, 이후 조회는 90% 절감된다. 동일 프롬프트 접두사가 반복될수록 손익분기점을 빠르게 넘어선다.
OpenAI Prompt Caching
OpenAI는 자동 캐싱을 적용한다. 프롬프트에서 1,024 토큰 이상인 접두사가 최근에 다른 요청에서도 나타났다면 자동으로 캐시 히트를 적용한다.
최소 캐시 블록 크기: 1,024 토큰 (자동 감지)
별도 API 변경: 없음
캐시 읽기 비용: 원래 입력 토큰 가격의 0.5× (50% 절감)
캐시 명중 여부 확인: usage.prompt_tokens_details.cached_tokens 필드비교
| 속성 | Anthropic | OpenAI |
|---|---|---|
| 캐시 제어 방식 | 명시적 (cache_control 마커) | 자동 |
| 절감률 | 90% (캐시 읽기) | 50% (캐시 읽기) |
| 최소 토큰 | 1,024 | 1,024 |
| 캐시 수명 | 5분 (기본) ~ 1시간 | 비공개 |
| 복수 중단점 | 최대 4개 지원 | 미지원 |
서빙 엔진 레벨 캐싱
자체 호스팅 환경에서는 vLLM과 SGLang이 프리픽스 캐싱을 구현한다.
vLLM Automatic Prefix Caching (APC)
vLLM의 APC는 KV 블록 단위 해시를 사용한다. 각 KV 블록(기본 16 토큰)의 내용을 해시해 블록 테이블에 저장한다. 새 요청이 들어올 때 같은 해시 시퀀스를 앞에서부터 찾아 최장 매칭을 구한다.
vLLM 0.6.0 이후 기본값 활성화:
vllm serve <model> --enable-prefix-caching내부적으로 prefix_caching_enabled=True 시 블록 해시 테이블이 LRU 캐시로 동작한다. GPU HBM이 부족해지면 오래된 캐시 블록을 퇴거(evict)시킨다.
SGLang RadixAttention
SGLang(arXiv:2312.07104)은 RadixAttention이라는 이름으로 KV 캐시를 기수 트리로 구조화한다. vLLM의 해시 방식과 달리 트리 구조 자체를 유지하므로 공통 접두사 탐색이 자연스럽고 분기 지점에서 서로 다른 요청이 같은 KV 블록을 공유하기 쉽다.
--context-length 한도 내에서 트리 노드가 쌓이며, 메모리 압박 시 LRU 정책으로 리프부터 퇴거된다.
PEEK: 대기 큐 인식 캐시 매칭
PEEK(arXiv:2607.02525)는 한 단계 더 나아가, 아직 스케줄되지 않은 대기 큐의 요청들도 트리에 미리 인덱싱한다. 덕분에 스케줄러가 캐시 히트를 최대화하는 순서로 요청을 배치한다. vLLM과 SGLang 두 엔진에서 3.0×, 2.6×의 캐시 히트율 향상을 보고했다(arXiv:2607.02525).
운영 패턴: 캐시를 최대로 활용하는 방법
프롬프트 구성 순서
프리픽스 캐싱이 효과를 내려면 불변 부분이 항상 먼저 나와야 한다.
[권장 순서]
┌─────────────────────────────┐ ← 항상 첫 번째, 절대 변하지 않음
│ 시스템 프롬프트 │ (역할, 페르소나, 지침)
├─────────────────────────────┤ ← 두 번째, 세션 전반에 공유
│ 공통 문서 / 배경 지식 │ (RAG 검색 결과, 긴 컨텍스트)
├─────────────────────────────┤ ← 세 번째, 대화 이력
│ 이전 대화 내용 │
├─────────────────────────────┤ ← 마지막, 매번 바뀌는 부분
│ 현재 사용자 메시지 │
└─────────────────────────────┘
[잘못된 순서의 예]
현재 날짜/시간을 시스템 프롬프트 상단에 삽입
→ 매 요청마다 앞부분이 달라져 캐시 히트 전무RAG(검색 증강 생성) 에서의 활용
검색 결과 문서가 여러 요청에 걸쳐 반복 등장하는 경우, 문서를 프롬프트 앞쪽에 고정하고 질문을 뒤쪽에 붙이면 문서 KV를 공유할 수 있다.
단, 검색 결과 순서가 요청마다 달라지면 캐시 미스가 된다. 일관된 문서 순서를 유지하는 것이 중요하다.
멀티턴 대화에서의 활용
멀티턴 대화는 이전 대화 이력이 자연스럽게 공통 프리픽스가 된다. [시스템 프롬프트 + 턴1 + 턴2 + ... + 현재 질문] 구조에서 시스템 프롬프트와 이전 턴들이 캐시되므로 턴이 쌓일수록 절감 효과가 커진다.
캐시 히트율 측정
Anthropic API
응답 헤더의 usage 필드에 캐시 정보가 포함된다.
"usage": {
"input_tokens": 512,
"cache_creation_input_tokens": 8000,
"cache_read_input_tokens": 7500
}cache_read_input_tokens / (input_tokens + cache_read_input_tokens)를 계산하면 유효 캐시 히트율을 구할 수 있다.
vLLM 내장 지표
vLLM은 /metrics 엔드포인트에서 Prometheus 메트릭을 노출한다.
vllm:gpu_prefix_cache_hit_rate # GPU HBM 캐시 히트율
vllm:cpu_prefix_cache_hit_rate # CPU DRAM 캐시 히트율 (CPU offload 활성화 시)
vllm:num_preemptions_total # 캐시 퇴거로 인한 선점 횟수현실적인 히트율 기대값
| 워크로드 유형 | 캐시 히트율 범위 |
|---|---|
| 고정 시스템 프롬프트 + 짧은 사용자 질문 | 70~90% |
| 멀티턴 대화 (평균 10턴) | 50~75% |
| 다양한 RAG 문서, 짧은 대화 | 20~50% |
| 모든 요청이 완전히 고유한 경우 | 0% |
한계와 주의사항
모델·버전·정밀도 구분: 동일한 토큰 시퀀스라도 모델이나 양자화 형식(FP16 vs FP8)이 다르면 KV 행렬이 달라 공유할 수 없다. 모델 버전 업그레이드 시 기존 캐시는 모두 무효화된다.
온도(temperature) 의존성: vLLM/SGLang 엔진 레벨 캐싱은 온도와 무관하게 동작한다(KV 행렬은 온도의 영향을 받지 않는다). 반면 일부 API는 temperature=0일 때만 캐싱을 보장한다.
메모리 용량 제약: 캐시는 GPU HBM 안에서 디코드 KV 캐시와 공간을 경쟁한다. 활성 요청 배치가 클수록 프리픽스 캐시가 퇴거되는 빈도가 높아진다.
보안 격리: 멀티테넌트 환경에서 서로 다른 사용자의 KV 캐시가 섞이면 정보 유출 위험이 있다. 대부분의 상용 API는 캐시를 동일 API 키 안에서만 공유한다. 자체 호스팅 시 테넌트 격리 정책을 명시적으로 설계해야 한다.
요점 정리
프리픽스 캐싱은 서빙 스택을 바꾸지 않고도 LLM 운영 비용을 의미 있게 줄일 수 있는 몇 안 되는 수단이다.
핵심 원칙 세 가지:
- 불변 부분을 앞에 놓는다 — 시스템 프롬프트, 공통 문서, 이전 대화 이력 순으로 구성한다.
- 캐시 히트율을 측정한다 — API 응답의
cache_read_tokens, vLLM의gpu_prefix_cache_hit_rate를 지속 추적한다. - 캐시와 활성 배치 간 메모리 균형을 확인한다 — 캐시가 너무 크면 활성 요청 KV가 퇴거되어 선점이 증가한다.
RAG 파이프라인, 멀티턴 에이전트, 고정 시스템 프롬프트를 쓰는 애플리케이션이라면 프리픽스 캐싱의 효과가 특히 크다. 반복 패턴이 없는 단발성 요청 중심 워크로드에서는 투자 가치가 낮다.
References
- Anthropic Prompt Caching 공식 문서: https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching
- OpenAI Prompt Caching 공식 문서: https://platform.openai.com/docs/guides/prompt-caching
- SGLang RadixAttention 논문: arXiv:2312.07104 — "Efficiently Programming Large Language Models using SGLang" (Lianmin Zheng et al., 2023)
- PEEK 논문: arXiv:2607.02525 — "PEEK: Predictive Queue-Informed KV Cache Management for LLM Serving" (2026)
- vLLM Automatic Prefix Caching 문서: https://docs.vllm.ai/en/latest/automatic_prefix_caching/apc.html
- vLLM PagedAttention 논문: arXiv:2309.06180 — "Efficient Memory Management for Large Language Model Serving with PagedAttention" (Woosuk Kwon et al., SOSP 2023)
- Zhiqiang Xie et al., "SGLang: Efficient Execution of Structured Language Model Programs", NeurIPS 2024
- C²KV: arXiv:2607.17715 — "C²KV: Composable KV Caches for Non-Prefix Reuse" (KDD 2026)