문서
프롬프트 캐싱
cache_control로 안정적인 프롬프트 접두부를 한 번 표시하거나, 해당 필드가 없는 OpenAI 형식으로 Claude 모델에 요청하면 Kunavo가 중단점을 배치합니다. 이후 해당 접두부를 재사용하는 호출은 입력 가격의 일부만 청구됩니다 — 대부분의 채팅 모델에서 입력 가격의 10%, 최저 2.5%. Kunavo의 라우팅 계층은 대화를 동일한 업스트림 키에 고정해 캐시를 따뜻하게 유지합니다.
30K 토큰 시스템 프롬프트에서 Claude Sonnet 5를 사용하는 경우 캐시 읽기 비용은 $0.14 / 1M이며, 일반 입력 비용인 $1.4 / 1M보다 저렴합니다. 세션당 같은 컨텍스트를 50회 다시 보내는 에이전트라면 캐시를 통해 입력 비용을 약 90% 절감할 수 있습니다.
활성화 방법
시스템 블록, 메시지 또는 도구 정의에 cache_control: { type: "ephemeral" } 중단점을 추가하세요. 첫 호출에서 모델은 해당 중단점까지의 구간을 캐시에 저장합니다. 이후 동일한 접두부 바이트를 공유하는 호출은 캐시를 적중합니다.
from openai import OpenAI
client = OpenAI(
api_key="sk-kn-...",
base_url="https://api.kunavo.com/v1",
)
# Mark the large, stable prefix once with cache_control.
# Every subsequent call that sends the same prefix reads it back
# from cache at 0.10× the input rate on Claude Sonnet 5.
# Per-model rates are in the pricing table below.
SYSTEM = [
{
"type": "text",
"text": open("long_system_prompt.txt").read(),
"cache_control": {"type": "ephemeral"},
},
]
resp = client.chat.completions.create(
model="claude-sonnet-5",
messages=[
{"role": "system", "content": SYSTEM},
{"role": "user", "content": "Summarize the doc above in 3 bullets."},
],
)
u = resp.usage
# OpenAI-compat fields populated by Kunavo:
# - prompt_tokens_details.cached_tokens — read from cache
# - cache_creation_input_tokens — written to cache this call
print(u.prompt_tokens_details.cached_tokens,
getattr(u, "cache_creation_input_tokens", 0))네이티브 Messages API에서도 와이어 형식은 동일합니다 — cache_control는 번역 없이 Claude에 그대로 전달됩니다:
# Native Anthropic Messages API — cache_control passes through untranslated.
curl https://api.kunavo.com/v1/messages \
-H "Authorization: Bearer $KUNAVO_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-5",
"system": [
{
"type": "text",
"text": "<your large stable system prompt>",
"cache_control": { "type": "ephemeral" }
}
],
"messages": [
{ "role": "user", "content": "Summarize the doc above in 3 bullets." }
],
"max_tokens": 1024
}'OpenAI 형식 엔드포인트의 자동 중단점
OpenAI Chat Completions 및 Responses 형식에는 cache_control 필드가 전혀 없습니다 — OpenAI는 자체 서버에서 암묵적으로 캐싱합니다. Claude는 그렇지 않습니다. 중단점으로 표시된 항목만 캐싱합니다. 따라서 OpenAI 형식으로 통신하는 클라이언트는 캐싱을 요청할 방법이 없고, 요청을 그대로 번역해 Claude에 전달하면 중단점이 하나도 없습니다. 그 결과 긴 대화의 모든 턴에서 전체 기록에 입력 요금이 다시 청구됩니다.
Claude 모델에 /v1/chat/completions 또는 /v1/responses를 통해 요청하면 Kunavo가 프로토콜에서 전달할 수 없는 중단점을 설정합니다. 별도로 활성화할 것은 없습니다. Claude 모델에만 적용됩니다. 다른 모든 모델 계열은 중단점 없이 공급업체가 암묵적으로 캐싱하는 프로토콜을 통해 제공됩니다.
# Plain OpenAI Chat Completions — no cache_control anywhere in the body.
# The format has no field for one; Kunavo inserts the breakpoints instead.
resp = client.chat.completions.create(
model="claude-sonnet-5",
messages=[
{"role": "system", "content": LONG_SYSTEM_PROMPT},
{"role": "user", "content": "first question"},
{"role": "assistant", "content": "...previous answer..."},
{"role": "user", "content": "follow-up"},
],
)
u = resp.usage
# Turn that writes the cache:
# u.cache_creation_input_tokens -> 18,000
# u.prompt_tokens_details.cached_tokens -> 0
# Next turn, same prefix, inside the 5-minute window:
# u.cache_creation_input_tokens -> 240 (only the new turn)
# u.prompt_tokens_details.cached_tokens -> 18,000
#
# Both stuck at 0 on a conversation well over the threshold? The prefix is
# changing between calls — a timestamp or request id inside the cached span.중단점의 위치와 캐시 예산을 사용하는 순서:
- 마지막 메시지의 순환 중단점 — 마지막 메시지의 마지막 콘텐츠 블록에 배치되어 그 앞의 모든 내용을 캐싱합니다. 요청이 대화 안에 남는 시스템 메시지로 끝나면(아래 참고) 대신 그 메시지 바로 앞의 블록에 배치됩니다.
messages에 어시스턴트 턴이 이미 있을 때만 추가됩니다. 캐시 쓰기는 입력의1.25×를 청구하므로, 아무도 다시 보내지 않을 프롬프트를 표시하면 비용만 사분의 일 더 들고 절감 효과는 없습니다. 이전 어시스턴트 턴이 있으면 이 접두부가 곧 다시 전송될 것이라는 근거가 됩니다. system에 하나,tools에 하나 — 프롬프트의 안정적인 앞부분입니다. 시스템 프롬프트를 한 번만 보내는 호출자도 다음 호출에 거의 항상 같은 프롬프트를 보내므로, 단발성 호출에서도 표시할 가치가 있습니다.- 대화 안에 남는 시스템 메시지 앞 — 순환 중단점과
system,tools중단점을 두고 남은 예산은, 뒤에 다른 내용이 이어지는 그런 메시지 가운데 마지막 메시지 바로 앞의 블록에 배치되고, 그다음에는 그 앞의 메시지 앞에 배치됩니다. 그런 메시지를 턴마다 옮기는 클라이언트에만 필요하므로 가장 나중에 채워집니다. 그런 메시지가 없는 대화, 즉 거의 모든 대화에는 이 위치가 없습니다.
두 가지 제한이 있습니다. 메시지, system, 도구 스키마를 합친 프롬프트가 8,192자 미만이면 아무것도 삽입되지 않습니다. Anthropic은 자체 최소 캐시 가능 길이(1,024토큰, Haiku는 2,048토큰)보다 짧은 접두부의 중단점을 조용히 무시하며, 쓰기나 읽기 요금을 청구하지 않으므로 중단점을 넣어도 이득이 없습니다. 또한 Anthropic은 요청당 최대 중단점 4개를 허용합니다. 다섯 번째는 조용히 무시되는 것이 아니라 400 오류를 일으킵니다.
모델이 처음 답변한 뒤에 보낸 시스템 또는 developer 메시지는 system로 끌어올려지지 않고, 보낸 턴 안에서 대화에 그대로 남습니다. 끌어올리면 그 메시지가 추가된 턴에서 프롬프트의 앞부분이 바뀌고 전체 기록이 캐시에 다시 기록되기 때문입니다. 업스트림이 받아들이는 경우 Claude는 이를 시스템 메시지로 받고, 그렇지 않으면 해당 사용자 턴 안에서 <system-reminder> 태그로 감싼 텍스트로 받습니다. 모델의 첫 답변 전에 보낸 시스템 메시지나, 자체 중단점이 한 시간 캐시를 요청하는 메시지는 여전히 system에 들어갑니다.
/v1/messages 엔드포인트에는 아무것도 삽입되지 않습니다. 본문은 전송된 그대로 전달되며, 본문에 있는 중단점은 모두 사용자가 지정한 것입니다.보고 방식은 바뀌지 않습니다. 중단점이 사용자가 지정한 것이든 게이트웨이가 지정한 것이든 응답 필드에서 설명한 동일한 cached_tokens 및 cache_creation_input_tokens 필드가 채워집니다. 따라서 사용량 객체를 확인하면 삽입된 중단점이 실제로 캐시 적중을 이끌어냈는지 알 수 있습니다.
가격
캐시 요금은 각 모델의 입력 가격을 기준으로 공급업체 자체 요율에 따라 산정됩니다. 아래 표가 기준이며, 모든 요율은 직접 입력한 값이 아니라 해당 모델의 입력 가격을 기준으로 계산됩니다. Anthropic과 OpenAI 모두 캐시 읽기에는 입력 가격의 0.10×를 청구합니다, 2개의 예외: 0.025× on Claude Fable 5.1, 0.05× on Claude Opus 5.5. 모든 Claude 모델의 캐시 쓰기에는 입력 가격의 1.25×를 청구합니다 (GPT-6 Astra, GPT-6 Sol, GPT-6 Luna, GPT-5.6 Sol 및 GPT-5.6 Terra에도 같은 요율이 적용됩니다). Kunavo는 Claude의 TTL 1시간 쓰기에도 동일한 1.25×를 청구하며, 이는 Anthropic의 2×보다 낮습니다. 그 외 모든 모델에는 별도의 쓰기 가격이 없습니다. 쓰기에는 일반 입력 요금이 적용됩니다. 어느 경우든 접두부를 한 번이라도 재사용하면 새로 전송하는 것보다 캐시를 사용하는 편이 저렴합니다. 각 요금 등급에는 모델 자체 할인이 적용되므로 캐시 가격도 해당 모델의 입력 및 출력 가격과 동일한 비율로 공급업체 정가보다 낮습니다.
Anthropic
| Model | Input | Cache read | Cache write |
|---|---|---|---|
| Claude Fable 5.1 | $7 | $0.175 0.025× | $8.75 1.25× |
| Claude Fable 5 | $7 | $0.7 0.10× | $8.75 1.25× |
| Claude Opus 5.5 | $2.8 | $0.14 0.050× | $3.5 1.25× |
| Claude Opus 5 | $3.5 | $0.35 0.10× | $4.375 1.25× |
| Claude Opus 4.8 | $3.5 | $0.35 0.10× | $4.375 1.25× |
| Claude Opus 4.7 | $3.5 | $0.35 0.10× | $4.375 1.25× |
| Claude Opus 4.6 | $3.5 | $0.35 0.10× | $4.375 1.25× |
| Claude Sonnet 5 | $1.4 | $0.14 0.10× | $1.75 1.25× |
| Claude Sonnet 4.6 | $2.1 | $0.21 0.10× | $2.625 1.25× |
| Claude Haiku 4.5 | $0.7 | $0.07 0.10× | $0.875 1.25× |
OpenAI
| Model | Input | Cache read | Cache write |
|---|---|---|---|
| GPT-6 Astra | $4 | $0.4 0.10× | $5 1.25× |
| GPT-6 Sol | $0.8 | $0.08 0.10× | $1 1.25× |
| GPT-6 Luna | $0.04 | $0.004 0.10× | $0.05 1.25× |
| GPT-5.6 Sol | $2 | $0.2 0.10× | $2.5 1.25× |
| GPT-5.6 Terra | $0.7 | $0.07 0.10× | $0.875 1.25× |
| GPT-5.5 | $2 | $0.2 0.10× | $2 1× |
max(catalog_cost, upstream × markup)를 청구합니다. 최저 요금은 새 입력 요금이 아니라 캐시된 입력 요금을 기준으로 계산되므로 절감액이 상쇄되지 않고 사용자에게 돌아갑니다.친화성 라우팅으로 캐시를 따뜻하게 유지
업스트림 프롬프트 캐시는 API 키마다 별도로 유지됩니다. 모든 요청이 임의의 업스트림 키로 전달되면 캐시 적중률은 약 1/N입니다. Kunavo는 시스템 프롬프트와 첫 사용자 메시지에서 안정적인 해시를 생성하고 동일한 접두부를 사용하는 모든 호출을 동일한 업스트림 키로 라우팅합니다. 가중 랑데부 해싱을 사용하므로 키 풀이 변경되어도 약 1/N개의 키만 다시 매핑됩니다.
설정할 필요가 없습니다. 친화성 라우팅은 모든 채팅 호출에 자동으로 적용됩니다. (이미지 / 비디오 / TTS는 임의 라우팅을 사용합니다. 해당 모달리티에는 키별 캐시가 없습니다.)
대시보드 지표
호출이 캐시를 적중하기 시작하면 /app/usage에 선택한 기간의 집계 지표 두 가지가 표시됩니다:
- 적중률 — 캐시된 입력 토큰 ÷ 전체 입력 토큰. 호출별 토큰 수를 바탕으로 정확하게 계산됩니다.
- 절감액 — 선택한 기간에 절감한 USD 금액입니다. 실제 캐시 읽기 요율을 사용해 모델별로 계산하며, 단순 평균값으로 추정하지 않습니다. 이 값은 카탈로그 요금 기준 추정치입니다. 실제 청구액에는 카탈로그 최저 요금이 적용되고 캐시된 호출의 청구액은 그보다 낮을 수 있으므로, 이 수치는 실제 절감액의 정확한 상한입니다. 일반적인 채팅 작업에서는 두 값의 차이가 몇 퍼센트 이내입니다.
각 호출의 상세 페이지(/app/usage/<id>)에는 캐시 및 캐시 쓰기 토큰 수가 0이 아닐 때 표시되며, 실제 청구 금액도 나옵니다.
응답 필드
Kunavo는 두 가지 응답 형식 모두에서 캐시 토큰을 제공합니다. OpenAI 호환 /v1/chat/completions 엔드포인트에서는 다음과 같습니다:
| 필드 | 의미 |
|---|---|
usage. | 전체 입력 토큰 수(캐시 및 캐시 쓰기 토큰 포함). |
usage. | 캐시에서 제공된 입력 토큰의 하위 집합. |
usage. | 이번 호출에서 캐시에 기록된 토큰(위 표의 모델별 캐시 쓰기 요금으로 청구). |
/v1/messages의 네이티브 Messages API에서는 Anthropic 원본 필드가 그대로 전달됩니다:
| 필드 | 의미 |
|---|---|
input_tokens | 캐시되지 않은 신규 입력. |
cache_ | 캐시에서 제공되며 입력 요금의 0.10×로 청구 (Claude Fable 5.1에서는 0.025×, Claude Opus 5.5에서는 0.05×). |
cache_ | 이번 호출에서 캐시에 기록됨(입력 가격의 1.25배로 청구 — TTL 1시간 쓰기도 마찬가지이며, Anthropic의 2배보다 낮음). |
다음 단계
- Messages API 레퍼런스 — 작업 예제가 포함된 네이티브 Anthropic 형식입니다.
- Claude 프롬프트 캐싱 — 캐시 상태를 진단하는 사용량 객체 값과 게이트웨이 경유 라우팅으로 적중률이 깨지는 세 가지 방식.
- 청구 및 원장 — 캐시 요금을 반영하는 max() 최저액이 업스트림 비용과 상호작용하는 방식.
- 전체 가격표 — 모든 채팅 모델의 신규 입력 / 출력 가격과 하단의 캐시 가격 하위 표.