Mert Özen Her Satırda Daha İleri
Yapay Zeka LLM Temelleri — #01

LLM Nedir? Geliştirici Gözüyle Büyük Dil Modelleri

Mert Özen 6 Kas 2026 9 dk 3 görüntülenme
LLM Nedir? Geliştirici Gözüyle Büyük Dil Modelleri

Büyük dil modeli bir sonraki token'ı tahmin eden bir fonksiyondur. Bu döngüyü yerel gemma3:4b ile token token kuruyor; eğitim ile inference, base ile instruct model, open-weight ile kapalı model ve yerel ile bulut arasındaki farkları görüyor, modelin tarih, hesap ve sipariş sorularında nerede yanıldığını gerçek çıktılarla inceliyoruz.

Sürüm notu: Bu yazıdaki örnekler Ollama 0.34 ile yerel modelde (gemma3:4b) denenmiştir; Node 22 kullanılmıştır.

Önce Tahmin Et

Bir büyük dil modeline (LLM) "Bugün günlerden ne?" diye sorduğunu düşün. Model sana doğru tarihi mi söyler, "bilmiyorum" mu der, yoksa kendinden emin bir tavırla yanlış bir tarih mi uydurur? Peki aynı modele beş haneli iki sayıyı çarptırırsan doğru sonucu verir mi?

Bu soruların cevabını yazının ortasında gerçek bir modelle göreceğiz. Cevap, LLM'in ne olduğunu anlamanın da en kısa yolu, çünkü modelin "bildiği" şeyle "ürettiği" şey arasındaki farkı açıkça ortaya koyuyor.

Bir Sonraki Token'ı Tahmin Eden Program

Bir LLM'i görünüşüyle değil de çalışma biçimiyle tarif edersek tek cümle yeter: verilen metnin devamında hangi token'ın geleceğini tahmin eden bir fonksiyon. Token, modelin okuyup yazdığı birimdir; bazen bir kelime, bazen bir kelimenin parçası, bazen tek bir rakam ya da noktalama işareti. Token'ları üçüncü yazıda ayrıntılı ölçeceğiz.

Model her adımda sözlüğündeki bütün token'lar için bir olasılık hesaplar, birini seçer, metne ekler ve aynı işi baştan yapar. Telefonundaki klavyenin kelime önerisini düşün; LLM bunun milyarlarca parametreyle eğitilmiş ve çok daha uzun bir bağlamı okuyabilen hâlidir. Bu döngüyü kendimiz kurup izleyebiliriz. Aşağıdaki TypeScript kodu modele her seferinde yalnızca bir token ürettiriyor, sonucu metne ekleyip tekrar gönderiyor:

import ollama from "ollama";

let text = "The novel Nineteen Eighty-Four was written by";

for (let step = 1; step <= 8; step++) {
  // raw: true sohbet template'ini atlar, num_predict: 1 yalnızca tek token ister
  const res = await ollama.generate({
    model: "gemma3:4b",
    prompt: text,
    raw: true,
    options: { temperature: 0, seed: 42, num_predict: 1 },
  });
  text += res.response;
  console.log(`${step}: ${JSON.stringify(res.response)}`);
}

console.log(text);

Kodu nasıl kurup çalıştıracağını bir sonraki yazıda adım adım göstereceğim; şimdilik çıktıya bak:

1: " George"
2: " Orwell"
3: " in"
4: " "
5: "1"
6: "9"
7: "4"
8: "9"
The novel Nineteen Eighty-Four was written by George Orwell in 1949

Model "George Orwell" diyeceğini önceden bilmiyordu; her turda yalnızca bir sonraki parçayı seçti. Yılın dört ayrı token olarak gelmesi de tesadüf değil: Gemma 3'ün tokenizer'ı rakamları tek tek böler. temperature: 0 ile her adımda en olası token'ın seçilmesini, seed ile de sonucun tekrarlanabilir olmasını istedik; bu ayarların ayrıntısı altıncı yazının konusu.

Burada dikkat etmen gereken şey şu: ortada bir veritabanı sorgusu, "Orwell" kaydını bulan bir arama yok. Model eğitim sırasında okuduğu metinlerde "Nineteen Eighty-Four" ile "George Orwell"ın yan yana geldiğini görmüş ve bu ilişki ağırlıklarının içine dağılmış durumda. Doğru cevap da yanlış cevap da aynı mekanizmadan çıkar.

Eğitim ve Inference

Bir LLM'in hayatı iki aşamadan oluşur. Eğitim (training), modelin devasa bir metin yığınını okuyup bir sonraki token'ı tahmin etmeyi öğrendiği aşamadır; büyük modellerde haftalar sürer ve binlerce GPU ister. Sonunda elimizde ağırlıklar (weights) kalır: modelin bütün "bilgisini" taşıyan milyarlarca sayı. Inference ise eğitilmiş modelin kullanılmasıdır. Senin bir prompt gönderip cevap aldığın her istek bir inference'tır.

Geliştirici olarak neredeyse her zaman inference tarafındasın. Ağırlıklar bir kez eğitilir ve sonra dondurulur. Model sen onunla konuştukça öğrenmez, dün söylediğin bir şeyi bugün hatırlamaz (bunu dördüncü yazıda göreceğiz) ve eğitim verisinin bittiği tarihten sonra olan hiçbir şeyi bilmez. Gemma 3'ün model kartında bu tarih Ağustos 2024 olarak geçiyor.

Modele yeni bir bilgi lazımsa onu yeniden eğitmek yerine o bilgiyi prompt'un içinde verirsin; RAG dediğimiz yaklaşım tam olarak bu ve on dördüncü yazıda ona geleceğiz. Ağırlıkları kendi verinle biraz değiştirmek de mümkün, buna fine-tuning (ince ayar) denir. Ama bu seride kod yazarak çözebileceğin işlere odaklanıyoruz.

Base Model ve Instruct Model

Yalnızca metni devam ettirmeyi öğrenmiş modele base model denir. Base model'e soru sorarsan cevap vermek zorunda hissetmez, metni "mantıklı" bir şekilde sürdürür. Soruyu bir sınav kâğıdındaki sorulardan biri sanıp altına yenilerini bile ekleyebilir. Sohbet eden asistanlar ise bunun üstüne talimat izlemek için ayrıca eğitilmiş instruct (ya da chat) modelleridir. Ollama'daki gemma3:4b instruct sürümdür.

Instruct model sohbeti belirli bir biçimde görmeyi bekler: kimin konuştuğunu ve sıranın kimde olduğunu gösteren özel token'larla. Bu biçimi modelin chat template'i belirler ve Ollama mesajlarını modele göndermeden önce bu template'e yerleştirir. raw: true ile template'i atlayıp modele çıplak metin verirsek instruct model bile eski alışkanlığına döner ve metni sürdürür:

$ curl -s http://localhost:11434/api/generate -d '{
  "model": "gemma3:4b",
  "prompt": "The capital of Turkey is",
  "raw": true,
  "stream": false,
  "options": { "temperature": 0, "seed": 42, "num_predict": 40 }
}' | jq '{ response, eval_count, done_reason }'
{
  "response": " Ankara.\n*   **Istanbul** is the largest city in Turkey.\n*   **Izmir** is the second largest city in Turkey.\n\n**Important Turkish Cities:**\n\n*   **",
  "eval_count": 40,
  "done_reason": "length"
}

Model "Ankara." dedikten sonra durmadı; metni bir listeye çevirdi ve 40 token'lık sınıra (num_predict) çarpınca kesildi. done_reason alanındaki length tam olarak bunu söylüyor. Üstelik listenin ikinci satırı yanlış: İzmir, Türkiye'nin ikinci değil üçüncü büyük şehri. Model akıcı ve kendinden emin cümleler kuruyor, ama akıcılık doğruluk demek değil. Bu duruma halüsinasyon denir ve on beşinci yazının konusu.

Open-Weight ve Kapalı Modeller, Yerel ve Bulut

Bazı modellerin ağırlıkları indirilebilir; bunlara open-weight (açık ağırlıklı) model denir. Gemma, Llama, Qwen ve Mistral bu gruptadır, ağırlıkları indirip kendi bilgisayarında ya da sunucunda çalıştırırsın. Öbür tarafta OpenAI'ın GPT modelleri, Anthropic'in Claude'u ve Google'ın Gemini'si gibi kapalı modeller var; onlara yalnızca sağlayıcının API'si üzerinden ulaşırsın.

Open-weight ile açık kaynak aynı şey değil. Ağırlıkların indirilebilmesi eğitim verisinin ya da eğitim kodunun açık olduğu anlamına gelmez, lisans da her zaman serbest değildir. Bunu doğrudan Ollama'ya sorarak görebilirsin:

$ ollama show gemma3:4b
  Model
    architecture        gemma3
    parameters          4.3B
    context length      131072
    embedding length    2560
    quantization        Q4_K_M

  Capabilities
    completion
    vision

  Parameters
    stop           "<end_of_turn>"
    temperature    1
    top_k          64
    top_p          0.95

  License
    Gemma Terms of Use
    Last modified: February 21, 2024
    ...

4,3 milyar parametre, 131072 token'lık context length, Q4_K_M quantization ve "Gemma Terms of Use" lisansı. Bu lisans OSI onaylı bir açık kaynak lisansı değil, Google'ın kendi kullanım şartları. Q4_K_M, ağırlıkların büyük kısmının yaklaşık 4,5 bit'le saklandığı bir quantization biçimi; model dosyası bu sayede 3,3 GB'a iniyor. Context length'e dördüncü, quantization'a on altıncı yazıda döneceğiz. Capabilities kısmına da dikkat: completion ve vision var, tools yok. Yani bu model tool calling yapamıyor; o yazılarda qwen3:4b kullanacağız.

Yerel ile bulut arasındaki seçim de buradan çıkıyor. Yerel modelde veri bilgisayarından çıkmaz, token başına ücret ödemezsin, internet olmadan da çalışırsın; karşılığında donanımınla sınırlısın ve küçük modeller büyüklerin kalitesine yetişemez. Bulut modelleri çok daha yeteneklidir ve çok daha uzun bağlam alır, ama her token'ın bir fiyatı vardır ve veri sağlayıcıya gider. Bu seride örnekleri yerelde çalıştırıyoruz, çünkü kavramlar aynı ve her şeyi kendi makinende ücretsiz deneyebilirsin. Bulut sağlayıcılarını ise dokümanlarına dayanarak anlatacağım.

LLM'in Yapamadıkları

Açılıştaki sorulara dönelim. Aynı modele üç soru soruyoruz:

import ollama from "ollama";

const questions = [
  "What is today's date? Answer in one sentence.",
  "What is the status of order #1042 at Bookstore? Answer in one sentence.",
  "What is 48271 * 9137? Answer with the number only.",
];

for (const question of questions) {
  const res = await ollama.chat({
    model: "gemma3:4b",
    messages: [{ role: "user", content: question }],
    options: { temperature: 0, seed: 42 },
  });
  console.log(`Q: ${question}`);
  console.log(`A: ${res.message.content.trim()}\n`);
}
Q: What is today's date? Answer in one sentence.
A: Today is November 3, 2023.

Q: What is the status of order #1042 at Bookstore? Answer in one sentence.
A: Please provide me with the status of order #1042 at Bookstore – I need more information to answer your question!

Q: What is 48271 * 9137? Answer with the number only.
A: 442927997

Üç cevap, üç ayrı ders. Tarih sorusunda model bir tarih uydurdu: bu deneme 6 Kasım 2026'da yapıldı, model ise 3 Kasım 2023 dedi. Modelin saati yok; bugünün tarihini ancak sen prompt'a koyarsan bilir. Sipariş sorusunda doğru davrandı ve bilgi istedi. Ama bu bir garanti değil, başka bir soruda aynı model pekâlâ bir kargo durumu uydurabilir. Gerçek sipariş verisine ulaşması için ona bir araç vermemiz gerekiyor; bunu tool calling yazılarında yapacağız. Çarpma sorusunda cevap 442927997 geldi, doğrusu 441052127. Model hesap yapmıyor, hesap sonucuna benzeyen token'lar üretiyor.

Buradan çıkan kural basit: LLM bir veritabanı, bir saat ya da bir hesap makinesi değil. Güncel bilgi, kesin hesap ve senin sistemine ait veri için LLM'in yanına normal kod koyarsın. LLM'in güçlü olduğu yer dil: özet çıkarmak, sınıflandırmak, metni bir biçimden ötekine çevirmek, serbest metinden yapı çıkarmak, kullanıcının ne istediğini anlamak.

Bu Seri Nasıl İlerleyecek?

İlk blok, yani 1–17. yazılar, kemik yapı. Her yazıda bir kavramı alıp yerel modelde gerçekten çalışan C# ve TypeScript örnekleriyle gösteriyorum: ilk istek ve cevabın içindeki alanlar, token, context window, mesaj rolleri, sampling, streaming, prompt yazmak, reasoning, structured output, tool calling, embedding, RAG, halüsinasyon, maliyet ve model seçimi, sağlayıcıdan bağımsız kod. İkinci blok, 18–20. yazılar, evrim: Transformer'dan ChatGPT'ye uzanan yol, 2023'ten bugüne modeller ve LLM API'lerinin nasıl değiştiği.

Ortam şöyle: Ollama 0.34, varsayılan model olarak gemma3:4b, tool calling ve thinking için qwen3:4b, embedding için nomic-embed-text, boyut karşılaştırması için gemma3:12b. C# tarafında .NET 10 ve Microsoft.Extensions.AI, TypeScript tarafında Node 22 ve ollama paketi var. Örnekler küçük bir Bookstore asistanı etrafında dönüyor: kitap önerisi, sipariş durumu sorgulama, yorumların özetini çıkarma. Kod ve veriler İngilizce; Türkçenin token maliyeti gibi konusu bizzat Türkçe olan örnekler bunun istisnası. Yazılardaki her çıktı gerçek bir çalıştırmadan kopyalandı, ama senin makinende sayılar ve süreler biraz farklı çıkabilir.

.NET Core Web API serisini okuduysan DI ve minimal API tarafı tanıdık gelecek; on yedinci yazıda modeli bir Web API'ye bağlayacağız. Web Güvenliği serisindeki OWASP yazıları da prompt injection konusunda işimize yarayacak.

Sık Düşülen Tuzaklar

İlk tuzak, LLM'i bilgi kaynağı sanmak. Model bir şeyi bildiği için değil, o cevap eğitim verisine göre olası göründüğü için söyler. Akıcı ve emin bir cümle doğru olduğu anlamına gelmez; İzmir örneğinde gördüğün gibi yanlış bilgi de aynı tonla gelir.

İkincisi, modelin seninle konuşurken öğrendiğini sanmak. Ağırlıklar inference sırasında değişmez. Bir sohbetin içinde model önceki mesajları hatırlıyormuş gibi görünür, ama bunun sebebi her istekte geçmişin yeniden gönderilmesidir. Uygulaman yeniden başladığında model hiçbir şey hatırlamaz.

Üçüncüsü, open-weight'i açık kaynak sanıp lisansı okumamak. Ticari bir projede kullanacağın modelin lisansını ollama show çıktısında ya da model kartında mutlaka kontrol et.

Dördüncüsü, kodla çözülecek işi LLM'e vermek. Tarih, para hesabı, stok sayısı gibi kesinlik isteyen işleri normal kodla yap, LLM'e dil işini bırak. Bir C# method'u her çağrıda aynı sonucu verir; bir LLM'den bunu bekleyemezsin.

Küçük Bir Deneme

★☆☆ next-token.ts içindeki cümleyi değiştir, örneğin "The author of The Lord of the Rings is" ile başla ve modelin token token nereye gittiğini izle. Döngüyü 8 yerine 20 adıma çıkardığında modelin ne zaman konudan saptığına bak.

★★☆ limits.ts dosyasına kendi sorularını ekle: dünkü bir haber, küçük bir kasabanın nüfusu, iki tarih arasındaki gün sayısı. Modelin hangilerinde uydurduğunu, hangilerinde bilgi istediğini not et ve cevapları gerçek bir kaynakla karşılaştır.

★★★ Yukarıdaki curl isteğini bir kez raw: true ile, bir kez de bu alanı silerek gönder ve iki cevabı karşılaştır. Ardından ollama show gemma3:4b --template komutuyla Ollama'nın prompt'unu hangi template'e yerleştirdiğini incele.

Bir sonraki yazıda Ollama'yı daha yakından tanıyacağız: ollama list ile modelleri görecek, /api/chat endpoint'ine curl ile istek atacak, ardından aynı isteği C#'ta Microsoft.Extensions.AI ile ve TypeScript'te ollama paketiyle yapıp cevabın içindeki token sayılarını ve süreleri tek tek okuyacağız.