Si vous envoyez un long prompt système — contexte RAG, catalogue d’outils, règles d’agent, exemples — vous payez probablement le plein tarif d’entrée à chaque appel. La mise en cache des prompts d’Anthropic réduit ce coût à 10 % du tarif sur la portion mise en cache. OpenAI fait la même chose implicitement. La plupart des équipes estiment que cela vaut 30 minutes de travail, car cela réduit régulièrement de 60 à 90 % le coût de leurs entrées.
Kunavo gère les deux. Vos cache_control personnels sont transmis tels quels par l’API Messages ; avec les API Chat Completions et Responses — dont le format ne comporte aucun champ de ce type à envoyer — Kunavo les définit pour vous et en ajoute autour de ce que vous avez envoyé, sans jamais dépasser la limite de 4. Cet article explique les deux approches, les pièges qui invalident discrètement les caches et la manière de vérifier votre taux d’utilisation du cache.
Avant et après
Une boucle naïve qui envoie dix fois le même prompt système de 18 k tokens :
# What most people start with: every call re-pays for the whole prompt.
import anthropic
client = anthropic.Anthropic(
api_key="sk-kn-...",
base_url="https://api.kunavo.com",
)
SYSTEM = open("system-prompt.md").read() # 18,000 tokens of rules + examples
# 10 user questions in a session. Every call sends the 18K-token system block.
for question in questions:
resp = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=600,
system=SYSTEM,
messages=[{"role": "user", "content": question}],
)
# Cost per call (input only): 18,000 × $3 / 1M = $0.054
# 10 calls: $0.54 in input alone.Il suffit maintenant de marquer le bloc système comme pouvant être mis en cache — un champ supplémentaire :
# The fix: mark the static prefix as cacheable. After the first call,
# subsequent calls within ~5 minutes pay 10% the input rate on the cached
# portion. Same answer, 89% cheaper.
resp = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=600,
system=[
{
"type": "text",
"text": SYSTEM,
"cache_control": {"type": "ephemeral"}, # mark cacheable
}
],
messages=[{"role": "user", "content": question}],
)
# First call (cache write): 18,000 × $3.75 / 1M = $0.0675 (1.25× input)
# Calls 2–10 (cache hit): 18,000 × $0.30 / 1M = $0.0054 each
# Total: $0.0675 + 9 × $0.0054 = $0.116 (was $0.54 — 78.5% saved)Vous venez d’économiser 78,5 % du coût d’entrée sur cette session. Le premier appel est en réalité légèrement plus cher que la version naïve (environ 1,25× le tarif d’entrée pour écrire le cache). Les appels 2 à 10 paient 10 % du tarif. Le seuil de rentabilité est atteint à l’appel 2 — dès l’appel 3, vous êtes gagnant. À l’appel 10, l’écart est considérable.
Style OpenAI : rien à faire
Le format OpenAI Chat Completions ne comporte aucun champ cache_control, car OpenAI met implicitement en cache sur ses propres serveurs. Claude ne le fait pas : il ne met en cache que ce qu’un point de rupture désigne. Ainsi, lorsque vous accédez à un modèle Claude via /v1/chat/completions ou /v1/responses, Kunavo définit les points de rupture à votre place : un point glissant sur le dernier message dès que la conversation comporte au moins un tour de l’assistant, puis un après system et un après tools. Tout ce que vous définissez vous-même reste exactement à l’endroit choisi — Kunavo ne remplit que les positions laissées vides, et seulement jusqu’à la limite de 4. Rien à configurer, et le même modèle coûte la même chose que vous passiez par la route Anthropic ou OpenAI :
# OpenAI Chat Completions style — Kunavo sets the breakpoints for you.
# No flag to set. The "usage" object tells you what was cached.
from openai import OpenAI
client = OpenAI(
api_key="sk-kn-...",
base_url="https://api.kunavo.com/v1",
)
resp = client.chat.completions.create(
model="claude-sonnet-4-6",
messages=[
{"role": "system", "content": LONG_SYSTEM_PROMPT}, # >1024 tokens
{"role": "user", "content": "Latest question…"},
],
)
# In the response:
# resp.usage.prompt_tokens_details.cached_tokens → 17,800
# resp.usage.prompt_tokens → 18,200
# 17.8K/18.2K = 98% of input came from cache. Bill reflects that automatically.Consultez usage.prompt_tokens_details.cached_tokens pour voir quelle quantité a été servie depuis le cache. Plus le préfixe fixe est grand, plus les économies sont importantes. Règle générale : si votre prompt système est plus court que votre contenu utilisateur variable, la mise en cache n’apporte pas grand-chose. Restructurez le prompt afin que les parties statiques soient volumineuses et placées au début.
Mise en cache multicouche — jusqu’à 4 points de rupture
Pour les boucles d’agents où certaines couches changent plus vite que d’autres, définissez plusieurs points de rupture cache_control. Chacun constitue un instantané de tout ce qui le précède :
# Anthropic supports up to 4 cache breakpoints per request — use them
# to keep the cache hot even as later layers change.
client.messages.create(
model="claude-sonnet-4-6",
max_tokens=600,
system=[
{"type": "text",
"text": ROLE_AND_RULES, # ~3,000 tokens
"cache_control": {"type": "ephemeral"}}, # breakpoint 1
{"type": "text",
"text": LARGE_KNOWLEDGE_BASE, # ~15,000 tokens, rarely changes
"cache_control": {"type": "ephemeral"}}, # breakpoint 2
],
messages=[
{"role": "user",
"content": [
{"type": "text",
"text": CONVERSATION_HISTORY, # grows each turn
"cache_control": {"type": "ephemeral"}}, # breakpoint 3
{"type": "text", "text": new_question},
]},
],
)
# When CONVERSATION_HISTORY changes, breakpoints 1+2 still hit cache.
# Only breakpoint 3 + the new question pay full input rate.La clé du cache est l’intégralité du préfixe. Ajoutez un token à la position N et chaque point de rupture situé à N ou après est invalidé. L’ordre compte : contenu le plus stable en premier. La couche de règles devrait rarement changer ; la base de connaissances est mise à jour chaque semaine ; la conversation s’allonge à chaque tour.
Façons courantes de casser discrètement la mise en cache
- Placer la date actuelle ou un request_id dans le prompt. Chaque appel crée un nouveau préfixe, le taux de succès du cache est donc de 0 %. Hachez les entrées de votre prompt et comparez-les entre les appels.
- Assemblage non déterministe du prompt système. Si vous construisez le système à partir d’un dictionnaire, l’ordre d’itération du dictionnaire est important dans certaines versions de Python. Triez explicitement les clés.
- La durée de vie du cache est d’environ 5 minutes. Les schémas de trafic clairsemés (un appel toutes les 10 minutes) n’obtiennent aucun accès au cache. Regroupez les appels ou acceptez cette perte.
- Le minimum de 1 024 tokens. En dessous de 1 k token, la mise en cache de style OpenAI ne s’active pas. Regroupez les petits fragments statiques en un seul préfixe plus long.
- Les outils / définitions de fonctions font partie du préfixe. L’ajout d’un nouvel outil au catalogue invalide le cache pour tout le monde. Gardez le catalogue d’outils stable et versionnez-le.
Vérifier le taux d’utilisation du cache
Une mise en cache que vous ne pouvez pas observer, ce n’est pas de l’ingénierie — c’est de l’espoir. Consignez usage à chaque appel :
# Always read usage. If cached_tokens is 0 when you expected a hit,
# something's wrong — usually a non-deterministic prefix.
resp = client.messages.create(...)
u = resp.usage
print({
"input_uncached": u.input_tokens,
"input_cache_read": u.cache_read_input_tokens,
"input_cache_write": u.cache_creation_input_tokens,
"output": u.output_tokens,
})
# A common gotcha: putting today's date or a request_id in the system prompt
# silently invalidates the cache. Hash your inputs; verify cache_read_input_tokens
# is non-zero on the 2nd identical call.Dans le tableau de bord Kunavo, la page Utilisation affiche la répartition du cache par modèle et par jour. Si vous voyez cache_read_input_tokens augmenter en pourcentage du total des entrées, la mise en cache fonctionne. Si la valeur reste à 0 ou fluctue fortement, parcourez la liste des pièges ci-dessus.
Ce que cela coûte réellement sur Kunavo
Le tarif du cache de chaque modèle est publié sur la page des tarifs :
- Modèles Anthropic : les lectures du cache représentent 10% du tarif d’entrée — 2.5% on Claude Fable 5.1, 5% on Claude Opus 5.5. Les écritures du cache coûtent 1,25× le tarif d’entrée — le multiplicateur de cinq minutes d’Anthropic — et Kunavo facture les écritures d’une heure au même tarif de 1,25×, contre 2× chez Anthropic.
- Modèles OpenAI / Gemini : les lectures du cache représentent 10% du tarif d’entrée (le ratio publié par les fournisseurs). Les écritures du cache coûtent 1,25× sur GPT-5.6 et GPT-6 Astra, et le tarif d’entrée normal sur tous les autres modèles.
- Tous les tarifs de mise en cache incluent déjà la remise Kunavo sur le modèle (inférieurs au tarif affiché du fournisseur en amont, selon le modèle). Ainsi, une lecture du cache Sonnet 4.6 sur Kunavo coûte
$3 × 0.40 × 0.10 = $0.12 per 1M tokens. Environ 25 fois moins cher que le tarif amont sans mise en cache.
Quand la mise en cache n’est pas la solution
Quelques cas où l’effort n’en vaut pas la peine :
- Prompts courts (moins de 1 k token au total). Les frais généraux dominent ; ne vous en préoccupez pas.
- Tâches ponctuelles sans trafic répétitif. Le premier appel est légèrement plus cher — la mise en cache ne devient rentable qu’à partir de l’appel 2.
- Tâches à sortie élevée et entrée faible (rédaction créative, génération de code). Les entrées représentent déjà une faible part de la facture. Concentrez-vous plutôt sur les plafonds du budget de sortie.
Pour tout le reste — chatbots RAG, agents avec un catalogue d’outils fixe, classificateurs appliqués à une grille statique, pipelines d’extraction structurée avec des few-shots cohérents — la mise en cache est l’optimisation au meilleur retour sur investissement que vous pouvez déployer en un après-midi. Associez-la aux quatre autres techniques de notre guide d’optimisation des coûts et une réduction des coûts de 70 % est réaliste, sans le moindre compromis sur la qualité des sorties.
Déjà sur Kunavo ? Ouvrez /app/usage et vérifiez la colonne du cache pour votre plus grand modèle. Si elle est à zéro, vous laissez de l’argent sur la table. Guide complet : /docs/caching.