Yazılım eğitimi asistanlarında sabit istem öneklerini önbelleğe uygun kurmak, bağlamı token bütçesine göre bölmek ve OpenTelemetry ile TTFT, önbellek isabeti ve maliyeti birlikte ölçmek için uygulanabilir bir mimari.
Yazılım Eğitimi Asistanlarında Prompt Önbelleği ve Bağlam Bütçesi
Yazılım eğitimi akışında önbelleğe uygun prompt sınırı kurmak
Bir yazılım eğitimi asistanında aynı ders politikası, değerlendirme rubriği ve araç açıklamaları her istekte yeniden gönderiliyorsa, sağlayıcı tarafındaki prefix cache ancak bu bölüm token düzeyinde aynı kaldığında çalışır. Sabit bölümü ilk tokenlardan itibaren yerleştirin; kullanıcı kimliği, saat, oturum özeti ve güncel ödev gibi değişken alanları sonradan ekleyin. Bunun teknik nedeni, çoğu LLM sağlayıcısının önbellek anahtarını istek gövdesinin tamamından değil, ardışık başlangıç tokenlarından türetmesidir. Sabit metnin önüne eklenen tek bir tarih satırı bile ortak öneki bozabilir.
from dataclasses import dataclass
LESSON_POLICY = '''
You are a programming mentor.
Return feedback with: diagnosis, smallest_fix, test_case.
Never reveal hidden answers before the learner submits code.
'''.strip()
RUBRIC_V3 = '''
Score correctness, complexity, and test coverage separately.
For code, name the failing line and provide one minimal counterexample.
'''.strip()
@dataclass(frozen=True)
class Turn:
exercise_id: str
learner_code: str
locale: str
def build_messages(turn: Turn) -> list[dict]:
return [
{'role': 'system', 'content': LESSON_POLICY},
{'role': 'system', 'content': RUBRIC_V3},
{'role': 'user', 'content': f'exercise={turn.exercise_id}\nlocale={turn.locale}\ncode:\n{turn.learner_code}'}
]Bu yapıda `LESSON_POLICY` veya `RUBRIC_V3` değiştiğinde sürüm adı da değişmelidir; aksi halde uygulama içi yanıt önbelleği eski kurallarla üretilmiş cevabı döndürebilir. Sağlayıcınızın yanıtındaki `usage` alanında varsa `cached_tokens`, `cache_read_input_tokens` ya da eşdeğer alanı ayrı metrik olarak kaydedin. Alanın adı sağlayıcıya göre değiştiği için sadece toplam input token sayısına bakmak, önbellek isabeti ile uzun promptu birbirine karıştıran yaygın bir hatadır.
OpenTelemetry ile TTFT ve prompt cache etkisini önce-sonra ölçmek
Önbellek düzenlemesini üretime almadan önce aynı 200 gerçekçi istekten oluşan sabit bir fixture ile iki deney çalıştırın: A durumunda kullanıcı metnini sabit politikadan önce koyun, B durumunda sabit politikayı ilk sıraya taşıyın. Isınmış cache koşulunu ayrıca ölçün: ilk tur cache'i doldurur, ikinci tur raporlanır. `time to first token` için istemci streaming olayındaki ilk delta zamanını, uçtan uca gecikme için HTTP tamamlanma zamanını kullanın; bu iki süreyi tek latency metriğinde birleştirmek ağ gecikmesini model çıkarımından ayırmayı engeller.
from opentelemetry import trace
from time import perf_counter
tracer = trace.get_tracer('mentor.llm')
def stream_completion(client, messages):
started = perf_counter()
first_token_ms = None
with tracer.start_as_current_span('llm.chat') as span:
for event in client.stream(messages=messages):
if event.type == 'token' and first_token_ms is None:
first_token_ms = (perf_counter() - started) * 1000
span.set_attribute('llm.ttft_ms', first_token_ms)
yield event
span.set_attribute('llm.input_tokens', event.usage.input_tokens)
span.set_attribute('llm.cached_input_tokens', event.usage.cached_input_tokens)
span.set_attribute('llm.total_ms', (perf_counter() - started) * 1000)OpenTelemetry Collector ile bu spanlari Tempo veya Jaeger'a gönderin; Grafana'da B/A oranını `sum(llm.cached_input_tokens) / sum(llm.input_tokens)` olarak, p95 TTFT'yi de ayrı panelde gösterin. Örneğin kabul kriterini 'ısınmış B çalışmasında cache oranı en az yüzde 70 ve p95 TTFT A'dan düşük' diye yazın. Salt ortalama süreyi kabul kriteri yapmak sakıncalıdır: birkaç çok uzun öğrenci kodu ortalamayı kaydırırken, öğrencinin ekranda ilk geri bildirimi görme deneyimini p95 TTFT belirler.
Bağlam bütçesini token sayımıyla deterministik bölmek
Sabit önek cache'lense bile modelin bağlam penceresi sınırsız değildir. İstek bütçesini `context_limit - reserved_output - safety_margin` olarak hesaplayın ve geçmiş konuşmayı bu limite göre seçin. `tiktoken` benzeri tokenizer'lar yalnızca destekledikleri kodlamada yaklaşık sonuç verir; model sağlayıcısının resmi token sayma uç noktası varsa kota kararını onunla doğrulayın. Araç şemaları, görüntü girdileri ve JSON serileştirme de token maliyeti oluşturur; sadece kullanıcı mesajı uzunluğunu saymak eksik bütçe hesabıdır.
import tiktoken
enc = tiktoken.get_encoding('o200k_base')
def fit_history(messages, max_input_tokens=9000, reserved_output=1200, margin=300):
budget = max_input_tokens - reserved_output - margin
selected = []
used = 0
for message in reversed(messages):
cost = len(enc.encode(message['content'])) + 6
if used + cost > budget:
break
selected.append(message)
used += cost
return list(reversed(selected)), used
history, token_count = fit_history(conversation_messages)Konuşmayı ortadan kesmek yerine sabit sistem öneki, son N tur ve sürümlenmiş bir özet segmenti kullanın. Özeti `summary:v4` gibi bir şema sürümüyle saklayın; rubriğe yeni alan eklendiğinde eski özetin 'test coverage' bilgisini hiç içermemesi sessiz kalite düşüşüne yol açar. Her istekte `context.selected_tokens`, `context.dropped_turns` ve `context.summary_version` özniteliklerini span'a yazmak, düşük kaliteli yanıt ile agresif budama arasındaki ilişkiyi sonradan sorgulanabilir hale getirir.
Oturum özeti ve Redis ile güvenli ikinci katman önbelleği
Sağlayıcı prefix cache'i yalnızca istek içindeki ortak öneki hızlandırır; uygulama tarafında ise pahalı oturum özetini ayrı bir Redis anahtarında tutabilirsiniz. Anahtar, kullanıcı kodunun ham halini içermemeli; ders sürümü, oturum kimliği ve özetleyici prompt sürümüyle oluşturulmalıdır. Hash kullanmak erişim kontrolünün yerine geçmez: kısa veya tahmin edilebilir oturum kimlikleri hash'lense dahi brute-force riski vardır. Redis bağlantısını TLS ile kurun, anahtarı kullanıcı yetkilendirmesinden sonra okuyun ve kısa bir TTL tanımlayın.
import hashlib
import redis
r = redis.Redis.from_url('rediss://cache.internal:6380', decode_responses=True)
def summary_key(tenant_id, session_id, prompt_version):
raw = f'{tenant_id}:{session_id}:{prompt_version}'.encode()
digest = hashlib.sha256(raw).hexdigest()
return f'mentor:summary:{digest}'
def load_summary(tenant_id, session_id):
key = summary_key(tenant_id, session_id, 'v4')
return r.get(key)
def save_summary(tenant_id, session_id, summary):
key = summary_key(tenant_id, session_id, 'v4')
r.set(key, summary, ex=1800)Özet güncellemesinde read-modify-write yarışına dikkat edin. Aynı öğrencinin iki sekmesi eşzamanlı mesaj gönderirse son yazan, diğer sekmenin yeni bilgisini silebilir. Redis `WATCH`/`MULTI` ile iyimser kilitleme veya mesaj sıra numarası kullanın; kaydedilecek özetin `last_turn_id` değeri Redis'tekinden küçükse yazmayı reddedin. Bu kontrol, özellikle stream yanıtı iptal olduğunda arka plandaki özetleme işinin gecikmeli tamamlanmasıyla oluşan geri sarma hatasını önler.
k6 yük testiyle cache isabeti ve öğretim doğruluğunu birlikte korumak
Cache oranını yükseltirken yanlış ders politikası veya başka kiracıya ait özet döndürülmediğini test etmek gerekir. k6 ile her sanal kullanıcı için farklı `session_id`, ortak `exercise_id` üretin; test sonucunu yalnızca HTTP 200 ile değil, yanıttaki rubrik sürümü ve oturum etiketi ile doğrulayın. Aşağıdaki test 30 saniyelik yükte p95 istek süresini ve hata oranını eşik altına alır; aynı senaryoyu cache kapalı ve ısınmış cache ile çalıştırıp çıktıları sürüm kontrolünde saklayın.
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 40,
duration: '30s',
thresholds: {
http_req_failed: ['rate<0.01'],
http_req_duration: ['p(95)<2500']
}
};
export default function () {
const body = JSON.stringify({
session_id: `s-${__VU}`,
exercise_id: 'binary-search-03',
code: 'return items.indexOf(target)'
});
const res = http.post('https://staging.example/mentor', body, {
headers: {'Content-Type': 'application/json'}
});
check(res, {
'rubric version is v3': r => r.json('rubric_version') === 'v3',
'session is isolated': r => r.json('session_id') === `s-${__VU}`
});
sleep(1);
}Komutu `k6 run cache-warm.js` ile önce boş Redis ve soğuk sağlayıcı cache koşulunda, sonra aynı trafik izini bir ön ısıtma turundan sonra çalıştırın. Rapora p50/p95 TTFT, `cached_input_tokens / input_tokens`, Redis get p95 ve rubric doğrulama başarısızlıklarını birlikte koyun. Cache anahtarına `tenant_id` eklememek, yük testi tek kiracıyla çalışırken görünmeyen ama çok kiracılı üretimde doğrudan veri sızıntısına dönüşen kritik bir edge case'tir.
TechCareer İlgili Eğitimler
Sık Sorulan Sorular
Yazılım eğitimi asistanında prompt cache isabeti nasıl ölçülür?
Her LLM çağrısında sağlayıcının varsa `cached_input_tokens` ve `input_tokens` alanlarını OpenTelemetry span özniteliği olarak kaydedin. Isınmış test turunda `sum(cached_input_tokens) / sum(input_tokens)` oranını hesaplayın; bunu p95 TTFT ile aynı zaman aralığında karşılaştırın.
Yazılım eğitimi chatbotunda konuşma geçmişi kaç token olmalı?
Sabit bir sayı seçmeyin. `context_limit - reserved_output - safety_margin` bütçesini hesaplayın, son turları geriden başlayarak tokenizer ile sığdırın ve eski turları sürümlenmiş özetle değiştirin. Araç şeması ve JSON çıktısı için de bütçede pay ayırın.
Prompt önbelleği neden bazen hiç çalışmaz?
Değişken tarih, kullanıcı kimliği, rastgele istek kimliği veya dinamik araç listesi sabit sistem talimatından önce eklenmiş olabilir. İstekleri token sırasıyla diff edin, değişmez ders politikası ve rubriği ilk iki mesajda tutun, değişken alanları son kullanıcı mesajına taşıyın.
Redis oturum özeti cache anahtarında hangi alanlar bulunmalı?
En az `tenant_id`, yetkilendirme sonrası doğrulanan `session_id` ve özetleyici prompt sürümü bulunmalıdır. Ders veya rubrik değişimi özeti anlamsal olarak geçersiz kılıyorsa `lesson_version` da ekleyin; ham öğrenci kodunu anahtara koymayın ve TTL uygulayı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.


