LLM을 위한 Exact vs Semantic 캐싱: 각각의 승리 지점과 측정 결과
요약
LLM 서비스 비용 절감을 위한 Exact-match 캐싱과 Semantic 캐싱의 차이점과 트레이드오프를 분석합니다. 각 방식의 작동 원리, 성능(Latency), 히트율(Hit-rate)의 수학적 근거를 비교하여 워크로드에 적합한 캐싱 전략을 제안합니다.
핵심 포인트
- Exact-match 캐싱은 비용이 낮고 정확하지만 낮은 히트율이 단점임
- Semantic 캐싱은 임베딩 기반으로 높은 히트율을 제공하나 정확도 리스크가 있음
- Exact-match는 O(1)의 속도를, Semantic은 O(log n)의 속도를 가짐
- 프롬프트 내 가변적 컨텍스트는 Exact-match의 히트율을 낮추는 주요 원인임
LLM API를 기반으로 서비스를 구축하고 있는데 비용 부담이 커지기 시작했다면, 캐싱(Caching)이 해결책이라는 이야기를 들어보셨을 것입니다. 이어지는 질문은 '어떤 종류'의 캐싱인가 하는 점이며, 솔직한 답변은 다음과 같습니다. 보통은 둘 다 사용하지만, 그 이유는 서로 다릅니다. Exact-match 캐싱(정확 일치 캐싱)은 실행 비용이 거의 들지 않고 결코 틀린 답을 반환하지 않지만, 실제 운영 환경에서는 요청 10건 중 1건 정도만 적중한다는 단점이 있습니다. Semantic 캐싱(의미론적 캐싱)은 그보다 몇 배 더 많은 양을 잡아내지만, 엔지니어링을 통해 관리해야 할 정확성 리스크를 동반합니다. 이 포스트에서는 각각의 방식이 언제 승리하는지, 트레이드오프(Tradeoff) 뒤에 숨겨진 수학적 원리는 무엇인지, 그리고 귀하의 워크로드에 어떤 방식을 적용할지 결정하는 방법을 살펴봅니다.
캐싱은 AI API 캐싱이라는 학문적 체계의 일부입니다. Exact와 Semantic은 세 가지 계층 중 두 가지이며, 나머지 하나는 별도로 다루는 프로바이더 네이티브 캐시 패스스루(Provider-native cache passthrough)입니다.
짧은 정의
**Exact-match 캐싱 (정확 일치 캐싱)**은 요청에 대한 결정론적인 핑거프린트(Fingerprint)(일반적으로 정규화된 메시지 배열, 모델 이름, temperature 및 기타 요청 매개변수에 대한 SHA-256)를 계산한 다음, Redis와 같은 키-값 저장소(Key-value store)에서 해당 핑거프린트를 조회합니다. 핑거프린트가 존재하면 캐시된 응답을 반환합니다. 조회 시간은 O(1)이며 p95 기준 10ms 미만입니다. 저장소는 캐시 크기 예산에 의해 제한되며, 항목은 LRU(Least Recently Used) 또는 TTL(Time To Live)에 의해 제거됩니다.
**Semantic 캐싱 (의미론적 캐싱)**은 임베딩 모델(종종 BGE-small, MiniLM 또는 text-embedding-3-small과 같이 작고 빠른 모델)을 사용하여 사용자의 프롬프트를 임베딩(Embedding)한 다음, 벡터 데이터베이스(Vector database)에서 가장 가까운 저장된 임베딩을 쿼리합니다. 입력된 임베딩과 가장 가까운 저장된 임베딩 사이의 코사인 유사도(Cosine similarity)가 임계값(보통 0.93–0.97)을 초과하면, 해당 저장된 임베딩과 연결된 캐시된 응답을 제공합니다. 조회 시간은 저장된 항목 수에 대해 O(log n)이며, 임베딩 추론(Inference)을 포함하여 p95 기준 약 20–40ms가 소요됩니다.
두 레이어 모두 _전체 응답(full response)_을 캐싱합니다. 제공자 네이티브 패스스루(Provider-native passthrough)는 이와 다르며, 제공자 측에서 _프리픽스 처리(prefix processing)_를 캐싱합니다. 이에 대해서는 Anthropic prompt caching, explained에서 다룹니다. 이 포스트의 나머지 내용은 응답 캐싱(response-caching) 레이어에 집중합니다.
히트율(Hit-rate) 격차는 실재하며 구조적입니다
실제 LLM 트래픽에서 완전 일치(Exact-match) 캐시 미스율(Miss-rate)이 높은 데에는 이유가 있습니다. 프로덕션 프롬프트는 거의 항상 요청마다 달라지는 컨텍스트(Context)를 포함합니다. 예를 들어 사용자 이름, 세션 ID, 현재 타임스탬프, 최근 검색된 RAG 구절, 가변적인 도구(Tool) 목록 등이 이에 해당합니다. 두 요청의 근본적인 사용자 의도가 동일하더라도, 프롬프트 문자열은 바이트(Byte) 단위로 다르며, SHA-256 핑거프린트(Fingerprint)도 갈라집니다. 그 결과, 완전 일치 캐시는 크론(Cron) 예약된 내부 쿼리, 결정론적인 시스템 전용 테스트 호출, 중복 제출된 사용자 작업과 같이 정말로 동일한 5~15%의 트래픽에 대해서만 히트(Hit)됩니다.
VERIFY (founder): 위 5~15% 범위를 지난 30일 동안 Prism 프로덕션 트래픽에서 측정된 실제 완전 일치 캐시 히트율로 교체하세요. 가능하다면 task_type별로 세분화하십시오. 출처:
cache_status='hit-exact'인usage_logs집계 데이터.
시맨틱 캐시(Semantic cache)는 완전 일치 캐시가 놓치는 변동 사항을 포착합니다. 두 사용자가 각각 "환불 정책이 무엇인가요?"와 "어떻게 돈을 돌려받나요?"라고 질문할 때, 이들은 바이트 단위로 다른 프롬프트를 보내지만, 임베딩(Embedding) 시 거의 평행한 벡터로 변환되며 두 벡터 사이의 코사인 유사도(Cosine similarity)는 약 0.960.98에 도달합니다. 임계값(Threshold) 0.95로 설정된 시맨틱 캐시는 두 질문 모두에 동일한 답변을 반환합니다. **프로덕션 시맨틱 캐시 히트율은 워크로드 형태에 따라 크게 달라지지만, 일반적으로 완전 일치 캐시가 잡아낸 것에 더해 2550% 정도 추가로 발생합니다.** 고객 지원 챗봇 및 FAQ 시스템은 높은 히트율을 보이는 반면, 가변적인 검색 컨텍스트를 가진 도구 호출(Tool-calling) 에이전트는 낮은 히트율을 보입니다.
VERIFY (창립자): 25–50% 범위를 Prism에서 측정한 기본 임계값(threshold) 0.95에서의 시맨틱 히트율(semantic hit rate)로 교체할 것. 이는 task_type(simple / code / reasoning / complex)별로 세분화되어야 함. 출처:
cache_status='hit-semantic'인usage_logs.
이 격차가 발생하는 구조적인 이유는 사용자 의도(user intent)가 사용자 입력(user input)보다 저차원적인 구조를 갖기 때문입니다. "환불 정책이 어떻게 되나요?"라고 물어보는 방법은 수천 가지가 될 수 있지만, 환불 정책 자체는 단 하나뿐입니다. 임베딩(Embeddings)은 입력의 차원을 의도로 압축하며, 이것이 바로 시맨틱 캐싱(semantic caching)이 작동하게 만드는 핵심 원리입니다.
Exact(정확 일치)가 승리하는 경우
다음 중 하나라도 해당한다면 Exact-match(정확 일치)가 올바른 선택이며, 종종 유일한 올바른 선택이 됩니다:
- 트래픽이 결정론적(deterministic)인 경우. 크론 잡(Cron jobs), ETL 파이프라인, 평가 실행(evaluation runs), 회귀 테스트(regression tests) 등이 이에 해당합니다. 동일한 프롬프트가 매번 동일한 방식으로 실행됩니다. 이 경우 Exact-match 히트율은 90%를 초과할 수 있으며, 임베딩 오버헤드(embedding overhead) 비용이 전혀 발생하지 않습니다.
- 정확성이 타협 불가능한 경우. 법률, 의료, 금융 워크로드와 같이 틀렸지만 유사한 답변을 제공하는 것이 실제적인 책임(liability) 문제가 될 수 있는 분야입니다. Exact 캐시는 증명 가능한 정확성을 가집니다. 요청이 바이트 단위로 동일(byte-identical)할 때에만 동일한 응답을 반환하기 때문입니다.
- 프롬프트가 짧고 캐시 규모가 작은 경우. 각 1KB인 50,000개의 항목을 캐싱한다면, Exact 캐시는 50MB의 Redis에 들어갈 수 있으며 조회(lookup) 과정도 매우 간단합니다. 이 규모에서는 시맨틱 캐싱의 임베딩 벡터 저장 공간(BGE-small 항목당 1.5KB 및 벡터 인덱스 오버헤드)이 훨씬 더 큰 비중을 차지하게 됩니다.
- 임베딩 지연 시간의 꼬리(latency tail)를 허용할 수 없는 경우. Exact 조회는 p95 기준 10ms 미만이지만, 시맨틱 방식은 임베딩 추론(embedding inference)을 위해 p95 기준 20–40ms를 추가로 소요합니다. 사용자가 200ms 이상의 지연을 체감하는 채팅 UX 환경에서는 매 밀리초(ms)가 중요합니다.
Semantic(의미적 일치)이 승리하는 경우
시맨틱 매치(Semantic-match)는 다음과 같은 상황에서 그 복잡성을 정당화합니다:
- 사용자가 동일한 질문을 10가지 다른 방식으로 표현할 때. 고객 지원 챗봇(Customer-support chatbots), 제품 내 도움말(In-product help), FAQ 서비스 등이 이에 해당합니다. 이러한 워크로드에서 정확히 일치(Exact-match) 방식의 캐시 히트율(Cache hit rate)은 한 자릿수 초반에 머물지만, 시맨틱(Semantic) 방식은 0.95 기준 40% 이상까지 올라갈 수 있습니다.
- 기초가 되는 답변이 자주 바뀌지 않는 지식 기반 LLM을 서비스할 때. 문서 Q&A, 정책 조회, "X를 어떻게 하나요?"와 같은 튜토리얼 등이 해당합니다. 원천 정보(Source-of-truth) 콘텐츠의 업데이트가 느리기 때문에 캐시는 몇 시간 또는 며칠 동안 유효하게 유지됩니다.
- 단위 경제성(Unit-economics) 계산이 임베딩(Embedding) 오버헤드를 정당화할 때. 0.015달러 규모의 호출(전형적인 Sonnet급 입력 + 출력)에서 시맨틱 히트(Semantic hit)가 발생하면 0.015달러의 비용을 절감합니다. BGE-small 모델을 사용한 임베딩 추론 비용은 호출당 약 0.00002달러입니다. 손익분기점 히트율은 _0.2% 미만_입니다. 즉, 오탐율(False-positive rate)이 허용 가능한 수준이라면 시맨틱 캐싱을 운영하여 손해를 볼 가능성은 거의 없습니다.
오탐(False-positive) 문제는 대부분의 시맨틱 캐싱 구현이 실패하는 지점입니다. 고객의 질문에 잘못된 답변을 반환하는 캐시는 캐시가 아예 없는 것보다 더 나쁩니다. 고객은 잘못된 정보를 가지고 떠나며 제품을 비난하게 되고, 여러분은 심지어 그런 일이 일어났는지조차 모를 수 있습니다. 이를 안전하게 만드는 규율은 다음에 다룰 _임계값 엔지니어링(Threshold engineering)_입니다.
임계값 수학 (The threshold math)
코사인 유사도(Cosine similarity) 임계값은 시맨틱 캐시에서 조절 가능한 유일한 레버입니다. 임계값을 너무 낮게 설정하면 확신에 찬 오답을 제공하게 되고, 너무 높게 설정하면 임베딩 오버헤드를 감수할 만큼 충분한 히트를 잡아내지 못합니다. 방어 가능한 기본값은 0.95이며, 그 이유는 다음과 같습니다.
이를 "이것이 진정한 일치인가?"라는 질문에 대한 정밀도/재현율(Precision/Recall) 문제로 생각하십시오. 임계값은 경계를 조정합니다:
- 임계값(Threshold) 0.99: 오탐률(False-positive rate)이 거의 0에 가깝지만, 정규화 후 바이트 단위로 일치하는 요청만 포착합니다. 사실상 단순함만 제외하면 Exact-match(정확히 일치)와 동일합니다. 유용하지 않습니다.
- 임계값(Threshold) 0.95 (기본값): 대부분의 실제 워크로드(Workload)에서 오탐률이 한 자릿수 초반대를 유지합니다. 재현율(Recall)이 좋습니다. "사용자가 다른 단어로 같은 것을 물어본" 대부분의 사례가 0.96 이상의 유사도를 기록합니다. 실행해 볼 가치가 있습니다.
- 임계값(Threshold) 0.90: 광범위한 채팅 워크로드에서 오탐률이 8~15%로 급증합니다. 여기서 발생하는 오작동은 의미적으로 관련은 있지만 서로 다른 질문들입니다. 예를 들어, "환불 정책이 무엇인가요"와 "배송 정책이 무엇인가요"는 모두 임베딩(Embedding) 상에서 서로 가깝게 위치하며, 0.90 임계값은 이 둘을 하나로 뭉뚱그려 버립니다. 거의 항상 잘못된 선택이 됩니다.
- 임계값(Threshold) 0.85: 오탐률이 재앙적인 수준입니다. 캐시가 사실상 콘텐츠를 인지하는 무작위 응답 생성기(Random-response generator)가 되어버립니다. 모든 히트(Hit)를 재검증하는 다운스트림 LLM 판독기(LLM judge)가 있지 않는 한 피해야 합니다.
이 곡선의 형태는 워크로드에 따라 달라집니다. 좁은 범위의 워크로드(예: 단일 제품 문서용 챗봇)는 모든 관련 질문이 밀집되어 있으므로 0.92 임계값을 안전하게 사용할 수 있습니다. 광범위한 워크로드(예: 범용 어시스턴트)는 질문 공간이 더 넓게 퍼져 있기 때문에 0.96 이상의 임계값을 사용해야 합니다.
올바른 접근 방식은 이를 계측(Instrument)하는 것입니다. 캐시를 0.95로 실행하고, 모든 히트의 유사도 점수(Similarity score)를 기록하십시오. 주기적으로 100개의 히트를 샘플링하여 캐시된 답변이 적절했는지 사람이 판단하게 하십시오. 만약 오탐률이 2% 미만이라면, 더 많은 히트를 회복하기 위해 임계값을 낮추는 실험을 할 수 있습니다. 오탐률이 5%를 초과한다면 임계값을 높이십시오.
실제 사례 예시
Claude Sonnet을 기반으로 구축된 고객 지원 챗봇을 운영한다고 가정해 봅시다. 트래픽 프로필은 다음과 같습니다:
- 일일 20,000건의 채팅 완료(Chat completions)
- 평균 프롬프트 길이: 800 입력 토큰 (시스템 프롬프트 + 검색된 컨텍스트 + 사용자 메시지)
- 평균 응답: 300 출력 토큰
- Claude Sonnet 가격 (예시): 입력 토큰 100만 개당 $3, 출력 토큰 100만 개당 $15
캐싱을 사용하지 않을 때의 제공업체 비용: 20,000 × (800 × $3 + 300 × $15) / 1,000,000 = $138 / 일 (~$4,200 / 월).
이제 캐싱을 적용해 보겠습니다:
- **Exact cache (정확한 캐싱)**가 트래픽의 8%를 포착합니다. 절감액: 8% × $138 = $11/일.
- **Semantic cache (의미론적 캐싱)**가 임계값(threshold) 0.95에서 남은 트래픽의 38%를 포착합니다. 절감액: 38% × 92% × $138 = $48/일.
- 총 회피된 지출: $59/일, 즉 청구액의 약 43%.
Semantic cache의 임베딩 (embedding) 비용: 20,000 × $0.00002 = $0.40/일. 무시할 수 있는 수준입니다.
인프라 비용: Redis 캐시 (관리형 약 $10/월) + Upstash Vector (50만 개의 벡터 기준 약 $30/월). 월 약 $1,800의 절감액 대비 총 비용은 약 $40/월입니다. 투자 회수 기간은 트래픽이 발생하는 단 하루입니다.
검증 (창업자): 위 계산 예시를 실제 Prism 고객 프로필이나 대표적인 집계 데이터, 그리고 현재 가격을 바탕으로 한 사례로 대체하십시오. 위의 예시 수치들은 합리적이지만 실제 고객 형태에 근거하여 구체화할 가치가 있습니다.
핵심은 특정 수치가 아닙니다. 캐싱이 조금이라도 작동하는 워크로드(workload)에서, 두 계층을 모두 운영하는 비용은 절감액에 비하면 오차 범위 수준이라는 점입니다. 유일한 실제 문제는 위양성(false-positive) 비율이며, 이는 임계값 엔지니어링 (threshold engineering)을 통해 해결됩니다.
Prism이 두 방식을 모두 실행하는 방법
Prism은 기본적으로 모든 유료 요청에 대해 exact, semantic, 그리고 제공업체 네이티브 패스스루 (provider-native passthrough)라는 세 가지 캐싱 계층을 동시에 실행합니다. 디스패처 (dispatcher)는 먼저 exact를 조회하고 (Redis, p95 기준 8ms 미만), 미스(miss)가 발생하면 semantic으로 넘어갑니다 (BGE-small 임베딩을 사용한 Upstash Vector, 0.95 코사인 유사도 기준, 임베딩 호출을 포함하여 p95 기준 약 30ms). 그 외의 경우에는 제공업체 네이티브 패스스루를 위해 cache-control 마커가 부착된 상태로 제공업체에 프록시 (proxy) 합니다. 모든 응답에는 어떤 계층(있다면)이 요청을 처리했는지 나타내는 X-Prism-Cache-Status 헤더와, 실제 절감된 달러 금액을 보여주는 X-Prism-Cache-Saved-Cents 헤더가 포함됩니다.
언급할 만한 몇 가지 설계 선택 사항은 다음과 같습니다:
지문 정규화 (Fingerprint normalization). Prism은 지문 생성 (fingerprinting) 전에 메시지 배열을 정규화합니다. 즉, 내부 캐시 제어 마커를 제거하고, 결정론적 키 (deterministic keys)를 정렬하며, 일관되게 토큰화 (tokenize) 하여, 실질적으로 동일한 요청들이 동일한 키로 해싱되도록 합니다. 관련 아티클인 Prompt cache fingerprinting pitfalls에서는 v1.1 개발 과정에서 저희를 괴롭혔던 예외 사례(edge cases)들을 자세히 다룹니다.
Pro+에서는 범위(scope)별로 임계값(Threshold) 설정이 가능합니다. 기본값은 0.95이지만, Pro+ 계정은 X-Prism-Cache-Threshold 헤더를 통해 프로젝트별로 이를 조정할 수 있습니다. /dashboard/cache에 있는 캐시 인스펙터(cache inspector)는 임계값 기준 히트율(hit-rate-at-threshold) 곡선을 보여주므로, 임계값을 높이거나 낮췄을 때 어떤 결과가 나타날지 확인할 수 있습니다.
스트리밍 호환성 (Streaming compatibility). 캐시 히트(Cache hit)가 발생하면 요청의 stream=true 플래그와 관계없이 스트리밍되지 않는 JSON을 반환합니다. 스트리밍 중간에 캐싱을 하는 것은 실수하기 쉬운 위험한 방식(footgun)입니다 (스트림이 끊기면 캐시가 오염될 수 있기 때문). 저희는 이 방식을 완전히 피했습니다.
가입하기 전에 절약 계산기 (savings calculator)를 통해 귀하의 워크로드에 대한 캐싱 ROI를 모델링해 볼 수 있습니다. 저희가 내부적으로 사용하는 것과 동일한 가격 입력값을 사용합니다.
결정 체크리스트 (Decision checklist)
귀하의 워크로드에 무엇을 실행할지 선택하고 있다면:
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기