Caché de prompts
AUTOMÁTICOLos modelos open-weight alojados almacenan los prefijos de prompt repetidos automáticamente. Cuando una solicitud comienza con el mismo prompt del sistema, herramientas y mensajes anteriores que una solicitud reciente en el mismo modelo, ese prefijo compartido se lee de la caché y se factura al 25% del precio de entrada del modelo. No hay que activar nada, y las escrituras en la caché son gratuitas.
Cómo funciona
- Prefijo, en orden — El prompt se lee en orden: prompt del sistema, definiciones de herramientas y luego los mensajes. La caché coincide desde el inicio de esa secuencia hasta el primer token que difiere.
- Qué se considera un acierto (hit) — Una solicitud cuyo prompt comienza con el mismo contenido que una solicitud reciente — típicamente el turno anterior de la misma conversación con nuevos mensajes añadidos. El prefijo coincidente es entrada en caché; todo lo posterior es entrada regular.
- Granularidad — La caché guarda un prompt en bloques de 1,568 tokens, así que un prompt de menos de unos 1,500 tokens no se almacena en caché. El recuento en caché de una respuesta es tu recuento de entrada multiplicado por la parte del prompt que está en caché, redondeado hacia abajo. No es necesariamente un múltiplo del tamaño del bloque.
- Sin acierto — Una solicitud cuyo comienzo no está en la caché se factura a la tarifa de entrada normal. No se publica ninguna duración para los prompts en caché y un acierto no está garantizado: lee
usagepara ver qué tomó una solicitud de la caché. - Sin interruptor — Una solicitud no necesita activarlo, y ningún campo desactiva la caché.
- Qué modelos — Cualquier id open-weight alojado. GET /v1/models reporta capabilities.prompt_caching: true y pricing.cached_input_per_million_usd para ellos. Los modelos Shannon facturan una tarifa plana.
Ver un acierto de caché en una respuesta
Envía dos solicitudes que empiecen con el mismo system prompt largo e imprime el uso de cada una. El primer número es la entrada de la solicitud; el segundo es la parte que se leyó de la caché.
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 Precios
Los tokens de entrada en caché se facturan al 25% de la tarifa de entrada del modelo, redondeado a $0.001 por 1M. Escribir en la caché no tiene coste extra y la salida se factura como habitualmente. La tarifa de caché de cada id está en la tabla de Modelos y precios. Modelos y precios
La entrada de una llamada se cobra como (entrada − en caché) × tarifa de entrada + en caché × tarifa de caché. El recuento en caché nunca es mayor que el recuento de entrada.
| Modelo | Entrada / 1M | Entrada en caché / 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 |
El registro de uso lista la entrada en caché de cada llamada. Sus tokens facturados y su costo ya incluyen la tarifa de caché. Claves y uso
Campos de uso
| Endpoint | Entrada en caché | Razonamiento |
|---|---|---|
/v1/chat/completions | usage.prompt_tokens_details.cached_tokens — parte de prompt_tokens | usage.completion_tokens_details.reasoning_tokens — parte de completion_tokens |
/v1/responses | usage.input_tokens_details.cached_tokens — parte de input_tokens | usage.output_tokens_details.reasoning_tokens — parte de output_tokens |
/v1/messages | usage.cache_read_input_tokens — reportado aparte: input_tokens es la parte no almacenada; cache_creation_input_tokens es siempre 0 | el razonamiento se cuenta en 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
}
} Una respuesta en streaming lleva los mismos campos en su uso final. No tienes que pedirlo:
| Endpoint | Dónde llega el uso |
|---|---|
/v1/chat/completions | usage en el último fragmento antes de data: [DONE]. Se envía en todos los streams. |
/v1/responses | response.usage del evento response.completed. |
/v1/messages | usage del evento message_delta. El usage de message_start contiene ceros. |
Cómo obtener más aciertos de caché
- Mantenga el prompt del sistema y las definiciones de herramientas idénticos byte a byte entre llamadas. Coloque valores específicos de cada llamada, como marcas de tiempo o ids de solicitud, al final del último mensaje, no en el prompt del sistema.
- Solo añada contenido al historial. Editar, recortar o resumir turnos anteriores cambia el prefijo, y todo lo posterior al primer cambio se factura como entrada regular.
- No reordene herramientas, mensajes o bloques de contenido entre llamadas, y serialice JSON (esquemas de herramientas, argumentos y resultados) de la misma manera siempre.
- Mantén un mismo id de modelo durante una conversación y envía la siguiente llamada poco después de la anterior.
La API mantiene estable el comienzo de una conversación en estos casos:
- Un mensaje
systemodeveloperenviado más adelante en una conversación se queda en su lugar. No cambia el comienzo del prompt, así que los turnos anteriores siguen en caché. - Los argumentos de las llamadas a herramientas en turnos anteriores del asistente se comparan por valor. El orden de las claves y los espacios de ese JSON no importan.
- Los tres endpoints leen una conversación de la misma manera. Una conversación continuada en otro endpoint conserva su prefijo compartido cuando el contenido es el mismo.
Campos de solicitud
Se aceptan prompt_cache_key (Chat Completions y Responses) y cache_control en los bloques de contenido de Messages, por lo que el código del cliente existente funciona sin cambios. Ninguno es obligatorio: el almacenamiento en caché es automático y funciona igual sin ellos.
| Campo | Enviado a | Qué es |
|---|---|---|
prompt_cache_key | /v1/chat/completions, /v1/responses | Una clave de enrutamiento de caché de la API de OpenAI. |
cache_control | /v1/messages | Un punto de corte de caché en un bloque de contenido, un bloque system o un mensaje de la API de Anthropic. |
stream_options | /v1/chat/completions | include_usage pide a la API de OpenAI el uso en un stream. Aquí todo stream termina con el uso. |
Conteo de tokens
Dos endpoints gratuitos, POST /v1/tokenize y POST /v1/messages/count_tokens, cuentan los tokens de un texto o de una solicitud completa para los modelos de pesos abiertos alojados antes de que la envíes. Tienen su propia página: Conteo de tokens