Sertaç Yıldırım saha notları

Ana sayfa → Teknik

Tool Tasarımı: API Sarmalayıcı Değil, Karar Yüzeyi

Üç haftada 11 tool’u 23’e çıkardık. Her biri istenen bir rapordu, her biri çalışıyordu. Sonra ölçtüm: doğru tool’u seçme oranı %96’dan %71’e düşmüştü. Tek satır kod bozulmamıştı. Sadece modelin önüne koyduğumuz menü büyümüştü ve menü, prompt’un kendisiydi.

Özet
  • Tool bir API değildir. API’yi insan okur ve dokümana bakar; tool’u model okur ve tek seferde seçer. Adı, açıklaması ve parametreleri prompt’un parçasıdır.
  • Her yeni tool, seçim problemini büyütür. 5 tool’da 20/20, 11 tool’da 26/27, 23 tool’da 17/24. Kod aynı; artan tek şey seçenek sayısı.
  • Ayrı karar mı, parametre mi? Birleştirme kuralı bu. 23 tool’u 9’a indirdik, isabet %94 oldu, hiçbir yetenek kaybolmadı.
  • Açıklama dört satırdır: ne yapar, ne zaman kullan, ne zaman kullanma (yerine hangisi), bir örnek soru. “Kullanma” satırı en çok işe yarayanı.
  • Hata mesajı bir talimattır. “400 Bad Request” gören model aynı çağrıyı tekrarlar; “tarih aralığı 31 günü aşamaz, daralt ve tekrar dene” diyen mesajı alan model düzeltir.
  • Cevabı tool kırpar. 2.300 satır döndüren tool, koşunun geri kalanını zehirler. Tool’un işi veri taşımak değil, karar verdirmektir.

Tool ile API arasındaki fark

Şirket içi agent yazısında tool’ları MCP server çalıştırıyordu ve ilk kural oradaydı: küçük modelde tool seçimini docstring belirler. O zaman 11 tool vardı ve 27 sorunun 26’sını doğru tool’a yönlendiriyordu. Sonra rapor istekleri geldi, biz de her istek için yeni bir tool yazdık. Yanlışımız buydu.

APITool
Kim çağırırKodu yazan geliştiriciModel, tek seferde, soru anında
Dokümana bakar mıEvet, ayrı sayfadaHayır; gördüğü tek şey ad + açıklama + şema
Yanlış seçerseDerleme ya da test hatasıSessizce yanlış cevap
Fazlası zararsız mıEvet, kullanılmazHayır: her turda yer kaplar, yanlış seçilebilir
AdlandırmaTutarlılık yeterAyırt edicilik şart
Tool yazarken kod yazmıyorsun, talimat yazıyorsun. Kodun kalitesi çalışmasını, açıklamanın kalitesi seçilmesini belirler.

Sahadan: 23 tool, %71 isabet

Ölçüm basitti: 24 gerçek soru, her birinin doğru cevabı hangi tool ile gelmeli, elle yazılı. Sonra agent’ı koştur ve ilk seçtiği tool’a bak.

Tool sayısıDoğru tool seçimiEn sık hata
520/20
11 (docstring düzeltmesiyle)26/27Hacim sorusunda bakiye tool’u
2317/24islem_listesi ile islem_ozeti karışıyor
9 (birleştirilmiş)22,5/24 — iki koşunun ortalamasıKYC’de tarih aralığı eksik

23 tool’a çıktığımızda karışan çiftlere baktım; hepsi aynı hastalıktaydı:

  • islem_listesi / islem_ozeti / islem_detay — üçü de “işlem” diye başlıyor, farkları açıklamanın üçüncü cümlesinde.
  • gunluk_depozit / depozit_raporu — biri tek gün, diğeri aralık. Modelin bunu anlaması için parametre listesini okuması gerekiyordu; okumuyor.
  • bekleyen_cekimler / cekim_kuyrugu — ikisi aynı şeydi. İki farklı kişi iki hafta arayla yazmıştı.

Birleştirme kuralı: ayrı karar mı, parametre mi?

İki tool’u birleştirip birleştirmeyeceğime tek soruyla karar verdim: kullanıcı bu ikisi arasında bir seçim yapıyor mu, yoksa aynı soruyu farklı kapsamla mı soruyor? Aynı soruysa tek tool, bir parametre.

Uc tool, bir tool
# ONCE: uc ayri tool, ucu de "islem" diye basliyor
gunluk_depozit(tarih)
depozit_raporu(baslangic, bitis)
depozit_ozeti(ay)

# SONRA: tek tool, kapali kume parametre
def depozit(baslangic: date, bitis: date,
            kirilim: Literal["gun", "ay", "toplam"] = "toplam"):
    """Belirtilen tarih araligindaki para yatirma (depozit) toplamlarini dondurur.

    NE ZAMAN KULLAN: "bugun kac dolar depozit oldu", "gecen ay ne kadar
      yatirildi", "haftalik depozit dagilimi" gibi sorularda.
    NE ZAMAN KULLANMA: para cekme sorulari icin; onlarda cekim() kullan.
    ORNEK: "bugun kac dolar depozit oldu?"
      -> depozit(baslangic=bugun, bitis=bugun, kirilim="toplam")
    """

Bu değişiklikle 23 tool 9’a indi: depozit, cekim, pozisyon, hacim, bakiye, kyc, mutabakat, musteri, islem. Kaybolan yetenek yok; aynı yetenekler daha az kapıdan giriyor. İsabet %71’den %94’e çıktı.

Tersi de doğru: iki iş gerçekten farklı kararlarsa tek tool’a tıkmak da hata. cekim(...) ile cekim_onayla(...) aynı tool olamaz, çünkü biri okuma diğeri yazma; birinin yanlış çağrılması rapor hatası, diğerininki para hareketi.

Aynı kararın iki parçası tek tool olur. İki ayrı karar tek tool olamaz; özellikle biri okuyup diğeri yazıyorsa.

İyi bir tool sözleşmesinin beş maddesi

1. Ad: fiil + nesne, ayırt edici

get_data değil, cekim değil — cekim_listele. Aynı önekle başlayan üç tool varsa model üçünü de aynı kapı sanır. Ön ek yerine farklı fiil kullan.

2. Açıklama: dört satır

Ne yapar · ne zaman kullan · ne zaman kullanma (ve yerine hangisi) · bir örnek soru. “Ne zaman kullanma” satırı bizde en çok işe yarayan satır oldu: karışan her tool çiftinde ikisine de birbirinin adını yazdık, karışma bitti.

Örnek soruyu kullanıcının cümlesiyle yaz, mühendis cümlesiyle değil. “Aggregate deposit volume” değil, “bugün kaç dolar depozit oldu?”

3. Parametreler: kapalı küme ve varsayılan

Serbest metin parametre, modelin uydurabileceği bir alandır. Kırılım Literal["gun","ay","toplam"] olduğunda model dördüncüyü uyduramaz. Her parametreye makul bir varsayılan koy: modelin doldurması gereken alan sayısı azaldıkça isabet artıyor. Bizde kirilim’a varsayılan koymak tek başına 2 soruyu düzeltti.

4. Cevap: kırpılmış, şemalı, sayılı

Tool’un cevabı doğrudan context’e girer. Kural: önce sayılar, sonra örnek, sonra devam anahtarı. Ham liste asla. Cevabın içine her zaman “kaç kayıt var” koy; model 5 örnek satır görüp “toplam 5 işlem” diye özet yazmasın diye.

5. Hata: ne yanlıştı, hangi alan, şimdi ne yap

Hata mesaji
# ONCE
{"error": "400 Bad Request"}
# model ayni cagriyi tekrar denedi, sonra pes etti

# SONRA
{"error": "tarih_araligi_uzun",
 "mesaj": "Tarih araligi en fazla 31 gun olabilir. Su an 92 gun.",
 "yapilacak": "baslangic tarihini 31 gun icinde sec ve tekrar cagir.",
 "alan": "baslangic"}
# model bir sonraki turda dogru cagriyi yapti

Hata mesajında bir kural daha var: kullanıcıdan gelen metni olduğu gibi geri yazma.{girdi} geçersiz” diyen bir hata mesajı, kullanıcının yazdığı talimatı modele taşır. Bu bir prompt injection yoludur; girdiyi kırp, tırnakla, ya da hiç yazma.

Yan etkili tool’lar ayrı sınıftır

9 tool’un 8’i okuma. Dokuzuncusu — cekim_onayla — para hareketi yapıyor ve tamamen farklı kurallara tabi:

Okuyan tool
  • Model istediği kadar çağırabilir.
  • Tekrarı zararsız; önbellekten dönebilir.
  • Hatası bir turluk kayıp.
  • Onay gerekmez.
Yazan tool
  • Şemada açıkça işaretli: "yan_etki": true.
  • Idempotency anahtarı zorunlu.
  • İnsan onayı olmadan çalışmaz; onay akışta, prompt’ta değil.
  • Her çağrı denetim log’una yazılır: kim, ne zaman, hangi argümanlarla.

Bunu ayırmadığımız ilk hafta, agent bir test ortamında “bekleyen çekimleri gözden geçir” isteğini “onayla” diye anladı ve 3 kaydı onayladı. Test ortamıydı, para yoktu; ders bedavaydı. Okuma ile yazmanın aynı menüde yan yana durması, modelin suçu değil.

Kullanılmayan tool zararsız değildir

23 tool’un 6’sı üç ay boyunca hiç çağrılmadı. “Dursun, bir gün lazım olur” dediğimiz tool’lar. Bedelleri:

  • Her turda tanımları pencereye giriyor: 6 tool × ~210 token = koşu başına boşa 1.260 token.
  • Her biri yanlış seçilme ihtimali taşıyor; ikisi gerçekten seçildi.
  • Yeni gelen biri menüyü okuyup hangisinin canlı olduğunu anlayamıyor.

Kural basit: 30 günde bir kez bile çağrılmayan tool menüden çıkar. Kod duruyor, testleri duruyor; sadece modelin menüsünde değil. Geri eklemek bir satır.

Ne izlemeli?

  • Tool başına seçim isabeti. Elle etiketlenmiş 20–30 soruluk bir sette; sürüm değişince tekrar koş (eval yazısı).
  • Tool başına hata oranı ve hata sonrası düzelme. Model hatadan sonra doğru çağrıyı yapabiliyor mu? Yapamıyorsa hata mesajı kötüdür.
  • Boş dönüş oranı. Sürekli boş dönen tool, yanlış soruyu cevaplıyordur.
  • Cevap boyutu, p95. En şişkin tool’u bu sayı söyler; kırpma orada başlar.
  • Çağrılmayan tool sayısı. 30 gün kuralının girdisi.
  • Karışan çiftler. Yanlış seçimlerde hangi ikili öne çıkıyor; açıklamaya “kullanma” satırı o çift için yazılır.

Kontrol listesi

Yeni tool eklemeden önce
  • Bu ayrı bir karar mı, mevcut bir tool’un parametresi mi?
  • Adı, mevcut tool’ların hiçbiriyle aynı önekle başlıyor mu?
  • Açıklamada “ne zaman kullanma” satırı var mı? Yerine hangi tool yazıyor?
  • Örnek soru, kullanıcının gerçekten yazdığı bir cümle mi?
  • Parametreler kapalı küme mi? Varsayılanları var mı?
  • Cevap kırpılmış mı? İçinde toplam sayı var mı?
  • Hata mesajı ne yapılacağını söylüyor mu? Kullanıcı metnini geri yazıyor mu?
  • Yan etkisi var mı? Varsa işaretli, idempotency anahtarlı ve onaylı mı?
  • Bu tool eklendikten sonra isabet ölçümü tekrar koşuldu mu?
  • Menüde 30 gündür çağrılmayan tool var mı?

Sonuç

Üç haftada 12 tool ekledik ve sistemi kötüleştirdik. Hiçbiri hatalı değildi; hepsi birlikte hatalıydı. Model bizim yazdığımız menüyü okuyor ve tek seferde seçiyor; menü uzadıkça ve başlıklar birbirine benzedikçe seçim bozuluyor.

9 tool’a indirdiğimizde kaybettiğimiz bir yetenek olmadı: aynı işler parametreyle yapılıyor. İsabet %71’den %94’e çıktı, koşu başına token düştü, yeni gelen biri menüye bakıp ne yapabildiğimizi anlayabiliyor. Bunların hiçbiri model değişikliği değil; hepsi metin.

Akılda kalacak cümle: tool’un kodu ne yaptığını, açıklaması ise seçilip seçilmeyeceğini belirler. İkincisini yazmadan birincisini yazmak, çalışan ama bulunamayan bir fonksiyon üretmektir.