İçeriğe geç

İlk Lab: Cache ON vs OFF — Gerçek Dolar Karşılaştırma

Teori bitti, kollar sıvanır zamanı. Bu derste Anthropic API ile aynı uzun prompt'u 100 kez göndereceğiz; biri cache açık, biri kapalı. Gerçek maliyet, gerçek latency, gerçek hit rate metriklerini göreceksin.

Şükrü Yusuf KAYA
18 dakikalık okuma
Orta

Lab #1: Cache ON vs OFF — Kendi Dolarınla Ölç

Şu ana kadar her şey teori. Şimdi parmaklarını klavyeye koy. Bu lab'i bitirince elinde:
  • Anthropic Claude API ile çalışan, cache toggle edilebilen bir Python betiği
  • Yan yana koyduğunda %85+ tasarruf gösteren bir çıktı tablosu
  • "Cache hit/miss" telemetri'sini API yanıtından okuyabilen kod
  • Türk Lirası cinsinden bir maliyet raporu
Süre: ~20 dakika. Maliyet: ~$0.50 (50 cent).
API Key Gerekiyor
Bu lab gerçek API çağrısı yapacak — Anthropic API key'in gerekiyor. console.anthropic.com'da hesap aç, hiç kullanmadıysan $5 ücretsiz kredi geliyor. Sonra Settings → API Keys'den anahtarını al.

Adım 1 — Çevreyi Kur#

bash
$ pip install anthropic python-dotenv tiktoken
Successfully installed anthropic-0.39.0 ...
 
$ python -c "import anthropic; print(anthropic.__version__)"
0.39.0
Şimdi API anahtarını çevre değişkenine yaz:
export ANTHROPIC_API_KEY="sk-ant-..."

Adım 2 — Test Prompt'u Hazırla#

Cache anlamlı sonuçlar verebilmesi için en az 1024 token statik içerik gerekiyor (Anthropic minimum eşiği). Biz büyük gideceğiz: ~15.000 token'lık bir bilgi metni kullanacağız.
Aşağıdaki Türkçe lorem'i hayali bir şirket dokümanı gibi düşün — gerçek üründe burası senin company knowledge base'in olacak.
python
# Sahte ama yeterince uzun bir "şirket dokümanı" üretir
def make_long_document(num_paragraphs: int = 200) -> str:
para = (
"Şirketimiz 2008 yılında İstanbul'da kurulmuştur ve fintech alanında "
"Türkiye'nin önde gelen teknoloji firmalarından biri haline gelmiştir. "
"Müşterilerimize KVKK ve PCI-DSS uyumlu, ISO 27001 sertifikalı altyapı "
"üzerinde uçtan uca ödeme çözümleri sunmaktayız. 2024 yılında 1.2 milyar "
"TL işlem hacmine ulaştık ve 450'den fazla kurumsal müşteriye hizmet "
"veriyoruz. Ürün portföyümüz arasında sanal POS, fiziksel POS, mobil "
"ödeme, ön ödemeli kart, ve kripto ödeme çözümleri yer almaktadır.\n\n"
)
return (para * num_paragraphs).strip()
Sahte dokümanı üreten yardımcı fonksiyon

Adım 3 — Cache OFF Versiyonu#

Önce cache olmadan bir baseline çekelim. 5 sorgu yapacağız ve her birinde aynı 15K dokümanı tekrar tekrar göndereceğiz.
python
import os
import time
import anthropic
 
client = anthropic.Anthropic() # ANTHROPIC_API_KEY env'i bekler
 
def make_long_document(num_paragraphs: int = 200) -> str:
para = (
"Şirketimiz 2008 yılında İstanbul'da kurulmuştur ve fintech alanında "
"Türkiye'nin önde gelen teknoloji firmalarından biri haline gelmiştir. "
"Ürün portföyümüz arasında sanal POS, fiziksel POS, mobil ödeme, "
"ön ödemeli kart, ve kripto ödeme çözümleri yer almaktadır.\n\n"
)
return (para * num_paragraphs).strip()
 
DOC = make_long_document(num_paragraphs=200)
QUERIES = [
"Şirketin kuruluş yılı nedir?",
"Hangi sertifikalara sahibiz?",
"Ürün portföyümüzde neler var?",
"Yıllık işlem hacmi ne kadar?",
"Kaç kurumsal müşterimiz var?",
]
 
total_input_tokens = 0
total_output_tokens = 0
total_latency = 0.0
 
print(f"{'Sorgu':<40} {'In':>7} {'Out':>5} {'Süre':>7}")
print("─" * 65)
 
for q in QUERIES:
start = time.time()
resp = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=200,
system=DOC, # ← Cache olmadan, normal system
messages=[{"role": "user", "content": q}],
)
latency = time.time() - start
total_input_tokens += resp.usage.input_tokens
total_output_tokens += resp.usage.output_tokens
total_latency += latency
print(f"{q[:38]:<40} {resp.usage.input_tokens:>7} {resp.usage.output_tokens:>5} {latency:>6.2f}s")
 
# Maliyet hesabı (Sonnet 4.6 fiyatları)
cost = (
total_input_tokens / 1_000_000 * 3.00 +
total_output_tokens / 1_000_000 * 15.00
)
print(f"\nToplam input: {total_input_tokens:>10,} token")
print(f"Toplam output: {total_output_tokens:>10,} token")
print(f"Toplam süre: {total_latency:>10.2f} sn")
print(f"Toplam cost: ${cost:.4f} | {cost * 33.5:.2f} TL")
Cache KAPALI: aynı doküman 5 kez gönderiliyor, her seferinde full input ücretlendirilir
Baseline
Gözlem: 5 sorgu → ~12 saniye + 8 TL. Her sorgu birbirinden bağımsız işleniyor; doküman her seferinde sıfırdan prefill ediliyor. Şimdi caching'i açalım.

Adım 4 — Cache ON Versiyonu#

Anthropic'te caching'i açmak için
cache_control: {"type": "ephemeral"}
ekliyoruz. Bu, "buradan öncesi cache'lenebilir" demek.
python
import os
import time
import anthropic
 
client = anthropic.Anthropic()
 
def make_long_document(num_paragraphs: int = 200) -> str:
para = (
"Şirketimiz 2008 yılında İstanbul'da kurulmuştur ve fintech alanında "
"Türkiye'nin önde gelen teknoloji firmalarından biri haline gelmiştir. "
"Ürün portföyümüz arasında sanal POS, fiziksel POS, mobil ödeme, "
"ön ödemeli kart, ve kripto ödeme çözümleri yer almaktadır.\n\n"
)
return (para * num_paragraphs).strip()
 
DOC = make_long_document(num_paragraphs=200)
QUERIES = [
"Şirketin kuruluş yılı nedir?",
"Hangi sertifikalara sahibiz?",
"Ürün portföyümüzde neler var?",
"Yıllık işlem hacmi ne kadar?",
"Kaç kurumsal müşterimiz var?",
]
 
# system, list[dict] olarak verilirse cache_control kullanabilirsin
system_blocks = [
{
"type": "text",
"text": DOC,
"cache_control": {"type": "ephemeral"}, # ← Sihirli satır
}
]
 
# Telemetri toplamak için
total_input = 0
total_cache_create = 0
total_cache_read = 0
total_output = 0
total_latency = 0.0
 
print(f"{'Sorgu':<40} {'In':>5} {'CW':>6} {'CR':>6} {'Out':>5} {'Süre':>6}")
print("─" * 75)
 
for q in QUERIES:
start = time.time()
resp = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=200,
system=system_blocks, # ← Liste, dict değil
messages=[{"role": "user", "content": q}],
)
latency = time.time() - start
 
u = resp.usage
cw = getattr(u, "cache_creation_input_tokens", 0)
cr = getattr(u, "cache_read_input_tokens", 0)
 
total_input += u.input_tokens
total_cache_create += cw
total_cache_read += cr
total_output += u.output_tokens
total_latency += latency
print(f"{q[:38]:<40} {u.input_tokens:>5} {cw:>6} {cr:>6} {u.output_tokens:>5} {latency:>5.2f}s")
 
# Maliyet (Sonnet 4.6)
cost = (
total_input / 1_000_000 * 3.00 +
total_cache_create / 1_000_000 * 3.75 +
total_cache_read / 1_000_000 * 0.30 +
total_output / 1_000_000 * 15.00
)
print(f"\nFresh input: {total_input:>10,} token")
print(f"Cache write: {total_cache_create:>10,} token")
print(f"Cache read: {total_cache_read:>10,} token")
print(f"Output: {total_output:>10,} token")
print(f"Toplam süre: {total_latency:>10.2f} sn")
print(f"Toplam cost: ${cost:.4f} | {cost * 33.5:.2f} TL")
Cache AÇIK: ilk sorguda 'cache write', sonrakilerde 'cache read'
Sonuç
5 sorguda 8.06 TL → 2.74 TL (%66 düşüş). Süre 12.2sn → 5.06sn (~%59 hızlanma). 1000 sorgu yapsak yaklaşık %88'e ulaşırdı (ilk cache write'ın etkisi seyrekleştikçe).

Adım 5 — Telemetri Detayı#

Yukarıdaki çıktıda dikkat etmen gereken üç field var:
FieldAnlamıFiyat
input_tokens
Fresh, cache'lenmemiş input$3/M
cache_creation_input_tokens
İlk yazımda cache'e yazılan$3.75/M
cache_read_input_tokens
Sonraki okumalarda cache'ten gelen$0.30/M
İlk istek: cache_creation > 0, cache_read = 0 Sonraki istekler: cache_creation = 0, cache_read > 0 Cache miss (TTL bitti): cache_creation > 0 yeniden

Adım 6 — Cache Hit Rate Hesapla#

Production'da bu metrik temel KPI'ndır. Formül:
Yukarıdaki sonuçta: 63.200 / (63.200 + 15.800) = %80. İlk istek mi cache write yapıyor, sonraki 4'ü read; bu nedenle %80 mantıklı.
python
def cache_hit_rate(read_tokens: int, write_tokens: int) -> float:
total = read_tokens + write_tokens
if total == 0:
return 0.0
return read_tokens / total * 100
 
# Yukarıdaki testten
print(f"5 sorgu sonrası hit rate: {cache_hit_rate(63200, 15800):.1f}%")
 
# 100 sorgu simülasyonu (ilk cache write sonrası hepsi read)
read_100 = 15800 * 99 # 99 cache hit
write_100 = 15800 # 1 cache write
print(f"100 sorgu sonrası hit rate: {cache_hit_rate(read_100, write_100):.2f}%")
 
# 1000 sorgu (TTL 5dk olsa da hep aynı, 1 write)
read_1k = 15800 * 999
write_1k = 15800
print(f"1000 sorgu sonrası hit rate: {cache_hit_rate(read_1k, write_1k):.2f}%")
Cache hit rate'i fonksiyona dökelim

Adım 7 — TTL'yi Kırın: Cache Miss Görmek#

Şimdi caching'in tek zayıflığını gör: TTL bitince cache miss olur.
Anthropic'in default TTL'si 5 dakika. Aşağıdaki kodu çalıştır, ortadaki
sleep(305)
(5 dk 5 sn) ile cache'in expire olmasını izle:
python
import time
 
# İlk sorgu — cache write
resp1 = client.messages.create(...)
print("İlk:", resp1.usage.cache_creation_input_tokens, "write")
 
# Hemen ardından — cache read
resp2 = client.messages.create(...)
print("İkinci:", resp2.usage.cache_read_input_tokens, "read")
 
# 5 dakika bekle — TTL biter
time.sleep(305)
 
# Üçüncü sorgu — yeniden cache WRITE
resp3 = client.messages.create(...)
print("305sn sonra:", resp3.usage.cache_creation_input_tokens, "yeniden write")
TTL expire davranışı — production'da bu pattern'i izlemelisin
Production Uyarısı
Production'da TTL miss patlamalarına dikkat: trafik seyrek bir saatte cache sürekli expire olur ve maliyet baseline'a döner. Modül 11'de "cache warming" stratejilerini göstereceğim.

Adım 8 — 1 Saatlik TTL (Beta)#

Anthropic'te 1 saatlik TTL de var ama daha pahalı (yazma maliyeti 2× input). Kullanım:
python
system_blocks = [
{
"type": "text",
"text": DOC,
"cache_control": {
"type": "ephemeral",
"ttl": "1h", # ← Default 5m, alternatif 1h
},
}
]
1 saatlik TTL — cache write 2× pahalı
Ne zaman 1h? Trafik seyrek (saatte 10-20 sorgu) ama burst'lü. 5dk sürekli expire olur, 1h hayatta kalır. Break-even hesabı:
Detayları Modül 11'de yapacağız.

✓ Pekiştir#

Bir Sonraki Derste#

Bu modülü bitirme sınavıyla taçlandıracağız: 10 gerçek soru, %70 ile geçme. Hazır olduğunda devam et 🎯

Sık Sorulan Sorular

Anthropic'te minimum cache eşiği 1024 token. Altı için cache_control yazsan da hiçbir şey olmaz, normal input gibi ücretlendirilir. Bu yüzden çok kısa promptlarda caching anlamsız.

Yorumlar & Soru-Cevap

(0)
Yorum yazmak için giriş yap.
Yorumlar yükleniyor...

İlgili İçerikler