Skip to content

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

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

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

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 가이드에서 이어집니다.

참고 자료

현재 단락 (1/47)

LLM API의 프롬프트 캐싱을 처음 보면 이상합니다. 같은 질문을 두 번 하면 싸지는 것이 아니라, **프롬프트의 앞부분이 같으면** 싸집니다. 뒷부분이 완전히 달라도 상관없습니...

작성 글자: 0원문 글자: 4,368작성 단락: 0/47