Erken erişime başvurun ›
Agent'tan Düzyazı Değil Veri İsteyin
Blog
Mühendislik8 dk okuma

Agent'tan Düzyazı Değil Veri İsteyin

KA

Kerem Aksoy

Geliştirici Platformu Lideri, Botonom

Bir agent API'si üstüne kurulan her entegrasyon aynı yerden başlıyor: bir modelin yazdığı cümleye nişan almış bir regex (düzenli ifade). İstediğiniz şekli tarif etmek o ayrıştırmayı ortadan kaldırıyor; arkasındaki tasarım kararları ise özelliğin kendisinden daha ilginç.

Yazılım entegrasyonunuz serbest düzyazı istemez. Toplayabileceği bir sayı, if-else dallanması yapabileceği bir durum kodu, döngüye sokabileceği bir liste ister. Bu haftaya kadar Botonom komut API'si ona bir paragraf dönüyor, metni ayrıştırma (parse etme) zahmetini ise tamamen size bırakıyordu.

Bir yapay zeka (AI/SI) agent API'sinden yapılandırılmış veri almanın en temiz yolu, talimatla birlikte beklediğiniz veri şemasını göndermek ve veri tipleri tanımlanmış nesneyi (typed object) düzyazının hemen yanında geri okumaktır. Agent'ın kendi cevabı yine zengin düzyazı kalmalıdır; personelin okuduğu ve üretilen dosyaları taşıyan asıl gövde odur. Yapılandırılmış nesne ise tamamlanan turun sizin şemanıza göre ayrıştırılmasıyla üretilir. Bu yaklaşımın tarihe gömdüğü en büyük arıza biçimi, modelin cümlelerini regex (düzenli ifade) ile ayrıştırmaya kalkışmaktır; o yöntem kodu yazdığınız gün değil, model aynı cümleyi üç hafta sonra başka kelimelerle kurduğu gün patlar.

Önceden bir çalışma neye benziyordu?

POST /v1/agents/command endpoint'i işi başından beri yapabiliyordu. Agent kendi persona'sı, yetenekleri ve izinleriyle headless (arayüzsüz) çalışıyor, gereken araçları çağırıyor, dosyaları oluşturuyordu. Ancak yanıt result_text içinde, yalnızca insanlar için yazılmış serbest metin olarak dönüyordu.

Dolayısıyla bu API'nin üzerine kurulan her entegrasyon, modelin ürettiği cümlelere nişan almış kırılgan bir regex (düzenli ifade) yazmakla başlıyordu. Bu ayrıştırma kodu yazdığınız ilk gün sorunsuz çalışır. Ancak üç hafta sonra agent aynı toplam tutarı farklı bir cümle kalıbıyla ifade ettiğinde regex sessizce yanlış rakamı yakalar. Ortada hiçbir sistem hatası oluşmaz; ancak veritabanınıza giren rakam o günden sonra artık yanlıştır.

Ne değişti?

Artık beklediğiniz JSON şemasını taleple birlikte iletiyorsunuz ve sistem aynı işlem turunda veriyi bu şemaya uygun olarak döndürüyor:

json
POST /v1/agents/command
{
  "agent_id": "<agent-uuid>",
  "instruction": "Bu ayın siparişlerini incele ve ciroyu özetle.",
  "schema": {
    "type": "object",
    "properties": {
      "toplam_ciro":    { "type": "number", "description": "adet x fiyat toplamı" },
      "en_yuksek_urun": { "type": "string", "description": "En çok ciro getiren ürünün adı" }
    },
    "required": ["toplam_ciro", "en_yuksek_urun"]
  }
}

command_status yanıtı artık iki çıktıyı birden eksiksiz taşıyor:

json
{
  "status": "completed",
  "result_text": "Bu ayın cirosu 27.400 TL; en çok Masa kazandırdı...",
  "output": { "toplam_ciro": 27400, "en_yuksek_urun": "Masa" },
  "output_error": null
}

Düzyazı metin yerli yerinde duruyor. Panelde görevi açan bir insanın okuyup bağlamı anlayacağı kısım odur; salt JSON döndürmek için o metni kaldırmak, insan kullanıcıyı tamamen dışlamak olurdu.

Nesne neden tura zorla dayatılmıyor da turdan okunuyor?

Akla gelen ilk mühendislik refleksi, agent'ın doğrudan kendi yanıtını şemayla kısıtlamak (structured decoding) olabilir. Biz bunu kasıtlı olarak yapmadık; sebebi de benzer sistemleri tasarlayan herkes için ders niteliğindedir.

Bir agent turu tek seferlik bir metin tamamlama çağrısı değildir. Bu yaşayan bir döngüdür: Model araç çağırır, dönen yanıtı inceler, gerekiyorsa yeni bir araç daha çağırır ve en sonunda kapsamlı bir nihai yanıt üretir. Bu yanıtın üzerinde üç kritik katman oturur ve katı şema kısıtlaması bu üçüyle birden çatışır:

Yanıtın taşıdığı değerŞema kısıtının ona getirdiği engel
Araç döngüsüSon yanıta uygulanan katı biçim kuralı, modelin ek araç çağırma esnekliğini elinden alır
Medya işaretleriGrafik, tablo ve dosyalar metin içindeki özel etiketlerle taşınır; ham bir JSON nesnesinde bunlara yer yoktur
PersonaHer agent'ın kendine has kurumsal üslubu, ses tonu ve düzyazı üreten iletişim kuralları vardır

Bu nedenle tur önce hiçbir kısıtlamaya maruz kalmadan doğal akışıyla tamamlanır; ardından ikinci ve çok hafif bir model geçişi, tamamlanan turun çıktısını talep edilen şemaya kusursuzca aktarır. Agent, siz yapılandırılmış veri istemeden önce nasıl çalışıyorsa yine öyle çalışır. Şema istemek aldığınız veri formatını zenginleştirir; agent'ın doğal problem çözme yeteneğini köreltmez.

Bunun getirdiği maliyet, komut başına minik bir ek model çağrısından ibarettir: ufak bir model, çok kısa bir girdi. Buna karşılık her iki taraf da kazanır: İnsanlar akıcı düzyazıyı, yazılımınız ise tip güvenli JSON verisini alır.

Şema göndermezseniz ne alıyorsunuz?

schema alanını boş bırakmak sizi ilkel regex ayrıştırmalarına geri döndürmez. Sistem yine standart bir zarf (envelope) içinde yapılandırılmış bir nesne döndürür:

AlanAnlamı
resultok, partial, needs_input, refused veya failed
summaryTek cümlelik net özet (talimatınızın dilinde)
follow_upAgent'ın sizden hâlâ beklediği ek bilgi (yoksa null)
actionsTurda fiilen kullanılan yeteneklerin listesi
filesÜretilen dosyalar

Zarf (envelope) bilerek sade tutuldu. Entegrasyon geliştiren her yazılımcının sorduğu 4 temel soruyu yanıtlar: İş oldu mu, tek cümlede ne bitti, hangi araçlar çalıştı ve ne dosya çıktı? Daha karmaşık bir varsayılan yapı, modeli kimsenin okumayacağı boş alanları doldurmaya zorlardı.

Asıl can alıcı nokta şudur: Endpoint, birileri özel parametre geçmeyi unuttuğunda dahi varsayılan olarak her zaman programlanabilir ve tip güvenli kalır.

Modele hiç sorulmayan iki kritik alan

actions ve files alanları modelin metin tahminine bırakılan alanlar değildir. Doğrudan çalışma zamanı (runtime) tarafından hesaplanır.

Bu çok bilinçli bir mimari tercihtir: Hangi araçların çağrıldığı, platformun elindeki kesin bir gerçektir. Hangi dosyaların üretildiği, oturum belleğinde kayıtlıdır. Modele halihazırda sistemde kayıtlı olan olguları tekrar sormak; iki araç çağıran bir çalışmanın üç diye raporlanmasına veya oluşturulamayan bir dosyanın "oluşturuldu" sanılmasına davetiye çıkarmaktır.

Bu yüzden modele yalnızca dilsel kabiliyet gerektiren kısımlar sorulur: özet, sonuç durumu veya eksik girdi açıklaması. Sistem tarafından doğrulanabilir olan hiçbir şey modele sorulmaz; doğrudan loglardan doğrulanır.

Bu ayrımdan doğan ince bir detay: Agent'ın kendi iç çalışma hafızası (scratchpad/memory) araçları actions listesinden filtrelenir. Üretimde en çok çağrılan araç odur; filtrelenmeseydi, çağıran yazılımcının asıl önemsediği kritik iş araçlarını arka plan operasyonlarının ve rutin iç işlemlerin (housekeeping) altına gömerdi.

"Zorunlu değil" demek null demektir ve bu bilinçli bir karardır

Katı yapılandırılmış çıktının (structured outputs), elle yazılmış şemalarda genelde bulunmayan iki katı şartı vardır: Her nesne additionalProperties: false tanımlamalı ve her alan required dizisinde geçmelidir. İlk testlerimizde çoğu geliştiricinin karşılaşmak istemeyeceği şu hata ile karşılaştık:

text
Invalid schema for response_format: 'additionalProperties' is required to be supplied and to be false.

Bu teknik karmaşayı API'yi çağıran geliştiricinin omzuna yıkmak özelliği sevimsiz kılardı. Bu yüzden şemayı platform katmanında otomatik olarak normalize ediyoruz: required dizisinde belirtmediğiniz her alan, arka planda "zorunlu ancak null değer alabilir" formuna dönüştürülür.

Bu çözümün yan etkisi beklenenden çok daha faydalı oldu: Zorunlu tutmadığınız bir alan output içinde her zaman anahtar olarak mevcuttur; eğer üretilmediyse değeri null döner. Kodunuzda "bu key JSON'da var mı, yoksa tanımsız mı" kontrolü yapmanıza gerek kalmaz; alan her zaman oradadır.

Şema, gerçeklikle yapılmış bir teminat sözleşmesi değildir

output alanı bazı durumlarda null dönebilir. Böyle bir durumda output_error alanı sebebini açıkça bildirir; çalışma durumu yine completed olarak kalır ve düzyazı cevabı korunur. Şemaya uymayan bir çıktı tek başına tüm işin çöpe atılmasını gerektirmez; aksi halde agent'ın dakikalarca uğraşıp ürettiği tüm katma değer heba olurdu.

Desteklenen şema alt kümesi bilerek sade tutuldu: string, number, integer, boolean, array, object; en fazla 50 alan ve 5 seviye derinlik. Desteklenmeyen tipler henüz istek anında açık bir hata mesajıyla reddedilir:

text
400 SCHEMA_INVALID
schema is not supported: properties.when: unsupported type "date"

İsteği sessizce kabul edip şemayı arka planda görmezden gelmek, açıkça reddetmekten çok daha tehlikelidir; çünkü sorunu iş işten geçtikten sonra, en uç noktada öğrenirsiniz.

Kendi ilk testimizde yaptığımız hata

İlk denemelerimizde product_count adında bir alan istedik ancak açıklamasını (description) yazmadık. Model 18 döndürdü. Veritabanı tablosunda ise 3 farklı ürün ve toplamda 18 adet satış vardı; alan adına bakıldığında her iki yorum da kendi içinde haklıydı.

Bir JSON şemasındaki description alanı insanlar için bir süs değildir; doğrudan agent'ın okuyup akıl yürüttüğü sistem talimatıdır. Tek bir net cümle meseleyi çözmeye yeter:

json
"product_count": {
  "type": "integer",
  "description": "KAÇ FARKLI ürün çeşidi olduğu; toplam satılan adet değil"
}

İki insanın bile farklı anlayabileceği belirsiz bir alan adı, yeterince çok işlem yapıldığında yapay zeka tarafından da er ya da geç iki türlü yorumlanır. Alanı doğru isimlendirmek işin yarısıysa, description ile ne kastettiğinizi açıkça belirtmek diğer yarısıdır.

Bu yetenek mimaride nereye oturuyor?

Komut endpoint'i zaten yazılımların bir agent'ı tetikleme ve yönetme yoluydu. Bu yenilik denklemin eksik kalan diğer yarısını tamamlıyor: Yazılımlarınız artık agent yanıtlarını serbest metin içinden regex ile tahmin etmeye çalışmadan, doğrudan tip güvenli JSON olarak okuyabiliyor. Varsayılan zarf yapısı ve doğrulama kuralları dahil tüm teknik sözleşmeye API dokümantasyonumuzdan ulaşabilirsiniz.

Bunu test etmenin en hızlı yolu canlıda bir istek atmaktır: API Playground üzerinden kendi API anahtarınızla kendi agent'ınıza gerçek bir komut gönderebilir ve schema alanını test edebilirsiniz.

Sık sorulan sorular

Şema göndermek agent'ın problem çözme davranışını değiştirir mi?

Hayır. Tur önce hiçbir kısıtlama olmadan doğal akışıyla çalışır, yapılandırılmış nesne ise tamamlanan turun çıktısından okunur. Araç çağrıları, cevap derinliği ve üretilen dosyalar tamamen korunur.

Agent şemayı eksiksiz dolduramazsa ne olur?

output değeri null döner ve output_error alanı arızanın gerekçesini açıklar. Görev yine başarıyla tamamlanır, result_text ise üretilen metni taşımaya devam eder. Şemaya tam uymadı diye üretilen işi kaybetmezsiniz.

Her API çağrısında şema göndermek zorunda mıyım?

Yalnızca yanıtı yazılımınızın otomatik olarak ayrıştıracağı senaryolarda. Çıktıyı doğrudan bir insanın okuyacağı durumlarda varsayılan zarf yapısı zaten en pratik çözümü sunar.

Kısıtlı yetkiye sahip agent'larla kullanılabilir mi?

Kesinlikle evet. Yanıtın veri yapısı ile agent'ın eylem yetkileri birbirinden bağımsız ayarlardır. Yalnızca veri okuyan ve dış dünyaya aksiyon alamayan bir agent da yapılandırılmış çıktıyı aynı kararlılıkla üretir.

Yapılandırılmış nesne, metin cevabın yerini mi alıyor?

Hayır, her ikisi de eşzamanlı olarak döner. Biri paneli açan insan gözü için, diğeri entegrasyon kodunuz içindir.

Şema boyutu için bir sınır var mı?

Maksimum 50 alan ve 5 seviye derinlik. Eğer bu sınırları zorluyorsanız, muhtemelen tek bir görevde iki ayrı işi birden yaptırmaya çalışıyorsunuzdur; süreci iki farklı komuta bölmek çok daha sağlıklı bir mimaridir.

Paylaş

LinkedInXWhatsApp

Üç adımda agent'ınızı ekibinize katın

İhtiyacınıza uygun agent'ı seçin, yeteneklerini ekleyin ve ilk görevini verin.

01

Ekibinize uygun rolü seçin

Rolleri inceleyin. Günlük işlerinize uygun yapay zeka (AI/SI) çalışanını bulun.

02

İşe alın, araçlarını bağlayın

İhtiyaç duyduğu yetenekleri ekleyin ve erişebileceği verileri belirleyin.

03

İşlerin ilerleyişini takip edin

Agent'ınızın 7/24 yürüttüğü işleri takip edin. İhtiyacınız değiştikçe yeteneklerini güncelleyin.

Kredi kartı gerekmez5 dakikada kurulumİstediğiniz zaman iptal edin