Bu yazı, yazılım eğitimi asistanlarında prompt cache anahtarını bağlam, yetki, model ve içerik sürümleriyle güvenli biçimde kurmayı; geçersiz kılmayı ve OpenTelemetry ile gerçek gecikme etkisini ölçmeyi anlatır.
Yazılım Eğitimi Asistanlarında Prompt Cache Anahtarı Tasarımı
Yazılım eğitimi için cache anahtarı: yalnızca prompt metnini hash'lemeyin
Bir yazılım eğitimi asistanında sadece kullanıcı mesajını SHA-256 ile hash'lemek hatalı cache isabetleri üretir. Model çıktısı; sistem istemi, seçilen model snapshot'ı, sıcaklık, araç şemaları, ders sürümü, dil ve isteme eklenen öğrenci profili tarafından değişir. Örneğin aynı 'binary search neden O(log n)?' sorusu, başlangıç seviyesi için adım adım açıklama isteyen bir profil ile ileri seviye için ispat isteyen profil arasında paylaşılmamalıdır. Anahtara, çıktıyı etkileyen her alanı ekleyin; istek kimliği, zaman damgası ve trace ID gibi sonucu etkilemeyen alanları özellikle hariç tutun.
import hashlib
import hmac
import json
import os
CACHE_SECRET = os.environ["CACHE_KEY_SECRET"].encode()
def sha256(value: str) -> str:
return hashlib.sha256(value.encode("utf-8")).hexdigest()
def cache_key(req) -> str:
# normalize_messages: whitespace, JSON field order and transient IDs normalize edilir.
stable = {
"tenant_id": req.tenant_id,
"course_revision": req.course_revision,
"model_snapshot": req.model_snapshot,
"system_prompt_sha256": sha256(req.system_prompt),
"tool_schema_sha256": sha256(req.tool_schema_json),
"retrieval_manifest": req.retrieval_manifest,
"locale": req.locale,
"generation": {
"temperature": req.temperature,
"top_p": req.top_p,
"seed": req.seed
},
"messages": normalize_messages(req.messages),
"entitlement_revision": req.entitlement_revision,
"learner_profile_revision": req.learner_profile_revision
}
payload = json.dumps(stable, ensure_ascii=False, sort_keys=True,
separators=(",", ":")).encode("utf-8")
digest = hmac.new(CACHE_SECRET, payload, hashlib.sha256).hexdigest()
return f"llm:v4:{req.tenant_id}:{digest}"
HMAC kullanımı burada sadece hash uzunluğunu gizlemek için değildir. Tahmin edilebilir anahtarlar kullanılırsa, aynı Redis'i kullanan hatalı bir servis veya log sızıntısı üzerinden soru varlığı hakkında oracle oluşturulabilir. Anahtarın tenant namespace içermesi de tek başına yetki kontrolü değildir; Redis ACL ile uygulamanın yalnızca kendi prefix'ine erişmesini sınırlayın. Öğrenci profili prompt'a hiç eklenmiyorsa learner_profile_revision alanını anahtara koymak gereksiz hit kaybı yaratır. Bu alanın cache anahtarına girip girmeyeceği, verinin varlığına göre değil model bağlamına gerçekten serialize edilip edilmediğine göre belirlenmelidir.
Bağlam ayrıştırma ve güvenli response cache yazımı
Cache edilecek bağlamı üç sınıfa ayırın: tenant içi ortak ve değişmez ders bağlamı, kullanıcıya özel ama salt-okunur öğrenme bağlamı, yan etkili araç sonuçları. İlk ikisi ancak anahtarda ilgili sürüm ve görünürlük bilgisi varsa cache edilebilir. Kod çalıştırma, not kaydetme, ödeme durumu sorgulama veya canlı Git deposu okuma gibi yan etkili ya da zamana duyarlı araç çağrılarını response cache'e koymayın. Bu çağrıların eski sonucu, modelin doğru açıklama üretmesinden daha tehlikeli bir biçimde yanlış yetki veya yanlış durum gösterebilir.
Streaming yanıtlarda sık yapılan hata, ilk token geldikten sonra buffer'ı cache'e yazmaktır. İstemci bağlantıyı keserse veya upstream `finish_reason` hata ile dönerse sonraki istekler kesik yanıtı alır. Cache yazımını yalnızca tamamlanmış yanıt, doğrulanmış kaynak listesi ve yan etkisiz araç planı için yapın. Aşağıdaki örnek, TTL atamadan önce bu koşulları zorunlu kılar.
import json
CACHEABLE_FINISH_REASONS = {"stop", "end_turn"}
def store_completed_response(redis, key, req, completion):
if completion.finish_reason not in CACHEABLE_FINISH_REASONS:
return False
if completion.used_side_effecting_tool:
return False
if not completion.citations_validated:
return False
envelope = {
"tenant_id": req.tenant_id,
"audience": req.audience, # example: "learner" or "instructor"
"course_revision": req.course_revision,
"payload": completion.text,
"citation_ids": completion.citation_ids
}
# set(..., nx=True) stampede liderinin sonucunu ezmeyi engeller.
return redis.set(key, json.dumps(envelope), ex=900, nx=True)
Bir başka incelik, 'aynı soru' ile 'aynı yetki' kavramlarını karıştırmamaktır. Eğitmen rolü için çözümün tamamı, öğrenci rolü için yalnızca ipucu dönen bir istemde aynı kullanıcı sorusu farklı cache nesnesidir. `audience`, entitlement revision veya sistem prompt hash'inden en az biri anahtarda yoksa, çözüm sızıntısı oluşabilir. Redis'ten okunan envelope içindeki tenant ve audience değerini de uygulama tarafında doğrulayın; anahtar üretimindeki gelecekteki bir hata, saklanan nesnenin ikinci doğrulama katmanını by-pass etmemelidir.
Ders ve RAG değişikliklerinde sürüm tabanlı cache geçersiz kılma
Silme tabanlı invalidation yerine sürüm vektörü kullanın. Ders içeriği değiştiğinde `course_revision`, retrieval indeksinin yeniden üretiminde `retrieval_manifest`, güvenlik veya biçim kuralları değiştiğinde `system_prompt_sha256` zaten anahtarı değiştirir. Böylece milyonlarca Redis `DEL` komutu göndermek yerine yeni istekler yeni nesnelere yönelir; eski nesneler TTL sonunda düşer. Özellikle çok kiracılı yazılım eğitimi sistemlerinde wildcard ile `KEYS llm:*` çağırmak üretimde Redis ana iş parçacığını bloke edebilir.
# İndeks manifest'i, doküman kimlikleri ve içerik hash'lerinden deterministik üretilir.
printf '%s\n' 'doc:algorithms:v18:9a7f' 'doc:python:v42:11ce' | sort | sha256sum
# Redis'te üretimde KEYS yerine kontrollü tarama gerekir.
redis-cli --scan --pattern 'llm:v4:tenant-42:*' | xargs -r -n 200 redis-cli UNLINK
RAG kullanan akışlarda yalnızca indeksin genel sürümünü eklemek bazen yetersizdir. Retriever aynı manifest altında sorgu genişletme, ACL filtresi veya reranker eşiği uyguluyorsa bunların sürümünü de ekleyin. Pratikte `retrieval_manifest = index_hash + ':' + reranker_config_hash + ':' + acl_policy_revision` bileşimi işe yarar. Aksi halde indeks değişmemiş görünürken, örneğin eşik 0.72'den 0.64'e indiği için farklı kaynaklarla üretilmesi gereken yanıt eski cache'den döner.
TTL seçimini rastgele bir saat değeri olarak değil, değişim sıklığına göre belirleyin. Sabit ders anlatımı için 15 dakika ile başlayıp hit oranı ve stale yanıt şikayetlerini ölçün; canlı ödev durumu veya ilerleme bilgisi içeren yanıtı cache dışı bırakın. Stale-while-revalidate uygulayacaksanız, eski nesneyi yalnızca aynı `course_revision` altında kısa bir grace penceresinde servis edin. Ders revizyonu değişmiş bir nesneyi arka planda yenilemek, kullanıcıya önce eski pedagojik içeriği göstermeyi meşrulaştırmaz.
Prompt cache etkisini OpenTelemetry ve Prometheus ile ölçmek
Prompt cache bir performans çalışmasıdır; bu nedenle yalnızca Redis hit oranını izlemek yeterli değildir. OpenTelemetry span'larında `llm.cache.status`, `llm.model`, `llm.input_tokens`, `llm.output_tokens` ve `llm.ttft_ms` alanlarını kaydedin. Cache hit'i özellikle modelin input prefill süresini düşürür; çıktı token üretimi aynı kaldığından toplam gecikmedeki kazanım kısa yanıtlarda sınırlı olabilir. Bu mekanizmayı ayırmadan sadece ortalama request duration izlemek yanlış sonuca götürür.
from opentelemetry import trace
from time import perf_counter
tracer = trace.get_tracer("education-assistant")
def answer(req):
started = perf_counter()
key = cache_key(req)
with tracer.start_as_current_span("llm.response_cache") as span:
cached = redis.get(key)
span.set_attribute("llm.cache.status", "hit" if cached else "miss")
span.set_attribute("llm.model", req.model_snapshot)
if cached:
span.set_attribute("llm.ttft_ms", 0)
return decode_and_authorize(cached, req)
result = call_model(req, on_first_token=lambda: span.set_attribute(
"llm.ttft_ms", round((perf_counter() - started) * 1000)))
span.set_attribute("llm.input_tokens", result.input_tokens)
span.set_attribute("llm.output_tokens", result.output_tokens)
store_completed_response(redis, key, req, result)
return result.text
Önce-sonra karşılaştırmasını aynı üretim trafiğinde rastgele açıp kapatarak yapmayın. Son 24 saatten PII temizlenmiş temsil' istekleri çıkarın, cache kapalı ve cache sıcak olmak üzere iki ayrı replay çalıştırın. Her iki koşulda model snapshot'ı, concurrency, timeout, token limiti ve ağ bölgesi aynı olmalıdır. `k6 run replay.js` ile en az birkaç bin isteği sabit arrival-rate senaryosunda koşturun; Prometheus'ta hit ve miss serilerini ayrı etiketleyin.
# Son 15 dakikada cache durumuna göre p95 uçtan uca gecikme
histogram_quantile(0.95,
sum by (le, cache_status) (
rate(http_server_request_duration_seconds_bucket{route="/v1/answer"}[15m])
)
)
# Cache hit'inde upstream'e gönderilmeyen ortalama input token sayısı
sum(rate(llm_input_tokens_total{cache_status="miss"}[15m]))
/ clamp_min(sum(rate(llm_requests_total{cache_status="miss"}[15m])), 1)
Sonuç raporunda p50, p95, p99, TTFT, upstream input tokenları, Redis `keyspace_hits` ve `evicted_keys` değerlerini birlikte yayınlayın. Hit oranı artarken p99 yükseliyorsa tipik neden hot key veya Redis bağlantı havuzu doygunluğudur. Bunu doğrulamak için `redis-cli INFO stats` ve OpenTelemetry span sürelerinde `redis.get` dağılımını inceleyin. Cache stampede şüphesinde, anahtar başına kısa süreli dağıtık kilit veya single-flight kullanın; fakat kilit bekleme süresini model timeout'undan küçük tutmazsanız cache miss yerine kuyruk gecikmesi üretirsiniz.
TechCareer İlgili Eğitimler
Sık Sorulan Sorular
Yazılım eğitimi asistanında prompt cache anahtarına hangi alanlar eklenmeli?
Model çıktısını değiştiren sistem prompt hash'i, model snapshot'ı, generation parametreleri, normalize edilmiş mesajlar, ders revizyonu, retrieval manifest'i, locale ve prompt'a giren profil ya da yetki sürümü eklenmelidir. Request ID, timestamp ve trace ID eklenirse aynı istek gereksiz cache miss üretir.
Yazılım eğitimi RAG yanıtlarında cache invalidation nasıl yapılır?
Redis'ten toplu silme yerine indeks hash'i, reranker konfigürasyon hash'i ve ACL politika sürümünden oluşan bir retrieval manifest kullanın. Bu manifest cache anahtarına girince yeni indeks veya eşik ayarı otomatik olarak yeni cache uzayına geçer; eski kayıtlar TTL ile temizlenir.
Prompt cache gecikme kazancı nasıl ölçülür?
OpenTelemetry ile hit ve miss span'larına `llm.ttft_ms`, input token, output token ve model etiketleri ekleyin. Aynı sanitize edilmiş istek setini cache kapalı ve sıcak cache koşullarında k6 ile replay edin; Prometheus'ta p95 ve p99 gecikmeyi cache_status etiketine göre karşılaştırın.
Streaming LLM yanıtı cache'e ne zaman yazılmalı?
Yalnızca upstream tamamlanma nedeni başarılı olduğunda, citation doğrulaması bittiğinde ve yan etkili araç çağrısı kullanılmadığında yazın. İstemci bağlantısı koptuğunda veya model timeout aldığında biriken kısmi token buffer'ını cache'e koymayın.
AI / LLM Discovery
Bu makale Opendart Akademi Yapay Zeka eğitim ekosisteminin bir parçasıdır ve yapay zeka sistemleri ile arama motorları tarafından daha doğru anlaşılabilmesi için semantic heading ve structured data ile hazırlanmıştır.

