로컬 LLM 프롬프트 캐싱 — 같은 시스템 프롬프트 재사용으로 속도 올리기
요약: 로컬 LLM에서 매 요청마다 긴 시스템 프롬프트를 처음부터 다시 프리필 계산하는 대신 프롬프트 프리픽스 캐싱을 사용하면 공통 앞부분의 KV 캐시를 재사용해 추론 속도를 높이고 불필요한 연산 비용을 크게 줄일 수 있다. 한 줄 요약: 프롬프트 캐싱은 공통 시스템 프롬프트의 KV 캐시를 재사용하여 반복되는 프리필 계산을 생략하고 응답 지연을 줄이는 효율적인 기술이다.
로컬 LLM에서 매 요청마다 긴 시스템 프롬프트를 처음부터 다시 프리필 계산하는 대신 프롬프트 프리픽스 캐싱을 사용하면 공통 앞부분의 KV 캐시를 재사용해 추론 속도를 높이고 불필요한 연산 비용을 크게 줄일 수 있다.
한 줄 요약: 프롬프트 캐싱은 공통 시스템 프롬프트의 KV 캐시를 재사용하여 반복되는 프리필 계산을 생략하고 응답 지연을 줄이는 효율적인 기술이다.
프롬프트(프리픽스) 캐싱은 공통 시스템 프롬프트의 KV 캐시를 재사용해 매 요청의 prefill 반복을 건너뛴다 — 프리픽스가 완전히 동일할 때만 적중하므로 동적 요소는 프롬프트 뒤쪽에 둔다
왜 매번 같은 앞부분을 다시 계산할까?#
로컬에서 LLM을 실행할 때 보통 시스템 프롬프트에 페르소나, 응답 규칙, 예시, 금지 사항 등을 길게 넣는다. 그런데 새로운 사용자 질문이 들어올 때마다 모델은 이 전체 프롬프트를 토큰화한 뒤 각 토큰에 대해 Key와 Value 행렬을 계산하는 프리필 단계를 처음부터 수행한다. 이전 요청과 시스템 프롬프트가 완전히 같아도 캐시가 없으면 이 계산을 매번 반복해야 한다.
프리필은 생성 단계보다 계산량이 많고, 특히 긴 시스템 프롬프트일수록 GPU 시간과 메모리 대역폭을 많이 소모한다. 결과적으로 동일한 규칙을 매번 처음부터 다시 연산하느라 전체 응답 속도가 느려지고, 연속 대화나 여러 질문을 처리할 때 체감 지연이 커진다.
초보자 비유로 설명하면, 매일 아침마다 회사 규정집 1장을 처음부터 끝까지 다시 읽고 나서 그날 업무 질문을 하는 것과 같다. 규정집 앞부분은 항상 똑같은데도 매번 처음부터 읽느라 시간을 허비하는 셈이다. 공통 서문은 책갈피를 꽂아두고 그 뒤에 나오는 구체적인 질문부터 읽기 시작하면 훨씬 효율적이다.
KV 캐시는 트랜스포머가 이전 토큰들의 정보를 미리 계산해 저장해 두는 메모리 공간이다. 새 토큰이 생성될 때 이전 토큰을 매번 다시 계산하지 않고 저장된 값을 바로 참조할 수 있게 해 준다. 하지만 일반적인 요청 단위에서는 이 캐시가 초기화되기 때문에 prefix가 같아도 다시 계산해야 했다.
프롬프트 캐싱은 어떻게 아끼나?#
프롬프트 프리픽스 캐싱은 여러 요청에서 앞부분(시스템 프롬프트)이 완전히 동일할 경우, 그 부분의 KV 캐시를 재사용하는 기술이다. 처음 한 번만 프리필 계산을 수행하고, 이후 요청에서는 캐시된 KV를 불러와 새로 추가된 사용자 메시지 부분부터 계산을 시작한다. 이로 인해 프리필 반복 계산이 사라져 전체 지연 시간이 크게 줄어든다.
| 상황 | 무엇이 일어나나 | 속도 | 대표 지원 |
|---|---|---|---|
| 캐시 없음(매번 프리필) | 시스템 프롬프트+입력 전체를 매 요청 재계산 | 기준(느림) | 사실상 전부 |
| 프리픽스 캐시 적중 | 공통 앞부분 KV 재사용, 새 토큰만 계산 | 빠름(프리필 반복 제거) | Ollama·vLLM·llama.cpp |
| 프리픽스 캐시 미적중 | 앞부분이 조금이라도 다르면 전체 재계산 | 기준(이득 없음) | - |
캐시가 없는 경우에는 매 요청마다 시스템 프롬프트 전체를 다시 토큰화하고 KV를 계산한다. 특히 규칙과 예시가 많은 긴 시스템 프롬프트라면 동일한 연산을 수없이 반복하게 되어 GPU 자원이 낭비되고 응답이 늦어진다. KV 캐시 비유로는 요리사가 매번 같은 밑반찬 재료를 처음부터 손질하는 것과 비슷하다. 손질 과정을 매번 반복하니 전체 요리 시간이 길어지는 셈이다.
프리픽스 캐시가 적중하면 공통 앞부분의 KV를 재사용하고 새로 들어온 사용자 입력 부분만 계산한다. 프리필 단계의 반복 계산이 사라지기 때문에 첫 토큰까지의 시간이 크게 단축되고, 연속적인 대화나 여러 질문을 빠르게 처리할 수 있다. 이는 로컬 환경에서 특히 유용한데, 한정된 GPU 자원으로 더 많은 요청을 효율적으로 소화할 수 있게 해 준다.
프리픽스 캐시가 미적중하는 경우에는 프롬프트 앞부분이 조금이라도 달라지면 전체를 다시 계산해야 한다. 예를 들어 시스템 프롬프트 안에 현재 날짜나 동적 변수를 넣으면 매번 prefix가 달라져 캐시 적중이 불가능해진다. 따라서 캐시를 제대로 활용하려면 프롬프트 구조 자체를 신경 써야 한다.
로컬에서 어떻게 적중률을 높이나?#
로컬 환경에서 프리픽스 캐싱의 적중률을 높이려면 프롬프트 구조를 의도적으로 설계해야 한다. 아래 세 가지 원칙을 지키면 캐시 재사용 빈도가 크게 올라간다.
- 고정 시스템 프롬프트를 맨 앞에 동일하게 배치한다. 페르소나 설명, 응답 형식 규칙, 금지 사항, 예시 대화 등 변하지 않는 내용을 가장 앞쪽에 몰아서 넣는다. 이렇게 하면 여러 요청이 동일한 prefix를 공유할 가능성이 높아진다.
- 동적 요소(날짜·사용자입력)는 뒤쪽에 배치한다. 현재 시간, 사용자 이름, 최근 대화 요약, RAG 검색 결과 등 매 요청마다 달라질 수 있는 내용은 시스템 프롬프트 뒤나 별도의 메시지로 분리한다. prefix 앞부분을 최대한 고정시켜 캐시 적중률을 유지하는 것이 핵심이다.
- 같은 프리픽스로 여러 요청을 묶는다. 가능하다면 하나의 긴 컨텍스트 안에 여러 질문을 넣거나, 세션 단위로 캐시가 유지되는 환경을 활용한다. vLLM 같은 추론 서버에서는 자동 prefix caching이 동작하는 경우가 많고, llama.cpp나 Ollama에서도 최근 버전에서 지원이 강화되고 있다. 요청을 적절히 그룹화하면 캐시 적중 확률이 더욱 올라간다.
참고: 2026-07-12 KST 기준으로 주요 로컬 LLM 런타임마다 프롬프트 캐싱 구현 방식과 자동 적용 여부가 상이하다. Ollama, vLLM, llama.cpp 등에서 지원 여부와 설정 방법을 반드시 공식 문서에서 확인하고, 실제 사용 환경에서 응답 지연 시간과 처리량을 직접 측정해 보는 것이 가장 정확한 결과를 얻는 방법이다.
이 시리즈: 이 시리즈 허브 — 로컬 LLM·RAG 7가지 관문 · speculative decoding로 속도 올리기 · 구조화 출력으로 파싱 실패 없애기
함께 읽기: 로컬 LLM 속도를 공짜로 올리기 — speculative decoding 쉽게 이해하기, 로컬 LLM에 JSON을 강제하기 — 구조화 출력으로 파싱 실패 없애기
참고 링크
Responses
No responses yet. Be the first to respond.