**KV cache(Key-Value 캐시)**는 대규모 언어 모델이 이미 처리한 토큰에 대해 계산한 각 레이어의 Key 및 Value 어텐션 텐서를 저장하는 추론 최적화 기법입니다. 자기회귀 디코딩 중 모델은 매 단계에서 이전의 모든 토큰을 다시 계산하는 대신 저장된 상태를 재사용하므로, 시퀀스가 길어질 때 중복 계산을 줄일 수 있습니다.
호스팅된 API를 호출하든 자체 GPU에서 오픈 웨이트 모델을 실행하든 KV cache는 지연 시간, 메모리 부담, 처리량의 중심에 있습니다. 작동 방식을 이해하면 첫 토큰까지 걸리는 시간과 스트리밍 속도가 다르게 느껴지는 이유, 긴 컨텍스트가 많은 VRAM을 소비하는 이유, API 요청 간 프롬프트 캐싱에 정확히 일치하는 접두사가 필요한 이유를 알 수 있습니다.
KV cache 없이 어텐션은 어떻게 작동할까?
KV cache가 없으면 자기회귀 Transformer는 새로운 AI 모델의 토큰을 하나 생성할 때마다 전체 시퀀스의 어텐션 투영을 처음부터 다시 계산해야 합니다.
각 Transformer 디코더 레이어에서 셀프 어텐션은 입력 토큰의 표현을 세 벡터로 투영합니다.
- Query ($Q$): 관련 컨텍스트를 찾는 현재 위치를 나타냅니다.
- Key ($K$): 각 위치가 Query와의 일치를 위해 제공하는 내용을 나타냅니다.
- Value ($V$): Query와 Key의 내적으로 어텐션 가중치를 계산한 후 집계할 정보를 담습니다.
디코더 전용 언어 모델은 텍스트를 한 번에 한 토큰씩 생성하므로, 토큰 $t+1$을 생성할 때는 최신 토큰의 Query 벡터가 토큰 $1$부터 $t$까지의 Key와 Value를 참조하기만 하면 됩니다. 런타임이 토큰 $t$를 출력한 후 해당 Key와 Value를 버리면, 단계 $t+1$에서는 정확히 같은 $K$ 및 $V$ 텐서를 다시 만들기 위해 접두사의 모든 토큰을 모든 레이어에 다시 통과시켜야 합니다. 프롬프트와 출력이 길어질수록 전체 생성 과정에서 이 반복 작업은 제곱에 비례해 증가합니다.
인과적 어텐션이 KV 캐싱을 가능하게 하는 이유는?
인과적 마스킹은 토큰의 Key와 Value 텐서가 오직 그 앞의 토큰에만 의존하고 나중에 생성되는 토큰에는 의존하지 않도록 보장합니다.
인과적 디코더는 왼쪽에서 오른쪽으로 처리하며, 토큰 $i$가 위치 $j > i$를 참조하지 못하게 막습니다. 정보가 시퀀스에서 앞으로만 흐르기 때문에 다음이 성립합니다.
- 레이어 $l$에서 토큰 $i$의 표현은 토큰 $1 \dots i$가 처리되면 완전히 고정됩니다.
- 시퀀스 끝에 토큰 $i+1$을 추가해도 어떤 레이어에서든 위치 $1 \dots i$의 은닉 상태, Key, Value는 바뀌지 않습니다.
- 런타임은 새로 계산한 $K_{i+1}$ 및 $V_{i+1}$ 벡터를 레이어별 버퍼인 KV cache에 추가하고, 다음 디코딩 단계에는 가장 새로운 토큰 하나만 전달할 수 있습니다.
Hugging Face Transformers KV cache 가이드와 Transformers 캐시 아키텍처 개요에 설명된 것처럼, 캐싱은 각 디코딩 단계를 전체 시퀀스 처리에서 이전 Key와 Value를 메모리에서 읽는 단일 토큰의 점진적 업데이트로 바꿉니다.
Prefill과 Decode는 KV cache를 어떻게 다르게 사용할까?
LLM 추론은 Prefill과 Decode라는 두 개의 구분된 단계로 나뉩니다. 두 단계는 KV cache와 근본적으로 다르게 상호작용하며 서로 다른 하드웨어 병목에 부딪힙니다.
| 추론 단계 | KV cache에서 일어나는 일 | 주요 하드웨어 병목 | 사용자가 보는 지표 |
|---|---|---|---|
| Prefill(프롬프트 처리) | 모든 프롬프트 토큰의 $K$와 $V$를 병렬로 계산하고 각 레이어의 초기 캐시를 채웁니다. | 연산량에 의해 제한됨(전체 프롬프트에 걸친 대규모 행렬 곱셈). | 첫 토큰까지 걸리는 시간(TTFT). |
| Decode(토큰 생성) | 한 번에 새 토큰 하나의 $Q$, $K$, $V$를 계산하고 새 $K$/$V$ 항목을 추가한 뒤 캐시된 전체 기록을 읽습니다. | 메모리 대역폭에 의해 제한됨(각 단계에서 모델 가중치와 늘어나는 KV 상태를 불러옴). | 토큰 간 지연 시간 / 출력 스트리밍 속도. |
NVIDIA의 Prefill, Decode, KV 캐싱에 관한 기술 설명에 따르면 Prefill 단계는 모든 입력 토큰을 동시에 처리합니다. 전체 프롬프트를 미리 알 수 있으므로 GPU는 투영을 밀집 행렬 연산으로 묶어 연산 장치를 충분히 활용하고 한 번에 KV cache를 채울 수 있습니다. 검색 증강 생성(RAG) 파이프라인의 여러 문서로 구성된 컨텍스트처럼 긴 프롬프트는 Prefill 작업량을 직접 늘리고 첫 토큰까지 걸리는 시간을 증가시킵니다.
첫 출력 토큰이 나오면 추론은 Decode 단계에 들어갑니다. 각 단계는 시퀀스당 새 토큰 하나만 처리하고, 그 Key와 Value 벡터를 캐시에 추가하며, 어텐션을 계산하기 위해 이전에 저장한 모든 $K$와 $V$ 텐서를 GPU 고대역폭 메모리(HBM)에서 읽습니다. 단계별 연산 집약도는 낮은 반면 메모리 읽기량은 시퀀스 길이와 배치 크기에 따라 증가하므로, 디코딩은 곧 순수 연산 FLOPs보다 메모리 대역폭과 사용 가능한 VRAM의 제약을 받습니다.
KV cache는 메모리를 얼마나 사용할까?
KV cache의 메모리 사용량은 시퀀스 길이, 배치 크기, 레이어 수, Key-Value 어텐션 헤드 수에 비례해 증가합니다.
표준 Transformer 캐시에서 쓰는 텐서 형태를 기준으로 하면, 각 레이어는 배치, KV 헤드, 시퀀스 길이, 헤드 차원에 걸친 Key 텐서 하나와 Value 텐서 하나를 저장합니다. 이를 바탕으로 시퀀스당 캐시 크기를 다음과 같이 표현할 수 있습니다.
bytes ≈ 2 × layers × kv_heads × head_dim × seq_len × bytes_per_element
이 공식의 각 항은 모델 설계자와 추론 엔지니어가 메모리를 관리하기 위해 조절하는 요소입니다.
- 2: Key(K)와 Value(V) 텐서를 모두 저장하는 것을 반영합니다.
- layers: 모델의 Transformer 디코더 블록 총수입니다.
- kv_heads와 head_dim: 레이어당 Key/Value 어텐션 헤드 수와 각 헤드의 차원입니다.
- seq_len: 캐시된 총 토큰 수로, 프롬프트 토큰과 지금까지 생성된 토큰을 합한 값입니다.
- bytes_per_element: 저장된 텐서의 수치 정밀도입니다. 예를 들어 FP16/BF16은 2바이트, 8비트 형식은 1바이트이며 NVFP4와 같은 4비트 KV cache 양자화는 더 작은 바이트 단위의 공간을 사용합니다.
kv_heads 줄이기: MHA, MQA, GQA
기존 Multi-Head Attention(MHA)에서는 각 Query 헤드가 전용 Key 헤드와 Value 헤드를 가집니다(kv_heads = query_heads). 컨텍스트 윈도와 배치 크기가 커지면서 헤드마다 별도의 K 및 V 투영을 저장하는 것이 주요 메모리 병목이 되었습니다.
두 가지 아키텍처 변경은 위 공식의 kv_heads를 직접 줄입니다.
- Multi-Query Attention(MQA): Noam Shazeer가 Fast Transformer Decoding: One Write-Head is All You Need (arXiv:1911.02150)에서 소개한 MQA는 한 레이어의 모든 Query 헤드가 하나의 Key 헤드와 하나의 Value 헤드를 공유합니다(
kv_heads = 1). 이 방식은 디코딩 중 KV cache 크기와 메모리 대역폭 트래픽을 크게 줄입니다. - Grouped-Query Attention(GQA): Ainslie 등이 GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints (arXiv:2305.13245)에서 소개한 GQA는 Query 헤드를 G개 그룹으로 나누고 각 그룹이 하나의 Key 헤드와 Value 헤드를 공유합니다. GQA는 MHA와 MQA의 중간에 위치하며, Multi-Head Attention에 가까운 품질을 유지하면서 그룹 감소에 비례해 KV cache 사용량과 필요한 대역폭을 줄입니다.
GQA와 함께 추론 엔진은 캐시된 K와 V 텐서를 더 낮은 정밀도의 형식으로 양자화해 bytes_per_element도 줄입니다. 이를 통해 더 긴 컨텍스트나 더 큰 동시 배치를 GPU 메모리에 수용할 수 있습니다.
서빙 엔진은 대규모 KV cache 메모리를 어떻게 관리할까?
운영 환경의 서빙 엔진은 연속된 텐서를 고정 크기 블록으로 나누어 KV cache 메모리를 관리합니다. 이렇게 하면 GPU가 VRAM을 낭비하지 않고 더 많은 동시 요청을 수용할 수 있습니다.
단순한 구현에서는 서빙 런타임이 각 요청의 최대 가능 시퀀스 길이에 맞춰 연속된 GPU 메모리 영역을 미리 할당합니다. 실제 출력 길이는 미리 알 수 없으므로 사전 할당은 심각한 내부 및 외부 메모리 단편화를 초래합니다. 예약된 공간은 사용되지 않는 반면 새로운 요청은 실행이 차단됩니다.
Kwon 등은 vLLM의 핵심 메커니즘인 PagedAttention을 Efficient Memory Management for Large Language Model Serving with PagedAttention (arXiv:2309.06180)에서 제시해 이 병목을 해결했습니다. 운영체제의 가상 메모리와 페이징에서 영감을 받았습니다.
- 비연속 고정 크기 블록: PagedAttention은 각 요청의 KV cache를 일정 수의 토큰에 대한 Key와 Value를 담는 고정 크기 블록으로 나누고, 논리 블록을 물리 블록에 대응시키는 테이블을 사용합니다.
- 필요에 따른 할당: 새 물리 블록은 새 토큰이 생성될 때만 할당되므로 내부 단편화가 사실상 사라집니다.
- 블록 단위 접두사 공유: 여러 요청이 시스템 프롬프트나 공통 few-shot 예제처럼 동일한 프롬프트 접두사를 공유하면, 논리 블록 테이블이 메모리의 같은 물리 KV 블록을 가리킬 수 있습니다. 시퀀스가 갈라질 때만 쓰기 시 복사를 사용합니다.
vLLM 논문의 평가(arXiv:2309.06180)에서 이 페이지 기반 KV 관리는 같은 GPU 메모리에 훨씬 큰 배치를 수용하여 비슷한 지연 시간에서 FasterTransformer와 Orca보다 2–4× 높은 처리량을 달성했습니다. vLLM과 NVIDIA TensorRT-LLM의 KV cache 재사용 시스템을 포함한 최신 서빙 스택은 블록 기반 KV 관리로 공통 접두사를 재사용하고 동시 처리량을 극대화합니다.
KV cache와 프롬프트 캐싱의 차이는?
KV cache는 디코딩 단계 사이에서 어텐션 상태를 재사용하는 요청별 기반 추론 메커니즘입니다. 반면 프롬프트 캐싱은 동일한 접두사를 공유하는 별도 호출 사이에서 해당 KV 블록을 보존하고 재사용하는 요청 간 서빙 및 API 기능입니다.
개발자는 지연 시간과 비용을 최적화할 때 두 용어를 자주 접하므로, 한 번의 생성 호출 안에서 일어나는 일과 여러 API 요청 사이에서 일어나는 일을 구분하면 도움이 됩니다.
| 구분 | KV cache(요청 내 디코딩) | 프롬프트 캐싱(요청 간 접두사 재사용) |
|---|---|---|
| 범위 | 단일 요청의 토큰 생성 단계 사이. | 짧은 보존 기간 내 여러 요청. |
| 방지하는 작업 | 새 토큰을 디코딩할 때마다 같은 응답의 이전 토큰을 다시 계산하는 작업. | 별도 호출에서 반복되는 정적 프롬프트 접두사에 대해 Prefill을 다시 실행하는 작업. |
| 수명 주기 | Prefill 중 생성되고 Decode 중 추가되며 요청이 완료되면 해제되거나 제거됩니다. | 이후 호출을 위해 제거 정책과 TTL을 적용해 블록 스토리지(GPU 또는 호스트 메모리)에 보존됩니다. |
| 청구 내역 표시 | 표준 추론에 포함되며 별도 항목으로 청구되지 않습니다. | API 제공업체가 캐시된 입력 토큰의 할인 요금과 낮은 TTFT로 제공하는 경우가 많습니다. |
인과적 어텐션은 프롬프트 캐싱에 엄격한 규칙을 부과합니다. 접두사는 첫 번째 토큰부터 정확히 일치해야 합니다. 각 토큰의 Key와 Value 텐서는 앞선 토큰의 정확한 시퀀스에 의존하므로 프롬프트 맨 앞의 타임스탬프, 사용자 ID, 지시 중 하나만 바꿔도 이후 모든 토큰의 캐시된 $K$와 $V$ 상태가 무효화됩니다.
제공업체별 보존 규칙, 최소 토큰 기준, 할인 구조는 프롬프트 캐싱의 개념과 제공업체의 가격 책정에 관한 전체 가이드를 참고하세요.
개발자와 팀을 위한 실용적인 핵심 사항
KV cache의 작동 방식을 이해하면 더 나은 프롬프트 구조, 안정적인 지연 시간, 낮은 인프라 비용으로 직결됩니다.
- 정적 콘텐츠를 프롬프트 맨 앞에 배치하세요: 시스템 지시, 도구 스키마, 공통 참조 문서를 동적 사용자 입력이나 요청별 메타데이터보다 앞에 둡니다. 동일한 접두사가 있으면 호스팅 API와 vLLM 또는 TensorRT-LLM 같은 로컬 엔진 모두 중복 Prefill을 실행하는 대신 캐시된 KV 블록을 재사용할 수 있습니다.
- 자체 호스팅 GPU에서 컨텍스트 길이가 동시 처리에 미치는 영향을 살펴보세요: KV cache 크기는
seq_len에 비례해 증가하므로 평균 컨텍스트 길이가 두 배가 되면 GPU 메모리에 동시에 담을 수 있는 요청 수는 절반이 됩니다. 자체 호스팅할 오픈 웨이트 모델을 선택할 때 Grouped-Query Attention(GQA)을 사용하는 아키텍처와 페이지 기반 KV 할당 및 KV 양자화를 지원하는 런타임을 우선 고려하세요. - 컨텍스트 윈도가 커도 불필요한 컨텍스트를 줄이세요: 매 턴마다 긴 기록을 입력하면 Prefill 지연 시간과 KV 메모리 부담이 커지고 토큰 비용이 증가합니다. 접두사 캐싱을 대상에 맞춘 검색 및 주기적인 요약과 결합하세요. 이 핵심 전략은 AI API 비용 절감 방법 가이드와 AI API 가격 비교에서 다룹니다.
자주 묻는 질문
KV cache가 모델의 출력 품질을 바꾸나요?
FP16 또는 BF16처럼 모델 고유의 추론 정밀도로 유지되는 표준 KV cache는 매 단계에서 접두사를 다시 계산하는 것과 수학적으로 같습니다. 인과적 마스킹이 미래 토큰이 과거의 Key와 Value 벡터를 바꾸지 못하게 하기 때문입니다. 품질과의 절충은 8비트 또는 4비트 압축 같은 손실 KV cache 양자화를 적용하거나 메모리를 절약하기 위해 오래된 토큰을 제거할 때만 발생합니다.
시작 부분이 바뀌면 KV cache가 프롬프트 중간의 토큰을 재사용할 수 없는 이유는 무엇인가요?
인과적 Transformer에서 각 토큰의 표현은 시퀀스의 모든 이전 토큰에 대한 어텐션을 포함합니다. 프롬프트의 첫 열 토큰이 바뀌면 열한 번째 토큰부터 은닉 상태와 그에 따른 Key 및 Value 투영도 바뀝니다. 이 상태는 앞에 있는 정확한 접두사에 의존하므로 서빙 엔진은 접두사가 처음부터 일치할 때만 요청 간에 캐시된 KV 블록을 재사용할 수 있습니다.
KV cache에 모델 가중치가 저장되나요?
아니요. 모델 가중치는 학습 중 얻은 정적 매개변수로 GPU가 처리하는 모든 요청에서 공유됩니다. KV cache는 동적이고 요청별로 다른 활성화 텐서, 즉 현재 컨텍스트에 있는 토큰의 Key 및 Value 투영을 담습니다. 추론 중 전체 GPU 메모리에는 정적 모델 가중치, 임시 런타임 활성화, 배치의 모든 활성 요청에 대한 동적 KV cache가 들어가야 합니다.
동시 요청이 많으면 출력 토큰을 더 생성하는 속도가 느려지는 이유는 무엇인가요?
Decode 단계에서는 새 토큰을 생성하는 매 단계마다 배치의 모든 활성 요청에서 이전 토큰 전체에 대해 저장된 Key와 Value 텐서를 읽어야 합니다. 시퀀스 길이와 동시 요청 수가 늘어나면 각 단계에서 GPU 메모리로부터 전송되는 KV 데이터 양이 증가합니다. 이로 인해 메모리 대역폭이 포화되어 스케줄러가 배치 크기를 제한하거나 메모리 읽기를 기다려야 합니다.
출처
- Hugging Face Transformers — KV Cache Strategies and Optimization
- Hugging Face Transformers — Cache Explanation and Architecture
- NVIDIA Technical Blog — Optimizing Inference for Long Context and Large Batch Sizes with NVFP4 KV Cache
- Kwon et al. (2023) — Efficient Memory Management for Large Language Model Serving with PagedAttention (arXiv:2309.06180)
- Ainslie et al. (2023) — GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints (arXiv:2305.13245)
- Shazeer (2019) — Fast Transformer Decoding: One Write-Head is All You Need (arXiv:1911.02150)
- NVIDIA TensorRT-LLM Documentation — KV Cache System


