18 Kod Çözme ve Yapılandırılmış Çıktı
Öğrenme hedefleri. Bu bölümün sonunda:
- her örnekleme parametresinin olasılık dağılımına ne yaptığını açıklayabilirsiniz;
- bir modele, bitirmesine izin verildiği her durumda şemaya uygun çıktı ürettirebilirsiniz;
- logprob’ları (modelin token’lara verdiği log olasılıkları) güven, yönlendirme ve çekimserlik için kullanabilirsiniz;
- tekrarı ve yozlaşmayı (degeneration: metnin kendini tekrar eden ya da anlamsız bir çıktıya kayması) rastgele parametre ayarlamak yerine teşhis edebilirsiniz.
Neye bakacağız. Önce örnekleme politikaları: greedy, beam, sıcaklık ve top-k / top-p / min-p kesimleri. Sonra greedy’nin neden tekrar döngülerine girdiği ve yapı üretmeye başladığınızda alışıldık cezaların neden yanlış araç olduğu. Sonra kısıtlı kod çözme; bir gramerin geçersiz çıktıyı düşük olasılıklı değil, erişilemez kıldığı yer — iki modelde ölçüldü, çünkü birinde neredeyse hiçbir şey, diğerinde on yedi doğruluk puanı kazandırıyor. Sonra araç çağrıları; güçlü modeldeki iyi sonucun bile yetmediği durum. Sonra logprob’lar; iyi ayırt eden, kötü kalibre olan ve yine de tek bir eşik karşılığında tutulan maddelerde size doğruluk kazandıran şey. Son olarak da akış (streaming); yapılandırılmış çıktının istediği her şeyin tersini isteyen şey.
18.1 Greedy, beam, sıcaklık, top-k / top-p / min-p
Bir dil modelinin ileri geçişi bir logit vektörüyle biter — sözlükteki her token için bir ham puan. Bölüm 7’nin tamamı o vektörü üretmekle ilgiliydi. Bu puanları gerçek token’lara çevirme işine kod çözme (decoding) diyoruz. Bu adımda olan şey öğrenme değil, çıkarım anında sizin kontrol ettiğiniz bir örnekleme politikası. Bu politika, çıktının karakterini çoğu insanın beklediğinden fazla değiştiriyor.
- Sıcaklık \(\tau\), softmax’tan önce logit’leri yeniden ölçekler: \(p_i \propto \exp(z_i/\tau)\). Düşük \(\tau\) keskinleştirir, yüksek \(\tau\) düzleştirir.
- Top-k yalnızca en yüksek olasılıklı \(k\) token’ı tutar, sonra yeniden normalize eder.
- Top-p (nucleus) kümülatif olasılığı \(p\)’ye ulaşan en küçük token kümesini tutar, sonra yeniden normalize eder (Holtzman vd. 2020).
Bunların çalışma sırası önemlidir ve insanları asıl şaşırtan kısım da budur. transformers’ta (5.x) tek bir kod çözme adımı şunu uygular: ham logit’lere tekrar cezası (ve no-repeat n-gram gibi diğer işlemciler), sonra sıcaklık, sonra top-k, sonra top-p, sonra min-p, sonra örnekleme. vLLM de önce cezaları — tekrar cezasının yanında frequency penalty (geçme sayısıyla büyüyen ceza) ve presence penalty (önceden geçen token’a sabit ceza) — ardından sıcaklığı uygular; ama min-p’yi top-k ve top-p’den önce çalıştırır. llama.cpp’nin varsayılan zincirinde ise sıcaklık bütün kesimlerden sonra, en sonda gelir. Yani sıra tek bir kütüphanenin içinde sabittir, kütüphaneler arasında değil; kullandığınız kütüphaneye bakın. Sıcaklığın önce geldiği sıralamada bundan iki sonuç çıkıyor. Birincisi, sıcaklık top-p’den önce çalıştığı için sıcaklığı yükseltmek hangi token’ların çekirdeğe (nucleus) gireceğini değiştirir. Yani sıcaklığın “yalnızca kontrastı değiştirdiği, sıralamayı asla değiştirmediği” yolundaki yaygın iddia, tek başına sıcaklık için doğrudur; ama kırpma da yapan bir hatta yanıltıcıdır. Aşağıdaki etkileşimli araç, çekirdeğe hangi token’ların girip çıktığını izlemenizi sağlıyor. İkincisi, cezalar (üç kütüphanede de) sıcaklıktan önce çalıştığı için aynı ceza değeri \(\tau = 0{,}2\)’de, \(\tau = 1{,}5\)’tekinden çok daha sert etki eder: ham logit’e uygulanan toplamsal bir \(\alpha\) cezası, ölçeklemeden sonra \(\alpha/\tau\) olur. İkisini birlikte ayarlıyorsanız önce sıcaklığı ayarlayın.
18.1.1 Keşfedin: sıcaklık, top-k ve top-p
Model az önce “After the lecture, the students were completely ____” (“Dersten sonra öğrenciler tamamen ____”) cümlesini okudu ve aşağıdaki logit’leri üretti. Örnek İngilizce, çünkü adayların her biri tek bir token; Türkçede “yorulmuşlardı” gibi bir devam çoğu tokenizer’da birkaç alt kelime token’ına bölünür ve aynı politika her parçada yeniden uygulanır. Gri çubuklar o anki sıcaklıktaki softmax dağılımını herhangi bir kesimden önce, turkuaz çubuklar ise örnekleme politikanızdan geçen token’ları, yeniden normalize edilmiş hâliyle gösteriyor. \(\tau = 0{,}2\) deneyin, sonra \(\tau = 1{,}8\). Sonra kuyruğu top-p \(= 0{,}6\) ile kesin.
Düşük bir sıcaklığın yapmadığı şeye dikkat edin: sıralamayı asla değiştirmez, yalnızca kontrastı değiştirir. Top-k ve top-p ise sert kesimlerdir; esas olarak modelin yorgun öğrenciler hakkındaki bir cümlede recursive kelimesini hiç seçmemesi için varlar. Bu üçlü, buradan sonraki her uygulamalı sistemde elinizdeki en ucuz ayar düğmesidir.
18.1.2 Greedy, beam ve min-p
Resmi üç politika daha tamamlıyor.
Greedy (açgözlü) kod çözme her adımda argmax’ı, yani en olası token’ı alır. Sıcaklığın 0’a gittiği limit durumudur ve tek bir doğru cevap olduğunda varsayılan olarak seçilmesi gereken budur. (Sıfıra bölme tanımsız olduğundan API’ler “sıcaklık 0” isteğini greedy kod çözme olarak uygular. Buna rağmen barındırılan bir API her seferinde aynı dizgiyi döndürmeyebilir: GPU’da isteklerin batch (toplu işlem) hâlinde işlenmesi ve kayan nokta yuvarlamaları, neredeyse eşit olasılıklı iki token arasındaki sırayı değiştirebilir; tek bir token farklı çıktığında da metnin geri kalanı değişir. Sabit bir seed (tohum) da bunu tek başına çözmez: seed yalnızca örneklemenin rastgele çekilişlerini sabitler, batch bileşimini, donanımı ya da kütüphane sürümünü sabitlemez.)
Beam search (ışın araması) en iyi k kısmi diziyi (k’ye beam genişliği denir) tutup hepsini genişletir; böylece her adımda en iyi token’ı seçmek yerine olasılığı yüksek bir bütün diziyi arar. Yine de genişliği sınırlı bir arama olduğu için en olası tek diziyi kaçırabilir.
Bölüm 15 bunu çeviri üzerinde düzgün biçimde ölçüyor ve bulgularından ikisini burada da hatırlatmakta yarar var. Kazançlar hızla azalıyor — beam 1’den 2’ye +0,61 BLEU, beam 2’den 64’e yedi kat hesaplama karşılığında yalnızca +0,57 daha. Beam’i genişletmenin çıktıyı kötüleştirdiği yolundaki yaygın uyarı (“beam search laneti”) ise hiç görünmedi; büyük olasılıkla kod çözücü arama sırasında uzunluğa göre normalize ettiği için. Uzunluk normalleştirmesi, bir aday dizinin log olasılığını uzunluğuna böler. Bu yapılmazsa her ek token toplam puana negatif bir log olasılık daha ekler ve arama gereğinden kısa çıktıları kayırır.
Min-p (Nguyen vd. 2024) daha yeni bir kesimdir. Top-p sabit bir kütle, top-k sabit bir sayı tutarken min-p, olasılığı en üst token’ın olasılığının belirli bir kesrine en az eşit olan her token’ı tutar:
\[ p_i \;\ge\; m \cdot \max_j p_j \quad\Longrightarrow\quad i \text{ tutulur} \]
Bu, kesimi bir sabite göre değil, dağılımın biçimine göre uyarlar. \(m\) için tipik değerler 0,05–0,1’dir: \(m = 0{,}1\) iken en üst token 0,6 ise 0,06’nın altındaki her token kesilir.
Model emin olduğunda (örneğin bir token’ın olasılığı 0,9 iken) min-p en üst token dışında neredeyse hiçbir şey tutmaz; istediğiniz de budur. Yirmi makul devam seçeneği arasında gerçekten kararsız olduğunda ise min-p hepsini tutar; oysa top-p 0,9, ne kadar makul olurlarsa olsunlar son birkaçını yalnızca kümülatif kütleye bakarak keserdi.
Hepsinin altında yatan genel kural: politika, görevin kaç tane iyi cevabı olduğuna bağlı olmalı. Bilgi çıkarma, sınıflandırma ve çevirinin bir tane var, dolayısıyla greedy ya da dar bir beam. Taslak yazma, beyin fırtınası ve diyaloğun çok var, dolayısıyla örnekleyin. Bölüm 15 bunu tersine çevirmenin bedelini ölçtü — sohbet varsayılanı olan 1,0 sıcaklık, bir çeviri modelini 30,17 BLEU’dan 14,34’e düşürdü.
18.2 Tekrar ve yozlaşma
Greedy ve düşük sıcaklıklı kod çözmenin karakteristik bir kusuru var: model bir döngüye düşer ve token sınırına çarpana kadar bir öbeği tekrarlar.
Mekanizma gizemli değil. Bir öbeği bir kez ürettikten sonra model o öbeği kendi bağlamının parçası yapmıştır ve gerçek metin üzerinde eğitilmiş bir dil modeli tekrarlanan öbeklerin ilk tekrardan sonra daha olası olduğunu öğrenmiştir.
Holtzman vd. (2020) buna ad verdi ve şaşırtıcı kısmı gösterdi: döngü düşük olasılıklı bir rastlantı değil. Tekrarlanan devam çoğu zaman, mevcut diziler arasında olasılığı en yüksek olanıdır; greedy kod çözmenin bu döngüye girmesinin, örneklemenin ise nadiren girmesinin nedeni budur.
Alışıldık kontroller ve her birinin bedeli:
| kontrol | ne yapar | neyi bozar |
|---|---|---|
| Örnekleme (top-p, min-p) | bazen argmax olmayan bir token seçer, döngüyü kırar | bir bilgi çıkarma görevinde istemeyebileceğiniz çeşitlilik |
| Tekrar cezası (repetition penalty) | zaten kullanılmış her token’ın logit’ini düşürür — pozitifken bölerek, negatifken çarparak (aşağıya bakın) | meşru biçimde tekrarlanan kelimeleri cezalandırır — adlar, teknik terimler, null |
| No-repeat n-gram (n-gram tekrar yasağı) | zaten üretilmiş her n-gram’ı yasaklar | gerçekten tekrarlanması gereken öbekleri de yasaklar; {"type": gibi ifadelerin tekrarlandığı yapılandırılmış çıktıda yıkıcıdır |
| Presence penalty (varlık cezası) | daha önce geçmiş her token’ın logit’inden sabit bir miktar çıkarır | aynı kusur, daha hafif biçimde; tırmanmaz |
| Frequency penalty (sıklık cezası) | kaç kez geçtiğiyle orantılı bir miktar çıkarır | her tekrarla tırmanır, bu yüzden uzun çıktılar kayar |
Tekrar cezası \(\theta\) ham logit üzerinde çalışıyor ve uygulamaların en sık yanlış yaptığı yer, logit’in işaretinin nasıl ele alındığı:
\[ z_i' = \begin{cases} z_i / \theta & z_i \ge 0 \\ z_i \cdot \theta & z_i < 0 \end{cases} \]
Negatif bir logit’i \(\theta > 1\) ile bölmek onu sıfıra doğru yükseltir — yani ceza değil ödül olur. Formüldeki iki dalın göstermelik olmamasının nedeni bu. Ceza CTRL’den gelir (Keskar vd. 2019); oradaki formül yalnızca böler. İşaret durumunu transformers gibi sonraki uygulamalar eklemiştir. OpenAI tarzı cezalar ise toplamsal oldukları ve bunun yerine sayımlara dayandıkları için bu sorundan kaçınıyor: \(z_i' = z_i - \alpha_{\text{presence}}\,\mathbb{1}[c_i > 0] - \alpha_{\text{freq}}\,c_i\); burada \(c_i\), \(i\) token’ının kaç kez geçtiği. Presence penalty bir kez devreye girer; frequency penalty her tekrarla büyümeye devam eder.
Bu cezalar gerekli tekrarı gereksiz tekrardan ayırt etmez; bu yüzden yapılandırılmış çıktı için yanlış araçtır. Bir JSON nesnesi meşru biçimde anahtarları, süslü parantezleri ve tırnak karakterlerini tekrarlar; aynı anahtarların yinelendiği bir JSON’a (örneğin bir nesne dizisine) no-repeat-3-gram kısıtı koymak, ikinci nesnede anahtarı yazmayı yasaklar ve şemaya aykırı çıktıyı neredeyse kaçınılmaz kılar. Yapı üretiyorsanız tekrarın çözümü bir ceza değil, Bölüm 18.3’teki gramerdir.
18.3 Kısıtlı kod çözme
Yukarıdakilerin hepsi bütün sözlük üzerindeki bir dağılımı yeniden biçimlendirir. Kısıtlı kod çözme daha katı bir şey yapar: her adımda, hangi token’ların çıktıyı gramere uygun biçimde sürdürebileceğini hesaplar ve diğer tüm token’ların logit’lerini \(-\infty\) yapar. Geçersiz çıktı artık yalnızca düşük olasılıklı değildir; erişilemez hâle gelir. Ancak bu “erişilemez” sözü üç koşula bağlı. Birincisi, şema kütüphanenin gerçekten desteklediği bir şema olmalı; desteklenmeyen anahtar kelimeler genellikle dayatılmak yerine yok sayılır. İkincisi, üretimin bitmesi gerekir: token sınırına takılan, zaman aşımına uğrayan ya da bağlantısı kopan bir koşu, o ana kadar gramere uygun ama belge olarak geçersiz bir ön ek bırakır. Üçüncüsü, gramer anlamı değil yapıyı kısıtlar; bu yüzden zorunlu bir alan makul bir uydurmayla doldurulabilir. Sonucu yine de ayrıştırıp doğrulayın; garanti çok değerlidir ama “hiç kontrol etme” anlamına gelmez.
constrained decoding (kısıtlı kod çözme) — her adımda logit’leri bir gramerin izin verdiği token’lara maskelemek. Tamamlanmış bir üretimin biçimini garanti eder ve doğru olup olmadığı hakkında hiçbir şey söylemez. ↩︎
Bu mekanizmanın gözden kaçması kolay bir özelliği var. Ölçümlerin neyi gösterip neyi göstermediğini belirlediği için onu ölçümlerden önce söyleyelim. Her adımda maskelemek, modelin dağılımından gramere koşullu örneklemekle aynı şey değildir. O adımda izin verilen bir token yalnızca çıkmazlara götürüyor olabilir ve yerel maskelemenin bunu hesaba katıp yeniden normalize etmesinin bir yolu yok. Sonuçta gramere uygun dizgiler üzerinde bir dağılım elde edersiniz; ama bu dizgilerin olabilirlikleri artık modelin kendi olabilirlikleriyle orantılı değildir (Park vd. 2024). Pratikte bu, kısıtsız modelin daha aşağı sıralayacağı gramere uygun çıktılar olarak kendini gösteriyor. Gramerle hizalanmış kod çözme bunu fazladan bir maliyetle düzeltiyor. Bölüm 18.9’daki her kütüphane ise ucuz ama dağılımı bozan sürümü sunuyor. Doğru varsayılan da budur; yine de bu sürümü kullandığınızın farkında olun.
Tek bir kod çözme adımı, gramerli ve gramersiz
Bu mekanizma, tokenizer’ın sözlüğü üzerinde çalışan bir sonlu durum makinesidir (Willard ve Louf 2023): regex’i — ya da iç içe geçmesi sınırlı bir JSON Schema’yı — bir otomata derleyin, hangi durumda olduğunuzu izleyin ve her durum için izin verilen sonraki token kümesini önceden hesaplayın. (Sonlu durum makinesini, “şu ana kadar ne yazıldı”ya bakarak bir sonraki adımda nelerin yazılabileceğini bilen bir akış şeması gibi düşünün.) Asıl mühendislik zorluğu da buradadır: token’lar gramer sembolleriyle hizalı değildir — tek bir token ": ya da ", " gibi birkaç karakter taşıyabilir — bu yüzden izin kümesi karakter düzeyinde değil, token düzeyinde hesaplanmalıdır; outlines ve xgrammar gibi kütüphanelerin var olma nedeni budur. Genel bir bağlamdan bağımsız gramer (CFG) sonlu durum makinesine sığmaz, çünkü sınırsız iç içe geçme bir yığın (stack) gerektirir — kaç parantezin açık kaldığını saymak için; CFG kabul eden kütüphaneler bunun yerine artımlı bir ayrıştırıcı (yığınlı otomat) koşturur. Bu, adım başına daha pahalıdır ama karşılığında sınırsız derinlikte özyinelemeye izin verir. Geng vd. (2023) aynı fikri genel yapılandırılmış NLP görevlerine uygular.
18.3.1 Gerçekte ne kazandırıyor
İlginç soru bir gramerin bir şemayı zorlayıp zorlayamayacağı değil — zorlayabilir — zorlanmamış bir modelin kendi başına uymayı nerede bıraktığı ve zorlama devreye girdiğinde bunun neye mal olduğudur. Giderek zorlaşan dört şema, 150 dengeli yorum, iki model; şemaya uyum bir kez yalnızca istenerek (asked), bir kez de zorlanarak (forced) ölçüldü. Satırlardaki dört şema düzeyi şunlar: L1 düz bir nesne ve doğal etiketli bir enum (flat, natural enum), L2 doğal olmayan etiketli bir enum (unnatural enum), L3 iç içe nesne ve dizi (nested + array), L4 iç içe nesne ve null olabilen bir alan (nested + nullable). Sütunlar sırasıyla ayrıştırılabilen çıktıların oranı (parses), şemaya uyan çıktıların oranı (schema-ok), doğruluk (accuracy) ve madde başına saniye (s/item):
qwen3.5:9b parses schema-ok accuracy s/item
L1 flat, natural enum asked 100.0% 98.0% 89.3% 1.23
L1 flat, natural enum forced 100.0% 100.0% 88.7% 1.30
L2 unnatural enum asked 99.3% 99.3% 86.7% 1.33
L2 unnatural enum forced 100.0% 100.0% 87.3% 1.36
L3 nested + array asked 100.0% 98.7% 88.0% 1.44
L3 nested + array forced 100.0% 100.0% 88.0% 1.62
L4 nested + nullable asked 100.0% 98.0% 88.7% 1.73
L4 nested + nullable forced 100.0% 100.0% 88.7% 1.74
llama3.2:3b parses schema-ok accuracy s/item
L1 flat, natural enum asked 98.0% 98.0% 83.3% 0.37
L1 flat, natural enum forced 100.0% 100.0% 85.3% 0.56
L2 unnatural enum asked 99.3% 97.3% 78.0% 0.43
L2 unnatural enum forced 100.0% 100.0% 80.0% 5.13
L3 nested + array asked 79.3% 79.3% 70.7% 0.37
L3 nested + array forced 100.0% 100.0% 88.0% 0.70
L4 nested + nullable asked 99.3% 98.7% 86.0% 0.53
L4 nested + nullable forced 100.0% 100.0% 86.7% 9.26
Üç bulgu var ve tekniğe bakışı asıl değiştiren ilki.
Güçlü bir modelde gramer neredeyse hiçbir şey kazandırmıyor. qwen3.5:9b, iç içe nesneler ve null olabilen bir alan dâhil her zorluk düzeyinde, şemaya yalnızca istendiğinde bile çıktıların %98–99,3’ünde uydu. Zorlama bunu %100’e çıkardı ve doğruluğu değiştirmedi. Modern talimat ayarlı modeller tarif ettiğiniz JSON’ı çoğunlukla üretir; gramer, geriye kalan yüzde bir iki için bir sigortadır.
Fark gözlenmeyen bu sonuca (null result) iki çekince koymak gerekiyor; ikisi de sonucun kendisinden önemli. Birincisi, sonuç yalnızca 150 örneğe dayanıyor: %88’lik bir doğruluğun %95 güven aralığı kabaca ±5 puan. Yani iki ila beş puanlık bir bozulma gerçekten olsa bile bu deney onu saptayamazdı. İkincisi, buradaki görev sınıflandırma. Tam vd. (2024), format kısıtlamasının sınıflandırmaya yardım ettiğini ve çok adımlı akıl yürütmeye zarar verdiğini buldu. GSM8K türü görevler JSON kipinde birkaç puan kaybetti; üstelik ayrıştırma hataları sıfıra yakındı. Yani kayıp ayrıştırmada değil, akıl yürütmede. Dolayısıyla bu bölümün sonucu onlarınkiyle çelişmiyor; onların bulgularının dar bir alt kümesiyle örtüşüyor ve genel bir iddiayı desteklemiyor. “Zorlamanın maliyeti yok” sonucunu bir düşünce zinciri görevine taşımayın; orada güvenli kalıp, modelin kısıtsız akıl yürütmesine izin verip yalnızca son cevap alanını kısıtlamaktır.
Zayıf bir modelde ise gramer, çalışmakla çalışmamak arasındaki farktır. llama3.2:3b, iç içe nesne ve dizi içeren şemada %79,3 şema geçerliliğine düştü; beş çıktıdan biri kullanılamaz durumdaydı. Zorlama bunu %100’e çıkardı ve doğruluk %70,7’den %88,0’a yükseldi. Bu 17,3 puanlık kazancın nedeni, bozuk çıkan beşte birin daha önce yanlış sayılmasıydı. Gramer modeli akıllandırmadı; bir biçimlendirme kusurunun bir akıl yürütme kusuru olarak sayılmasını durdurdu.
Bedel gecikmedir ve tahmin edeceğiniz yerde değildir. Ek yük 1,01 kat ile 17,5 kat arasında değişti (üst uç, zayıf modelin L4’teki değeri: madde başına 0,53 saniyeden 9,26 saniyeye) ve şema karmaşıklığıyla birlikte monoton artmadı: llama3.2:3b’de L1 ve L3 ucuz, L2 ve L4 pahalıydı; qwen3.5:9b’de ise en pahalısı L3’tü. İki uç değer farklı modellere ait ve asıl bulgu da bu: qwen3.5:9b’de gramerin bedeli 1,006 kat ile 1,13 kat arasında, yani neredeyse maliyetsiz; llama3.2:3b’de ise 1,5 kat ile 17,5 kat arasında. Model şemayla zaten uyuşuyorsa gramer ucuzdur; uyuşmuyorsa pahalıdır.
Pahalı çıkan iki durumun ortak bir özelliği var: şema, modelin üretmek istemediği bir şey talep ediyor; birinde doğal olmayan bir enum (izin verilen değerlerin açık listesi), diğerinde null olabilen bir alan. Bu, gramerin modelin dağılımıyla uyumlu ilerlemek yerine onunla mücadele etmek zorunda kalmasıyla tutarlı. Gerçi bu ölçüm mekanizmayı değil, yalnızca örüntüyü ortaya koyuyor.
Bu da tahmin yürütmek yerine ölçmek için bir neden daha. Gramerin bedeli yalnızca şema karmaşıklığına bağlı olsaydı, onu şemaya bakarak önceden hesaplayabilirdiniz. Oysa görünüşe göre şemayla model arasındaki uyuşmazlığa bağlı ve bunu ikisini de çalıştırmadan göremezsiniz.
18.3.2 Neyi düzeltemez
Bir gramer biçimi kısıtlar. Neyin doğru olduğunu bilemez; bunun doğurduğu kusuru doğrudan görelim. Örnek Bölüm 13.8’den; orada şema, tam sayı tipinde bir answer alanı içeren bir nesne istiyordu:
POST /api/generate format={"answer": integer}
prompt: "What is the capital of France?"
-> {"answer": 1}
Şema-geçerli, ayrıştırılabilir, tip olarak doğru ve anlamsız. Kısıtlı kod çözme bir ayrıştırma kusurunu anlamsal bir kusura dönüştürür. Bu genellikle istediğiniz ödünleşimdir (trade-off), çünkü doğrulayabileceğiniz yanlış bir değer, bir çökmeden iyidir. Ama bu bir ödünleşimdir, bir çözüm değil. Size verdiği her garanti sözdizimseldir.
Buradan iki sonuç çıkıyor:
- Yalnızca yapıyı değil değerleri de doğrulayın. Bir enum kontrol edilebilir; serbest metinli bir alan edilemez. Görev elverdiği ölçüde sözleşmenizdeki alanları enum’larla sınırlayın.
- Bir şema kaçış kapısının yerine geçmez. Modelin bilmiyorum demesinin geçerli bir yolu yoksa, gramer modelin bunun yerine başka bir şey söylemesini garanti eder. Tipe
nullekleyin ve modelin onu gerçekten kullandığını ayrıca ölçün; bu kitapta ölçülmüş bir bulgu değil, bir kontrol adımı. Bölüm 11.11’in dediği gibi, hiç devreye girmeyen bir kaçış kapısı süstür.
18.4 Araç argümanlarını güvenilir kılmak
Yukarıdakilerin en çok işe yaradığı yer bilgi çıkarma değil, araç çağrılarıdır. Bir araç çağrısı zaten yapılandırılmış bir çıktıdır — bir işlev adı ve tipli bir argüman nesnesi — ve doğruluğu her zamankinden önemli kılan bir özelliği var: sonrasında bir şey çalışıyor.
Bozuk bir özet kötü bir özettir. Bozuk bir argüman nesnesi ise ya bir çökmedir ya da daha kötüsü, yanlış değerle başarılı olan bir çağrıdır.
Uygulamada bu şöyle görünür: işlev çağırma (function calling) ile modele bir araç tanımları listesi gönderirsiniz; her tanım bir ad, bir açıklama ve argümanlar için bir JSON Schema içerir. Model de düz metin yerine bir araç adı ve bir argüman nesnesiyle yanıt verir. Bu argümanların gerçekten zorlanıp zorlanmadığı bir bayrağa bağlıdır. Barındırılan API’ler genellikle iki düzey sunar. “JSON kipi” yalnızca çıktının sözdizimsel olarak geçerli bir JSON olmasını garanti eder, şemanıza uymasını değil; şemayı zorlayan kip ise (örneğin OpenAI’ın API’si buna strict der) şemanızı yukarıda anlatılan türden bir gramere derler. Hangisini açtığınızı bilin.
Yukarıdaki ölçümlerden üç kural çıkıyor.
Argümanları her zaman kısıtlayın. Güçlü modeldeki iyi sonuç burada yetmez. %98 şema geçerliliği bilgi çıkarma için mükemmel, yürütme için kabul edilemezdir: günde bin çağrıda bu, günde yirmi kusur demektir ve her biri bir stack trace (hataya yol açan çağrı zincirinin kaydı) ya da yanlış bir eylemdir. Gramer, tamamlanan her çağrı için bunu sıfıra indirir. Gecikme bedeli gerçektir ve şemadan şemaya değişir; ama yayına almadan önce ölçebilirsiniz.
Argümanları aracın izin verdiği kadar dar tipleyin. Dört işlemlik bir enum varken araç beşinci bir işlemle çağrılamaz. Dizgi olarak tiplenmiş bir tarih "dün" olabilir; bir desenle tiplendiğinde olamaz. Şemaya taşıyabildiğiniz her kısıt, yazmak zorunda kalmadığınız bir doğrulama ve erişilemez hâle gelen bir hata sınıfıdır.
Geçerli bir çağrı yine de doğru bir çağrı değildir. Gramer {"operation": "delete", "id": 4} ifadesinin iyi biçimli olduğunu garanti eder. 4’ün doğru id olup olmadığını bilmez. Bu problem ve onu çevreleyen onay ve yetkilendirme mekanizmaları, araç tasarımı bölümünün (Bölüm 24) konusudur.
18.5 Logprob’lar, güven ve çekimserlik
Model her token’ın yanında ona atadığı log olasılığı da bildirir — token’ın logprob’u. Bu, modelin ne kadar emin olduğuna dair mevcut en ucuz sinyaldir. API’niz onu döndürüyorsa elde etmenin ek bir maliyeti yoktur ve çoğu hat onu çöpe atar. Her barındırılan API ya da model logprob döndürmez; döndürenler de çoğu zaman yalnızca en olası birkaç adayı (top_logprobs) verir. Kullandığınız API’nin logprob verip vermediğini ve kaç aday döndürdüğünü önce kontrol edin: aşağıdaki yöntem için A ile B’nin ikisi de listede olmalı, yoksa iki seçenek üzerinden yeniden normalize etmek mümkün olmaz.
Soru, bu sinyalin kullanılabilir olup olmadığı. Ölçüm qwen3.5:9b ile 400 dengeli yorum üzerinde yapıldı. Cevap tek bir token’la sınırlandı: olumlu için A, olumsuz için B. Böylece üretilen ilk token cevabın kendisi oluyor. Bu token’ın olasılığı da yalnızca bu iki seçenek üzerinden yeniden normalize edilerek düzgün bir ikili olasılığa dönüştürülebiliyor.
logprob (log olasılık) — modelin bir token’a atadığı log olasılığı. Yalnızca cevap tek bir token olduğunda güven olarak yorumlanabilir; uzun bir cevap için ortalama logprob çoğunlukla ifadenin ne kadar sıradan olduğunu ölçer. ↩︎
18.5.1 Ayırt ediyor
Herhangi bir güven sinyali hakkındaki ilk soru, maddeleri doğru sıralayıp sıralamadığıdır: modelin emin olduğu maddeler, gerçekten doğru cevapladığı maddeler mi? Bu soruyu iki AUC cevaplıyor. AUC (ROC eğrisinin altındaki alan), rastgele seçilmiş bir olumlu örneğin rastgele seçilmiş bir olumsuzdan daha yüksek puan alma olasılığıdır: 0,5 şans düzeyi, 1 kusursuz sıralama demektir. Aşağıdaki çıktıda ilk AUC satırı etiket olasılığının olumluları olumsuzlardan ne kadar iyi ayırdığını, ikincisi güvenin modelin kendi doğru ve yanlış cevaplarını ne kadar iyi ayırdığını veriyor; son iki satır, model haklıyken ve yanılırken ortalama güvendir.
accuracy 86.75%
AUC of P(positive) against the true label 0.9492
AUC of confidence for predicting its own correctness 0.8268
mean confidence when the model was right 0.9481
mean confidence when the model was wrong 0.7793
Puan iyi; model tahmin yürüttüğü maddelere belirgin biçimde daha düşük güven veriyor. 0,9492’lik bir AUC, olasılığın olumluları olumsuzların üstünde sıralamada neredeyse eğitilmiş bir sınıflandırıcı kadar başarılı olduğunu söylüyor. 0,8268 ise güvenin, modelin kendi doğru cevaplarını yanlışlarından ayırdığını söylüyor. Kadavath vd. (2022) bu ikinci sonucun genel hâlini ortaya koyar.
18.5.2 Kalibre değil
Ayırt etme ile kalibrasyon farklı özelliklerdir ve ikincisi burada sağlanmıyor. Tablo 400 cevabı beyan edilen güvene göre kutulara ayırıyor (confidence bin: güven aralığı, n: kutudaki madde sayısı, accuracy: kutudaki doğruluk, mean confidence: kutudaki ortalama güven). ECE (beklenen kalibrasyon hatası, tanımı Bölüm 12’de), her kutudaki güven ile doğruluk arasındaki farkın, kutu büyüklükleriyle ağırlıklandırılmış ortalamasıdır:
confidence bin n accuracy mean confidence
[0.50, 0.55) 15 33.3% 52.4%
[0.55, 0.60) 10 50.0% 57.5%
[0.60, 0.65) 10 70.0% 62.5%
[0.65, 0.70) 8 62.5% 66.4%
[0.70, 0.75) 7 85.7% 72.7%
[0.75, 0.80) 8 87.5% 77.6%
[0.80, 0.85) 13 61.5% 82.7%
[0.85, 0.90) 20 85.0% 87.6%
[0.90, 0.95) 25 68.0% 92.6%
[0.95, 1.00) 284 95.1% 99.4%
ECE = 7.04%
\([0{,}50;\ 1{,}00)\) üzerinde on eşit genişlikli kutu kullanıldı. Bunu belirtmek gerekir, çünkü ECE bu seçime duyarlıdır ve bu kutulama sonucu güzelleştirmiyor: 400 maddenin 284’ü en üst kutuya düşüyor ve %7,04’ün yaklaşık %44’ü tek başına bu kutudan geliyor. Eşit kütleli bir kutulama (her kutuya aynı sayıda madde düşer) ya da hiç kutu gerektirmeyen Brier skoru (verilen olasılıkla gerçekleşen 0/1 sonuç arasındaki farkın karesinin ortalaması), aynı verinin daha sağlam bir özetidir.
Tablodan iki sonuç çıkıyor ve ikisi aynı ölçüde sağlam değil. Model yüksek güven bölgesinde bile aşırı emin: %92,6 olasılık verdiği kutuda 25 maddenin 17’sinde haklı. Bu %68,0’lık oranın %95 Wilson aralığı \([48;\ 83]\) ve aralığın tamamı modelin beyan ettiği güvenin altında kalıyor. Sağlam olan bulgu bu.
İnsanların aktardığı ise en alt kutu ve genellikle gördüğünden fazla temkini hak ediyor: 15’te 5 doğru, yani %33,3’lük bir nokta kestirimi ve \([15;\ 58]\) aralığı. Bu aralık %50’yi içeriyor; dolayısıyla “şansın altında” iddiasını kanıtlamıyor. Geniş bir aralık, yararsızlığın kanıtı da değildir. Bu kutunun gösterdiği şey daha sınırlı: 0,5’e yakın bir etiket olasılığı, doğru olmanın kalibre bir kestirimi değildir; bu sonuç da on beş maddeye dayanıyor. (Model bir log olasılık bildirir; 0,5 ise olasılığın kendisidir ve log cinsinden yaklaşık \(-0{,}69\) eder. Eşik uygulamadan önce dönüştürün.)
0,5’e yakın bir etiket olasılığını “vakaların yarısında doğru” diye okumayın. Yine de işe yarayabileceği yer sıralama: kalibre olmayan bir skor, şüpheli belgeleri bir insana yönlendirmeye yetecek kadar iyi sıralayabilir ve aşağıdaki çekimserlik deneyi bunu yapıyor. Bu kullanımı değerlendirirken bu kutuya değil, bir doğruluk–kapsam eğrisine bakın.
Gerektirdiği çabaya göre sıralanmış iki çözüm var. Sıcaklık ölçekleme (Guo vd. 2017), ayrılmış (held-out) bir dilimde tek bir skaler \(T\) değeri kestirir ve logit’leri bu değere böler. Bu, Bölüm 18.1’deki \(\exp(z/\tau)\) ifadesinin aynısıdır; tek farkı üretim sırasında değil, sonradan uygulanmasıdır. Monoton olduğu için AUC’yi ve bir sonraki kısımdaki çekimserlik eğrisini aynen korur, ECE’yi ise genellikle en az yarı yarıya düşürür. Bu yüzden ilk denenecek yöntem budur. Tek bir skalerin düzeltebileceği şey, buradaki üst kutulardaki gibi sistematik bir aşırı güvendir; tablonun ortasındaki kutudan kutuya zikzakları gideremez. Tek bir skaler yetmiyorsa bir sonraki adım Bölüm 12’nin izotonik ya da Platt eşlemesidir.
18.5.3 Çekimserlik için hemen kullanışlı
Sinyal kalibre olmasa bile, ürettiği sıralama yönlendirme için yeterli. İlk sütun en az güvenilen maddelerin yüzde kaçında çekimser kalındığını, ikincisi tutulan madde sayısını, üçüncüsü yalnızca tutulan maddeler üzerindeki doğruluğu veriyor:
abstain on the least-confident kept accuracy on what is kept
0% 400 86.75%
5% 380 89.47%
10% 360 90.83%
20% 320 92.50%
30% 280 95.00%
50% 200 97.50%
En az güvenilen beşte biri bir insana ya da daha büyük bir modele göndermek, tutulan maddelerdeki doğruluğu modeli hiç değiştirmeden %86,75’ten %92,50’ye çıkarıyor. Paydaya dikkat edin: %92,50, modelin tuttuğu 320 madde üzerindeki doğruluğudur, hattın tamamının doğruluğu değil. Diğer 80’in neye mal olduğu — bir insanın ya da daha büyük bir modelin hata oranı — burada ölçülmedi ve uçtan uca sayı ikisinin kapsama ağırlıklı bileşimidir. Doğruluğu ve kapsamı her zaman birlikte raporlayın. Yine de bu, çoğu prompt (istem) mühendisliği çabasının sağladığından daha büyük bir kazanç ve bedeli de tek bir eşik.
Bu, kitaptaki en ucuz yönlendirme sinyalidir ve diğer her şeyle birleştirilebilir: bir eşiğin altında çekimser kalın, çekimser kalınan maddeleri daha büyük bir modele aktarın ve kapsamı doğrulukla birlikte raporlayın. Eşiğin veriden ayarlanan bir nicelik olduğuna dikkat edin; onu ayrılmış bir dilimde seçin. Bu, Bölüm 12’nin karar eşiğine uyguladığı disiplinin aynısı. Eşiği raporladığınız veride seçmek, aynı hatanın kılık değiştirmiş hâlidir.
Son iki tablo aynı 400 yorumu tarif ediyor. Yan yana konduklarında, bozuk bir kalibrasyonun sinyali kullanmanızı neden engellemediğini gösteriyorlar:
Kötü kalibre, doğru sıralanmış — ve ikinci kısım sayesinde kullanışlı
Sol: her nokta bir güven kutusu; modelin belirttiği güvene ve gerçekte ulaştığı doğruluğa yerleştirilmiş. Kalibre bir model her noktayı kesikli köşegene koyardı; bu modelin noktaları ise dağılıyor. İki gül rengi nokta akılda tutulmaya değer kusurlar: modelin yazı tura dediği kutu yalnızca 15 maddede %33,3’te kaldı; %92,6 dediği kutu ise 25 maddede %68,0’da. Sağ: aynı 400 yorum, aynı kalibre olmayan güvene göre sıralanmış ve en az güvenilen uçtan kırpılmış. Doğruluk her adımda tırmanıyor; asıl mesele de bu — sayılar yanlış olduğu yerde bile sıralama doğru.
18.5.4 Hepsini sınırlayan çekince
Bu, cevabın iki token’lık bir alfabeden tek bir token olması sayesinde işe yaradı. Bu, mümkün olan en kolay durumdur ve teknik bu durumdan uzaklaştıkça hızla bozulur:
- Çok token’lı cevaplar. Bir cümle üzerindeki ortalama logprob çoğunlukla ifadenin ne kadar sıradan olduğunu ölçer, içeriğin doğru olma olasılığını değil.
- Açık uçlu üretim. Okunacak “cevap token’ı” yoktur.
- Uzun yapılandırılmış çıktı. İyi biçimli bir JSON nesnesinin olasılığına, modelin emin olduğu noktalama işaretleri hâkimdir.
Bu, bir çekince olduğu kadar bir tasarım argümanıdır da: bir güven sinyali istiyorsanız görevi, cevap tek bir kısıtlı token olacak şekilde yapılandırın. Bu tür etiketler doğruluktan ödün vermeyi de gerektirmez: Bölüm 17’deki on iki prompt varyantının karşılaştırmasında anlamsız A/B etiketlerini kullanan varyant ikinci oldu ve olumlu/olumsuz etiketli varyantın on puandan fazla önüne geçti.
18.6 Akış ve artımlı ayrıştırma
Akışın var olma nedeni, kullanıcıların sizin ölçtüğünüz gecikmeye değil, algıladıkları gecikmeye tepki vermesidir. Tamamlanması dört saniye süren bir yanıt, ilk kelimeleri iki yüz milisaniyede beliren aynı yanıttan daha yavaş hissettirir — ikisi aynı anda bitse, yani hiçbir verim (throughput) metriği onları ayırt edemese bile.
Buraya kadar anlatılanlarla çatışan nokta şu: yapılandırılmış çıktı ile akış zıt şeyler ister. Bir JSON nesnesi ancak son süslü parantezi geldiğinde ayrıştırılabilir. Bu yüzden akla ilk gelen uygulama bütün yanıtı tamponlar ve hiçbir şey akıtmaz. Artan çaba sırasına göre üç çıkış yolu:
| yaklaşım | kullanıcının gördüğü | bedel |
|---|---|---|
| Tamponla ve doğrula | önce hiçbir şey, sonra her şey | en basiti; gecikmenin tamamı algılanır |
| Artımlı ayrıştırma | alanlar tamamlandıkça belirir | ön ekleri kabul eden bir ayrıştırıcı; kısmi durumlar görünür olur |
| Çağrıyı böl | düz metin akar, yapı sonra gelir | iki çağrı ve birbirleriyle çelişebilirler |
Kurmaya değer olan orta satırdır ve doğru yapılması gereken şey şu: kısmi bir ayrıştırma, tamamlanmış olandan farklı bir tiptir. {"duygu": "olu kötü bir nesne değildir; tamamlanmamış bir nesnedir. Henüz bilinmiyor durumunu temsil edemeyen, çıktıyı kullanan bir sistem ya çöker ya da anlamsız bir şey gösterir. None’ın iki anlama gelmesine izin vermek yerine bu durumu açıkça modelleyin: bir alan ya eksiktir, ya beklemededir ya da mevcuttur.
Bölüm 18.3’ten pratik bir not çıkıyor: bir gramer ve artımlı bir ayrıştırıcı, aynı otomatın iki uçtan görünüşüdür.
Üretimi zaten kısıtlıyorsanız, hangi token’lara izin verildiğine karar veren durum makinesi, çıktıyı kullanan tarafa hangi alanların kesinleştiğini de söyleyebilir. Çoğu yazılım yığını bu ikisini birbirine bağlamaz; arayüz gerektiriyorsa bu bağlantıyı kurmak makul bir iştir.
18.7 Sezgi kontrolleri
Her birini açmadan önce cevaplayın. İlki cebirden çıkıyor; diğer beşi bu bölümün tartışmayla değil ölçümle çözdüğü sorular.
Not1. Sıcaklığı düşürmek modeli daha doğru yapar mı?
Modeli daha belirlenimci yapar; bu aynı şey değildir. Sıcaklık softmax’tan önce logit’leri yeniden ölçekler. Dolayısıyla seçenekler arasındaki kontrastı değiştirir ama sıralamayı asla değiştirmez: \(\tau = 0{,}1\)’deki argmax token’ı ile \(\tau = 1{,}9\)’daki argmax token’ı aynıdır.
Yani greedy kod çözme bir maddede yanılıyorsa, sıcaklığı düşürmek bunu düzeltmez; yalnızca modelin daha tutarlı biçimde yanılmasını sağlar. Sıcaklığın kontrol ettiği şey varyanstır. Sıcaklığı düşürmek örneklenen çıktının doğruluğunu artırabilir — her çekiliş argmax’a daha sık denk gelir; Bölüm 15’in 1,0 sıcaklıkta gördüğü de buydu. Ama sıcaklık düştükçe örneklenen çıktının doğruluğu greedy’ninkine yaklaşır; limitte ikisi aynıdır ve argmax’ı yanlış olan bir madde yanlış kalır.
Not2. JSON ayrıştırma kusur oranınız %2. Kısıtlı kod çözme buna değer mi?
Tümüyle sonrasında ne olduğuna bağlı. Çıkarılan bilgi bir tabloya yazılacaksa %2, bir yeniden deneme demektir; üzerinde durmaya gerek yok. Araç çağrıları için %2, her ellinci istekte yanlış bir eylem ya da bir stack trace demektir; cevap, tartışmaya gerek kalmadan evettir.
Sonra bedeli küçük varsaymak yerine ölçün: buradaki ek yük 1,01 kat ile 17,5 kat arasındaydı ve en kötüsü şemanın modelin üretmek istemediği bir şeyi talep ettiği yerdeydi.
Not3. Bir gramer geçerli JSON garanti eder. Neyi garanti etmez?
İçerikle ilgili hiçbir şeyi. Bölüm 13.8’de ölçüldü: tam sayı bir answer talep eden bir şema, Fransa’nın başkenti için {"answer": 1} döndürdü — geçerli, tipli, ayrıştırılabilir, anlamsız.
Kısıtlı kod çözme ayrıştırma kusurlarını anlamsal kusurlara dönüştürür. Bu genellikle istediğiniz ödünleşimdir, çünkü yanlış bir değer doğrulanabilir, bir çökme doğrulanamaz — ama yine de bir ödünleşimdir. Görev elverdiği ölçüde alanları enum’larla sınırlayın, değerleri yapıdan ayrı doğrulayın ve modele bilmiyorum diyebileceği açık bir çıktı seçeneği verin.
Not4. Zayıf modeliniz %79 şema-geçerli. Kötü bir model mi?
Kısmen, ama sayının düşündürdüğünden az. Burada ölçüldü: iç içe bir şemada %79,3 şema geçerliliğindeki llama3.2:3b %70,7 doğruluk aldı — gramer açıkken ise %100 geçerli ve %88,0 doğru oldu.
Aradaki farkın on yedi puanı hiçbir zaman bir akıl yürütme kusuru değildi; akıl yürütme kusuru diye sayılan bir biçimlendirme kusuruydu. Küçük bir modelin görevinizi yapamayacağı sonucuna varmadan önce, noktalamayı değil görevi ölçtüğünüzden emin olun.
Not5. Model %92 emin olduğunu söylüyor. İnanmalı mısınız?
Olasılık olarak hayır. 400 maddede ölçüldü: modelin 0,90–0,95 olasılık verdiği cevapların %68,0’ı doğruydu. Beklenen kalibrasyon hatası %7,04’tü. 0,5 olasılığa en yakın kutu ise 15 maddede %33,3 doğruydu — şans düzeyini içerecek kadar geniş bir aralık; sayının kalibre bir olasılık olmadığı dışında hiçbir şeyi kanıtlayamayacak kadar da geniş.
Ama sıralama iyiydi — kendi doğruluğunu öngörmede AUC 0,8268 — ve yönlendirme için bu yeterli. Logprob’ları maddeleri sıralamak için kullanın, yüzde raporlamak için değil; sayının kendisine ihtiyacınız varsa ayrılmış bir dilimde kalibre edin.
Not6. Serbest metinli bir cevap için güven puanı istiyorsunuz. Nasıl?
Logprob’ların ortalamasını alarak değil. Bu ortalama çoğunlukla içeriğin doğru olma olasılığını değil, ifadenin ne kadar sıradan olduğunu ölçer.
Bunun yerine görevi yeniden yapılandırın. Cevabı ve onu sınıflayan tek bir kısıtlı token isteyin — bir hüküm, bir kategori, bir evet/hayır — ve o token’ın logprob’unu okuyun. Bu bölümün çekimserlik eğrisi, cevap iki token’lık bir alfabeden tek bir token olduğu için işliyor; bu özellik bulduğunuz değil, tasarladığınız bir şeydir.
18.8 Mülakat soruları
Kaynak konusunda — Bölüm 2’deki çekincenin aynısı. Bu sorular, bu kitabın kullandığı iki güvenilir açık kaynakta sıkça geçenlerdir; bunlara bu bölümün ölçümlerinin cevaplanabilir kıldığı sorular eklendi.
18.8.1 Mekanizmayı anlayıp anlamadığınızı sınayanlar
S: Sıcaklık gerçekte ne yapar?
Softmax’tan önce logit’leri yeniden ölçekler, \(p_i \propto \exp(z_i/\tau)\). Üzerine düşündüğünüzü gösteren sonucu söyleyin: sıralamayı asla değiştirmez, yalnızca kontrastı; dolayısıyla sıcaklık yanlış bir argmax’ı düzeltemez. Sonra onu top-k ve top-p’den ayırın: bunlar adayları tümüyle kaldıran sert kesimlerdir. Min-p’den de ayırın: onun kesimi en üst token’ın olasılığıyla ölçeklenir, bu yüzden dağılımın ne kadar sivri olduğuna uyum sağlar.
S: Kısıtlı kod çözme nasıl çalışır?
Şemayı tokenizer’ın sözlüğü üzerinde bir otomata derleyin. Her adımda, gramere uygun biçimde devam edemeyecek her token’ın logit’ini maskeleyin. Geçersiz çıktı düşük olasılıklı olmakla kalmaz, erişilemez hâle gelir. İyi bir cevap şöyle devam eder: sözdizimini garanti eder, başka hiçbir şeyi değil; ve gecikmeye mal olur. Bu bedel burada 1,01 kat ile 17,5 kat arasında ölçüldü; en kötü sonuç, şemanın modelin üretmek istemediği bir şeyi talep ettiği yerde çıktı.
S: Beam search neden çeviride standart, sohbette ise kullanılmıyor?
Çünkü beam search en yüksek olasılıklı diziyi arar; bu da görevin yaklaşık tek bir doğru cevabı olduğunda istediğiniz, çok cevabı olduğunda ise kesinlikle istemediğiniz şeydir: açık uçlu metinde en olası dizi genellikle sıradan ve tekrarlıdır (Holtzman vd. 2020). Bölüm 15 ikisini karıştırmanın bedelini öbür yönde, tek cevap istenen yerde örnekleme yaparak ölçtü: sohbet varsayılanı olan 1,0 sıcaklık bir çeviri modelini 30,17 BLEU’dan 14,34’e düşürdü.
18.8.2 Bir tane yayına alıp almadığınızı sınayanlar
S: Üretimde araç çağrıları yaklaşık %2 oranında başarısız oluyor. Ne yaparsınız?
Argümanları kısıtlarım — %98’in yeterli olmadığı durum budur, çünkü sonrasında bir şey çalışıyor. Sonra tipleri daraltırım: işlemler için enum’lar, tarihler için desenler; böylece bütün hata sınıfları erişilemez olur. Sonra kısıtın gerçekten uygulandığını doğrularım, çünkü format’ı yok sayan bir sunucu sessizce başarısız olur. Ve geçerli bir çağrının yine de doğru bir çağrı olmadığını açıkça söylerim: id’nin tipi doğru, değeri yanlış olabilir. Bu da kod çözücünün değil, araç tasarımının problemidir (Bölüm 24).
S: Sisteminize “bilmiyorum” dedirtmeyi nasıl sağlarsınız?
Ona bunu söyleyebileceği açık bir çıktı seçeneği verin — şemada bir null ya da açık bir çekimserlik değeri. Sonra bu seçeneği ne zaman kullanacağına karar veren bir eşik belirleyin. Cevabı tek bir token’a kısıtlayın, logprob’unu okuyun ve eşiği ayrılmış bir dilimde seçin. Burada ölçüldü: modelin en az emin olduğu %20’de çekimser kalmak, tutulan maddelerdeki doğruluğu %86,75’ten %92,50’ye çıkardı (kapsam %80); modelde hiçbir değişiklik gerekmedi, ama çekimser kalınan %20’nin nereye gittiği ve neye mal olduğu ayrıca ölçülmeli. Kapsamı doğrulukla birlikte raporlayın, yoksa sayı anlamsızdır.
S: Değerlendirmeniz, modelin %92 emin olduğunu ve vakaların %68’inde haklı çıktığını söylüyor. Sorun ne?
Modelde bir sorun yok; siz bir ayırt etme sinyalini kalibrasyon sinyali olarak okuyorsunuz. Logprob cevapları iyi sıraladı — kendi doğruluğunu öngörmede AUC 0,8268 — ama kalibrasyonu kötüydü: ECE %7,04. Sıralamayı yönlendirme için kullanın; sayının kendisine ihtiyacınız varsa ayrılmış veride kalibre edin. Gereken yöntemler Bölüm 12’de.
18.9 2026 alet çantası
Bu bölümdeki her şey aşağıdaki sürümlerle tek bir dizüstü bilgisayarda çalıştı.
| kütüphane | kullanılan sürüm | burada ne işe yarıyor |
|---|---|---|
ollama |
0.24.0 | qwen3.5:9b ve llama3.2:3b’yi sunmak ve şemayı zorlayan format parametresi |
| Python | 3.14.5 | ayrıştırmayı standart kütüphanedeki json.loads yapar; çevresindeki yirmi satır, zorunlu alanlar ve enum değerleri için yazdığımız kendi kontrollerimizdir, çünkü ayrıştırmak şemayı doğrulamak demek değildir. Çekimserlik eğrisi, standart kütüphanede olmayan numpy’ı kullanıyor |
Yukarıda kullanılmayan ama bilinmesi gereken araçlar:
| kütüphane | güncel sürüm | ne zaman kullanılır |
|---|---|---|
outlines |
1.3.3 | Bölüm 18.3’teki otomatın referans uygulaması (Willard ve Louf 2023); grameri bir sunucu bayrağının arkasında değil, kendi sürecinizin içinde çalıştırmak istediğinizde |
xgrammar |
0.2.5 | aynı fikrin verim için optimize edilmiş hâli; yukarıda ölçülen 17,5 katlık ek yük kabul edilemez olduğunda başvurulacak araç |
lm-format-enforcer |
0.11.3 | transformers ve vLLM üretim döngülerine takılan şema zorlaması |
guidance |
0.3.1 | üretimi sabit şablon metniyle iç içe geçirir; böylece model yalnızca boşlukları doldurur |
pydantic / jsonschema |
2.13.4 / 4.26.0 | gramer biçimi garanti ettikten sonra değerleri doğrulamak — Bölüm 18.3’te hâlâ atmanız gerektiği savunulan adım |
18.10 Lab: geçersiz çıktı üretemeyen bir bilgi çıkarma hattı
Hattı kurun, sonra garantinin neyi kapsayıp neyi kapsamadığını ölçün.
18.10.1 Adım 1 — şemayı prompt’tan önce yazın
Alanlar, tipler, değerler sınırlı bir listeden geldiği her yerde enum’lar ve kaynakta yok için açık bir null. Şema şartnamedir; prompt ise onu isteme biçiminizdir.
18.10.2 Adım 2 — zorlanmamış baseline’ı ölçün
Buradaki baseline (karşılaştırma tabanı), zorlamasız koşulun kendisidir. Şemayı 150 maddede, zorlama olmadan yalnızca prompt’ta isteyin. Ayrıştırma oranını, şema geçerliliğini ve doğruluğu kaydedin. Güçlü bir modelde %98 civarı bekleyin; mesele de bu: zorlamanın ne kazandırdığını bilmek için bu sayıya ihtiyacınız var.
18.10.3 Adım 3 — grameri açın ve gerçekten açık olduğunu doğrulayın
Şemayı zorlayın. Sonra kısıtın gerçekten devrede olduğunu teyit edin: modelin aksi hâlde ihlal edeceği bir şemayla tek bir istek gönderin. Bir sunucunun format’ı bir uç noktada sessizce yok sayıp diğerinde uyguladığını Bölüm 13.8 buldu; bu kontrol olmadan kusur görünmez.
18.10.4 Adım 4 — gecikme bedelini şema başına ölçün
İki kipte de süreyi ölçün. Buradaki ek yük 1,01 kat ile 17,5 kat arasındaydı ve şema karmaşıklığı arttıkça düzenli olarak artmıyordu; dolayısıyla sizin şemanızın bedeli ampirik bir sorudur. Büyükse, şemanın hangi kısmının pahalı olduğunu alanları teker teker çıkararak bulun.
18.10.5 Adım 5 — geçerli çıktının ne sıklıkla yanlış olduğunu sayın
Garanti varken bu adımı atlamak cazip gelir. Şema-geçerli çıktıları alın ve değerleri etiketlerinizle karşılaştırın. Geçerliliği ve doğruluğu iki ayrı sayı olarak raporlayın, çünkü bir hat birincide %100 ve ikincide kötü olabilir ve kayıtlarınızda yalnızca biri görünür.
18.10.6 Adım 6 — çekimserlik ekleyin
Cevap alanını tek bir token’a kısıtlayın, logprob’unu okuyun ve doğruluk–kapsam eğrisini çizin. Eşiği ayrılmış bir dilimde seçin — raporladığınız veride değil — ve hangi kapsamda yayına aldığınızı belirtin.
18.10.7 Neyi teslim edeceksiniz
Zorlanmış ve zorlanmamış koşular için geçerlilik, doğruluk ve gecikme içeren bir tablo; Adım 3’teki doğrulama; doğruluk–kapsam eğrisi; ve garantinizin hangi kusurları kapsamadığına dair bir paragraf.
18.11 Alıştırmalar
- Sıcaklık ölçeklemesinin argmax token’ı asla değiştirmediğini cebirsel olarak gösterin. Bu, greedy kod çözme hakkında ne ima ediyor?
- Etkileşimli araçta \(\tau = 1\) ve top-k \(= 12\) ayarlayın. En az dört token’ı hâlâ tutan en küçük top-p’yi bulun ve cevabınızın arkasındaki kümülatif kütle mantığını açıklayın.
- Sıcaklığı 0 yapın ve aynı prompt’u barındırılan bir API üzerinde 20 kez çalıştırın. Çıktılar birebir aynı mı? Bulduğunuzu açıklayın.
- %40 JSON kusur oranı olan bir bilgi çıkarma görevi alın. Kısıtlı kod çözme ekleyin ve yeni kusur oranını — ve yeni hata biçimlerini — raporlayın.
18.12 Daha derine
Okumadan önce: bir prompt alın, sıcaklık 0’da on kez üretin ve aynı dizgiyi aldığınızı teyit edin. Alıp almadığınız, değerlendirmenizdeki diğer her sayının nasıl raporlanması gerektiğine karar verir.
| kaynak | ne olduğu |
|---|---|
outlines |
kütüphane olarak kısıtlı üretim; kaynak kodu Bölüm 18.3’teki otomatın en net açıklamasıdır |
| How to generate text — Hugging Face | kod çözme stratejileri, çalıştırılabilir kod ve her birinin başarısız olduğu örneklerle |
| Controllable Text Generation — Lilian Weng | bu bölümün yalnızca bir kısmına değindiği alanı derinlemesine tarayan bir yazı |
vllm |
üretim ortamında model sunma, yapılandırılmış çıktı desteğiyle; gerçekte hangi ayarların kullanıcıya açıldığını görmek için örnekleme parametrelerini okuyun |
| Stanford CS336 | çıkarım ve kod çözmeyi uygulama tarafından da içeriyor |
| Let’s build GPT: from scratch — Andrej Karpathy | videonun başlarında bigram baseline’ı için yazılan generate işlevi, olabilecek en basit örnekleme döngüsüdür (softmax, ardından bir token çekmek); duraklatıp düzenleyebileceğiniz kod hâlinde. nanoGPT’deki sürümü buna sıcaklık ve top-k ekler |
| konu | kaynak |
|---|---|
| en yüksek olasılıklı metnin neden en iyi metin olmadığı | Holtzman vd. (2020) |
| dağılımla ölçeklenen bir kesim | Nguyen vd. (2024) |
| bir şemayı token maskesine derlemek | Willard ve Louf (2023) |
| genel yapılandırılmış görevler için aynı fikir | Geng vd. (2023) |
| modellerin ne bildiklerini bilip bilmedikleri | Kadavath vd. (2022) |
| adım adım maskelemenin modelin dağılımını nasıl bozduğu | Park vd. (2024) |
| format kısıtının sınıflandırmaya yardım edip akıl yürütmeye zarar vermesi | Tam vd. (2024) |
| sıcaklık ölçeklemeyle kalibrasyon | Guo vd. (2017) |
| tekrar cezasının kaynağı | Keskar vd. (2019) |
18.13 Akılda kalması gerekenler
Sıcaklık sıralamayı asla değiştirmez. Softmax’tan önce logit’leri yeniden ölçekler, dolayısıyla varyansı kontrol eder; onu düşürmek örneklenen çıktının doğruluğunu greedy’ninkine yaklaştırır, limitte ikisi aynıdır. Greedy bir maddede yanılıyorsa, daha düşük bir sıcaklık onun daha tutarlı biçimde yanılmasını sağlar.
Politikayı görevin kaç tane iyi cevabı olduğuna göre seçin. Tek cevap: greedy ya da dar bir beam. Çok cevap: örnekleyin. Bölüm 15 bunu tersine çevirmenin bedelini BLEU’nun yarısından fazlası olarak ölçtü (30,17 → 14,34).
Tekrar döngüleri tesadüf değil, yüksek olasılıklıdır; greedy’nin bu döngülere düşmesinin nedeni budur. Onları düzelten cezalar gerekli tekrarı gereksiz tekrardan ayırt etmez. Bu yüzden tekrarlanan anahtarların ve parantezlerin doğru olduğu yapılandırılmış çıktı için yanlış araçtır.
Güçlü bir modelde gramer son yüzde bir-ikiyi kazandırır.
qwen3.5:9byalnızca istendiğinde, sınanan her şema zorluğunda %98–99,3 şema-geçerliydi. Zorlama onu %100’e çıkardı ve doğruluğa dokunmadı.Zayıf bir modelde ise çalışmakla çalışmamak arasındaki farktır.
llama3.2:3biç içe bir şemada %79,3’e düştü; gramerle %100 geçerliydi ve doğruluk %70,7 → %88,0 yükseldi, çünkü bir biçimlendirme kusuru bir akıl yürütme kusuru olarak sayılıyordu.Gramerin bedeli gecikmedir ve öngörülemez — burada 1,01 kat ile 17,5 kat arası ve şema karmaşıklığı arttıkça düzenli olarak artmıyor. En kötü sonuç, şemanın modelin üretmek istemediği bir şeyi talep ettiği yerde çıktı. Kendi şemanızda ölçün.
Bir şema biçimi garanti eder, asla doğruluğu değil. Fransa’nın başkenti için
{"answer": 1}geçerli, tipli ve anlamsızdır. Kısıtlı kod çözme ayrıştırma kusurlarını anlamsal kusurlara çevirir; bu iyi bir ödünleşimdir, bir çözüm değil.Araç argümanlarını tartışmadan kısıtlayın. %98 bilgi çıkarma için yeterlidir, ama ardından bir şey çalıştırılacaksa kabul edilemez: günde bin çağrıda bu, yirmi yanlış eylem ya da stack trace demektir.
Logprob’lar iyi ayırt eder, kötü kalibre olur. Etikete göre AUC 0,9492, kendi doğruluğunu öngörmede 0,8268; ECE ise %7,04. 0,90–0,95 kutusu yalnızca %68,0 doğruydu; 0,5 olasılığa en yakın kutu ise 15 maddenin 5’inde doğruydu, üstelik ciddi bir belirsizlikle. Onlarla sıralayın; onları olasılık diye aktarmayın.
Çekimserlik, tutulan maddelerde doğruluğu artırmanın en ucuz yoludur. Modelin en az emin olduğu %20’yi dışarıda bırakmak, tutulan maddelerdeki doğruluğu %86,75’ten %92,50’ye çıkardı (kapsam %80); modelde hiçbir değişiklik gerekmedi. Diğer %20’nin maliyeti ayrıca ölçülmeli. Eşiği ayrılmış veride seçin ve kapsamı onunla birlikte raporlayın.
Kullanılabilir bir güven sinyali bulunmaz, tasarlanır. Burada işe yaradı, çünkü cevap iki token’lık bir alfabeden tek bir token’dı. Serbest metin üzerinde logprob’ların ortalamasını almak, ifadenin ne kadar sıradan olduğunu ölçer.
Modelin bilmediği bir şeyi sorduğunuzda bu bölümdeki ayarların hiçbiri yardım etmez; Bölüm 19, üretimden önce doğru belgeleri bulup bağlama koyan adıma, erişime geçiyor.