프롬프트 캐싱

반복되는 앞부분을 다시 계산하지 않는다

일부 추론 엔진은 이전 요청의 프롬프트를 처리하며 만든 KV 캐시를 재사용할 수 있습니다. 그래서 앞부분이 같은 후속 요청은 그 부분을 다시 계산하는 값을 전부 내지 않아도 됩니다. 이때 재사용된 부분이 캐시 토큰(cached tokens) 으로 잡히고, 더 낮은 단가로 청구됩니다.

과금 방식

prompt_tokens 에는 캐시로 처리된 부분이 이미 포함되어 있습니다 — 별도로 세는 값이 아닙니다. 우리는 이 값을 다시 빼서 따로 가격을 매깁니다.

billable_prompt = prompt_tokens - cached_tokens

cost = billable_prompt × 프롬프트 단가
     + cached_tokens    × 캐시 읽기 단가
     + completion_tokens × 완성 단가

카탈로그에 캐시 읽기 단가가 따로 없는 모델은 캐시 적중분을 프롬프트 단가의 10% 로 자동 계산합니다 — 요금 계산 방식 을 보세요. 이 비율을 직접 계산할 필요는 없습니다. GET /models 로 조회하는 판매 단가에 이미 반영되어 있습니다.

bash
curl -s "https://openrouter.myip.co.kr/api/v1/models" | jq '.data[] | select(.id=="lgai/exaone-4.0-32b") | .pricing'
json
{
  "prompt": "0.000030000000",
  "completion": "0.000150000000",
  "input_cache_read": "0.000003000000",
  "input_cache_write": null,
  "currency": "KRW"
}

캐시 쓰기 토큰(새 캐시 항목을 만드는 데 든 토큰)은 usage_records 에 기록만 되고 청구되지 않습니다 — 업스트림 엔진마다 캐시 쓰기 토큰 수를 보고하는 방식이 제각각이라, 안전하게 청구할 수 있을 만큼 일관되지 않기 때문입니다.

얼마나 절약됐는지 확인하기

usage 객체에는 prompt_tokens_details 세부 항목이 들어 있습니다.

json
{
  "usage": {
    "prompt_tokens": 10339,
    "completion_tokens": 60,
    "total_tokens": 10399,
    "prompt_tokens_details": {
      "cached_tokens": 10318,
      "cache_write_tokens": 0
    },
    "cost": 0.003410,
    "cost_details": { "upstream_inference_cost": 0.002598 }
  }
}

cached_tokens 가 0보다 크면 프롬프트 일부가 캐시에서 서빙되어 할인된 단가로 청구됐다는 뜻입니다. 정산이 끝나면 같은 값이 GET /generationnative_tokens_cached 로도 돌아옵니다.

우리에게 없는 것

MyIP OpenRouter 는 수십 개의 외부 provider 를 모아놓은 것이 아니라 작고 고정된 카탈로그를 서빙합니다. 그래서 openrouter.ai 가 프롬프트 캐싱 문서에서 다루는 것 중 여기서는 적용되지 않는 것들이 있습니다. 명확히 짚어 둡니다.

  • cache_control 필드가 없습니다. Anthropic 식의 명시적 캐시 breakpoint 나 OpenAI 식의 prompt_cache_options / prompt_cache_breakpoint 는 우리가 서빙하지 않는 모델들을 위한 provider 고유 메커니즘입니다. 이 필드를 보내도 라우팅 대상이 아닌 다른 필드와 마찬가지로 업스트림에 그대로 전달될 뿐이고, 우리 두 카탈로그 모델은 알지 못하는 필드를 그냥 무시합니다.
  • session_id 스티키 라우팅이 없습니다. openrouter 는 같은 요청이 계속 같은 provider 로 가게 해서 여러 후보 엔드포인트에 걸쳐 캐시를 따뜻하게 유지하려고 session_id 를 씁니다. 우리는 이 장치가 필요 없습니다 — 로컬로 서빙하는 모델은 항상 같은 슬롯이 응답하고, 외부로 전달하는 모델도 openrouter 마켓플레이스처럼 여러 provider 에 동시에 걸쳐 있지 않습니다. 고정할 세션 자체가 없습니다.
  • provider 별 캐시 단가표가 없습니다. 서빙 엔진이 cached_tokens 로 보고하는 값은 무엇이든 위의 산식 하나로 가격이 매겨집니다 — 업스트림 벤더마다 다른 가격표가 있는 게 아니라 단가표가 하나뿐입니다.

이 중 어느 것도 여러분이 따로 조치할 필요는 없습니다. 기존 클라이언트 코드가 습관적으로(예를 들어 openrouter.ai 에도 같이 보내던 코드라서) cache_control 이나 session_id 를 보내더라도 여기서는 해가 되지 않습니다 — 라우팅 키가 아니므로 그대로 통과되고, 이해하지 못하는 모델은 무시할 뿐입니다.

실무에서 의미하는 것

  • 요청 단위로 캐싱을 켜거나 끄는 절차는 없습니다.
  • messages 배열의 앞부분(같은 시스템 프롬프트, 앞쪽에 고정된 few-shot 예시)을 요청마다 그대로 유지하고 바뀌는 내용을 뒤쪽으로 미루면, 캐싱을 지원하는 엔진이 재사용 가능한 접두사를 찾을 가능성이 높아집니다 — 다른 prefix 캐시와 같은 원리입니다.
  • 캐싱이 실제로 도움이 됐는지는 짐작하지 말고 prompt_tokens_details.cached_tokens 로 사후에 확인하세요.

관련 문서

마지막 수정 2026. 9. 5.