Skip to content

Split View: LLM 캐싱의 원리 — 프롬프트 캐싱과 Prefix Cache는 왜 돈을 아껴주는가

|

LLM 캐싱의 원리 — 프롬프트 캐싱과 Prefix Cache는 왜 돈을 아껴주는가

들어가며 — "앞부분이 같으면 싸진다"의 미스터리

LLM API의 프롬프트 캐싱을 처음 보면 이상합니다. 같은 질문을 두 번 하면 싸지는 것이 아니라, 프롬프트의 앞부분이 같으면 싸집니다. 뒷부분이 완전히 달라도 상관없습니다. 심지어 어떤 제공자는 캐시에 "쓰는" 비용을 더 받고, "읽는" 비용은 10분의 1로 깎아줍니다. 이 이상한 가격표는 마케팅이 아니라 트랜스포머 내부의 물리학을 그대로 반영한 것입니다.

이 글은 그 물리학을 바닥부터 올라갑니다. 트랜스포머가 텍스트를 생성할 때 내부에서 무슨 일이 일어나는지, KV 캐시가 무엇이고 왜 프리픽스(앞부분)에만 효력이 있는지, vLLM과 SGLang 같은 서빙 엔진이 이를 어떻게 구현하는지, 그리고 Anthropic·OpenAI의 프롬프트 캐싱을 실전에서 어떻게 설계해야 하는지까지.

1단계 — 추론은 두 국면으로 나뉜다: Prefill과 Decode

트랜스포머 추론에는 성격이 전혀 다른 두 국면이 있습니다.

  • Prefill(프리필) — 입력 프롬프트 전체를 한 번에 처리하는 국면입니다. 프롬프트의 모든 토큰을 병렬로 계산할 수 있어 GPU의 연산 능력을 꽉 채워 씁니다(compute-bound). 첫 토큰이 나오기까지의 지연(TTFT)은 대부분 여기서 결정됩니다.
  • Decode(디코드) — 답변을 토큰 하나씩 생성하는 국면입니다. 매 토큰마다 모델 전체를 한 번 통과해야 하고, 이때는 연산보다 메모리 대역폭이 병목입니다(memory-bound).

프롬프트 캐싱이 절약해 주는 것은 정확히 prefill 국면의 연산입니다. 10만 토큰짜리 시스템 프롬프트가 캐시에 있다면, 그 10만 토큰을 다시 prefill하지 않아도 됩니다. 그래서 캐시 히트는 비용만 줄이는 게 아니라 TTFT를 극적으로 줄입니다.

2단계 — 어텐션과 K/V: 토큰마다 만들어지는 명함

왜 prefill을 건너뛸 수 있을까요. 어텐션 내부를 봐야 합니다.

트랜스포머의 각 층에서, 각 토큰은 세 가지 벡터로 변환됩니다 — Query(질의), Key(키), Value(값). 직관적으로 말하면 각 토큰은 자신을 소개하는 명함(K)내용물(V) 을 만들어 두고, 새 토큰은 자신의 질문(Q) 으로 이전 토큰들의 명함을 훑어 관련도를 계산한 뒤, 관련도만큼 내용물을 섞어 갑니다.

핵심 성질이 하나 있습니다. GPT류 모델의 어텐션은 인과적(causal) 입니다 — 각 토큰은 자기보다 앞에 있는 토큰만 볼 수 있습니다. 이것이 의미하는 바:

토큰 i의 K와 V는 토큰 1부터 i까지만의 함수다. 뒤에 어떤 토큰이 오든 절대 변하지 않는다.

이 성질이 모든 캐싱의 뿌리입니다. "지금까지의 텍스트"가 같다면, 각 토큰의 K/V 벡터는 비트 단위로 동일하게 계산됩니다. 그렇다면 한 번 계산한 것을 왜 또 계산합니까? 저장해 두면 됩니다.

3단계 — KV 캐시: 저장해 두면 된다

KV 캐시는 바로 그 저장소입니다. decode 국면에서 새 토큰을 생성할 때, 모델은 이전 모든 토큰의 K/V가 필요합니다. 캐시가 없다면 매 토큰 생성마다 지금까지의 전체 시퀀스를 다시 계산해야 하고, 생성 비용이 시퀀스 길이의 제곱으로 폭발합니다. KV 캐시가 있으면 새 토큰의 Q/K/V만 계산하고, 이전 것들은 캐시에서 읽습니다.

공짜는 아닙니다. KV 캐시는 메모리를 먹습니다. 토큰 하나가 차지하는 KV 캐시 크기는 대략 이렇게 계산됩니다:

토큰당 KV 캐시 = 2 (K와 V) × 층 수 × KV 헤드 수 × 헤드 차원 × 바이트 수

예: 7B급 모델 (32층, 히든 4096, fp16)
   = 2 × 32 × 4096 × 2바이트 = 토큰당 약 512KB
   → 4,000토큰 대화 하나 = 약 2GB
   → 동시 사용자 수십 명이면 GPU 메모리가 순식간에 바닥

이 메모리 압박이 최신 아키텍처의 상당 부분을 설명합니다 — GQA(여러 Q 헤드가 K/V 헤드를 공유)와 MQA는 KV 헤드 수를 줄여 캐시를 몇 분의 일로 줄이려는 설계이고, KV 캐시 양자화(FP8/INT4)도 같은 압박에서 나왔습니다. 긴 컨텍스트 시대의 진짜 비용은 가중치가 아니라 KV 캐시인 경우가 많습니다.

4단계 — Prefix Cache: 요청 사이에도 재사용하기

여기까지의 KV 캐시는 한 요청 안의 이야기였습니다. Prefix Cache(프리픽스 캐시)는 이를 요청 사이로 확장합니다.

두 요청이 같은 앞부분(예: 같은 시스템 프롬프트 + 같은 문서)을 공유한다면, 그 앞부분의 K/V는 완전히 동일합니다 — 앞서 본 인과성 덕분에요. 그러니 첫 요청 때 계산한 K/V 블록을 버리지 말고 보관했다가, 다음 요청에서 프리픽스가 일치하면 prefill 없이 그대로 이어 쓰면 됩니다.

왜 "앞부분"만 되는가? 인과성의 뒷면입니다. 토큰 i의 K/V는 1..i의 함수이므로, 중간의 한 토큰이라도 달라지면 그 지점 이후의 모든 토큰의 K/V가 달라집니다. 프롬프트 중간에 타임스탬프 하나를 끼워 넣으면, 그 뒤의 10만 토큰 캐시가 전부 무효가 되는 이유입니다. 캐시는 "포함된 내용"이 아니라 "정확히 같은 프리픽스"에만 반응합니다.

실제 서빙 엔진의 구현:

  • vLLM — Automatic Prefix Caching(APC): vLLM의 PagedAttention은 KV 캐시를 OS의 페이징처럼 고정 크기 블록으로 관리합니다. APC는 각 블록을 "그 블록까지의 토큰 열" 해시로 식별해서, 같은 해시의 블록이 이미 있으면 재사용합니다. 블록 단위라서 부분 일치도 자연스럽게 처리됩니다.
  • SGLang — RadixAttention: 공유 프리픽스들을 radix tree(기수 트리) 로 관리합니다. 수백 개의 요청이 같은 시스템 프롬프트에서 갈라져 나가는 형태(트리!)를 자료구조가 그대로 반영해서, 멀티턴 대화·병렬 분기 같은 워크로드에서 특히 효율적입니다. LRU로 오래된 가지를 쳐냅니다.

5단계 — 제공자의 프롬프트 캐싱: 가격표 읽는 법

API 제공자의 "프롬프트 캐싱"은 이 prefix cache를 상품화한 것입니다. 이제 가격표가 물리학으로 읽힙니다.

Anthropic (Claude) — 명시적 캐싱. 요청에 cache_control 브레이크포인트(최대 4개)를 표시합니다.

  • 캐시 쓰기: 기본 입력가의 1.25배(5분 TTL) 또는 2배(1시간 TTL) — K/V를 계산하고 보관하는 비용입니다.
  • 캐시 읽기: 기본 입력가의 약 0.1배 — prefill 연산을 건너뛰므로 10분의 1입니다.
  • 손익분기: 5분 TTL은 2번째 요청부터 이득(1.25 + 0.1 < 2), 1시간 TTL은 3번 이상 재사용해야 이득(2 + 0.2 < 3).
  • 최소 캐시 길이: 모델에 따라 프리픽스가 1024~4096토큰 이상이어야 캐시됩니다. 짧은 프리픽스는 마커를 붙여도 조용히 캐시되지 않습니다.
  • 렌더 순서는 tools → system → messages — 도구 목록이 가장 앞에 놓이므로, 도구를 추가·삭제·재정렬하면 전체 캐시가 무효화됩니다.

OpenAI — 자동 캐싱. 1024토큰 이상의 프롬프트에서 프리픽스가 일치하면 별도 표시 없이 적용되고, 캐시된 입력 토큰은 공개 기준 50% 할인됩니다. 명시 마커가 없어 편하지만, 어디까지 캐시됐는지의 제어권도 없습니다.

두 방식 모두 검증 방법은 같습니다 — 응답의 usage 필드를 보세요. Anthropic이라면 cache_read_input_tokens가 0이 아니어야 캐시가 실제로 읽히고 있는 것입니다. 반복 요청에서 계속 0이라면 어딘가에 침묵의 캐시 파괴자가 있습니다.

6단계 — 실전 설계 규칙

원리를 알면 규칙은 저절로 나옵니다.

  • 안정된 것을 앞에, 변하는 것을 뒤에. 고정 시스템 프롬프트·문서·도구 정의가 앞, 사용자 질문·타임스탬프·요청 ID가 뒤입니다. 프롬프트를 조립하는 코드의 "순서"가 캐싱 성능을 결정합니다.
  • 침묵의 캐시 파괴자를 색출하라. 시스템 프롬프트에 박힌 datetime.now(), 요청마다 새로 찍히는 UUID, 정렬하지 않은 JSON 직렬화(키 순서가 매번 다름), 사용자별로 달라지는 도구 목록 — 전부 프리픽스 바이트를 바꿔 캐시를 부숩니다.
  • 대화는 누적 프리픽스다. 멀티턴 대화에서 이전 턴 전체가 프리픽스가 되므로, 턴이 쌓일수록 캐시 이득이 커집니다. 마지막에 추가된 턴 끝에 브레이크포인트를 두는 것이 표준 패턴입니다.
  • 모델을 바꾸면 캐시도 사라진다. K/V는 특정 모델의 가중치로 계산된 값이므로 캐시는 모델별입니다. 중간에 모델을 갈아타면 처음부터 다시 씁니다.
  • 셀프 호스팅이라면 켜는 것을 잊지 말 것. vLLM의 APC나 SGLang을 쓰는 것만으로 챗봇류 워크로드의 prefill 비용이 크게 줄어듭니다. 특히 "같은 문서에 여러 질문" 패턴에서 효과가 극적입니다.

마치며 — 가격표는 물리학이다

정리하면 이렇게 압축됩니다. 어텐션은 인과적이라 앞쪽 토큰의 K/V는 불변이고, KV 캐시는 그것을 한 요청 안에서, prefix cache는 요청 사이에서 재사용하며, 프롬프트 캐싱의 가격표(쓰기 할증, 읽기 할인, 프리픽스 전용, 최소 길이)는 그 재사용의 비용 구조를 그대로 값으로 옮긴 것입니다. "왜 앞부분만 되지?"라는 질문의 답은 마케팅 정책이 아니라 토큰 i의 K/V가 1..i만의 함수라는 한 줄의 수학이었습니다.

서빙 비용 전반의 그림은 AI 모델 개발 생애주기의 서빙 절과, GPU를 쪼개 쓰는 MIG 가이드에서 이어집니다.

참고 자료

LLM Caching, Explained — Why Prompt Caching and Prefix Caches Save You Money

Introduction — The Mystery of "Same Prefix, Cheaper Request"

Prompt caching looks strange at first. You don't get a discount for asking the same question twice — you get one when the front of your prompt matches, even if everything after it is completely different. Stranger still, some providers charge extra to write the cache and a tenth of the price to read it. That odd price sheet isn't marketing. It is a direct reflection of the physics inside a transformer.

This article climbs up from that physics: what actually happens inside a transformer during generation, what the KV cache is and why it only works on prefixes, how serving engines like vLLM and SGLang implement prefix caching, and how to design for Anthropic's and OpenAI's prompt caching in practice.

Step 1 — Inference Has Two Phases: Prefill and Decode

Transformer inference has two phases with completely different characters.

  • Prefill — processing the entire input prompt at once. Every prompt token can be computed in parallel, saturating the GPU's arithmetic units (compute-bound). Time-to-first-token (TTFT) is mostly decided here.
  • Decode — generating the answer one token at a time. Each token requires a full pass through the model, and the bottleneck is memory bandwidth, not arithmetic (memory-bound).

What prompt caching saves is precisely the prefill computation. If your 100K-token system prompt is in cache, those 100K tokens never get prefilled again. That is why a cache hit doesn't just cut cost — it dramatically cuts TTFT.

Step 2 — Attention and K/V: Every Token Prints a Business Card

Why can prefill be skipped? Look inside attention.

In every layer of a transformer, each token is transformed into three vectors — Query, Key, and Value. Intuitively: each token prints a business card (K) and a payload (V), and every new token uses its question (Q) to scan the previous tokens' business cards, compute relevance, and blend in their payloads proportionally.

One property matters above all. Attention in GPT-style models is causal — each token can only see tokens before it. Which means:

Token i's K and V are a function of tokens 1..i only. Nothing that comes later can ever change them.

That property is the root of all caching. If "the text so far" is identical, every token's K/V vectors compute to bit-identical values. So why compute them twice? Store them.

Step 3 — The KV Cache: So Store Them

The KV cache is exactly that store. During decode, the model needs the K/V of every previous token. Without a cache, each generated token would require recomputing the whole sequence so far, and generation cost would explode quadratically. With the cache, only the new token's Q/K/V are computed; everything else is read.

It isn't free — the KV cache eats memory. Per-token size is roughly:

KV cache per token = 2 (K and V) × layers × KV heads × head dim × bytes

Example: a 7B-class model (32 layers, hidden 4096, fp16)
   = 2 × 32 × 4096 × 2 bytes ≈ 512 KB per token
   → one 4,000-token conversation ≈ 2 GB
   → a few dozen concurrent users exhausts GPU memory fast

This memory pressure explains much of modern architecture: GQA (many Q heads sharing fewer K/V heads) and MQA exist to shrink the cache by an integer factor, and KV-cache quantization (FP8/INT4) comes from the same squeeze. In the long-context era, the real cost is often the KV cache, not the weights.

Step 4 — Prefix Cache: Reuse Across Requests

So far the KV cache lived within one request. A prefix cache extends it across requests.

If two requests share the same front portion (same system prompt + same document), that portion's K/V is exactly identical — thanks to causality. So instead of discarding the K/V blocks computed for the first request, keep them, and when the next request's prefix matches, continue from them with no prefill.

Why prefixes only? The flip side of causality. Since token i's K/V depends on 1..i, changing even one token in the middle changes the K/V of every token after it. Insert one timestamp into the middle of a prompt, and the cache for the 100K tokens behind it is void. The cache responds not to "contains the same content" but to "byte-identical prefix."

Real serving-engine implementations:

  • vLLM — Automatic Prefix Caching (APC): vLLM's PagedAttention manages the KV cache in fixed-size blocks, like OS paging. APC identifies each block by a hash of "all tokens up to this block," so an existing block with the same hash is simply reused. Being block-granular, partial overlaps work naturally.
  • SGLang — RadixAttention: manages shared prefixes in a radix tree. Hundreds of requests branching off one system prompt form a tree — and the data structure mirrors it exactly, which makes it especially efficient for multi-turn chat and parallel branching. Old branches are evicted LRU-style.

Step 5 — Provider Prompt Caching: How to Read the Price Sheet

Provider "prompt caching" is this prefix cache productized. Now the price sheet reads as physics.

Anthropic (Claude) — explicit caching. You mark cache_control breakpoints in the request (up to 4).

  • Cache write: 1.25× base input price (5-minute TTL) or (1-hour TTL) — the cost of computing and retaining the K/V.
  • Cache read: ~0.1× base input price — prefill is skipped, hence one tenth.
  • Break-even: with the 5-minute TTL the second request already wins (1.25 + 0.1 < 2); the 1-hour TTL needs three or more uses (2 + 0.2 < 3).
  • Minimum cacheable prefix: 1024–4096 tokens depending on the model. Shorter prefixes silently don't cache even with a marker.
  • Render order is tools → system → messages — tools sit at the very front, so adding, removing, or reordering a tool invalidates the entire cache.

OpenAI — automatic caching. Prompts of 1024+ tokens with matching prefixes are cached without any marker, and cached input tokens are discounted 50% per the public docs. No markers means convenience — and no control over what got cached.

Verification is the same either way — read the usage fields on the response. On Anthropic, cache_read_input_tokens must be nonzero for the cache to actually be read. If it stays zero across repeated requests, a silent cache-buster is hiding somewhere.

Step 6 — Practical Design Rules

Once you know the mechanism, the rules write themselves.

  • Stable content first, volatile content last. Fixed system prompt, documents, and tool definitions go up front; user questions, timestamps, and request IDs go at the end. The ordering in your prompt-assembly code determines your cache performance.
  • Hunt the silent cache-busters. A datetime.now() embedded in the system prompt, a fresh UUID per request, unsorted JSON serialization (key order differs every time), per-user tool lists — all of them change prefix bytes and shatter the cache.
  • A conversation is a growing prefix. In multi-turn chat the entire previous conversation is the prefix, so cache savings grow with every turn. The standard pattern puts a breakpoint at the end of the most recently appended turn.
  • Switching models discards the cache. K/V values are computed by a specific model's weights, so caches are per-model. Change models mid-session and you rewrite from scratch.
  • Self-hosting? Turn it on. Just enabling vLLM's APC or using SGLang cuts prefill costs substantially for chat-like workloads — dramatically so for "many questions against the same document" patterns.

Closing — The Price Sheet Is Physics

Compressed to one paragraph: attention is causal, so earlier tokens' K/V are immutable; the KV cache reuses them within a request; the prefix cache reuses them across requests; and prompt caching's price sheet — write premium, read discount, prefix-only, minimum length — is that reuse's cost structure translated into prices. The answer to "why only the front part?" was never policy. It was one line of math: token i's K/V is a function of 1..i alone.

The broader serving-cost picture continues in the serving section of the AI model development lifecycle and the GPU-partitioning MIG guide.

References