Ünite 1 / 11

LLM API Temelleri: İstek, Yanıt ve Mesaj Rolleri

Kazanimlar:

  • Bir LLM API isteğinin temel yapısını (uç nokta, model, mesajlar, max_tokens) açıklayabilir
  • system, user ve assistant rollerinin farkını ve durumsuz (stateless) konuşma geçmişini kavrar
  • Dönen yanıtın alanlarını (içerik blokları, stop_reason, usage) okuyup yorumlayabilir

Önceki modüllerde yapay zekayı bir sohbet penceresinden kullandık. Ama yapay zekayı kendi ürününüzün, otomasyonunuzun ya da iş akışınızın içine gömmek istiyorsanız, sohbet arayüzü yetmez; modele programatik olarak, yani kodla veya bir otomasyon aracıyla bağlanmanız gerekir. Bu köprünün adı API'dir (Application Programming Interface — Uygulama Programlama Arayüzü, iki yazılımın belirli kurallarla konuşmasını sağlayan sözleşme). Bu üniteyi bitirdiğinizde bir LLM (Large Language Model — Büyük Dil Modeli) API isteğinin nelerden oluştuğunu, mesaj rollerinin ne işe yaradığını ve dönen yanıtı nasıl okuyacağınızı bileceksiniz. Bu, modülün geri kalanının üzerine kurulacağı temeldir.

API Nasıl Çalışır?

API'de temel akış şudur: siz belirli bir biçimde bir istek (request) gönderirsiniz; sunucu belirli bir biçimde bir yanıt (response) döner. LLM'lerde bu genellikle tek bir adrese (uç nokta — endpoint, sunucuda isteğinizi karşılayan sabit adres) yapılan bir HTTP çağrısıdır (HTTP: web üzerinde istek-yanıt taşıyan standart protokol). Örneğin bir mesajlaşma API'sinde tüm istekler tek bir adrese gider ve gövdesinde (body) JSON (JavaScript Object Notation — anahtar/değer çiftlerinden oluşan, hem insanın hem makinenin okuyabildiği metin biçimi) taşınır.

Bir istekte en az şu üç şeyi belirtirsiniz:

  • model: Hangi modeli kullanacağınız (ör. hızlı ve ucuz bir model mi, güçlü bir model mi).
  • max_tokens: Modelin en fazla kaç token (metnin işlendiği en küçük birim, bir sonraki ünitede ayrıntılı işlenecek) üretebileceği; yani çıktı sınırı.
  • messages: Konuşmayı oluşturan mesajların listesi.

Adım Adım: Bir İstek Nasıl Kurulur?

  1. Uç noktayı ve kimlik bilgisini hazırlayın. İsteğe API anahtarınızı (kimliğinizi kanıtlayan gizli dize) bir başlıkta (header) eklersiniz. Anahtarı asla koda gömmezsiniz; 9. ünitede güvenli saklamayı işleyeceğiz.
  2. Modeli ve çıktı sınırını seçin. Basit bir görev için hafif model + küçük max_tokens; karmaşık bir görev için güçlü model + daha büyük sınır.
  3. Mesaj listesini kurun. Sistem talimatını, kullanıcı mesajını ve (varsa) geçmiş turları sıraya dizin.
  4. İsteği gönderin ve yanıtı ayrıştırın (parse). Dönen JSON içinden metin içeriğini, durma nedenini ve token kullanımını okuyun.

Mesaj Rolleri: system, user, assistant

Bir konuşma, sırayla dizilmiş mesajlardan oluşur ve her mesajın bir rolü vardır. Rol, modelin o metne nasıl davranacağını belirler.

Rol

Kim yazar

Amaç

system

Geliştirici / operatör

Tüm konuşma boyunca geçerli kalıcı talimat, kişilik ve kurallar

user

Son kullanıcı

Kullanıcının o anki sorusu veya girdisi

assistant

Model

Modelin ürettiği yanıt (ve önceki yanıtlar)

system rolü çoğu sağlayıcıda istek gövdesinde ayrı bir system alanı olarak; user ve assistant ise messages listesinde sırayla verilir. Kritik nokta: sistem talimatı üst düzey yönergedir, kullanıcı mesajı ise o an cevaplanacak istektir.

{ "model": "claude-opus-4-8", "max_tokens": 1024, "system": "Sen bir kurumsal destek asistanısın. Kısa, resmi ve doğrulanmış yanıt ver. Emin olmadığın bilgiyi uydurma.", "messages": [ { "role": "user", "content": "İade sürecimi nasıl başlatırım?" } ]}

Konuşma Durumsuzdur (Stateless)

En sık yapılan kavram hatası burada: LLM API çağrıları durumsuzdur (stateless — sunucu iki istek arasında hiçbir hafıza tutmaz). Model, bir önceki isteğinizi hatırlamaz. Çok turlu bir sohbet kuruyorsanız geçmiş turları her yeni istekte tekrar göndermeniz gerekir. Modelin "hafızası", gönderdiğiniz messages listesinden ibarettir.

{ "model": "claude-opus-4-8", "max_tokens": 512, "messages": [ { "role": "user", "content": "Merhaba, adım Deniz." }, { "role": "assistant", "content": "Merhaba Deniz, nasıl yardımcı olabilirim?" }, { "role": "user", "content": "Az önce adımı söyledim, hatırlıyor musun?" } ]}

Üçüncü mesajın doğru cevaplanabilmesi, önceki iki mesajı da göndermenize bağlıdır. Göndermezseniz model "Deniz"i bilemez ve yanlış cevaplar. Bu, doğrudan maliyeti de etkiler: konuşma uzadıkça liste büyür, her istek daha çok token tüketir.

İpucu: Uzun konuşmalarda tüm geçmişi göndermek yerine eski turları özetleyip taşımak (özet + son birkaç tur) hem maliyeti düşürür hem bağlam penceresini korur. Bunu 6. ve 11. ünitelerde derinleştireceğiz.

Yanıtı Okumak

Model bir yanıt döndüğünde düz metin değil, yapılandırılmış bir nesne alırsınız. Tipik alanlar:

{ "id": "msg_01ABC...", "model": "claude-opus-4-8", "role": "assistant", "content": [ { "type": "text", "text": "İade başlatmak için hesabınızdaki 'Siparişlerim' sayfasına gidin..." } ], "stop_reason": "end_turn", "usage": { "input_tokens": 47, "output_tokens": 88 }}

  • content: Yanıtın kendisi; içerik blokları (content blocks) listesidir. Metin bloğunun text alanı asıl cevaptır.
  • stop_reason: Modelin neden durduğu. end_turn = doğal bitiş; max_tokens = çıktı sınırına takıldı (yanıt yarım kalmış olabilir); refusal = güvenlik nedeniyle reddetti. Kodunuz her zaman önce stop_reason'a bakmalıdır.
  • usage: Girdi ve çıktı token sayıları. Maliyet ve limit takibinin temelidir.
Dikkat: stop_reason max_tokens ise yanıt tamamlanmamış demektir. Bunu "başarılı yanıt" gibi işleyip kullanıcıya yarım metin göstermek, üretimdeki en yaygın hatalardan biridir. Ya max_tokens'ı yükseltin ya da akış (streaming) kullanın.

Zayıf prompt / Güçlü prompt

Aynı görev, iki farklı sistem promptuyla:

# ZAYIFSen bir asistansın. Sorulara cevap ver.

# GÜÇLÜSen bir kurumsal destek asistanısın. Kurallar:- Yalnızca sağlanan politika belgesindeki bilgilere dayan; belgede yoksa "Bu bilgi elimde yok, ilgili birime yönlendiriyorum" de.- Yanıtları 3 cümleyi geçme, resmi ve net ol.- Kişisel veri (TCKN, kart no) isteme ve tekrar etme.- Emin olmadığında tahmin yürütme.

Güçlü sürüm; kapsamı, biçimi, güvenlik sınırını ve belirsizlikte davranışı tanımlar. Model çıktısının tutarlılığı doğrudan bu netlikten gelir.

Üç Mini Vaka

Vaka 1 — Destek botu (durumsuzluk tuzağı). Bir e-ticaret ekibi botu canlıya aldı; kullanıcı "az önceki siparişi iptal et" dediğinde bot sipariş numarasını "unutuyordu". Sebep: her isteği yalnızca son mesajla gönderiyorlardı. Çözüm: son 6 turu messages listesine eklediler. Sonuç: bağlam korundu, ama istek başına girdi 40 token'dan ~600 token'a çıktı — maliyet dersini 2. ünitede işleyeceğiz.

Vaka 2 — Yarım kalan sözleşme özeti. Bir hukuk ekibi 10 sayfalık sözleşmeleri özetletiyordu; max_tokens: 300 düşük kaldı, özetler cümlenin ortasında kesiliyordu. stop_reason her seferinde max_tokens idi ama kimse bakmıyordu. max_tokens'ı 1500'e çıkarıp stop_reason kontrolü eklediler; kesik özet oranı %18'den %0'a düştü.

Vaka 3 — Rolleri karıştırmak. Bir pazarlama ekibi tüm talimatı user mesajının içine yazıyor, system'i boş bırakıyordu. Kullanıcı girdisi talimatla karışınca model bazen kullanıcının "önceki kuralları unut" demesine uyuyordu. Kalıcı kuralları system'e taşıdılar; kullanıcı girdisiyle talimatı ayırınca kural ihlali belirgin biçimde azaldı.

Sık yapılan hatalar

  • Geçmişi göndermeyi unutmak: Model "hatırlamıyor" sanılır; oysa durumsuzdur. Bağlamı siz taşırsınız.
  • `stop_reason`'a bakmamak: max_tokens ile kesilen yanıt tam sanılır.
  • Talimatı `user` içine gömmek: Kalıcı kurallar system'e; anlık girdi user'a gider. Karıştırmak güvenlik açığı doğurur.
  • `content`'i düz string sanmak: Yanıt bir blok listesidir; ilk metin bloğunun text alanını okuyun, kör indeksle content[0] almadan önce tipini doğrulayın.
  • Anahtarı koda gömmek: Ortam değişkeni kullanın (9. ünite).

Daha Derine: İçerik Blokları ve Çok Parçalı Yanıtlar

Yanıttaki content alanının neden bir liste olduğunu anlamak, ileride karşılaşacağınız gelişmiş özellikler için temeldir. Model bazen tek bir metin bloğu değil, birkaç blok döndürür: bir düşünme bloğu, ardından bir metin bloğu; ya da bir metin bloğu, ardından bir araç çağrısı (tool use) bloğu. Bu yüzden content[0]'ı kör bir refleksle "cevap" saymak kırılgandır. Doğru yaklaşım listeyi dolaşıp tipine göre ayıklamaktır: type alanı text olan blokların text içeriğini toplarsınız, başka tipleri (düşünme, araç) ayrı ele alırsınız.

Bu ayrım pratikte şuna yarar: modelin akıl yürütmesini (varsa) kullanıcıya göstermeden loglayabilir, araç çağrılarını ayrı bir mantığa yönlendirebilir ve yalnızca gerçek cevabı ekrana basabilirsiniz. Modül ilerledikçe (özellikle 4. ve 11. ünitede) bu blok yapısının, çıktıyı doğrulamak ve yönlendirmek için ne kadar işe yaradığını göreceksiniz.

Bir başka pratik nokta: aynı modele farklı sağlayıcı platformlarından (doğrudan API, bir bulut sağlayıcısı üzerinden) erişebilirsiniz. Uç nokta adresi ve kimlik doğrulama biçimi değişse de mesaj rolleri, durumsuzluk ve yanıt yapısı gibi temel kavramlar aynı kalır. Bu yüzden bu ünitedeki temeller, hangi platformu kullanırsanız kullanın geçerlidir.

Özetle

Bir LLM API isteği model, çıktı sınırı ve mesaj listesinden oluşur; roller (system, user, assistant) modelin davranışını belirler. Çağrılar durumsuzdur: bağlamı her istekte siz taşırsınız. Yanıt yapılandırılmış bir nesnedir; content, stop_reason ve usage alanlarını okuyup yorumlamak üretimdeki dayanıklılığın temelidir.

Uygulama görevi

Kendi mesleğinizden bir görev seçin (ör. gelen e-postayı sınıflandırma, kısa özet çıkarma). Bir kağıda: (1) system promptunu 4-5 kurallı yazın, (2) örnek bir user mesajı ve varsa 2 turluk geçmiş kurun, (3) max_tokens için makul bir değer belirleyin ve gerekçesini yazın, (4) dönen yanıtta hangi stop_reason değerlerini nasıl ele alacağınızı listeleyin.

Kontrol listesi

  • [ ] Bir isteğin üç zorunlu parçasını (model, max_tokens, messages) sayabiliyorum.
  • [ ] system, user, assistant rollerinin farkını açıklayabiliyorum.
  • [ ] Çağrıların durumsuz olduğunu ve geçmişi taşımam gerektiğini biliyorum.
  • [ ] content, stop_reason ve usage alanlarını okuyup yorumlayabiliyorum.
  • [ ] max_tokens ile kesilen yanıtı fark edip ele alabiliyorum.