Caching
캐싱
같은 질문에 두 번 과금하지 않습니다. Celon은 요청을 Exact → Semantic 순서의 이중 캐시로 조회하고, hit 시 업스트림 호출 없이 즉시 응답합니다. 캐시 계층의 어떤 실패도 요청을 실패시키지 않습니다 — 항상 miss로 강등될 뿐입니다.
Exact 캐시
완성에 영향을 주는 필드(model, messages, temperature, top_p, max_tokens, response_format)를 키 정렬된 안정적 JSON으로 직렬화한 뒤 SHA-256 해시를 키로 전체 응답을 저장합니다. 완전히 동일한 요청은 즉시 hit되며, 응답 메타에 cache_hit: "exact"로 표시됩니다.
Semantic 캐시
표현이 조금 달라도 의미가 같은 질문을 잡아냅니다. system 프롬프트 앞 500자 + 마지막 user 메시지를 openai/text-embedding-3-small로 임베딩하고, 최근 요청 인덱스와 코사인 유사도를 비교해 임계값 이상이면 저장된 응답을 반환합니다(cache_hit: "semantic").
- 같은
model값끼리만 매칭됩니다 — 모델별 독립 인덱스. - 인덱스는 모델당 최근 512개 항목의 링 버퍼이며, Upstash가 설정된 경우 KV에 미러링되어 재시작 후에도 유지됩니다.
- 임베딩은 OpenAI 어댑터를 사용하므로
OPENAI_API_KEY가 없으면 semantic 계층은 자동 비활성화됩니다 (exact 캐시는 계속 동작).
임계값은 SEMANTIC_CACHE_THRESHOLD 환경변수로 조정합니다 (기본 0.97). 낮추면 hit율이 올라가지만 의미가 다른 질문에 캐시 응답이 나갈 위험이 커집니다 — 프로덕션에서는 0.95 미만으로 내리지 않는 것을 권장합니다.
캐시 대상 조건
다음 조건을 모두 만족하는 요청만 캐시 조회·저장 대상이 됩니다.
| 조건 | 설명 |
|---|---|
stream !== true | 스트리밍 요청은 캐시하지 않습니다. |
temperature ≤ 0.3 | 결정적인 요청만 캐시합니다. OpenAI 기본값은 1.0이므로 temperature를 명시적으로 낮춰야 캐시 대상이 됩니다. |
tools 미사용 | function calling 요청은 캐시하지 않습니다. |
celon.no_cache !== true | 요청 단위 opt-out이 없어야 합니다. |
본문 < 32,000자 | 전체 메시지 텍스트 합이 32,000자 미만이어야 합니다. |
TTL과 백엔드
- TTL은
CACHE_TTL_SECONDS환경변수로 설정하며 기본값은 86,400초 (24시간)입니다. - 백엔드는
UPSTASH_REDIS_REST_URL/UPSTASH_REDIS_REST_TOKEN이 설정되면 Upstash Redis REST, 아니면 in-memory LRU입니다. - 캐시 저장은 응답 반환 후 비동기로 수행됩니다 — 요청 지연에 영향을 주지 않습니다.
비용 0 처리와 saved_usd 계산
캐시 hit는 업스트림 호출이 없으므로 cost_usd: 0, provider: "cache"로 응답하고, 사용량 원장에도 비용 0으로 기록됩니다. 절감액(saved_usd)은 항상 Tier 1 baseline(anthropic/claude-fable-5) 가격 기준으로 계산합니다 — “항상 프론티어를 썼다면 냈을 금액”과의 차이입니다.
# 캐시 hit — 업스트림 호출 없음
cost_usd = 0
saved_usd = costOf("anthropic/claude-fable-5", prompt_tokens, completion_tokens)
# 캐시 miss, Tier 2/3로 라우팅된 경우
saved_usd = max(0, costOf(baseline, tokens) - costOf(routed_model, tokens))
# Tier 1 · 명시 모델 · fusion
saved_usd = 0