Mise en cache du prompt
AUTOMATIQUELes modèles open-weight hébergés mettent en cache les préfixes de prompt répétés automatiquement. Lorsqu'une requête commence par le même prompt système, les mêmes outils et les mêmes messages qu'une requête récente sur le même modèle, ce préfixe partagé est lu depuis le cache et facturé à 25 % du prix d'entrée du modèle. Rien n'est à activer, et les écritures au cache sont gratuites.
Comment ça marche
- Préfixe, dans l'ordre — Le prompt est lu dans l'ordre : prompt système, définitions d'outils, puis les messages. Le cache correspond depuis le début de cette séquence jusqu'au premier token différent.
- Qu'est-ce qu'un 'hit' — Une requête dont le prompt commence par le même contenu qu'une requête récente — typiquement le tour précédent de la même conversation avec de nouveaux messages ajoutés. Le préfixe correspondant est de l'entrée mise en cache ; tout ce qui suit est de l'entrée régulière.
- Granularité — Le cache conserve un prompt par blocs de 1,568 tokens : un prompt de moins d'environ 1,500 tokens n'est donc pas mis en cache. Le nombre en cache dans une réponse est votre nombre d'entrée multiplié par la part du prompt en cache, arrondi à l'inférieur. Ce n'est pas forcément un multiple de la taille de bloc.
- Sans hit — Une requête dont le début n'est pas dans le cache est facturée au tarif d'entrée normal. Aucune durée de vie n'est publiée pour les prompts en cache et un hit n'est pas garanti : lisez
usagepour voir ce qu'une requête a pris dans le cache. - Pas d'interrupteur — Une requête n'a pas à l'activer, et aucun champ ne désactive le cache.
- Quels modèles — Chaque ID open-weight hébergé. GET /v1/models rapporte capabilities.prompt_caching: true et pricing.cached_input_per_million_usd pour ceux-ci. Les modèles Shannon facturent un tarif forfaitaire.
Voir un hit de cache dans une réponse
Envoyez deux requêtes qui commencent par le même long prompt système et affichez l'utilisation de chacune. Le premier nombre est l'entrée de la requête, le second est la partie qui a été lue dans le cache.
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.shannon-ai.com/v1")
handbook = open("handbook.txt").read() # a long text that stays the same
def ask(question):
response = client.chat.completions.create(
model="Kimi-K3-3BIT-REAP",
messages=[
{"role": "system", "content": handbook},
{"role": "user", "content": question},
],
)
usage = response.usage
print(usage.prompt_tokens, usage.prompt_tokens_details.cached_tokens)
ask("What is the refund policy?")
ask("Who approves travel?") # same start: read the second number import { readFileSync } from "node:fs";
import OpenAI from "openai";
const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.shannon-ai.com/v1" });
const handbook = readFileSync("handbook.txt", "utf8"); // a long text that stays the same
async function ask(question) {
const response = await client.chat.completions.create({
model: "Kimi-K3-3BIT-REAP",
messages: [
{ role: "system", content: handbook },
{ role: "user", content: question },
],
});
const usage = response.usage;
console.log(usage.prompt_tokens, usage.prompt_tokens_details.cached_tokens);
}
await ask("What is the refund policy?");
await ask("Who approves travel?"); // same start: read the second number # handbook.txt is a long text that stays the same. jq builds the JSON body from it
# and prints the usage object of the reply. Run it twice with different questions.
jq -Rs '{
model: "Kimi-K3-3BIT-REAP",
messages: [
{role: "system", content: .},
{role: "user", content: "What is the refund policy?"}
]
}' handbook.txt \
| curl -s https://api.shannon-ai.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d @- \
| jq .usage Tarification
Les tokens d'entrée mis en cache sont facturés à 25 % du tarif d'entrée du modèle, arrondi à $0.001 per 1M. L'écriture dans le cache ne coûte rien de plus, et la sortie est facturée normalement. Le tarif de cache de chaque ID figure dans le tableau Modèles & Tarification. Modèles et tarifs
L'entrée d'un appel est facturée comme (entrée − cache) × tarif d'entrée + cache × tarif du cache. Le nombre en cache n'est jamais supérieur au nombre d'entrée.
| Modèle | Entrée / 1M | Entrée en cache / 1M |
|---|---|---|
DeepSeek-V4-Pro-0813-3BIT-REAP | $1.95 | $0.488 |
GLM-5.2-3BIT-REAP | $0.73 | $0.183 |
Kimi-K3-3BIT-REAP | $3.83 | $0.958 |
Nemotron3Ultra-3BIT-REAP | $0.75 | $0.188 |
MiniMax-M3-3BIT-REAP | $0.50 | $0.125 |
DeepSeek-V4-Flash-0731-W4A16-AUTOROUND-REAP | $0.50 | $0.125 |
Kimi-K2.6-W4A16-AUTOROUND-REAP | $0.78 | $0.195 |
Laguna-S-2.1-W4A16-AUTOROUND-REAP | $0.50 | $0.125 |
inkling-W4A16-AUTOROUND-REAP | $1.42 | $0.355 |
MiMo-V2.5-Pro-W8A16 | $0.50 | $0.125 |
MiMo-V2.5-W8A16 | $0.50 | $0.125 |
Hy3-W8A16 | $0.50 | $0.125 |
Le journal d'utilisation liste l'entrée en cache de chaque appel. Ses tokens facturés et son coût incluent déjà le tarif du cache. Clés et utilisation
Champs d'utilisation
| Point de terminaison | Entrée mise en cache | Raisonnement |
|---|---|---|
/v1/chat/completions | usage.prompt_tokens_details.cached_tokens — partie de prompt_tokens | usage.completion_tokens_details.reasoning_tokens — partie de completion_tokens |
/v1/responses | usage.input_tokens_details.cached_tokens — partie de input_tokens | usage.output_tokens_details.reasoning_tokens — partie de output_tokens |
/v1/messages | usage.cache_read_input_tokens — rapporté séparément : input_tokens est la partie non mise en cache ; cache_creation_input_tokens est toujours 0 | la réflexion est comptée dans output_tokens |
{
"usage": {
"prompt_tokens": 20000,
"completion_tokens": 812,
"total_tokens": 20812,
"prompt_tokens_details": {
"cached_tokens": 18000
},
"completion_tokens_details": {
"reasoning_tokens": 604
}
}
} {
"usage": {
"input_tokens": 20000,
"input_tokens_details": {
"cached_tokens": 18000
},
"output_tokens": 812,
"output_tokens_details": {
"reasoning_tokens": 604
},
"total_tokens": 20812
}
} {
"usage": {
"input_tokens": 2000,
"cache_read_input_tokens": 18000,
"cache_creation_input_tokens": 0,
"output_tokens": 812
}
} Une réponse en streaming porte les mêmes champs dans son utilisation finale. Vous n'avez pas à la demander :
| Point de terminaison | Où arrive l'utilisation |
|---|---|
/v1/chat/completions | usage sur le dernier chunk avant data: [DONE]. Il est envoyé sur chaque flux. |
/v1/responses | response.usage de l'événement response.completed. |
/v1/messages | usage de l'événement message_delta. Le usage de message_start contient des zéros. |
Optimiser les hits de cache
- Gardez le prompt système et les définitions d'outils strictement identiques entre les appels. Placez les valeurs variables, comme les horodatages ou les IDs de requête, à la fin du dernier message, et non dans le prompt système.
- Ajoutez uniquement à l'historique. Modifier, tronquer ou résumer des tours précédents modifie le préfixe, et tout ce qui suit le premier changement est facturé comme une entrée régulière.
- Ne réorganisez pas les outils, les messages ou les blocs de contenu entre les appels, et sérialisez le JSON (schémas d'outils, arguments et résultats) de la même manière à chaque fois.
- Restez sur un seul id de modèle pendant une conversation, et envoyez l'appel suivant peu après le précédent.
L'API garde le début d'une conversation stable dans ces cas :
- Un message
systemoudeveloperenvoyé plus tard dans une conversation reste à sa place. Il ne modifie pas le début du prompt, donc les tours qui le précèdent restent en cache. - Les arguments des appels d'outil dans les tours précédents de l'assistant sont comparés par valeur. L'ordre des clés et les espaces de ce JSON n'ont pas d'importance.
- Les trois points de terminaison lisent une conversation de la même façon. Une conversation poursuivie sur un autre point de terminaison conserve son préfixe commun quand le contenu est identique.
Champs de requête
prompt_cache_key (Chat Completions et Responses) et cache_control sur les blocs de contenu Messages sont acceptés, permettant au code client existant de fonctionner sans modification. Aucun n'est requis : la mise en cache est automatique et fonctionne de la même manière sans eux.
| Champ | Envoyé à | Ce que c'est |
|---|---|---|
prompt_cache_key | /v1/chat/completions, /v1/responses | Une clé de routage de cache de l'API OpenAI. |
cache_control | /v1/messages | Un point d'arrêt de cache sur un bloc de contenu, un bloc system ou un message de l'API Anthropic. |
stream_options | /v1/chat/completions | include_usage demande à l'API OpenAI l'utilisation sur un flux. Ici, chaque flux se termine par l'utilisation. |
Comptage des tokens
Deux points de terminaison gratuits, POST /v1/tokenize et POST /v1/messages/count_tokens, comptent les tokens d'un texte ou d'une requête entière pour les modèles open-weight hébergés avant que vous l'envoyiez. Ils ont leur propre page : Décompte de tokens