Prompt caching
OTOMATISModel open-weight hosted menyimpan cache prefix prompt yang berulang secara otomatis. Saat permintaan dimulai dengan system prompt, tools, dan pesan sebelumnya yang sama dengan permintaan terbaru pada model yang sama, prefix bersama tersebut dibaca dari cache dan ditagih 25% dari harga input model. Tidak ada yang perlu diaktifkan, dan penulisan cache adalah gratis.
Cara kerja
- Prefix, secara berurutan — Prompt dibaca secara berurutan: system prompt, definisi tool, lalu pesan. Cache cocok dari awal urutan tersebut hingga token pertama yang berbeda.
- Apa yang dihitung sebagai hit — Permintaan yang prompt-nya dimulai dengan konten yang sama dengan permintaan terbaru — biasanya giliran sebelumnya dari percakapan yang sama dengan pesan baru yang ditambahkan. Prefix yang cocok adalah input ter-cache; semua setelahnya adalah input reguler.
- Granularitas — Cache menyimpan prompt dalam blok berukuran 1,568 token, sehingga prompt yang lebih pendek dari sekitar 1,500 token tidak di-cache. Jumlah cached dalam balasan adalah jumlah input Anda dikalikan porsi prompt yang ter-cache, dibulatkan ke bawah. Jumlah itu belum tentu kelipatan ukuran blok.
- Tanpa hit — Permintaan yang bagian awalnya tidak ada di cache ditagih dengan tarif input reguler. Tidak ada masa berlaku yang dipublikasikan untuk prompt yang di-cache dan hit tidak dijamin: baca
usageuntuk melihat apa yang diambil permintaan dari cache. - Tanpa sakelar — Permintaan tidak perlu ikut serta, dan tidak ada field yang mematikan caching.
- Model mana saja — Setiap id open-weight hosted. GET /v1/models melaporkan capabilities.prompt_caching: true dan pricing.cached_input_per_million_usd untuk mereka. Model Shannon menagih satu tarif flat.
Melihat cache hit dalam balasan
Kirim dua permintaan yang diawali system prompt panjang yang sama dan cetak usage dari masing-masing. Angka pertama adalah input permintaan, angka kedua adalah bagian yang dibaca dari 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 Harga
Token input ter-cache ditagih 25% dari tarif input model, dibulatkan menjadi $0.001 per 1M. Menulis ke cache tidak memerlukan biaya tambahan, dan output ditagih seperti biasa. Tarif cache setiap id ada di tabel Models & pricing. Model & harga
Input sebuah panggilan ditagih sebagai (input − cached) × tarif input + cached × tarif cached. Jumlah cached tidak pernah lebih besar daripada jumlah input.
| Model | Input / 1M | Input ter-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 |
Log penggunaan mencantumkan input ter-cache dari setiap panggilan. Token yang ditagih dan biayanya sudah memasukkan tarif cached. Keys & usage
Field penggunaan
| Endpoint | Input ter-cache | Penalaran |
|---|---|---|
/v1/chat/completions | usage.prompt_tokens_details.cached_tokens — bagian dari prompt_tokens | usage.completion_tokens_details.reasoning_tokens — bagian dari completion_tokens |
/v1/responses | usage.input_tokens_details.cached_tokens — bagian dari input_tokens | usage.output_tokens_details.reasoning_tokens — bagian dari output_tokens |
/v1/messages | usage.cache_read_input_tokens — dilaporkan terpisah: input_tokens adalah bagian yang tidak ter-cache; cache_creation_input_tokens selalu 0 | thinking dihitung dalam 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
}
} Balasan yang di-stream membawa field yang sama dalam usage akhirnya. Anda tidak perlu memintanya:
| Endpoint | Tempat usage tiba |
|---|---|
/v1/chat/completions | usage pada chunk terakhir sebelum data: [DONE]. Dikirim di setiap stream. |
/v1/responses | response.usage dari event response.completed. |
/v1/messages | usage dari event message_delta. usage pada message_start berisi nol. |
Mendapatkan lebih banyak cache hit
- Pastikan system prompt dan definisi tool stabil secara byte-per-byte di seluruh panggilan. Letakkan nilai per-panggilan seperti timestamp atau request id di akhir pesan terbaru, bukan di system prompt.
- Hanya tambahkan (append) ke riwayat. Mengedit, memotong, atau meringkas giliran sebelumnya akan mengubah prefix, dan semua setelah perubahan pertama akan ditagih sebagai input reguler.
- Jangan mengubah urutan tools, pesan, atau blok konten antar panggilan, dan serialisasi JSON (skema tool, argumen tool, dan hasil) dengan cara yang sama setiap saat.
- Tetaplah memakai satu id model dalam satu percakapan, dan kirim panggilan lanjutan tidak lama setelah panggilan sebelumnya.
API menjaga awal percakapan tetap stabil dalam kasus berikut:
- Pesan
systemataudeveloperyang dikirim belakangan dalam percakapan tetap berada di tempatnya. Pesan itu tidak mengubah awal prompt, sehingga giliran sebelumnya tetap ter-cache. - Argumen panggilan tool pada giliran assistant sebelumnya dibandingkan berdasarkan nilai. Urutan key dan spasi pada JSON itu tidak berpengaruh.
- Ketiga endpoint membaca percakapan dengan cara yang sama. Percakapan yang dilanjutkan di endpoint lain mempertahankan prefix bersamanya jika kontennya sama.
Field permintaan
prompt_cache_key (Chat Completions dan Responses) serta cache_control pada blok konten Messages diterima, sehingga kode klien yang ada tetap berjalan tanpa perubahan. Keduanya tidak wajib: caching bersifat otomatis dan bekerja dengan cara yang sama tanpanya.
| Field | Dikirim ke | Artinya |
|---|---|---|
prompt_cache_key | /v1/chat/completions, /v1/responses | Cache routing key dari API OpenAI. |
cache_control | /v1/messages | Cache breakpoint pada blok konten, blok system, atau pesan dari API Anthropic. |
stream_options | /v1/chat/completions | include_usage meminta usage pada stream dari API OpenAI. Di sini setiap stream diakhiri dengan usage. |
Menghitung token
Dua endpoint gratis, POST /v1/tokenize dan POST /v1/messages/count_tokens, menghitung token dari sebuah teks atau seluruh permintaan untuk model open-weight hosted sebelum Anda mengirimnya. Keduanya punya halaman sendiri: Penghitungan token