İçeriğe geç
XDD.baby Yazılım Öğrenme
Sözlük Hata rehberi 0/56

Blok 7 · Ders 47

Büyük dil modelleri ve ilk API isteğin

LLM nedir, nasıl çalışır (token, bağlam, sıcaklık), sınırları neler; Claude API'ye ilk isteği gönderiyor ve maliyeti hesaplıyorsun.

Bu dersin sonunda

  • Bir dil modelinin metni parça parça tahmin ederek ürettiğini kendi yazdığın oyuncak bir modelle gösterebilirsin
  • Token, bağlam penceresi ve sıcaklığın ne olduğunu, cevabı ve faturayı nasıl etkilediğini anlatabilirsin
  • Halüsinasyonun neden olduğunu açıklayabilir, modelin cevabına ne zaman güvenmemen gerektiğini ayırt edebilirsin
  • Claude Console'dan API anahtarı alıp .env'de saklayabilir, tarayıcıya ve GitHub'a sızmasını önleyebilirsin
  • TypeScript SDK ile sistem talimatlı bir mesaj gönderip cevabı akış olarak ekrana yazdırabilirsin
  • usage bilgisinden bir isteğin maliyetini hesaplayıp işe uygun modeli seçebilirsin
Bu sayfada
  1. Dil modeli ne yapar? Sonraki parçayı tahmin eder
  2. Token: modelin gördüğü parçalar
  3. Bağlam penceresi: modelin görebildiği alan
  4. Sıcaklık: ne kadar zar atılsın?
  5. Halüsinasyon ve modelin sınırları
  6. API anahtarı almak ve saklamak
  7. SDK ile ilk mesaj
  8. Sistem talimatı: maçtan önceki brifing
  9. Cevabı akış olarak almak
  10. Hatalar ve yeniden deneme
  11. Maliyet ve model seçimi
  12. Görevler
  13. Kendini sına
  14. Kayıt noktası

Bu dersle yedinci bloğa, yapay zekâya giriyorsun. Şimdiye kadar yazdığın her programın kuralını sen koydun. Bu blokta kuralını senin yazmadığın bir programla çalışacaksın: bir büyük dil modeli. Ona metin göndereceksin, o da sana metin üretecek.

Önce bu modellerin içeride ne yaptığını kendi yazacağın oyuncak bir modelle göreceksin. Sonra Anthropic'in Claude modeline TypeScript'ten ilk isteğini atacak, cevabı akış olarak alacak ve faturanın nasıl hesaplandığını öğreneceksin.

Dil modeli ne yapar? Sonraki parçayı tahmin eder

Claude ya da ChatGPT ile konuştuysan şunu merak etmişsindir: bu program cevabı bir veritabanından mı buluyor, yoksa insan gibi mi düşünüyor? İkisi de değil. Bir dil modelinin yaptığı iş şaşırtıcı derecede tek tip: metnin devamında hangi parçanın gelmesinin en olası olduğunu tahmin etmek.

Telefonunda "Maça" yazınca klavye "geliyorum", "girdim" gibi öneriler çıkarır, çünkü hangi sözcüğün hangisini sık izlediğini öğrenmiştir. Büyük dil modeli bu fikrin dev bir hâlidir: kitaplar, siteler ve kodlar gibi çok büyük miktarda metinle eğitilmiş, bir parçadan sonra ne geleceğini çok iyi tahmin eden bir program.

Model tek bir parça seçer, onu metnin sonuna ekler, sonra uzamış metne bakıp bir sonrakini tahmin eder. Uzun bir cevap, bu döngünün yüzlerce kez dönmesiyle oluşur. Claude'un cevabının ekrana parça parça akması da bu yüzden: model gerçekten de parça parça üretiyor.

1. Şimdiye kadarki metin Ahri Q yeteneğini ? 2. Her aday parçaya bir olasılık verir atar %60 kullanır %25 geliştirir %10 unutur %1 3. Birini seç ve metnin sonuna ekle Ahri Q yeteneğini atar uzayan metinle başa dön
Şekil 47.1 Dil modelinin tek işi: sonraki parçayı tahmin et, ekle, başa dön. Olasılıklar örnektir.

Oyuncak bir dil modeli

Bu fikri kendi elinle kurmak, onu okumaktan çok daha iyi öğretir. Bu derste bütün dosyalar C:\kod\yapay-zeka klasöründe. Klasörü oluştur (mkdir C:\kod\yapay-zeka), VS Code'da File → Open Folder ile aç ve oyuncak-model.ts adında bir dosya oluştur. Modelin "eğitim verisi" dört cümle olacak:

oyuncak-model.ts
const metinler = [    "Garen Demacia için savaşır",    "Lux Demacia için büyü yapar",    "Ahri Ionia için büyü yapar",    "Yasuo Ionia için kılıç sallar"] // Eğitim: her sözcükten sonra hangi sözcüğün kaç kez geldiğini sayconst sayim: Record<string, Record<string, number>> = {}for (const metin of metinler) {    const sozcukler = metin.split(" ")    for (let i = 0; i < sozcukler.length - 1; i++) {        const simdiki = sozcukler[i]        const sonraki = sozcukler[i + 1]        if (!sayim[simdiki]) {            sayim[simdiki] = {}        }        sayim[simdiki][sonraki] = (sayim[simdiki][sonraki] ?? 0) + 1    }} console.log(sayim["için"])console.log(sayim["Demacia"])
Çıktı
{ 'savaşır': 1, 'büyü': 2, 'kılıç': 1 }{ 'için': 2 }

Record<string, number>, anahtarları metin, değerleri sayı olan bir obje tipidir. sayim iç içe bir obje: her sözcüğün altında, ondan sonra gelen sözcüklerin kaç kez geldiği duruyor. Çıktıyı oku: "için"den sonra dört kez bir şey gelmiş, ikisinde "büyü", birer kez de "savaşır" ve "kılıç". Bu tablo, oyuncak modelin bütün "bilgisi". (Türkçe harfli anahtarları Node tırnak içinde yazar; bu yalnızca yazım biçimi.)

Şimdi bu tabloyla metin üretelim. Son iki console.log satırını sil, yerine şunu yaz:

oyuncak-model.ts
// Adayların içinden en sık geleni seçfunction enOlasi(adaylar: Record<string, number>): string {    let secilen = ""    let enCok = 0    for (const [sozcuk, kac] of Object.entries(adaylar)) {        if (kac > enCok) {            secilen = sozcuk            enCok = kac        }    }    return secilen} // İlk sözcükten başla, devamı kalmayana dek bir sonrakini eklefunction uret(ilkSozcuk: string): string {    const sozcukler = [ilkSozcuk]    let son = ilkSozcuk    while (sayim[son]) {        son = enOlasi(sayim[son])        sozcukler.push(son)    }    return sozcukler.join(" ")} console.log(uret("Lux"))console.log(uret("Ahri"))console.log(uret("Garen"))console.log(uret("Yasuo"))
Çıktı
Lux Demacia için büyü yaparAhri Ionia için büyü yaparGaren Demacia için büyü yaparYasuo Ionia için büyü yapar

uret fonksiyonu, Şekil 47.1'deki döngünün ta kendisi: son sözcüğe bak, en sık gelen devamı seç, ekle, tekrarla. İlk iki cümle doğru.

Son ikisine dikkatle bak: Garen büyü yapmaz, kılıcıyla savaşır; Yasuo da büyücü değil. Model bu iki cümleyi hiç görmedi; "için"den sonra en sık "büyü" geldiği için her şampiyona büyü yaptırdı. Cümleler akıcı, dilbilgisi kusursuz ve yanlış. Birazdan bu durumun adını koyacağız.

Gerçek bir dil modeli bundan çok daha güçlüdür. Sözcük yerine daha küçük parçalarla çalışır, yalnız son sözcüğe değil önceki metnin tamamına bakar ve tahmini bir sayım tablosundan değil, eğitimde ayarlanmış milyarlarca sayıdan oluşan bir sinir ağından alır. Ama temel döngü aynı: tahmin et, ekle, tekrarla.

Token: modelin gördüğü parçalar

Model ne harfleri ne de sözcükleri doğrudan görür. Metin önce token denen parçalara bölünür. Bir token bazen bütün bir sözcük, bazen sözcüğün bir kısmı, bazen bir noktalama işaretidir. Model okurken de yazarken de token token ilerler; oyuncak modelinin sözcük sözcük ilerlemesi gibi.

Türkçe Sih irdar Vad isi 'ne hoş geld in 8 parça İngilizce Welcome to Sum moner 's Rift 6 parça Temsilî bölme: gerçek sınırları her modelin kendi kuralları belirler. Ekli Türkçe sözcükler çoğu zaman birden çok parçaya ayrılır. Bir istekte kaç token harcadığını cevaptaki usage alanı söyler.
Şekil 47.2 Model metni harf harf ya da sözcük sözcük değil, token token görür.

Neden umursamalısın? Çünkü bu derste göreceğin üç şey token ile ölçülür:

  • Fiyat: Claude'a gönderdiğin ve ondan aldığın her token ücretlendirilir.
  • Sınır: Modelin bir seferde görebileceği metin token sayısıyla sınırlıdır (sıradaki bölüm).
  • Süre: Cevap token token üretildiği için uzun cevap daha uzun sürer.

Bir metnin kaç token tuttuğunu gözle bilemezsin. Sayı metnin içeriğine ve modelin bölme kurallarına göre değişir: belgelere göre aynı metin, Claude'un yeni modellerinde eski modellere göre yaklaşık yüzde 30 daha fazla token tutuyor. Bir fikir vermesi için belgedeki bir örnek: "You are a scientist" sistem talimatı ile "Hello, Claude" mesajı, Claude Opus 5.5'te toplam 14 girdi token'ı sayılıyor. Kesin sayıyı iki yerden öğrenirsin: her cevabın usage alanından ve isteği göndermeden önce saymaya yarayan ücretsiz countTokens uç noktasından.

Bağlam penceresi: modelin görebildiği alan

Model bir cevap üretirken neye bakabilir? Yalnız o istekte gönderdiğin şeylere: sistem talimatı, mesajlar ve o an ürettiği cevabın kendisi. Bunların toplamının sığması gereken alana bağlam penceresi denir. Claude Opus 5.5, Sonnet 5.5 ve Haiku 5.5'te bu pencere 1 milyon token; tek bir cevap en çok 128 bin token olabilir.

Bunun iki önemli sonucu var:

  1. Model seni hatırlamaz. Her istek ayrıdır. İkinci isteğe birincinin metnini koymazsan model onu hiç görmemiş olur. Claude.ai gibi sohbet uygulamaları her mesajda önceki konuşmayı yeniden gönderir; kendi uygulamanda bu işi senin kodun yapacak (Ders 48).
  2. Büyük pencere "her şeyi koy" demek değil. Belgeler, bağlamdaki token sayısı arttıkça modelin doğruluğunun ve bir şeyi hatırlama başarısının düştüğünü söylüyor. Gerekeni koy, gereksizi koyma.
Bağlam penceresi Opus 5.5'te 1 milyon token Sistem talimatı Mesaj geçmişi Yeni soru Cevap + düşünme Önceki istekler gönderilmezse model görmez Hepsi aynı sınıra sığmalı: sistem + mesajlar + cevap Girdi sığmazsa: istek reddedilir (400, prompt is too long) Cevap sınıra dayanırsa: kesilir (model_context_window_exceeded)
Şekil 47.3 Model yalnız o istekte gönderilenleri görür.

Şekildeki iki kural pencere taşınca ne olduğunu söylüyor: girdi sığmazsa istek 400 ile reddedilir, cevap sınıra dayanırsa yarıda kesilir. Bu derste o sınıra yaklaşmayacaksın; bütün bir kitabı modele vermeye kalktığında karşına çıkar.

Sıcaklık: ne kadar zar atılsın?

Oyuncak modelin her çalıştırmada aynı cümleleri kurdu, çünkü her adımda en sık geleni seçti. Gerçek modeller her adımda adayların olasılıklarını hesaplar ve bu listeden bir seçim yapar. Seçimin ne kadar maceracı olacağını belirleyen ayara sıcaklık denir.

Bunu oyuncak modelinde dene. Dosyanın sonuna, olasılığı kadar şans veren ikinci bir seçici ekle. Fikir bir torba: her sözcük için, kaç kez geldiyse o kadar bilet at; sonra torbadan rastgele bir bilet çek. "için"den sonra "büyü"nün iki bileti, "savaşır" ile "kılıç"ın birer bileti olur.

oyuncak-model.ts
// Torbaya her sözcükten, kaç kez geldiyse o kadar bilet at; rastgele birini çekfunction rastgeleSec(adaylar: Record<string, number>): string {    const torba: string[] = []    for (const [sozcuk, kac] of Object.entries(adaylar)) {        for (let i = 0; i < kac; i++) {            torba.push(sozcuk)        }    }    return torba[Math.floor(Math.random() * torba.length)]} function uretZarla(ilkSozcuk: string): string {    const sozcukler = [ilkSozcuk]    let son = ilkSozcuk    while (sayim[son]) {        son = rastgeleSec(sayim[son])        sozcukler.push(son)    }    return sozcukler.join(" ")} console.log("Zarla üretilenler:")console.log(uretZarla("Garen"))console.log(uretZarla("Garen"))console.log(uretZarla("Garen"))
Çıktıörnek, sende farklı çıkabilir
Lux Demacia için büyü yaparAhri Ionia için büyü yaparGaren Demacia için büyü yaparYasuo Ionia için büyü yaparZarla üretilenler:Garen Demacia için büyü yaparGaren Demacia için savaşırGaren Demacia için kılıç sallar

uretZarla, uret'in neredeyse aynısı; tek fark vurgulu satırda: enOlasi yerine rastgeleSec. Programı birkaç kez çalıştır, son üç satır çoğu zaman değişir. Bazen doğru cümleyi (savaşır), bazen yanlışlarını kurar.

enOlasi sıcaklığı sıfıra çekilmiş bir model gibidir: her seferinde en sık geleni seçer. rastgeleSec ise sayımın verdiği olasılıkları olduğu gibi kullanır: "büyü" dört biletin ikisini tuttuğu için yüzde 50, "savaşır" ve "kılıç" yüzde 25 şansla gelir. Sıcaklığın 1 olduğu durum budur.

Sıcaklık 1'in altına indikçe sık gelenin şansı büyür, üstüne çıktıkça şanslar birbirine yaklaşır. Genel kural:

  • Düşük sıcaklık: model neredeyse her zaman en olası parçayı seçer. Cevaplar tutarlıdır ama tekrarcıdır.
  • Yüksek sıcaklık: daha az olası parçalara da şans verilir. Cevaplar çeşitlenir ama konudan sapma ve saçmalama riski artar.
Düşük sıcaklık Sıcaklık 1 Yüksek sıcaklık hep en sık olan torbadan çekiliş şanslar yaklaşır %96 %2 %2 %50 %25 %25 %40 %30 %30 büyü savaşır kılıç büyü savaşır kılıç büyü savaşır kılıç hep aynı cümle Claude'un sabit ayarı çeşitli, sapma riski
Şekil 47.4 "için"den sonra ne gelsin? Aynı adaylar, üç sıcaklıkta. Ortadaki oranlar torbanın gerçek oranları; yandakiler örnektir.

Bir gerçeği baştan bil: Claude'un yeni modellerinde sıcaklığı sen değiştiremezsin. Opus 5.5, Sonnet 5.5 ve Haiku 5.5 sıcaklığı varsayılan değerinde, yani 1'de tutar: sonraki parçayı, torbadaki gibi, hesapladıkları olasılıklara göre seçerler. İsteğe temperature alanını başka bir değerle eklersen istek 400 hatasıyla reddedilir. Daha eski modellerde (ör. hâlâ kullanılabilen Haiku 4.5) 0 ile 1 arasında bir değer verebilirsin; başka şirketlerin API'lerinde de bu ayarla karşılaşacaksın.

Kavramın asıl dersi şu: aynı soruya her seferinde biraz farklı cevap gelmesi bir hata değil, seçim adımının doğası. Belgelere göre sıcaklığı 0 yapmak bile birebir aynı cevabı hiçbir zaman garanti etmedi. Tutarlı biçimde cevap almayı Ders 48'de öğreneceksin.

Halüsinasyon ve modelin sınırları

Oyuncak modelinin "Garen Demacia için büyü yapar" demesini hatırla. Model yalan söylemedi; yalnızca kalıplara göre en olası devamı seçti ve olası görünen her şey doğru değildi. Dil modelinin gerçekte olmayan bir bilgiyi akıcı ve kendinden emin bir dille üretmesine halüsinasyon denir. Büyük modellerde bu çok daha seyrektir ama ortadan kalkmış değildir. Gerçek dünyadan üç örnek:

  • 2023, New York: Bir avukat dava dilekçesi için ChatGPT'den emsal karar istedi. Model mahkeme adları ve tarihlerle altı karar sıraladı; hiçbiri gerçek değildi. Mahkeme (Mata v. Avianca davası) avukatlara 5.000 dolar para cezası verdi.
  • 2023, Google Bard tanıtımı: Google'ın sohbet modeli, tanıtım ilanında Güneş Sistemi dışındaki bir gezegenin ilk fotoğrafını James Webb Uzay Teleskobu'nun çektiğini söyledi; o fotoğraf 2004'te başka bir teleskopla çekilmişti. Hatanın haberlere çıktığı gün şirketin borsa değeri yaklaşık 100 milyar dolar düştü.
  • 2024, Kanada: Air Canada'nın sohbet botu, yakını ölen bir yolcuya indirimli bilet farkını uçuştan sonra da geri isteyebileceğini söyledi; şirketin kuralı böyle değildi. Uyuşmazlığa bakan kurul, botun sözünden şirketi sorumlu tuttu ve farkı ödetti.

Neden olur? Model eğitimde "doğru" cümleyi değil, olası cümleyi üretmeyi öğrenir. Çoğu zaman olası olan doğrudur. Ama nadir bir bilgi, eğitimden sonra olmuş bir olay ya da hiç var olmayan bir şey sorulduğunda, olası görünen bir uydurmayı da aynı kendinden emin tonla yazabilir. Model (sen araç vermedikçe) internete ya da bir veritabanına bakmaz; her şeyi eğitimde gördüğü kalıplardan üretir.

SınırNedenNe yaparsın?
Güncel bilgiEğitim verisi belli bir tarihte biter; dün çıkan yamayı bilmez.Güncel bilgiyi (yama notu, kural) isteğin içine sen koy.
Hesap ve saymaMetni harf harf değil token token görür; harf saymada ve uzun hesaplarda yanılabilir.Hasar, altın, fiyat gibi hesapları kendi fonksiyonun yapsın.
Senin verinVeritabanını, dosyalarını, kullanıcılarını görmez.Gereken veriyi isteğe ekle; modele araç vermeyi Ders 49'da öğreneceksin.
TutarlılıkSeçim adımında rastgelelik var.Önemli çıktıyı kullanmadan önce denetle.
HafızaHer istek ayrıdır.Konuşma geçmişini her istekte gönder.

API anahtarı almak ve saklamak

Claude, Anthropic'in sunucularında çalışır. Ona Ders 24'te Data Dragon'a yaptığın gibi bir HTTP isteği gönderirsin; farkı, bu hizmetin ücretli olması. Sunucunun her istekte "bu isteği kim gönderiyor, faturayı kime yazayım?" sorusuna cevap alması gerekir. Cevap, isteğin bir başlığında taşınan API anahtarıdır; Ders 26'daki Authorization başlığının işini görür. Anahtarı ele geçiren senin adına, senin paranla istek atar.

Console'dan anahtar almak

Anahtarlar Claude Console'da oluşturulur. Console, sohbet ettiğin claude.ai'den ayrı bir sitedir ve API kullanımı sohbet planından ayrı faturalanır (bazı ücretli planlar her ay bir miktar API kredisi içerir).

  1. Hesap aç. platform.claude.com adresine git, hesap aç ya da giriş yap. Fiyat sayfasındaki bilgiye göre yeni kullanıcılar API'yi denemek için küçük bir ücretsiz kredi alıyor.
  2. Harcamana sınır koy. Settings → Billing sayfasında kredini görürsün; ödeme yöntemi ve kredi işleri de buradadır. Aynı sayfanın Spend limits bölümünde Set limit ile aylık bir üst sınır koy (öğrenirken 5 dolar gibi küçük bir sayı yeter). Sınıra gelince istekler 400 hatasıyla durur (mesaj You have reached your specified API usage limits diye başlar) ama faturan büyümez.
  3. Anahtarı oluştur. Settings → API keys sayfasında Create key düğmesine bas. Anahtara bir ad ver (ders-47), bir son kullanma süresi seç (ör. 30 gün) ve Linked account olarak kendini bırak. Çalışma alanı (workspace) seçeneğinde tek bir alan seç (yeni bir hesapta yalnız Default Workspace vardır); seçmezsen her isteğe ayrıca çalışma alanı kimliği eklemen gerekir.
  4. Kopyala ve sakla. Anahtar sk-ant- ile başlar ve yalnız bir kez gösterilir. Hemen kopyala ve birazdan oluşturacağın .env dosyasına yapıştır. Kaybedersen geri göremezsin; yenisini oluşturursun.

.env ve .gitignore

Anahtar asla kodun içine yazılmaz. Ders 29'daki düzeni kur ve sırayı bozma: önce .gitignore, sonra .env. Böylece .env dosyası bir an bile Git'in göreceği bir yerde durmaz.

.gitignore
node_modules.env
.env
ANTHROPIC_API_KEY=sk-ant-api03-buraya-kendi-anahtarin

Değişkenin adı tam olarak ANTHROPIC_API_KEY olmalı: SDK anahtarı kendiliğinden bu addan okur. Değeri tırnaksız ve boşluksuz yapıştır. Programı da her seferinde node --env-file=.env dosya.ts ile çalıştıracaksın.

Anahtar tarayıcıya girmez

Ders 44'teki kuralı hatırla: tarayıcıda çalışan koda giren her şey, sayfayı açan herkesin bilgisayarına iner. Bunu sahte bir anahtarla denedik: Ders 40'taki gibi bir Vite projesinde .env'e VITE_ANTHROPIC_API_KEY=sk-ant-api03-SAHTE-ANAHTAR-123 yazdık, bir bileşende import.meta.env.VITE_ANTHROPIC_API_KEY ile okuduk ve npm run build ile derledik. Sonra derlenen dosyalarda sk-ant aradık (findstr /m aranan metnin geçtiği dosyaların adını yazar):

Terminal — PowerShell
PS C:\kod\vite-deneme> findstr /m "sk-ant" dist\assets\*.jsdist\assets\index-B5rposho.js

O dosya, sayfayı açan herkesin tarayıcısına inen dosya. İçinde anahtar olduğu gibi duruyordu:

dist\assets\index-B5rposho.js içinden
Kl=new Ul({apiKey:`sk-ant-api03-SAHTE-ANAHTAR-123`})

Next.js'teki NEXT_PUBLIC_ önekli değişkenler de böyle derlenen dosyaya yazılır. Sayfayı açan biri F12 ile Network ya da Sources sekmesine bakıp anahtarı kopyalayabilir. Doğru düzen, Ders 30'daki ara sunucu fikridir: tarayıcı yalnız senin sunucuna soru gönderir; anahtarı bilen ve Claude'a istek atan, sunucudaki koddur (bir Route Handler ya da Server Action).

Tarayıcı kullanıcının bilgisayarı anahtar yok Senin sunucun Route Handler anahtar .env'de gizli kalır Claude API api.anthropic.com anahtarı denetler soru anahtarla cevap cevap ✗ Doğrudan istek: anahtar herkesin eline geçer
Şekil 47.5 Anahtar yalnız sunucuda durur. Tarayıcıdan Claude'a doğrudan istek atmak, anahtarı herkese vermek demektir.

SDK de seni bu hatadan korumaya çalışır: tarayıcıda çalıştırılmaya kalkılınca hata verir.

Sık hataIt looks like you're running in a browser-like environment.

Ne zaman çıkar? SDK'yı tarayıcıda çalışan bir koda (React bileşeni, "use client" dosyası, Vite sayfası) koyup sayfayı açınca. Tarayıcı konsolunda (F12 → Console) şu mesaj çıkar; hatanın adı kullandığın derleme aracına göre AnthropicError ya da AnthropicError2 gibi görünebilir:

Tarayıcı konsolu (F12 → Console)
It looks like you're running in a browser-like environment. This is disabled by default, as it risks exposing your secret API credentials to attackers.If you understand the risks and have appropriate mitigations in place,you can set the `dangerouslyAllowBrowser` option to `true`, e.g., new Anthropic({ apiKey, dangerouslyAllowBrowser: true });

Nasıl düzelir? Mesaj "bu varsayılan olarak kapalı, çünkü gizli anahtarını saldırganlara açar" diyor. dangerouslyAllowBrowser: true yazıp susturma; adındaki dangerously (tehlikeli biçimde) sözcüğü uyarının kendisi. Hata çıkması seni korumaz da: yukarıdaki denemedeki gibi anahtar derlenen dosyaya çoktan yazılmıştır. SDK kodunu sunucuya taşı, anahtarı öneksiz bir ortam değişkeninde tut, o anahtarı Console'dan silip yenisini oluştur.

Anahtar GitHub'a girmez

GitHub herkese açık depolarda sızmış anahtarları tarar; Anthropic de bu taramanın ortağıdır. Açık bir depoya Claude anahtarı gönderirsen anahtar kendiliğinden devre dışı bırakılır ve sana e-posta gelir. Buna güvenme; gizli depolar, ekran görüntüleri ve Discord mesajları bu taramaya girmez.

Bir anahtarın sızdığından şüphelenirsen Ders 29'daki kuralı uygula: Console'da Settings → API keys sayfasında anahtarı bul ve Delete ile sil (Disable yalnız geçici olarak kapatır, sonradan yeniden açılabilir), yeni anahtar oluştur ve .env'i güncelle. Git geçmişinden silmek yetmez; dışarı çıkmış anahtar yanmış sayılır.

SDK ile ilk mesaj

Claude'a fetch ile de istek atabilirsin; Ders 30'da dış API'lere böyle bağlandın. Bir isteğin aslında neye benzediğine bak:

İsteğin kendisi (kısaltılmış)
POST https://api.anthropic.com/v1/messagesx-api-key: sk-ant-api03-...anthropic-version: 2023-06-01content-type: application/json {"model":"claude-opus-5-5","max_tokens":1000,"messages":[{"role":"user","content":"..."}]}

Başlıkları her seferinde doğru yazmak, gelen JSON'u tiplerle okumak, geçici hatalarda yeniden denemek, akışı parçalara ayırmak... Bunların hepsini senin yerine yapan hazır bir paket var: Anthropic'in resmî SDK'sı.

Projeyi kurmak

C:\kod\yapay-zeka klasöründe VS Code'un terminalini aç. Projeyi Ders 14'teki gibi başlat, SDK'yı kur, TypeScript'i ve Node tiplerini geliştirme bağımlılığı olarak ekle:

Terminal — PowerShell
PS C:\kod\yapay-zeka> npm init -yWrote to C:\kod\yapay-zeka\package.json:...PS C:\kod\yapay-zeka> npm pkg set type=modulePS C:\kod\yapay-zeka> npm install @anthropic-ai/sdk added 7 packages, and audited 8 packages in 7s found 0 vulnerabilitiesPS C:\kod\yapay-zeka> npm install -D typescript @types/node@24 added 4 packages, and audited 12 packages in 2s found 0 vulnerabilities

@types/node@24, Ders 39'daki gibi Node 24'ün tip tanımlarını getirir. Bu ders hazırlanırken kurulan sürümler SDK için 0.133.0, TypeScript için 7.0.2 idi; package.json'da sende daha yeni sayılar görebilirsin. Tip denetimi için klasöre bir tsconfig.json ekle ve denetimi bir kez çalıştır:

tsconfig.json — yapay-zeka — Visual Studio Code
tsconfig.json
{    "compilerOptions": {        "target": "esnext",        "module": "nodenext",        "types": ["node"],        "strict": true,        "noEmit": true,        "skipLibCheck": true    }}
PROBLEMSOUTPUTDEBUG CONSOLETERMINAL
PS C:\kod\yapay-zeka> npx tsc --noEmitPS C:\kod\yapay-zeka> 
Ln 1, Col 1Spaces: 4UTF-8JSON

npx tsc --noEmit hiçbir şey yazmadıysa her şey yolunda: şimdilik denetlenecek tek dosya oyuncak-model.ts ve tipleri doğru.

"types": ["node"] Node'a özgü adları (process gibi) tanıtır; "noEmit": true "yalnız denetle, dosya üretme" demektir; "skipLibCheck": true ise node_modules içindeki tip dosyalarını yeniden denetleyip zaman kaybetmeyi önler. Kodu Node doğrudan çalıştırır, npx tsc --noEmit yalnızca tiplerini denetler (Ders 39).

İlk istek

ilk-mesaj.ts dosyasını oluştur ve yaz:

ilk-mesaj.ts
import Anthropic from "@anthropic-ai/sdk" const client = new Anthropic() const mesaj = await client.messages.create({    model: "claude-opus-5-5",    max_tokens: 1000,    messages: [        { role: "user", content: "Ahri oynamaya yeni başlayan birine tek cümlelik bir taktik ver." }    ]}) for (const blok of mesaj.content) {    if (blok.type === "text") {        console.log(blok.text)    }}console.log("Girdi token:", mesaj.usage.input_tokens)console.log("Çıktı token:", mesaj.usage.output_tokens)

Önce tipleri denetle, sonra anahtarı .env'den okuyarak çalıştır:

Terminal — PowerShell
PS C:\kod\yapay-zeka> npx tsc --noEmitPS C:\kod\yapay-zeka> node --env-file=.env ilk-mesaj.tsÖnce E ile büyüle; tutarsa Q ve W ile vur, ıskalarsan geri çekil.Girdi token: 31Çıktı token: 48# Cevap ve sayılar örnektir; sende farklı olur.

Satır satır:

  • new Anthropic() bir istemci (client) oluşturur. Anahtarı vermedin, çünkü SDK onu kendiliğinden ANTHROPIC_API_KEY ortam değişkeninden okur. Adı belgelerdeki gibi client koyduk; istediğin adı verebilirsin.
  • model: cevabı hangi modelin vereceği. claude-opus-5-5, Claude Opus 5.5'in kimliğidir; harfi harfine yazılmalı.
  • max_tokens: cevaba izin verdiğin en çok token. Bir sınırdır, hedef değil; model işi bitince daha önce durur. Yeni modellerin cevaptan önceki düşünmesi de bu sınırdan yer.
  • messages: konuşma. Her mesajın bir role'ü (kim konuşuyor) ve bir content'i (ne dedi) var. İlk mesaj hep "user", yani sensin.
  • await: istek ağda gidip geldiği için Promise döner (Ders 15); "type": "module" sayesinde dosyanın en üstünde await kullanabiliyorsun.

Cevabın içi

mesaj değişkenine gelen obje, API'nin gönderdiği JSON'un tiplerle sarılmış hâlidir. Kısaltılmış bir örnek:

Örnek yanıt (kısaltılmış)
{    "model": "claude-opus-5-5",    "id": "msg_013mHbppMPd2PrVJzGMZPt2D",    "type": "message",    "role": "assistant",    "content": [        {            "type": "text",            "text": "Önce E ile büyüle; tutarsa Q ve W ile vur, ıskalarsan geri çekil."        }    ],    "stop_reason": "end_turn",    "stop_sequence": null,    "stop_details": null,    "usage": {        "input_tokens": 31,        "output_tokens": 48    }}
  • role: "assistant": bu mesajı model yazdı. Konuşmayı sürdürmek istersen bu mesajı messages dizisine ekleyip yeni sorunu arkasına koyarsın (Ders 48).
  • content bir dizi, çünkü cevap birden çok bloktan oluşabilir. Bu derste yalnız "text" bloklarıyla ilgileniyoruz. Opus 5.5 zor bir soruda cevaplamadan önce düşünür; o zaman dizinin başında type: "thinking" olan bir blok da görürsün. Bu bloğun metni varsayılan olarak boş gelir, ama düşünme token'ları output_tokens'a eklenir ve ücretlendirilir. Basit sorularda model hiç düşünmeyebilir.
  • stop_reason modelin neden durduğunu söyler: "end_turn" işini bitirdi, "max_tokens" senin koyduğun sınıra takıldı ve cevap yarıda kaldı, "model_context_window_exceeded" bağlam penceresi doldu, "refusal" güvenlik sebebiyle cevap vermeyi reddetti.
  • usage faturanın temelidir: input_tokens gönderdiğin, output_tokens modelin ürettiği token sayısı.

Kodda neden blok.type === "text" diye sorduğumuzu merak ettiysen, kısayolu dene:

Sık hataerror TS2339: Property 'text' does not exist on type 'ContentBlock'.

Ne zaman çıkar? Cevabın ilk bloğunun metnini doğrudan okumaya kalkınca: console.log(mesaj.content[0].text).

Terminal — PowerShell
PS C:\kod\yapay-zeka> npx tsc --noEmitilk-mesaj.ts:13:30 - error TS2339: Property 'text' does not exist on type 'ContentBlock'.  Property 'text' does not exist on type 'BashCodeExecutionToolResultBlock'. 13 console.log(mesaj.content[0].text)                                ~~~~ Found 1 error in ilk-mesaj.ts:13

Nasıl düzelir? ContentBlock bir birleşim tipi (Ders 39): metin bloğu, düşünme bloğu, araç blokları... Hepsinde text alanı yok; TypeScript ikinci satırda bunlardan birini örnek gösteriyor. İlk bloğun metin olacağının garantisi de yok, çünkü düşünme bloğu önde gelebilir. Önce türü daralt: for (const blok of mesaj.content) { if (blok.type === "text") { ... } }.

Sık hataError: Could not resolve authentication method.

Ne zaman çıkar? SDK anahtarı bulamayınca. En sık sebebi programı --env-file=.env olmadan çalıştırmak. .env'deki değişkenin adını yanlış yazmak (ANTROPIC_API_KEY) ya da değeri boş bırakmak da aynı hatayı verir.

Terminal — PowerShell
PS C:\kod\yapay-zeka> node ilk-mesaj.tsfile:///C:/kod/yapay-zeka/node_modules/@anthropic-ai/sdk/client.mjs:338            throw new Error('Could not resolve authentication method. Expected one of apiKey, authToken, credentials, config, or profile to be set. Or for one of the "X-Api-Key" or "Authorization" headers to be explicitly omitted');                  ^ Error: Could not resolve authentication method. Expected one of apiKey, authToken, credentials, config, or profile to be set. Or for one of the "X-Api-Key" or "Authorization" headers to be explicitly omitted    at Anthropic.validateHeaders (file:///C:/kod/yapay-zeka/node_modules/@anthropic-ai/sdk/client.mjs:338:19)    ...    at async file:///C:/kod/yapay-zeka/ilk-mesaj.ts:5:15 Node.js v24.20.0

Nasıl düzelir? Mesaj "kimlik doğrulama yöntemi bulunamadı, apiKey ya da benzerlerinden biri gerekli" diyor. Yığın izinde (Ders 13) kendi dosyanı ara: ilk-mesaj.ts:5, yani create satırı. Dikkat et: hata new Anthropic() satırında değil, istek hazırlanırken ortaya çıktı; istek hiç yola çıkmadı. Programı node --env-file=.env ilk-mesaj.ts ile çalıştır; olmazsa .env'deki adı ve değeri denetle.

Sık hata.env: not found

Ne zaman çıkar? --env-file=.env yazdın ama terminal başka bir klasördeyken, ya da dosyanın adı farklıyken (env, .env.txt).

Terminal — PowerShell
PS C:\kod> node --env-file=.env yapay-zeka\ilk-mesaj.tsC:\Program Files\nodejs\node.exe: .env: not found

Nasıl düzelir? --env-file yolu, terminalin bulunduğu klasöre göre arar. cd C:\kod\yapay-zeka ile proje klasörüne geç. Dosya hâlâ bulunamıyorsa Windows dosyanın sonuna gizlice .txt eklemiş olabilir (Ders 0); VS Code'un dosya listesinde adına bak.

Sık hataerror TS2769: No overload matches this call.

Ne zaman çıkar? max_tokens alanını unutunca. TypeScript isteği göndermeden yakalar.

Terminal — PowerShell
PS C:\kod\yapay-zeka> npx tsc --noEmitilk-mesaj.ts:5:44 - error TS2769: No overload matches this call.  The last overload gave the following error.    Property 'max_tokens' is missing in type '{ model: "claude-opus-5-5"; messages: { role: "user"; content: string; }[]; }' but required in type 'MessageCreateParamsBase'....Found 1 error in ilk-mesaj.ts:5

Nasıl düzelir? Uzun mesajın kilit cümlesi üçüncü satırda: "max_tokens alanı eksik ama zorunlu". model, max_tokens ve messages her istekte zorunlu üçlüdür. Tip denetimini atlayıp doğrudan çalıştırsaydın aynı hatayı API 400 invalid_request_error olarak, istek gidip geldikten sonra verirdi. npx tsc --noEmit alışkanlığı sana bu turu kazandırır.

Sistem talimatı: maçtan önceki brifing

İlk isteğinde modelin nasıl cevap vereceğine hiç karışmadın. Bir uygulamada ise modelin rolünü, dilini, uzunluğunu sen belirlersin. Bunun yeri sistem talimatıdır: kullanıcının mesajlarından ayrı duran, bütün konuşma boyunca geçerli kurallar. Modele gönderdiğin metnin tamamına ise istem denir.

ilk-mesaj.ts dosyasını koc.ts adıyla kopyala, system alanını ekle (vurgulu satır) ve soruyu değiştir. Token satırlarını bu kez sildik, cevabın kendisine odaklanalım:

koc.ts
import Anthropic from "@anthropic-ai/sdk" const client = new Anthropic() const mesaj = await client.messages.create({    model: "claude-opus-5-5",    max_tokens: 2000,    system: "Sen sabırlı bir LoL koçusun. Türkçe cevap ver ve en fazla üç cümle yaz.",    messages: [        { role: "user", content: "Koridorda rakibim beni hep erken öldürüyor. Ne yapmalıyım?" }    ]}) for (const blok of mesaj.content) {    if (blok.type === "text") {        console.log(blok.text)    }}
Örnek yanıtörnek, sende farklı çıkabilir
İlk dakikalarda minyonlarının arkasında kal ve yalnız son vuruşa odaklan; rakip yeteneklerini harcamadan saldırıya geçme. Ormancısını haritada göremiyorsan kuleye yakın oyna. Altıncı seviyeye kadar sabırlı ol, güçlenince karşılık ver.

Sistem talimatını silip aynı soruyu sorarsan model büyük ihtimalle başlıklı, maddeli ve çok daha uzun bir cevap yazar. Talimat cevabın biçimini değiştirdi; kısa cevap ayrıca daha az çıktı token'ı, yani daha az para demek. İyi bir sistem talimatı kısa ve somuttur: rol, dil, uzunluk, biçim. Kullanıcıdan gelen metni sistem talimatının içine yapıştırma; o alan senin kurallarına ayrılmıştır. İyi istemin parçalarını ve bu kuralın sebebini Ders 48'de ayrıntılı göreceksin.

Cevabı akış olarak almak

Uzun bir cevabın üretilmesi saniyeler sürebilir. messages.create bütün cevap bitene kadar bekler; kullanıcı da o süre boyunca boş bir ekrana bakar. Claude.ai'de cevabın yazılır gibi akmasının sebebi akıştır (Ders 27'de gördüğün akışla aynı fikir: veri tek seferde değil, parça parça gelir): model her parçayı ürettiği anda sana yollar.

Akışsız boş ekran, bekleniyor… tamamı ilk parça yaklaşık 0,5 sn'de Akışla 0 sn 2 sn 4 sn 6 sn 8 sn
Şekil 47.6 Akışsız istekte kullanıcı sonuna kadar boş ekrana bakar; akışla ilk parça hemen gelir. Süreler örnektir.

Akışın bir faydası daha var: belgeler, büyük bir max_tokens ile akışsız istek göndermemeni söylüyor; bazı ağlar uzun süre sessiz kalan bağlantıları koparabilir. koc.ts'i akis.ts adıyla kopyala ve isteği akışa çevir:

akis.ts
import Anthropic from "@anthropic-ai/sdk" const client = new Anthropic() const akis = client.messages.stream({    model: "claude-opus-5-5",    max_tokens: 2000,    system: "Sen sabırlı bir LoL koçusun. Türkçe cevap ver ve en fazla üç cümle yaz.",    messages: [        { role: "user", content: "Koridorda rakibim beni hep erken öldürüyor. Ne yapmalıyım?" }    ]}) akis.on("text", (parca) => {    process.stdout.write(parca)}) const sonMesaj = await akis.finalMessage()console.log()console.log("Durma sebebi:", sonMesaj.stop_reason)console.log("Token:", sonMesaj.usage.input_tokens, "girdi,", sonMesaj.usage.output_tokens, "çıktı")
Örnek yanıt (metin parça parça akar)örnek, sende farklı çıkabilir
İlk dakikalarda minyonlarının arkasında kal ve yalnız son vuruşa odaklan; rakip yeteneklerini harcamadan saldırıya geçme. Ormancısını haritada göremiyorsan kuleye yakın oyna. Altıncı seviyeye kadar sabırlı ol, güçlenince karşılık ver.Durma sebebi: end_turnToken: 64 girdi, 97 çıktı

Üç yeni şey var:

  • client.messages.stream(...) isteği akış olarak açar. await yok, çünkü hemen bir akış objesi döner; cevap arkadan gelir.
  • akis.on("text", ...) her yeni metin parçasında çalışacak bir fonksiyon kaydeder. Ders 22'deki addEventListener gibi bir olay dinleyicisi. console.log her seferinde alt satıra geçerdi; process.stdout.write ise yazdığını aynı satırda bırakır, böylece parçalar yan yana dizilir.
  • await akis.finalMessage() akış bitene kadar bekler ve sana messages.create'in döndürdüğü objenin aynısını verir. stop_reason ve usage gibi bilgileri buradan okursun. Hemen ardındaki boş console.log() imleci yeni satıra indirir.

Perde arkasında SDK, HTTP cevabını açık tutar ve sunucunun art arda gönderdiği olayları (server-sent events) okur. Belgelerdeki kısa bir örnek akış böyle görünür; SDK bunları senin için çözüp text olayına çevirir:

Belgedeki örnek akış (kısaltılmış)
event: message_startdata: {"type": "message_start", "message": {"id": "msg_1nZdL29xx5MUA1yADyHTEsnR8uuvGzszyY", "type": "message", "role": "assistant", "content": [], ...}} event: content_block_startdata: {"type": "content_block_start", "index": 0, "content_block": {"type": "text", "text": ""}} event: content_block_deltadata: {"type": "content_block_delta", "index": 0, "delta": {"type": "text_delta", "text": "Hello"}} event: content_block_deltadata: {"type": "content_block_delta", "index": 0, "delta": {"type": "text_delta", "text": "!"}} event: content_block_stopdata: {"type": "content_block_stop", "index": 0} event: message_deltadata: {"type": "message_delta", "delta": {"stop_reason": "end_turn", "stop_sequence":null}, "usage": {"output_tokens": 15}} event: message_stopdata: {"type": "message_stop"}

content_block_delta olaylarındaki text değerleri senin parca değişkenine gelen metinlerdir. Akışın arasında, içinde metin taşımayan ping olayları da gelebilir; SDK onları senin yerine atlar.

Hatalar ve yeniden deneme

API'nin hata kodları Ders 26'da öğrendiğin durum kodlarıdır; Anthropic her birine ayrıca bir tür adı verir:

Kod ve türAnlamıYeniden dene?
400
invalid_request_error
İstek bozuk ya da kendi koyduğun harcama sınırına geldin.Hayır, isteği düzelt.
401
authentication_error
Anahtar eksik, yanlış, silinmiş ya da süresi dolmuş.Hayır, anahtarı düzelt.
403
permission_error
Anahtarın bu işe izni yok.Hayır.
404
not_found_error
Adres ya da model adı yanlış.Hayır, adı düzelt.
429
rate_limit_error
Çok sık ya da çok büyük istek gönderdin; retry-after başlığı kaç saniye bekleyeceğini söyler.Evet, bekleyip.
500
api_error
Anthropic tarafında beklenmeyen bir hata.Evet.
529
overloaded_error
API geçici olarak aşırı yüklü; bütün kullanıcıları etkileyebilir.Evet, biraz sonra.

İyi haber: SDK geçici hataları (bağlantı kopması, 429, 5xx) kendisi iki kez daha dener, her denemede biraz daha uzun bekler ve sunucu retry-after gönderdiyse ona uyar. Ders 30'da elle yazdığın yeniden deneme döngüsü burada hazır geliyor. Deneme sayısını istemciyi oluştururken değiştirebilirsin: new Anthropic({ maxRetries: 4 }). 0 yazarsan hiç denemez.

Yeniden denemenin işe yaramadığı hatalarda programın çökmesin, kullanıcıya anlaşılır bir şey söylesin. SDK her durum kodu için ayrı bir hata sınıfı verir; onları Ders 16'daki gibi instanceof ile, en özelden en genele doğru ayır. hatalar.ts dosyasını oluştur:

hatalar.ts
import Anthropic from "@anthropic-ai/sdk" const client = new Anthropic() try {    const mesaj = await client.messages.create({        model: "claude-opus-5-5",        max_tokens: 1000,        messages: [{ role: "user", content: "Merhaba" }]    })    for (const blok of mesaj.content) {        if (blok.type === "text") {            console.log(blok.text)        }    }} catch (hata) {    if (hata instanceof Anthropic.AuthenticationError) {        console.log("Anahtar geçersiz: .env dosyasındaki ANTHROPIC_API_KEY değerine bak.")    } else if (hata instanceof Anthropic.RateLimitError) {        console.log("Hız sınırına takıldın: biraz bekleyip yeniden dene.")    } else if (hata instanceof Anthropic.APIError) {        console.log(`API hatası: ${hata.status} ${hata.type}`)    } else {        throw hata    }}

Anthropic.APIError bütün API hatalarının atasıdır; status alanında durum kodu, type alanında tür adı durur. Son else dalı, tanımadığın hataları yutmamak için onları yeniden fırlatır (Ders 13). Bilerek dene: .env'deki anahtarın son harfini değiştir ve çalıştır. Geçersiz anahtar her seferinde 401 aldığı için çıktın bu olur:

Terminal — PowerShell
PS C:\kod\yapay-zeka> node --env-file=.env hatalar.tsAnahtar geçersiz: .env dosyasındaki ANTHROPIC_API_KEY değerine bak.

Sonra anahtarı düzeltmeyi unutma. Hatayı yakalamasaydın Node ne yazardı, aşağıdaki kartlarda var. Kartlardaki çıktıları gerçek API'ye istek atmadan, API'nin bu durumlarda döndürdüğü hata gövdelerini taklit eden yerel bir deneme sunucusuyla ürettik; Görev 5'te böyle bir sunucuyu sen de yazacaksın. İstek kimliği (req_...) sende farklı olur.

Sık hataAuthenticationError: 401 authentication_error

Ne zaman çıkar? Anahtar yanlış ya da eksik kopyalandıysa, Console'dan silindiyse ya da süresi dolduysa.

Hata çıktısıörnek, sende farklı çıkabilir
file:///C:/kod/yapay-zeka/node_modules/@anthropic-ai/sdk/core/error.mjs:45            return new AuthenticationError(status, error, message, headers, type);                   ^ AuthenticationError: 401 {"type":"error","error":{"type":"authentication_error","message":"invalid x-api-key"},"request_id":"req_011CSHoEeqs5C35K2UUqR7Fy"}    at APIError.generate (file:///C:/kod/yapay-zeka/node_modules/@anthropic-ai/sdk/core/error.mjs:45:20)    ...    at async file:///C:/kod/yapay-zeka/ilk-mesaj.ts:5:15 {  status: 401,  ...  type: 'authentication_error'} Node.js v24.20.0

Nasıl düzelir? Mesaj "geçersiz anahtar" diyor (invalid x-api-key). Yeniden denemek işe yaramaz; SDK de denemez. Anahtarı .env'e tırnaksız ve boşluksuz yeniden yapıştır; elinde yoksa Console'dan yeni anahtar oluştur.

Sık hataNotFoundError: 404 not_found_error

Ne zaman çıkar? Model adını yanlış yazınca. En sık yanlış, sürümdeki tireyi noktayla yazmak: claude-opus-5.5. TypeScript bunu yakalayamaz, çünkü SDK yeni modeller çıkabilsin diye model alanına her metni kabul eder.

Hata çıktısıörnek, sende farklı çıkabilir
NotFoundError: 404 {"type":"error","error":{"type":"not_found_error","message":"model: claude-opus-5.5"},"request_id":"req_011CSHoEeqs5C35K2UUqR7Fy"}    at APIError.generate (file:///C:/kod/yapay-zeka/node_modules/@anthropic-ai/sdk/core/error.mjs:51:20)    ...

Nasıl düzelir? Mesaj hangi model adının bulunamadığını söylüyor. Adı model tablosundan harfi harfine kopyala: claude-opus-5-5.

Sık hataInternalServerError: 529 overloaded_error

Ne zaman çıkar? Anthropic'in sunucuları geçici olarak çok yoğunsa. Senin kodunla ilgisi yoktur ve SDK bu hatayı zaten iki kez yeniden denemiştir.

Hata çıktısıörnek, sende farklı çıkabilir
InternalServerError: 529 {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"},"request_id":"req_011CSHoEeqs5C35K2UUqR7Fy"}    at APIError.generate (file:///C:/kod/yapay-zeka/node_modules/@anthropic-ai/sdk/core/error.mjs:63:20)    ...

Nasıl düzelir? Biraz sonra yeniden dene; uygulamanda kullanıcıya "şu an çok yoğun, birazdan tekrar dene" de. Sonsuz döngüde art arda istek göndermek yükü artırır. 429 (RateLimitError) benzer görünür ama sebebi çoğu zaman sensin: kısa sürede çok fazla istek ya da token gönderdin; retry-after başlığı kaç saniye bekleyeceğini söyler.

Maliyet ve model seçimi

API'nin faturası iki kalemden oluşur: gönderdiğin token'lar girdi fiyatından, modelin ürettiği token'lar çıktı fiyatından ücretlendirilir. Fiyatlar bir milyon token başına, dolar olarak verilir. 12 Ekim 2026 itibarıyla Anthropic'in resmî fiyat sayfasındaki temel fiyatlar:

Modelmodel alanıGirdi ($)Çıktı ($)Ne zaman?
Claude Haiku 5.5claude-haiku-5-50,100,50Kısa ve çok sayıda iş: sınıflandırma, kısa özet, yönlendirme
Claude Sonnet 5.5claude-sonnet-5-5210Günlük işler: kod, yazı, sohbet; hız ve kalite dengesi
Claude Opus 5.5claude-opus-5-5420Zor akıl yürütme, uzun ve karmaşık işler
Claude Fable 5.1claude-fable-5-11050En zor işler; en yetenekli ve en pahalı

Haiku 5.5'in fiyatı, isteğin girdisi 100.000 token'ı aşınca 0,50 $ girdi ve 2,50 $ çıktıya yükselir; diğer üç model 1 milyon token'lık pencerenin tamamında aynı fiyatı uygular. Fiyatlar değişebilir; uygulamanı yayına almadan önce fiyat sayfasına yeniden bak.

Tablodan iki şey hemen göze çarpıyor. Birincisi, çıktı girdiden beş kat pahalı: uzun cevaplar faturayı uzun sorulardan daha hızlı büyütür. Bu yüzden "en fazla üç cümle" gibi bir sistem talimatı paradan da tasarruf ettirir. İkincisi, modeller arasındaki fark büyük: Opus 5.5, Haiku 5.5'in kırk katı, Fable 5.1 ise yüz katı fiyatında. Hesabı koda dökelim. maliyet.ts dosyasını oluştur:

maliyet.ts
type Fiyat = { girdi: number, cikti: number } // 1 milyon token başına dolar (resmî fiyat sayfası, 12 Ekim 2026)const fiyatlar: Record<string, Fiyat> = {    "claude-opus-5-5": { girdi: 4, cikti: 20 },    "claude-sonnet-5-5": { girdi: 2, cikti: 10 },    "claude-haiku-5-5": { girdi: 0.1, cikti: 0.5 }} function maliyet(model: string, girdiToken: number, ciktiToken: number): number {    const fiyat = fiyatlar[model]    return (girdiToken * fiyat.girdi + ciktiToken * fiyat.cikti) / 1000000} // Koç botu: her soruda 1.200 girdi, 300 çıktı token'ı; günde 1.000 sorufor (const model of Object.keys(fiyatlar)) {    const tekSoru = maliyet(model, 1200, 300)    const aylik = tekSoru * 1000 * 30    console.log(`${model}: soru başına ${tekSoru.toFixed(5)} dolar, ayda ${aylik.toFixed(2)} dolar`)}
Çıktı
claude-opus-5-5: soru başına 0.01080 dolar, ayda 324.00 dolarclaude-sonnet-5-5: soru başına 0.00540 dolar, ayda 162.00 dolarclaude-haiku-5-5: soru başına 0.00027 dolar, ayda 8.10 dolar

Tek bir soru kuruşlar tutuyor; denemelerin seni zorlamaz. Ama aynı uygulama günde bin soruyla ayda 8 dolar da tutabilir, 324 dolar da. Gerçek sayıları tahmin etme, ölç: her cevabın usage alanındaki input_tokens ve output_tokens değerlerini bu fonksiyona ver. Opus 5.5'te düşünme token'ları output_tokens'ın içindedir; zor sorularda bu sayı cevabın uzunluğundan büyük çıkabilir.

Hangi modeli seçeceğine alışkanlık değil, işin zorluğu karar verir. 10–20 gerçek örnek soru topla, önce ucuz bir modelle dene; cevaplar yetmiyorsa bir üst modelle aynı örnekleri karşılaştır ve farkın parasına değip değmediğine bak. Bu dersin örneklerinde Opus 5.5 kullandık; Anthropic'in belgelerindeki örneklerin çoğu da bu modeli kullanıyor. Kendi denemelerinde model alanını claude-haiku-5-5 yapıp cevapları ve faturayı karşılaştırabilirsin; karar senin.

Görevler

Görevleri C:\kod\yapay-zeka klasöründe, her biri için yeni bir dosyada yap. API'ye istek atan görevler birkaç kuruş tutar; çıktıları örnektir. Önce kendin dene, takılırsan ipuçlarını sırayla aç.

Görev 1

TFT koçu

tft-koc.ts adında bir program yaz. Sistem talimatıyla modeli bir TFT koçuna çevir: Türkçe cevap versin, en fazla üç madde yazsın ve her madde - ile başlasın. Soru şu olsun: "Altın biriktirmek mi, sürekli dükkânı yenilemek mi?" Cevabın metnini, ardından durma sebebini ve token sayılarını yazdır. Çıktın şuna benzemeli:

Metin
- ...- ...- ...Durma sebebi: end_turnToken: 70 girdi, 120 çıktı

Sonra sınırı dene: sistem talimatını tamamen sil ve aynı soruyu sor. Cevabın biçimi ve çıktı token'ı sayısı nasıl değişti?

İpucu 1

koc.ts dosyasından başla. Değişecek yerler: system metni, kullanıcının sorusu ve sonda yazdırdıkların.

İpucu 2

Durma sebebi mesaj.stop_reason'da, token sayıları mesaj.usage.input_tokens ve mesaj.usage.output_tokens'ta.

Çözümü göster
tft-koc.ts
import Anthropic from "@anthropic-ai/sdk" const client = new Anthropic() const mesaj = await client.messages.create({    model: "claude-opus-5-5",    max_tokens: 2000,    system: "Sen bir TFT koçusun. Türkçe cevap ver. En fazla üç madde yaz ve her madde \"- \" ile başlasın.",    messages: [        { role: "user", content: "Altın biriktirmek mi, sürekli dükkânı yenilemek mi?" }    ]}) for (const blok of mesaj.content) {    if (blok.type === "text") {        console.log(blok.text)    }}console.log("Durma sebebi:", mesaj.stop_reason)console.log("Token:", mesaj.usage.input_tokens, "girdi,", mesaj.usage.output_tokens, "çıktı")
Örnek yanıtörnek, sende farklı çıkabilir
- Erken oyunda güçlü birimlerin varsa altın biriktir; her 10 altın, tur sonunda 1 altın faiz getirir.- Canın hızla düşüyorsa faizi bırak ve dükkânı yenileyerek takımını güçlendir.- 50 altına ulaştığında fazlasını harcayabilirsin; faiz 5 altında durur.Durma sebebi: end_turnToken: 71 girdi, 118 çıktı

Metin içindeki çift tırnağı \" ile yazdık, çünkü metnin kendisi de çift tırnakla açılıyor. Sistem talimatını silince model büyük ihtimalle başlıklı ve çok daha uzun bir cevap verir; çıktı token'ı, yani fatura birkaç katına çıkabilir.

Görev 2

Aylık bütçe

Maç özeti üreten bir uygulama yazacaksın. Her özet ortalama 3.000 girdi ve 600 çıktı token'ı harcıyor; günde 200 özet bekliyorsun. Bütçen ayda 72 dolar. butce.ts adında, API'ye hiç istek atmayan bir program yaz:

  • aylikMaliyet(model, girdi, cikti, gunlukIstek) fonksiyonu ayda kaç dolar tutacağını sente yuvarlanmış olarak döndürsün (ay 30 gün).
  • Fiyat tablosunda olmayan bir model adı gelirse anlaşılır bir hata fırlatsın.
  • Her model için tutarı ve bütçeye sığıp sığmadığını yazdır. Bütçeye tam eşit tutar sığar sayılır.
  • En sonda fonksiyonu yanlış yazılmış bir adla (claude-sonet-5-5) çağır, hatayı yakala ve mesajını yazdır.
Metin
claude-opus-5-5: ayda 144.00 dolar, sığmazclaude-sonnet-5-5: ayda 72.00 dolar, sığarclaude-haiku-5-5: ayda 3.60 dolar, sığarFiyatı bilinmeyen model: claude-sonet-5-5
İpucu 1

Fiyat tablosunu maliyet.ts'ten al. Tek isteğin maliyetini bul, sonra gunlukIstek * 30 ile çarp.

İpucu 2

Ondalık sayı tuzağını hatırla (Ders 9): Haiku'nun tutarı yuvarlamadan 3.5999999999999996 çıkar. Sente yuvarlamak için Math.round(tutar * 100) / 100.

İpucu 3

Sonnet'in tutarı bütçeye tam eşit. < ile karşılaştırırsan "sığmaz" dersin; <= kullan. Bilinmeyen model için if (!fiyat) { throw new Error(...) }, çağırırken de try/catch.

Çözümü göster
butce.ts
type Fiyat = { girdi: number, cikti: number } const fiyatlar: Record<string, Fiyat> = {    "claude-opus-5-5": { girdi: 4, cikti: 20 },    "claude-sonnet-5-5": { girdi: 2, cikti: 10 },    "claude-haiku-5-5": { girdi: 0.1, cikti: 0.5 }} function aylikMaliyet(model: string, girdi: number, cikti: number, gunlukIstek: number): number {    const fiyat = fiyatlar[model]    if (!fiyat) {        throw new Error(`Fiyatı bilinmeyen model: ${model}`)    }    const tekIstek = (girdi * fiyat.girdi + cikti * fiyat.cikti) / 1000000    const tutar = tekIstek * gunlukIstek * 30    return Math.round(tutar * 100) / 100} const butce = 72for (const model of Object.keys(fiyatlar)) {    const tutar = aylikMaliyet(model, 3000, 600, 200)    let durum = "sığmaz"    if (tutar <= butce) {        durum = "sığar"    }    console.log(`${model}: ayda ${tutar.toFixed(2)} dolar, ${durum}`)} try {    aylikMaliyet("claude-sonet-5-5", 3000, 600, 200)} catch (hata) {    if (hata instanceof Error) {        console.log(hata.message)    }}
Çıktı
claude-opus-5-5: ayda 144.00 dolar, sığmazclaude-sonnet-5-5: ayda 72.00 dolar, sığarclaude-haiku-5-5: ayda 3.60 dolar, sığarFiyatı bilinmeyen model: claude-sonet-5-5

Sınır denemesi: butce değerini 71.99 yap; Sonnet "sığmaz"a döner. 3.6 yaparsan Haiku yine "sığar" der, çünkü tutarı sente yuvarladın; yuvarlamasaydın 3.5999999999999996 <= 3.6 bu kez şans eseri doğru çıkardı ama paraya şansla güvenilmez.

Görev 3

Haiku'nun iki fiyatı

Haiku 5.5, isteğin girdisi 100.000 token'a kadarsa 1 milyon token başına 0,10 $ girdi ve 0,50 $ çıktı, 100.000'i aşarsa 0,50 $ girdi ve 2,50 $ çıktı ister. haiku-fiyat.ts dosyasına haikuMaliyet(girdi, cikti) fonksiyonunu yaz ve sınır değerleriyle dene. Şunu yazdırmalı:

Metin
0 girdi, 0 çıktı: 0 dolar100000 girdi, 1000 çıktı: 0.0105 dolar100001 girdi, 1000 çıktı: 0.0525005 dolarTek token fazlası faturayı 5 katına çıkardı.
İpucu 1

Fiyatları önce düşük değerlerle kutuya koy, girdi sınırı aşıyorsa yüksek değerlerle değiştir. Sınır "aşarsa" diyor: 100.000 tam sınırda, hâlâ ucuz tarife.

İpucu 2

Son satırdaki oranı haikuMaliyet(100001, 1000) / haikuMaliyet(100000, 1000) ile bul ve Math.round ile yuvarla.

Çözümü göster
haiku-fiyat.ts
function haikuMaliyet(girdi: number, cikti: number): number {    let girdiFiyati = 0.1    let ciktiFiyati = 0.5    if (girdi > 100000) {        girdiFiyati = 0.5        ciktiFiyati = 2.5    }    return (girdi * girdiFiyati + cikti * ciktiFiyati) / 1000000} console.log(`0 girdi, 0 çıktı: ${haikuMaliyet(0, 0)} dolar`)console.log(`100000 girdi, 1000 çıktı: ${haikuMaliyet(100000, 1000)} dolar`)console.log(`100001 girdi, 1000 çıktı: ${haikuMaliyet(100001, 1000)} dolar`)const oran = haikuMaliyet(100001, 1000) / haikuMaliyet(100000, 1000)console.log(`Tek token fazlası faturayı ${Math.round(oran)} katına çıkardı.`)
Çıktı
0 girdi, 0 çıktı: 0 dolar100000 girdi, 1000 çıktı: 0.0105 dolar100001 girdi, 1000 çıktı: 0.0525005 dolarTek token fazlası faturayı 5 katına çıkardı.

> yerine >= yazsaydın 100.000 token'lık istek de pahalı tarifeden hesaplanırdı. Kuralın sözcüğü ("aşarsa") hangi işaretin doğru olduğunu söyler.

Görev 4

Akışı say

akis-sayac.ts adında bir program yaz: soruyu akış olarak sorsun, gelen metni ekrana yazsın ve sonunda kaç parça ve kaç karakter geldiğini söylesin. Cevap max_tokens sınırına takılıp yarıda kesildiyse bir uyarı da yazsın. Soru: "TFT'de altın ve faiz nasıl yönetilir? Ayrıntılı anlat." Uyarıyı görebilmek için max_tokens değerini bilerek küçük tut (ör. 300).

İpucu 1

akis.ts'ten başla. on("text", ...) içindeki fonksiyon her parçada çalışır: iki sayacı orada artır. Karakter sayısı parca.length.

İpucu 2

Sayaçlar let olmalı ve dinleyicinin dışında, en üstte açılmalı. Kesilme bilgisi finalMessage()'in döndürdüğü objenin stop_reason alanında: "max_tokens".

Çözümü göster
akis-sayac.ts
import Anthropic from "@anthropic-ai/sdk" const client = new Anthropic()let parcaSayisi = 0let karakterSayisi = 0 const akis = client.messages.stream({    model: "claude-opus-5-5",    max_tokens: 300,    messages: [{ role: "user", content: "TFT'de altın ve faiz nasıl yönetilir? Ayrıntılı anlat." }]}) akis.on("text", (parca) => {    parcaSayisi++    karakterSayisi += parca.length    process.stdout.write(parca)}) const sonMesaj = await akis.finalMessage()console.log()console.log(`${parcaSayisi} parça, ${karakterSayisi} karakter geldi.`)if (sonMesaj.stop_reason === "max_tokens") {    console.log("Uyarı: cevap max_tokens sınırına takılıp yarıda kesildi.")}
Örnek yanıt (kısaltılmış)örnek, sende farklı çıkabilir
TFT'de ekonomi, faiz sistemi üzerine kuruludur. Her tur sonunda elindeki her 10 altın için 1 altın faiz alırsın ve bu en çok 5 altına kadar çıkar......Kritik bir eşikteysen birkaç tur faizden vazgeçip36 parça, 702 karakter geldi.Uyarı: cevap max_tokens sınırına takılıp yarıda kesildi.

Sınır denemesi: max_tokens değerini 4000 yap; uyarı büyük ihtimalle kaybolur ve stop_reason end_turn olur. Çok küçük bir değerde (ör. 50) parça sayısı 0 bile çıkabilir: model önce düşündüyse sınırın tamamını düşünmeye harcamıştır. Uygulamanda "kesildi" durumunu kullanıcıya mutlaka göster; yarım cevap tam cevap gibi görünür.

Görev 5

Bedava deneme sunucusu

SDK'nın yeniden deneme davranışını, tek kuruş ödemeden kendi gözünle gör. Ders 27'deki gibi node:http ile bir sahte Claude sunucusu yaz:

  • sahte-sunucu.ts 3047 numaralı kapıyı dinlesin, gelen her isteği numarasıyla yazdırsın.
  • İlk iki isteğe 529 ve gövde olarak {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"}} döndürsün.
  • Üçüncü istekten itibaren, gerçek API'nin biçiminde ve içinde "Sahte sunucudan selam!" yazan bir mesaj döndürsün.

Sonra sahte-deneme.ts yaz: SDK'yı baseURL: "http://localhost:3047" ve sahte bir anahtarla bu sunucuya yönlendir, cevabın metnini ve geçen süreyi yazdır. İki programı iki ayrı terminalde çalıştır. Son olarak iki sınırı dene: sunucu üç kez hata verirse ne olur? İstemci maxRetries: 0 ile oluşturulursa?

İpucu 1

Gerçek bir mesajın en az şu alanları var: id, type: "message", role: "assistant", model, content (içinde { type: "text", text: "..." }), stop_reason, stop_sequence, usage (input_tokens, output_tokens). Hepsini JSON.stringify ile gönder, Content-Type başlığını unutma.

İpucu 2

İstek sayacını sunucu fonksiyonunun dışında let ile aç. Hata yanıtından sonra return yazmazsan aynı isteğe ikinci kez yanıt yazmaya çalışırsın (Ders 27'deki ERR_HTTP_HEADERS_SENT).

İpucu 3

new Anthropic({ apiKey: "sahte-anahtar", baseURL: "http://localhost:3047" }). SDK isteği baseURL'in sonuna /v1/messages ekleyerek gönderir. Süreyi ölçmek için istekten önce Date.now()'ı bir kutuya koy.

Çözümü göster
sahte-sunucu.ts
import http from "node:http" const HATA_SAYISI = 2let istekSayisi = 0 const sunucu = http.createServer((req, res) => {    istekSayisi++    console.log(`${istekSayisi}. istek: ${req.method} ${req.url}`)     if (istekSayisi <= HATA_SAYISI) {        res.writeHead(529, { "Content-Type": "application/json" })        res.end(JSON.stringify({ type: "error", error: { type: "overloaded_error", message: "Overloaded" } }))        return    }     res.writeHead(200, { "Content-Type": "application/json" })    res.end(JSON.stringify({        id: "msg_sahte",        type: "message",        role: "assistant",        model: "claude-opus-5-5",        content: [{ type: "text", text: "Sahte sunucudan selam!" }],        stop_reason: "end_turn",        stop_sequence: null,        usage: { input_tokens: 10, output_tokens: 5 }    }))}) sunucu.listen(3047, () => {    console.log("Sahte Claude hazır")})
sahte-deneme.ts
import Anthropic from "@anthropic-ai/sdk" const client = new Anthropic({    apiKey: "sahte-anahtar",    baseURL: "http://localhost:3047"}) const baslangic = Date.now()const mesaj = await client.messages.create({    model: "claude-opus-5-5",    max_tokens: 100,    messages: [{ role: "user", content: "Merhaba" }]}) for (const blok of mesaj.content) {    if (blok.type === "text") {        console.log(blok.text)    }}console.log(`Geçen süre: ${Date.now() - baslangic} ms`)

Önce birinci terminalde node sahte-sunucu.ts ile sunucuyu başlat, sonra ikinci terminalde node sahte-deneme.ts ile deneme programını çalıştır. İki terminalin çıktısı:

Terminal 1: node sahte-sunucu.ts
Sahte Claude hazır1. istek: POST /v1/messages2. istek: POST /v1/messages3. istek: POST /v1/messages
Terminal 2: node sahte-deneme.tsörnek, sende farklı çıkabilir
Sahte sunucudan selam!Geçen süre: 1442 ms

Senin programın create'i yalnız bir kez çağırdı, ama sunucuya üç istek geldi: SDK ilk iki 529'dan sonra bekleyip yeniden denedi, üçüncüde başardı. Bir buçuk saniyenin neredeyse tamamı bu bekleyişler. Süre sende biraz farklı olur, çünkü SDK beklemelere küçük rastgele farklar ekler.

Sınırlar: sunucuyu durdur (Ctrl+C), HATA_SAYISI'nı 3 yap ve yeniden başlat. Sunucu yine üç istek görür ama üçü de hata olduğu için deneme programı InternalServerError: 529 {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"}} ile çöker: bir deneme ve iki yeniden deneme bitmiştir. HATA_SAYISI'nı 2'ye geri alıp sunucuyu yeniden başlat (sayaç da sıfırlansın), sonra istemciye maxRetries: 0 ekle: tek istek gider ve program ilk hatada aynı mesajla durur. Böyle bir sahte sunucu ücretsizdir ve gerçek API'nin nadiren göstereceği hataları istediğin an üretir.

Kendini sına

Soru 1

Oyuncak modeldeki metinler dizisine "Garen Demacia için savaşır" cümlesini iki kez daha eklersen uret("Lux") ne yazar? Bu ne gösteriyor?

Cevabı göster

Lux Demacia için savaşır. Artık "için"den sonra üç kez "savaşır" geliyor; en olası devam o. Garen'in cümlesi düzeldi, ama bu kez Lux, Ahri ve Yasuo savaşır oldu. Model neyin doğru olduğunu bilmiyor, yalnızca sayıyor; veri değişince doğrularla yanlışlar yer değiştirdi.

Soru 2

Claude Opus 5.5 ile 2.000 girdi ve 500 çıktı token'ı harcayan bir isteğin maliyeti kaç dolar? Aynı istek Haiku 5.5'te kaç tutar?

Cevabı göster

Opus 5.5'te girdinin milyonu 4 dolar: 2.000 token 0,008 dolar tutar. Çıktının milyonu 20 dolar: 500 token 0,010 dolar tutar. Toplam 0,018 dolar. Haiku 5.5'te girdi 0,0002, çıktı 0,00025 dolar tutar; toplam 0,00045 dolar, yani kırk kat daha ucuz. Çıktı token'ı girdinin dörtte biri olmasına rağmen Opus'ta faturanın büyük kısmını çıktı oluşturdu.

Soru 3

Hangi hatalarda isteği aynen yeniden göndermek işe yarar: 400, 401, 429, 529?

Cevabı göster

Yalnız 429 ve 529 (genel olarak 5xx): ikisi de geçicidir ve SDK onları zaten iki kez yeniden dener. 400 (bozuk istek) ve 401 (geçersiz anahtar) aynen tekrarlanırsa hep aynı hatayı verir; önce isteği ya da anahtarı düzeltmen gerekir.

Soru 4

Bu mesajı oku: sorun ne, nasıl düzeltirsin?

Hata çıktısı
Error: Could not resolve authentication method. Expected one of apiKey, authToken, credentials, config, or profile to be set. Or for one of the "X-Api-Key" or "Authorization" headers to be explicitly omitted    at Anthropic.validateHeaders (file:///C:/kod/yapay-zeka/node_modules/@anthropic-ai/sdk/client.mjs:338:19)
Cevabı göster

SDK kimlik bilgisi bulamadı: ANTHROPIC_API_KEY ortam değişkeni tanımlı değil ya da boş. En olası sebep programı node --env-file=.env dosya.ts yerine node dosya.ts ile çalıştırmak; ya da .env'deki değişkenin adını yanlış yazmak. İstek hiç gönderilmediği için bu hata para tutmaz.

Soru 5

Uygulamandaki koç botu, dün çıkan yamada Ahri'nin hangi değerlerinin değiştiğini soran kullanıcıya, sayılarla dolu kendinden emin bir cevap veriyor. Güvenir misin?

Cevabı göster

Hayır. Modelin eğitim verisi belli bir tarihte biter; dün çıkan yamayı bilemez ve olası görünen sayılar uydurmuş olabilir (halüsinasyon). Doğru yol, güncel yama notunu resmî bir kaynaktan alıp isteğin içine koymak ve modelden yalnız o metne dayanarak cevap vermesini istemek.

Soru 6

İlk isteğinde modele adını söyledin. İkinci, ayrı bir istekte "Benim adım ne?" diye sordun ve model bilmediğini söyledi. Neden?

Cevabı göster

Model seni hatırlamaz; her istek ayrıdır ve model yalnız o istekte gönderilenleri, yani bağlam penceresindekileri görür. İkinci istekte ilk konuşmayı göndermediğin için adın penceresinde yoktu. Sohbet uygulamaları her mesajda önceki konuşmayı yeniden gönderir; bunu kendi kodunda Ders 48'de yapacaksın.

Kayıt noktası

yapay-zeka yeni bir proje klasörü; önce git init. Commit'ten önce git status ile .env dosyasının listede olmadığını gözünle gör: .gitignore işini yapıyorsa orada görünmez.

Bir sonraki derste modelden tutarlı sonuç almayı öğreneceksin: iyi bir istemin parçaları, örnekli istem ve cevabı programının güvenle kullanabileceği, doğrulanmış JSON olarak almak.

İşaret yalnızca bu tarayıcıda saklanır, kimseye gönderilmez.