← semua materi
15:00 Teknis Β· 08 Nov 2026 Β· 15:04

πŸ”¬ BACOT β€” Sesi 15:00 Technical Exploration


πŸ“š Topik: Prompt Caching, Token Budget & Optimasi Biaya LLM

Level: menengah Β· Kategori: AI Engineering Β· Verifikasi: docs resmi per 2026-11-08


🎯 Tujuan Belajar

Setelah sesi ini, kamu bisa:

  1. Hitung break-even caching sebelum menulis satu baris kode integrasi
  2. Tahu kenapa cache miss terjadi di prompt yang "kelihatan sama"
  3. Rancang layout prompt (tools β†’ system β†’ messages) supaya cache hit stabil sepanjang umur aplikasi
  4. Pilih TTL dan provider berdasarkan pola trafik, bukan berdasarkan harga headline
  5. Pasang observability supaya cache hit rate jadi metrik yang dipantau, bukan asumsi

πŸ—οΈ Arsitektur & Alur Teknis

Apa yang sebenarnya di-cache

Bukan teks. Yang disimpan adalah KV tensors β€” intermediate state hasil komputasi attention untuk prefix tertentu. Konsekuensinya:

Sifat Implikasi praktis
Hash-nya kumulatif per prefix Ubah 1 token di awal β†’ seluruh hash di belakangnya berubah
Prefix harus match dari token ke-0 Bukan "mirip", harus identik byte-per-byte setelah rendering
Cache entry dipakai ulang lintas request Berlaku selama TTL belum habis
Tidak bisa dibersihkan manual Hanya expire (OpenAI docs, FAQ)

Urutan hierarki cache (Anthropic)

tools[]  β†’  system[]  β†’  messages[]  β†’  (breakpoint terakhir)
   ↑ dibangun berurutan, tiap level menumpuk di atas level sebelumnya

Artinya: tool definition yang berubah meng-invalidate seluruh cache system + messages. Ini sumber cache miss nomor satu di produksi β€” orang menambahkan tool baru per-request berdasarkan permission user.

Mekanisme breakpoint & lookback (Anthropic, sumber: docs resmi)

Turn 1: blok 1..10, breakpoint di 10  β†’ write entry @10
Turn 2: blok 1..15, breakpoint di 15  β†’ miss @15, lookback β†’ hit @10, write @15
Turn 3: blok 1..35, breakpoint di 35  β†’ cek 35..16, entry @15 di luar jendela β†’ MISS

Fix: tambah breakpoint kedua di blok 15. Ini bukan bug, ini desain jendela lookback.

Perbedaan model mental antar provider

Aspek Anthropic (Messages API) OpenAI (GPT-5.6+) Gemini DeepSeek
Aktivasi opt-in cache_control (auto atau per blok) default on default on (implicit) default on
Minimum cacheable 512–4.096 tok, tergantung model 1.024 visible tok (GPT-5.6+) 2.048–4.096 tok tidak dipublikasi eksplisit
Biaya write 1.25Γ— (5m) / 2Γ— (1h) 1.25Γ— (30m) / 2.5Γ— (12h) tidak ada write fee, tapi ada storage tidak ada write fee
Biaya read 0.1Γ— (0.05Γ— Opus/Sonnet 5.5, 0.025Γ— Fable/Mythos 5.1) 0.1Γ— (0.05Γ— GPT-6.1 Sol/Terra) ~0.1Γ— input ~2% input (50Γ— lebih murah)
TTL 5 menit (refresh gratis saat hit) / 1 jam 30 menit / 12 jam dikontrol eksplisit (min 1 menit) jam–hari, otomatis
Storage fee tidak ada tidak ada ada, per MTok/jam tidak ada

⚠️ Angka di tabel ini berubah. Anthropic baru saja menurunkan multiplier read dari 0.1Γ— β†’ 0.05Γ— untuk Opus 5.5 / Sonnet 5.5, dan ke 0.025Γ— untuk Fable 5.1 / Mythos 5.1. Kalau kamu baca artikel 2025, angkanya salah.


πŸ“Š Angka & Benchmark

Harga Anthropic (docs resmi, diakses 2026-11-08, USD/MTok)

Model Input Output Write 5m Write 1h Read
Fable 5.1 $10 $50 $12.50 $20 $0.25 (0.025Γ—)
Opus 5.5 $4 $20 $5 $8 $0.20 (0.05Γ—)
Sonnet 5.5 $2 $10 $2.50 $4 $0.10 (0.05Γ—)
Haiku 4.5 $1 $5 $1.25 $2 $0.10 (0.1Γ—)

Minimum cacheable token (Anthropic): - 512 tok β†’ Fable 5.1, Mythos 5.1, Opus 5.5, Opus 5, Sonnet 5.5, Haiku 5.5 - 1.024 tok β†’ Opus 4.8, Sonnet 5, Sonnet 4.6/4.5, Opus 4.1, Sonnet 4 - 2.048 tok β†’ Mythos Preview, Opus 4.7 - 4.096 tok β†’ Opus 4.6, Opus 4.5, Haiku 4.5

Perhatikan: Haiku 4.5 butuh 4.096 token minimum β€” model termurah justru paling sulit di-cache. Ironi yang sering bikin perhitungan orang meleset.

Harga OpenAI (GPT-5.6+)

Harga Gemini (AI Studio pricing, diakses 2026-11-08)

Model Input Cached input Storage
Gemini 3.8 Flash $0.75 (naik $1.50 per 2027-01-01) $0.075 $0.50 / MTok / jam
Gemini 3.6 Flash $0.75 $0.075 $0.50 / MTok / jam
Gemini 3.1 Pro Preview $2.00 (≀200k) $0.20 $4.50 / MTok / jam
Gemini 2.5 Pro $1.25 $0.125 $4.50 / MTok / jam

Storage fee adalah pembeda utama. Gemini satu-satunya dari empat provider ini yang menagih cache per jam disimpan, terlepas dari berapa kali dibaca.

Harga DeepSeek (docs resmi, per 1M token)

Model Cache hit (off-peak/peak) Cache miss (off-peak/peak) Output
deepseek-flash $0.003 / $0.006 $0.15 / $0.30 $0.60 / $1.20
deepseek-v4-pro $0.022 / $0.044 $0.66 / $1.32 $1.98 / $3.96

Cache hit 50Γ— lebih murah dari miss. Peak hours: 01:00–04:00 dan 06:00–10:00 UTC, Sen–Jum.


πŸ’» Kode Nyata

1. Model biaya & break-even β€” runnable, zero dependency

"""breakeven.py β€” stdlib saja, Python 3.11+"""
def reads_to_breakeven(write_mult, read_mult):
    """Berapa cache-read dibutuhkan agar premium write tertutup."""
    return (write_mult - 1.0) / (1.0 - read_mult)

def cost_mtok(prefix_tok, n_req, write_mult, read_mult, price_mtok, hit_ratio=1.0):
    reuse = max(n_req - 1, 0)
    hits = reuse * hit_ratio
    misses = reuse - hits
    return prefix_tok * (write_mult + hits * read_mult + misses) * price_mtok / 1e6

def gemini_cost(prefix_tok, cached_mtok, storage_mtok_hour, hours):
    return prefix_tok * (cached_mtok + storage_mtok_hour * hours) / 1e6

assert abs(reads_to_breakeven(1.25, 0.1) - 0.2778) < 1e-3
assert reads_to_breakeven(2.0, 0.1) > 1.0   # 1h TTL butuh >1 read

P, N, price = 20_000, 100, 2.0              # Sonnet 5.5
uncached = P * N * price / 1e6
cached = cost_mtok(P, N, 1.25, 0.05, price)
print(f"uncached ${uncached:.4f} | cached ${cached:.4f} | -{1-cached/uncached:.0%}")

wasted = cost_mtok(P, N, 1.25, 0.05, price, hit_ratio=0.0)
assert abs(wasted - P * (1.25 + (N - 1)) * price / 1e6) < 1e-12

Output nyata dari eksekusi:

Sonnet 5.5  100 req cached = $0.2480 (uncached $4.0000, -94%)
tanpa hit   $4.0100 vs uncached $4.0000 = +0.2% lebih mahal
Gemini      cache 1 jam = $0.2350; plain 1 req = $0.1000 -> butuh >1 read
  n= 2 read/jam: cached $0.2350 vs plain $0.2000 -> plain unggul
  n= 5 read/jam: cached $0.2350 vs plain $0.5000 -> cache unggul

Cara baca hasil ini: - 0.278 read untuk 5m TTL β†’ praktis balik modal di request kedua kalau prefix sama - write tanpa hit cuma rugi 0.2% karena write charge 1.25Γ— hanya berlaku sekali dari 100 request β€” premium write itu kecil, dan hampir selalu tertutup - Gemini butuh >1 read dalam 1 jam karena storage fee. Di 2 read masih kalah; baru unggul di 5+.

2. Anthropic β€” explicit breakpoint yang benar

import anthropic  # pip install anthropic (Messages API, non-beta, per docs 2026)

client = anthropic.Anthropic()

SYSTEM = "Kamu analis kontrak. Jawab ringkas, kutip pasal." * 200  # ~2k token, stabil
DOC    = open("kontrak.txt").read()   # ~40k token, stabil per dokumen

def ask(question: str, doc_id: str):
    return client.messages.create(
        model="claude-sonnet-5-5",
        max_tokens=1024,
        system=[
            # breakpoint 1: system prompt, dipakai semua dokumen
            {"type": "text", "text": SYSTEM,
             "cache_control": {"type": "ephemeral"}},
            # breakpoint 2: dokumen, dipakai semua pertanyaan atas dokumen ini
            {"type": "text", "text": DOC, "cache_control": {"type": "ephemeral"}},
        ],
        messages=[{"role": "user", "content": question}],
    )

r = ask("Apa klausul terminasi?")
u = r.usage
print(u.cache_creation_input_tokens, u.cache_read_input_tokens, u.input_tokens)

Kenapa 2 breakpoint, bukan 1: pertanyaan berubah tiap request, dokumen tidak. Kalau breakpoint cuma di akhir (setelah pertanyaan), hash selalu berubah β†’ tidak pernah hit. Ini kesalahan paling umum.

Kalau system prompt sudah β‰₯ minimum tapi dokumen berubah-ubah per user (tiap user beda dokumen), breakpoint 1 tetap berguna sendirian β€” cross-user cache hit pada system prompt.

3. Anthropic β€” automatic caching untuk chat multi-turn

resp = client.messages.create(
    model="claude-sonnet-5-5",
    max_tokens=2048,
    cache_control={"type": "ephemeral"},   # TTL top-level, breakpoint auto geser
    system="Kamu asisten yang mengingat percakapan.",
    messages=history,
)

Breakpoint otomatis pindah ke blok cacheable terakhir tiap request. Cocok kalau setiap turn menambah <20 blok β€” lewat dari itu, jendela lookback tidak menemukan write sebelumnya dan kamu perlu breakpoint tambahan.

Aturan kombinasi (docs): - Blok terakhir sudah punya cache_control TTL sama β†’ automatic jadi no-op - TTL beda β†’ HTTP 400 - 4 breakpoint eksplisit sudah terpakai β†’ HTTP 400 (tidak ada slot untuk automatic)

4. OpenAI β€” TTL campuran dalam satu request

from openai import OpenAI
client = OpenAI()

BASE = "..."  # instruksi panjang, stabil sepanjang hari, >1024 token

resp = client.responses.create(
    model="gpt-5.6",
    prompt_cache_options={"ttl": "30m"},          # default request
    input=[
        {"role": "developer",
         "content": [{"type": "input_text", "text": BASE}],
         "prompt_cache_breakpoint": {"ttl": "12h"}},   # override: prefix panjang
        {"role": "user", "content": "Ringkas bagian 3."},
    ],
)
usage = resp.usage
print(usage.input_tokens_details.cached_tokens)

Cara hitung biaya input yang benar (dari docs OpenAI, diadaptasi):

def input_cost(usage, price_per_mtok, cached_mult=0.1, write_mult=1.25):
    inp  = usage.input_tokens
    cach = usage.input_tokens_details.cached_tokens
    wr   = usage.input_tokens_details.cache_write_tokens
    ordinary = inp - cach - wr
    weighted = ordinary + cach * cached_mult + wr * write_mult
    return weighted * price_per_mtok / 1_000_000

⚠️ Write charge bukan fee tambahan di atas harga normal β€” token masuk salah satu dari tiga bucket: uncached, cached, atau cache-write. Menjumlahkan keduanya = double count.

5. Instrumentasi β€” cache hit rate sebagai metrik

from dataclasses import dataclass

@dataclass
class CacheStat:
    read: int = 0
    write: int = 0
    fresh: int = 0

    def record(self, usage):
        self.read  += getattr(usage, "cache_read_input_tokens", 0) or 0
        self.write += getattr(usage, "cache_creation_input_tokens", 0) or 0
        self.fresh += getattr(usage, "input_tokens", 0) or 0

    @property
    def hit_rate(self) -> float:
        total = self.read + self.write + self.fresh
        return self.read / total if total else 0.0

    def alert(self, floor=0.6) -> str | None:
        if self.hit_rate < floor and (self.read + self.write + self.fresh) > 50_000:
            return f"cache hit rate {self.hit_rate:.1%} di bawah floor {floor:.0%}"
        return None

Pasang ini per-endpoint, bukan global. Global hit rate 85% bisa menyembunyikan satu endpoint yang 0% dan membakar 40% budget.

6. Script verifikasi cepat (jalankan sebelum deploy)

# pastikan prefix benar-benar > minimum & konsisten
python3 -c "
import anthropic,json,hashlib
c=anthropic.Anthropic()
h=lambda s:hashlib.sha256(s.encode()).hexdigest()[:12]
r=c.messages.create(model='claude-sonnet-5-5',max_tokens=16,
  system=[{'type':'text','text':open('system.txt').read(),
           'cache_control':{'type':'ephemeral'}}],
  messages=[{'role':'user','content':'ping'}])
print('write',r.usage.cache_creation_input_tokens,'read',r.usage.cache_read_input_tokens)
"
# jalankan 2x. run pertama: read=0, write>0. run kedua: read>0, write=0 atau kecil.

Kalau run kedua write masih besar β†’ prefix berubah. Cek: timestamp di system prompt, tool list yang di-generate, JSON key ordering, atau user ID yang di-interpolasi.


βš–οΈ Trade-off & Alternatif

Keputusan Untung Buntung Kapan pilih
Cache 5m TTL write murah (1.25Γ—) butuh trafik rapat Chat session, agent loop β€” request tiap detik
Cache 1h TTL tahan jeda panjang write 2Γ— β€” rugi berat kalau tidak di-read Batch job, cron harian, dokumen dipakai sepanjang jam kerja
Cache 12h (OpenAI) prefix lintas shift write 2.5Γ— Knowledge base stabil, dipakai ribuan request/hari
Gemini implicit nol konfigurasi storage fee per jam jalan terus Kalau TTL pendek & read banyak
Gemini explicit kontrol penuh kapan cache hidup harus manage lifecycle manual Workload batch terukur
DeepSeek termurah per token rate limit & concurrency terbatas (2.500 flash / 500 pro) Task non-latency-critical, volume besar
Batch API ~50% diskon tambahan, stacking dengan cache latency jam-an Backfill, eval, klasifikasi massal

Catatan penting soal stacking: diskon batch dan cache read bertumpuk. Anthropic mendokumentasikan pola optimal untuk batch: kirim 1 request dengan shared prefix + 1h cache dulu, tunggu selesai, baru kirim sisanya. Ini jauh lebih efektif daripada 5m TTL karena batch job biasanya selesai dalam 5 menit–1 jam.

Alternatif selain caching (sering lebih besar dampaknya):

Teknik Efek Biaya implementasi
Turunkan max_tokens potong biaya output langsung 1 baris
Routing model (Haiku untuk klasifikasi, Sonnet untuk reasoning) 5–20Γ— lebih murah di task sederhana 1 fungsi klasifikasi
Context compaction potong input historis sedang β€” tapi merusak cache dari token pertama yang berubah
Structured output yang lebih pendek hemat output token rendah
Retrival lebih selektif (RAG chunk kecil) input lebih sedikit sedang

Jebakan: compaction dan caching saling bertentangan. Compaction memotong konteks β†’ prefix berubah β†’ cache miss. Docs OpenAI eksplisit menyebut ini. Hitung total biaya sebelum/sesudah compaction, jangan cuma lihat hit rate yang turun.


🏭 Use Case Produksi & Failure Mode

Kasus 1: Agent coding dengan 40 tool definition

Gejala: hit rate 12%, biaya input 6Γ— estimasi. Penyebab: tool list di-generate per request berdasarkan permission user, urutan tool berubah karena iterasi dict dari DB. Fix: sort tool list deterministik, pisahkan tool yang jarang dipakai ke toolset terpisah (bukan di array utama), cache tool+system sebagai satu breakpoint. Pelajaran: perubahan urutan = perubahan prefix = miss. Docs OpenAI menyebut tools ordering sebagai faktor invalidasi eksplisit.

Kasus 2: RAG dengan timestamp di system prompt

Gejala: hit rate 0% padahal prompt "sama". Penyebab: f"Tanggal hari ini: {datetime.now()}" di awal system prompt. Fix: pindahkan timestamp ke setelah breakpoint, atau bundel jadi granularitas harian.

Kasus 3: Parallel request saat warm-up

Gejala: 20 request paralel, semuanya kena write charge, nol read. Penyebab: cache entry baru tersedia setelah response pertama mulai. Docs Anthropic eksplisit: "For concurrent requests, note that a cache entry only becomes available after the first response starts." Fix: serialize request pertama (warm), baru fan-out. Atau terima biaya write 20Γ— sebagai trade-off latency.

Kasus 4: Model swap di tengah deployment

Gejala: hit rate drop ke 0 setelah upgrade model. Penyebab: ganti model = cache terpisah. Tidak ada cache sharing lintas model. Fix: rollout bertahap; jangan swap model di jam sibuk.

Kasus 5: Prompt di bawah minimum

Gejala: cache_creation_input_tokens = 0 dan cache_read_input_tokens = 0 selamanya, tanpa error. Penyebab: prompt < 1.024/2.048/4.096 token. Tidak ada error yang dikembalikan β€” caching dilewati diam-diam. Fix: log kedua field itu; kalau keduanya 0, prompt tidak pernah di-cache. Catatan docs OpenAI: memperpanjang prefix pendek sampai minimum bisa lebih murah daripada tidak cache sama sekali β€” ada titik break-even. Tapi jangan tambah token sampah; tambah contoh/rubrik yang benar-benar memperbaiki output.

Kasus 6: Cross-tenant cache leak (mitos vs fakta)

Cache tidak dibagi lintas organisasi. Anthropic: isolasi per workspace dalam organisasi (Claude API) atau per organisasi (Bedrock/Vertex). OpenAI: tidak dibagi lintas organisasi maupun lintas regional boundary, dan tidak bisa di-clear manual. Prompt caching eligible untuk ZDR dan HIPAA di kedua provider.


πŸ› οΈ Latihan Praktis Kecil (Β±25 menit)

Target: buktikan sendiri bahwa urutan prompt menentukan hit rate.

  1. Simpan breakeven.py di atas, jalankan. Catat angka hemat untuk kasusmu sendiri (ganti P, N, price dengan workload realistis).

  2. Kalau punya API key β€” jalankan pola verifikasi 2-run:

# run A
r1 = call(system_with_timestamp)   # write>0, read=0
r2 = call(system_with_timestamp)   # write>0 LAGI, read=0  <- bug
# run B
r1 = call(system_without_timestamp)  # write>0, read=0
r2 = call(system_without_timestamp)  # write=0, read>0     <- benar
  1. Tanpa API key: tulis fungsi hit_rate() dan bikin unit test pakai dict palsu berisi tiga angka β€” pastikan hit_rate benar saat total = 0 (jangan ZeroDivisionError).

  2. Hitung: untuk workload-mu, berapa request/jam minimum agar 1h TTL di Anthropic mengalahkan 5m TTL? Pakai reads_to_breakeven(2.0, 0.1) = 11.1 read β€” artinya TTL 1 jam butuh β‰₯12 read dalam window 1 jam untuk menang atas 5 menit.


βœ… Cek Pemahaman

  1. System prompt kamu 800 token, dokumen 30.000 token berubah tiap user, model Sonnet 5.5. Kalau kamu taruh cache_control hanya di akhir dokumen, apa yang terjadi pada cache_read_input_tokens? Di mana seharusnya breakpoint?

  2. Agent kamu mengirim 25 blok pesan per turn. Di turn ke-2 hit, turn ke-3 miss. Kenapa? Perbaikan minimal apa?

  3. Gemini 3.1 Pro dengan prefix 100k token, dibaca 3Γ— dalam 1 jam. Lebih murah cache atau tidak? Tunjukkan hitungannya. (Input $2/MTok ≀200k, cached $0.20, storage $4.50/MTok/jam.)

Kunci 1. `cache_read` = 0 permanen. Hash prefix berubah tiap user karena dokumen beda, dan breakpoint di akhir dokumen ikut berubah. Breakpoint seharusnya di **akhir system prompt** (yang stabil lintas user) β€” itu saja yang bisa hit. 2. Jendela lookback 20 blok. Turn 2 breakpoint di blok 25, cari write turn 1 di blok 25 (ada). Turn 3 breakpoint di blok 50, cek 50..31 β€” write turn 2 di blok 25 di luar jendela. Fix: breakpoint kedua di blok 25. 3. Cached: `100k Γ— (0.20 + 4.50Γ—1) / 1e6 = $0.47`. Plain 3Γ—: `100k Γ— 2.00 Γ— 3 / 1e6 = $0.60`. Cache menang tipis ($0.47 vs $0.60) β€” dan itu **hanya** kalau ketiga read dalam window storage yang sama. Di 2 read: cached $0.47 vs plain $0.40 β†’ plain menang. Storage fee adalah variabel penentu, bukan harga cached-nya.

πŸ”‘ Poin Kunci


➑️ Eksplorasi Lanjut


πŸ“„ Sumber (diakses 2026-11-08):

[1] Anthropic. "Prompt caching" β€” platform.claude.com/docs/en/build-with-claude/prompt-caching [2] OpenAI. "Prompt caching" β€” developers.openai.com/api/docs/guides/prompt-caching [3] Google. "Context caching" β€” ai.google.dev/gemini-api/docs/caching [4] Google. "Gemini Developer API pricing" β€” aistudio.google.com/docs/pricing [5] DeepSeek. "Models & Pricing" β€” api-docs.deepseek.com/quick_start/pricing [6] DeepSeek. "Context Caching" β€” api-docs.deepseek.com/guides/kv_cache

⚠️ Limitasi: Semua harga berubah cepat β€” Anthropic menurunkan multiplier read Opus 5.5/Sonnet 5.5 ke 0.05Γ— dan Gemini mengumumkan kenaikan harga per 2027-01-01. Verifikasi ulang sebelum commit ke anggaran. Minimum token GPT-5.5 ke bawah "bervariasi menurut request settings" dan tidak dipublikasikan sebagai angka tunggal β€” jangan asumsikan 1.024 untuk model lama tanpa mengukur.