Blog'a Dön
Context EngineeringLLMSystem DesignRAG

Context Engineering: LLM Uygulamalarının Gerçek Becerisi

Context engineering rehberi — LLM'nin gerçekte ne gördüğünü nasıl tasarlarsınız, token bütçesini nasıl yönetirsiniz ve neyi ölçmeniz gerekir?

Yayınlanma 2026-03-18|12 min

Context Engineering Nedir ve Neden Önemli?

Hepimiz yaşadık: saatlerce prompt üzerinde uğraşıyorsun, sonra asıl sorunun prompt'un etrafındaki her şey olduğunu fark ediyorsun. İşte tam burada prompt engineering'den context engineering'e geçiş başlıyor. Prompt engineering modele ne söylediğinle ilgili. Context engineering ise modelin gördüğü her şeyle ilgili — system prompt'lar, getirilen belgeler, konuşma geçmişi, tool çıktıları, yapılandırılmış metadata ve her bir parçanın context window içindeki sırası.

Şöyle düşün: bir LLM'nin çıktı kalitesi, girdi kalitesiyle doğrudan sınırlı. Harika yazılmış bir talimat, alakasız belgelerle birleştiğinde hâlâ kötü sonuç veriyor. Ama ortalama bir prompt, tam olarak doğru context ile birleştiğinde? Çoğu zaman mükemmel sonuç çıkıyor. Bunu bir kez içselleştirdiğinde, context window'u birinci sınıf bir tasarım yüzeyi olarak görmeye başlıyorsun — tıpkı bir API kontratına veya veritabanı şemasına gösterdiğin titizlik gibi.

Context window bir metin kutusu değil — bir mühendislik ürünü. İçine giren her token, çıktı kalitesine ölçülebilir katkısıyla orada olduğunu hak etmeli.

Prodüksiyon sistemlerinde context neredeyse hiçbir zaman sabit değil. Anlık olarak birden fazla kaynaktan birleştiriliyor: vektör veritabanları, bilgi grafikleri, kullanıcı oturum durumu, tool çağrı sonuçları ve önceki konuşmaların özetleri. Zor olan kısım şu: bütün bu farklı sinyalleri seçip, sıralayıp, sıkıştırıp, biçimlendirip tutarlı bir girdiye dönüştürmen gerekiyor — hem de sabit bir token limiti içinde.

Context Window'u Tasarım Yüzeyi Olarak Düşünmek

Günümüz LLM'leri 8.000'den 1.000.000'un üzerine kadar uzanan context window'lar sunuyor. Bu kadar alanı çöp kutusu gibi kullanmak cazip gelebilir — potansiyel olarak ilgili her belgeyi üst üste koyup modelin halletmesini ummak. Ama pratikte bu yaklaşım birkaç iyi bilinen şekilde geri tepiyor.

  • Dikkat seyrelmesi: Context büyüdükçe modelin dikkati daha fazla token'a dağılıyor. Kritik bilgiye ayrılan ağırlık azalıyor ve model önemli şeyleri kaçırmaya başlıyor.
  • Ortada kaybolma etkisi: Araştırmalar gösteriyor ki LLM'ler context'in başına ve sonuna çok daha fazla dikkat ediyor. Ortadaki bilgi? Hatırlama oranı ciddi şekilde düşüyor.
  • Gecikme ve maliyet: Çıkarım süresi ve API maliyeti token sayısıyla birlikte artıyor. Gereksiz context hem yavaşlatıyor hem pahalıya mal oluyor.
  • Çelişen sinyaller: Tekrarlayan veya çelişkili belgeler modelin kafasını karıştırıyor. Sonuç: belirsiz yanıtlar, halüsinasyonlar veya tutarsız çıktılar.

Context window'u bir tasarım yüzeyi olarak ele aldığında, neyin girip neyin dışarıda kalacağına ve her öğenin nereye oturacağına bilinçli kararlar veriyorsun. System prompt genellikle en üstte yer alır. Sonra yapılandırılmış metadata gelir, ardından getirilen context ve en sonda kullanıcının sorgusu. Her bölümün bir görevi var ve aralarındaki sınırlar net olmalı — XML etiketleri, markdown başlıkları veya modelin güvenilir şekilde ayrıştırabileceği yapısal işaretleyiciler kullanarak.

Context Oluşturma Kalıpları

Context oluşturma — ham malzemelerden nihai girdiyi inşa etme süreci — birkaç farklı mimari kalıp izleyebilir. Hangisini seçeceğin gecikme gereksinimlerine, kullanıcı sorgularının ne kadar öngörülebilir olduğuna ve kaç farklı bilgi kaynağından beslediğine bağlı.

Statik Context

En basit kalıp: system prompt ve destekleyici belgeler deploy sırasında sabitleniyor. Dar ve iyi tanımlı görevlerde iyi çalışır — tek bir ürün için müşteri destek botu veya sabit bir stil kılavuzuyla çalışan kod inceleme asistanı gibi. Statik context hızlı, belirleyici ve versiyon kontrolü kolay. Dezavantajı? Yeni sorgulara veya değişen bilgi tabanlarına uyum sağlayamıyor.

Dinamik Context

Dinamik oluşturma, çıkarım anında kullanıcının sorgusuna, oturum durumuna veya diğer çalışma zamanı sinyallerine göre context öğelerini seçer ve biçimlendirir. Tipik bir kurulumda sorgu bir intent sınıflandırıcıdan geçer, sonra o intent için uygun bir context şablonu oluşturulur — doğru tool şemaları, few-shot örnekleri veya alana özel talimatlar çekilir. Bu kalıp, tek bir deployment içinde farklı istek türlerini karşılaması gereken çok yetenekli agent'lar için çok uygun.

Retrieval Tabanlı Context (RAG)

RAG en yaygın dinamik kalıp ve büyük ihtimalle zaten kullanmışsındır. Kullanıcının sorgusu vektör uzayına gömülüyor, en yakın komşu belgeler vektör veritabanından getiriliyor, alaka düzeyine göre yeniden sıralanıyor ve context window'a enjekte ediliyor. Daha gelişmiş versiyonları dense retrieval ile sparse keyword aramayı birleştirir (hybrid search), çok adımlı sorular için query decomposition uygular veya modelin üretim sırasında ek context talep ettiği iterative retrieval kullanır.

Tip

İyi sonuç veren bir yaklaşım: statik ve retrieval tabanlı context'i birleştir. Talimatlar, çıktı formatı ve guardrail'ler için statik context kullan. Güncel kalması gereken alan bilgisi için retrieval tabanlı context kullan. Bu hibrit yaklaşım talimat katmanını kararlı ve versiyon kontrollü tutarken, bilgi katmanının bağımsız olarak gelişmesini sağlıyor.

Token Bütçe Yönetimi

Her context window'un sabit bir token limiti var ve bu bütçeyi bilinçli şekilde yönetmen gerekiyor. En sık gördüğüm hata şu: getirilen belgeler mevcut token'ların büyük çoğunluğunu yiyor, system talimatları veya konuşma geçmişi gibi kritik öğelere yer kalmıyor. Çözüm basit — toplam token bütçesinin sabit veya oransal bir payını her context bileşenine ayır, sonra bu limitleri oluşturma sırasında uygula.

Somut bir örnek: her bileşene maksimum bir token payı veriliyor ve oluşturma fonksiyonu, payını aşan içeriği kesiyor.

python
from dataclasses import dataclass
from tiktoken import encoding_for_model

@dataclass
class TokenBudget:
    """Bağlam bileşenleri arasında token tahsisini yönetir."""
    model: str
    max_context: int
    # Modelin yanıtı için token ayır
    response_reserve: int = 4096

    def __post_init__(self):
        self.encoder = encoding_for_model(self.model)
        self.available = self.max_context - self.response_reserve

    def count(self, text: str) -> int:
        """Verilen metin için token sayısını döndürür."""
        return len(self.encoder.encode(text))

    def allocate(self, components: dict[str, str],
                 priorities: dict[str, float]) -> dict[str, str]:
        """
        Öncelik ağırlıklarına göre bileşenlere token tahsis eder.
        Daha yüksek öncelikli bileşenler en son kesilir.
        Bileşenler: {"system": "...", "retrieved": "...", "history": "..."}
        Öncelikler: {"system": 1.0, "retrieved": 0.6, "history": 0.4}
        """
        # Ham token sayılarını hesapla
        counts = {k: self.count(v) for k, v in components.items()}
        total_needed = sum(counts.values())

        if total_needed <= self.available:
            return components  # Her şey sığıyor

        # Önceliğe göre sırala — en düşük öncelik önce kesilir
        sorted_keys = sorted(priorities, key=lambda k: priorities[k])
        remaining = self.available

        # İlk geçiş: bileşen başına tahsisi hesapla
        allocations = {}
        for key in reversed(sorted_keys):
            # Yüksek öncelikli bileşenler ihtiyaçlarını talep eder
            claim = min(counts.get(key, 0), remaining)
            allocations[key] = claim
            remaining -= claim

        # Her bileşeni tahsisine göre kes
        result = {}
        for key, text in components.items():
            max_tokens = allocations.get(key, 0)
            tokens = self.encoder.encode(text)[:max_tokens]
            result[key] = self.encoder.decode(tokens)

        return result

Öncelik ağırlıklarına göre context window kapasitesini bileşenler arasında dağıtan bir token bütçe yöneticisi.

Pratikte öncelik ağırlıklarını deneysel olarak ayarlaman gerekiyor. System talimatları neredeyse her zaman en yüksek önceliği hak eder — görevi ve guardrail'leri tanımlıyorlar. Getirilen belgeler sıradaki gelir, sonra konuşma geçmişi. Konuşma geçmişini daha agresif özetleyebilir veya kesebilirsin, kalitede büyük bir kayıp olmaz.

Context Sıralaması ve Dikkatin Gerçekte Nasıl Çalıştığı

Context window içinde öğelerin nereye konduğu çoğu kişinin düşündüğünden daha fazla önemli. Birçok çalışma "ortada kaybolma" olgusunu doğruladı: ilgili bilgi uzun bir context'in ortasına yerleştiğinde, başa veya sona koyulmasına kıyasla hatırlama oranı ciddi şekilde düşüyor. Bunun doğrudan mimari sonuçları var.

  1. System talimatlarını ve kritik kısıtlamaları en başa koy. Öncelik etkisinden faydalanırlar ve tüm üretim için davranış çerçevesini belirlerler.
  2. Kullanıcının sorgusunu ve son talimatları en sona koy. Yakınlık etkisi sayesinde model, üretim öncesi gördüğü son token'lara güçlü şekilde dikkat eder.
  3. Getirilen belgeleri ortaya yerleştir, ama alaka düzeyine göre sırala — en ilgili olan en önde. Bu, ortada kaybolma sorununu kısmen telafi eder.
  4. Yapısal ayırıcılar kullan (XML etiketleri, markdown başlıkları, ayırıcı token'lar). Modelin context bölümlerini birbirinden ayırt etmesini kolaylaştırır ve kaynak atıfını iyileştirir.
  5. Konuşma geçmişi uzadığında eski dönüşleri özetle, sadece en son alışverişleri tam tut. Ortayı sıkıştırırken yakınlığı korursun.

Bir de context caching var. Artık birçok API sağlayıcı bu özelliği sunuyor. Context'in ön ekini — genellikle system prompt ve statik talimatları — önbelleğe alıp istekler arasında yeniden kullanmanı sağlıyor. Hem gecikmeyi hem maliyeti azaltıyor. Ama aynı zamanda kararlı içeriği neden başa koyman gerektiğini de pekiştiriyor: caching'e uygun olan kısım orası.

Context Kalitesini Ölçmek

Ölçmediğin şeyi iyileştiremezsin. Sayısal değerlendirme olmadan context oluşturmayı optimize etmek tahmin yürütmekten ibaret. İhtiyacın olan metrikler iki gruba ayrılıyor: retrieval kalitesi (doğru belgeler context'e girdi mi?) ve downstream görev kalitesi (model aldığı context ile doğru ve faydalı bir çıktı üretti mi?).

Retrieval kalitesi için standart bilgi erişim metriklerini kullan — precision, recall, mean reciprocal rank (MRR) ve normalized discounted cumulative gain (nDCG). Downstream kalite metrikleri göreve özel: olgusal soru-cevap için doğruluk, özetleme için ROUGE veya BERTScore, kod üretimi için geçiş oranları, açık uçlu görevler için insan tercih derecelendirmeleri.

Aşağıdaki değerlendirme aracı, RAG sisteminde context kalitesini ölçüyor. Getirilen belgeleri ground-truth ilgili belgelerle karşılaştırırken aynı zamanda uçtan uca yanıt kalitesini de takip ediyor.

python
import numpy as np
from dataclasses import dataclass, field

@dataclass
class ContextEvalResult:
    """Tek bir sorgu için değerlendirme metriklerini saklar."""
    query: str
    precision: float = 0.0
    recall: float = 0.0
    mrr: float = 0.0
    context_utilization: float = 0.0
    answer_correct: bool = False

@dataclass
class ContextEvaluator:
    """Getirme ile zenginleştirilmiş sistem için bağlam kalitesini değerlendirir."""
    results: list[ContextEvalResult] = field(default_factory=list)

    def evaluate_retrieval(
        self,
        query: str,
        retrieved_ids: list[str],
        relevant_ids: set[str],
        total_context_tokens: int,
        used_context_tokens: int,
        answer_correct: bool,
    ) -> ContextEvalResult:
        """
        Getirme ve bağlam kalitesi metriklerini hesaplar.
        retrieved_ids: bağlamdaki belge kimliklerinin sıralı listesi
        relevant_ids: ilgili belge kimliklerinin temel doğruluk kümesi
        """
        # Kesinlik: getirilen belgelerin ilgili olanların oranı
        relevant_retrieved = [d for d in retrieved_ids if d in relevant_ids]
        precision = len(relevant_retrieved) / len(retrieved_ids) if retrieved_ids else 0.0

        # Hatırlama: ilgili belgelerin getirilen oranı
        recall = len(relevant_retrieved) / len(relevant_ids) if relevant_ids else 0.0

        # Ortalama Karşılıklı Sıralama: ilk ilgili sonucun 1 / sırası
        mrr = 0.0
        for rank, doc_id in enumerate(retrieved_ids, start=1):
            if doc_id in relevant_ids:
                mrr = 1.0 / rank
                break

        # Bağlam kullanımı: bütçenin ne kadarı faydalı bilgi taşıdı
        utilization = used_context_tokens / total_context_tokens if total_context_tokens else 0.0

        result = ContextEvalResult(
            query=query,
            precision=precision,
            recall=recall,
            mrr=mrr,
            context_utilization=utilization,
            answer_correct=answer_correct,
        )
        self.results.append(result)
        return result

    def summary(self) -> dict[str, float]:
        """Tüm değerlendirilen sorgular üzerinden metrikleri toplar."""
        n = len(self.results)
        if n == 0:
            return {}
        return {
            "mean_precision": np.mean([r.precision for r in self.results]),
            "mean_recall": np.mean([r.recall for r in self.results]),
            "mean_mrr": np.mean([r.mrr for r in self.results]),
            "mean_utilization": np.mean([r.context_utilization for r in self.results]),
            "accuracy": np.mean([r.answer_correct for r in self.results]),
        }

Retrieval precision, recall, MRR, context kullanımı ve uçtan uca yanıt doğruluğunu ölçen bir değerlendirme aracı.

Context utilization metriğine özellikle dikkat et. Yanıta gerçekten katkı sağlayan token'ların toplam tüketilen token'lara oranını gösteriyor. Yüksek recall ama düşük utilization varsa, bütçeyi alakasız içeriğe harcıyorsun demek — retrieval veya reranking aşamasının iyileştirilmesi gerektiğinin net bir sinyali. Bunu zaman içinde takip etmek, context oluşturma iyileştirmelerinin gerçek verimlilik kazanımlarına dönüşüp dönüşmediğini gösteriyor.

Warning

Context kalitesini tek başına değerlendirme. Precision ve recall'da iyi puan alan bir retrieval hattı, context kötü sıralanmışsa veya kritik talimatlar getirilen belgeler tarafından bastırılıyorsa yine kötü yanıtlar üretebilir. Bu tür sorunları yakalamak için retrieval metriklerinin yanında mutlaka uçtan uca görev kalitesini de ölç.

Önemli Çıkarımlar

Context engineering, prodüksiyon LLM uygulamaları geliştiren ekipler için hızla temel bir beceri hâline geliyor. Modeller akıllandıkça darboğaz model zekâsından girdi kalitesine kayıyor — ve girdi kalitesi, mühendislik çözümleri olan bir mühendislik problemi.

  • Context window'u çöp kutusu değil, tasarım yüzeyi olarak ele al. Her token, çıktı kalitesi üzerindeki ölçülebilir etkisiyle yerini hak etmeli.
  • Context oluşturma kalıbını — statik, dinamik veya retrieval tabanlı — uygulamanın gerçek ihtiyaçlarına göre seç. Kararlı talimatları adaptif retrieval ile birleştiren hibrit yaklaşımları değerlendir.
  • Öncelik tabanlı tahsisle açık token bütçe yönetimi uygula. System talimatları ve guardrail'ler, getirilen içeriğe yer açmak için asla feda edilmemeli.
  • Dikkatin nasıl çalıştığına saygı göster: kritik bilgiyi başa ve sona koy, yapısal ayırıcılar kullan, uzun konuşma geçmişlerini özetle.
  • Hem retrieval metrikleri (precision, recall, MRR) hem de uçtan uca görev metrikleriyle context kalitesini titizlikle ölç. Boşa giden bütçeyi tespit etmek için context utilization'ı takip et.
  • Yinelemeye devam et. Context engineering tek seferlik bir kurulum değil — değerlendirme verileri ve gelişen model yetenekleriyle beslenen sürekli bir optimizasyon döngüsü.

Alan henüz genç ve en iyi pratikler hızla değişiyor. Ama temel içgörü kalıcı: context window'a giren şeyin kalitesi, çıkan şeyin kalitesini belirliyor. Bu girdiyi özenle, ölçümle ve sistematik titizlikle mühendislik etmek, LLM'lerle çalışan her ekip için en yüksek kaldıraçlı işlerden biri.