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.
- 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.
| API | Tool | |
|---|---|---|
| Kim çağırır | Kodu yazan geliştirici | Model, tek seferde, soru anında |
| Dokümana bakar mı | Evet, ayrı sayfada | Hayır; gördüğü tek şey ad + açıklama + şema |
| Yanlış seçerse | Derleme ya da test hatası | Sessizce yanlış cevap |
| Fazlası zararsız mı | Evet, kullanılmaz | Hayır: her turda yer kaplar, yanlış seçilebilir |
| Adlandırma | Tutarlılık yeter | Ayırt edicilik şart |
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çimi | En sık hata |
|---|---|---|
| 5 | 20/20 | — |
| 11 (docstring düzeltmesiyle) | 26/27 | Hacim sorusunda bakiye tool’u |
| 23 | 17/24 | islem_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.
# 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.
İ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
# 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:
- Model istediği kadar çağırabilir.
- Tekrarı zararsız; önbellekten dönebilir.
- Hatası bir turluk kayıp.
- Onay gerekmez.
- Ş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
- 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.