LabHub

블로그

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

한국어English日本語中文

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

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

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

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

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

프롬프트 캐싱이 절약해 주는 것은 정확히 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만 토큰 캐시가 전부 무효가 되는 이유입니다. 캐시는 "포함된 내용"이 아니라 "정확히 같은 프리픽스"에만 반응합니다.

실제 서빙 엔진의 구현:

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

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

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

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

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

6단계 — 실전 설계 규칙

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

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

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

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

참고 자료

댓글

아직 댓글이 없습니다.

로그인하면 댓글을 쓸 수 있습니다