Ana sayfa → Teknik
Agent Orchestrator: Zeki Tek Agent Değil, Yönlendirilmiş Akış
Salı 02:40. Gece mutabakat işini agent’a verdik: “dün bankadan gelen dosya ile bizim kayıtlar arasındaki farkı bul, sebebini araştır, sabaha özet bırak.” Sabah gelen özet üç satırdı ve yanlıştı. Log’a baktım: 17 tur, 9 dakika 12 saniye, aynı tool’a arka arkaya 4 çağrı. Model kötü değildi. İş kötü tarif edilmişti: ona bir görev değil, boş bir oda verdik.
- Serbest agent, akışı da modele havale etmektir. Model her turda “şimdi ne yapsam” sorusunu yeniden cevaplar. 17 turluk koşuda 9 tur işi ilerletmedi; sadece durumu yeniden anlamaya çalıştı.
- Orchestrator akışı yazar, modeli boşluklara koyar. Aynı işi 4 adıma böldük: veri çek (kod) → eşleştir (kod) → eşleşmeyenleri sınıflandır (model) → özet yaz (model). 17 tur → 2 tur, 9 dakika → 38 saniye.
- Karar testi üç soru. Girdi sonlu mu? Kuralı bir cümlede yazabiliyor musun? Yanlışın bedeli geri alınabilir mi? İlk ikisi evet ise karar koda aittir; model orada sadece gecikme ve belirsizlik ekler.
- Üç desen yeter. Zincir (sıra belli), yönlendirici (giriş tipi belirsiz), planlayıcı–işçi (adım sayısı girdiye bağlı). Dördüncüsünü icat etmeden önce üçünü dene.
- Dört fren birlikte çalışır. Tur sınırı, token bütçesi, adım zaman aşımı, tekrar koruması. Biri eksikse diğer üçü de bir geceyi kurtarmıyor.
- Akış yazılı değilse koşular karşılaştırılamaz. Aynı soruya iki farklı yol izleyen sistemde “dün neden yavaştı” sorusunun cevabı yoktur. Orchestrator’ın asıl ürünü hız değil, tekrarlanabilirliktir.
Agent döngüsü ne yapıyor?
Şirket içi agent yazısında üç parça vardı: karar veren model, çalıştıran MCP server, ikisini yöneten agent. Agent’ın işi bir döngüydü:
mesajlar = [system_prompt, kullanici_sorusu]
tur = 0
while tur < TUR_SINIRI:
cevap = model.sor(mesajlar, tools) # model karar verir
if cevap.tool_calls:
for cagri in cevap.tool_calls:
sonuc = mcp.calistir(cagri) # MCP calistirir
mesajlar.append(sonuc) # agent biriktirir
tur += 1
continue
return cevap.metin # duz metin geldi: is bitti
Bu döngü rapor sorularında çalıştı: “bugün kaç dolar depozit oldu?” tek tool, tek tur, bitti. Sonra ondan iş yapmasını istedik. Mutabakat işi tek tool değil: dosya oku, kayıt çek, eşleştir, farkı sınıflandır, özet yaz. Beş adım. Döngüye tekrar baktığımda şunu fark ettim: adımların sırası hiçbir yerde yazmıyor. Sırayı her turda model seçiyor, üstelik önceki turları hatırlayarak değil, önüne konan mesaj yığınını baştan okuyarak.
Sahadan: 17 turluk gece
O gecenin log’unu tur tur çıkardım. 11 tool’u olan bir agent, tek bir istekle: “dünün mutabakat farkını bul, sebebini araştır, özet bırak.”
| Tur | Model ne yaptı | Değerlendirme |
|---|---|---|
| 1–2 | banka_dosyasi_oku, islem_listesi | Doğru başlangıç |
| 3 | islem_listesi yeniden, bu kez farklı tarih aralığıyla | İlk aralık dünü kapsamıyordu; model fark etti, düzeltti. Değerli tur |
| 4–7 | Eşleştirmeyi kendi kafasında yapmaya çalıştı; 2.300 satırı metin olarak taşıdı | Boşa tur. Bu iş JOIN, model işi değil |
| 8 | bakiye_getir | İlgisiz. Mutabakat farkıyla ilgisi yok |
| 9–12 | islem_detay 4 kez, 4 farklı referansla | İkisi aynı referans. Tekrar koruması olmadığı için ikisi de çalıştı |
| 13–15 | Özet yazmaya başladı, yarıda kesip yeniden veri çekti | Context dolmuştu; ilk turlar kaymıştı (ayrı yazının konusu) |
| 16–17 | Üç satırlık özet | Rakamlar 4–7. turlardaki yarım eşleştirmeden geldi: yanlış |
Toplam: 17 tur, 9 dakika 12 saniye, 11 tool çağrısı, ikisi birebir aynı. 9 tur işi ilerletmedi. Ertesi gece aynı istekle tekrar çalıştırdım: bu kez 12 tur ve başka bir yol. Cevap yine yanlıştı ama başka bir sebepten. Beni asıl rahatsız eden bu oldu: iki koşu karşılaştırılamıyordu. Düzeltecek bir şey yoktu, çünkü düzeltilecek bir akış yoktu.
Kararı kim vermeli: model mi, kod mu?
Akışı yazmaya oturduğumda her adım için tek soru sordum: bu kararı model mi vermeli? Soru zamanla üç maddelik bir teste dönüştü.
| Soru | Evet ise | Hayır ise |
|---|---|---|
| Girdi sonlu ve tanımlı mı? (tarih, tutar, enum) | Kod | Model adayı |
| Kuralı bir cümlede yazabiliyor musun? | Kod | Model adayı |
| Yanlış kararın bedeli geri alınabilir mi? | Model çalışabilir | Model + insan onayı |
Mutabakat işinde bu test şunu verdi:
- “Dün” hangi tarih aralığı? Sonlu, kuralı tek cümle: iş günü 00:00–23:59, Europe/Istanbul. Kod. O gecenin 3. turu bu yüzden vardı; kodda olsa hiç olmayacaktı.
- 2.300 kayıt ile 2.287 kaydı eşleştir. Referans numarası, tutar, tarih. Kod. Bir
JOINve bir tolerans eşiği. Modelin 4 turu buna gitti. - Eşleşmeyen 13 kaydın sebebi ne? Serbest metinli açıklama alanı var: “MT103 ref hatalı”, “müşteri iadesi”, “komisyon farkı”. Kuralı tek cümlede yazamıyorum; bugün 13 satır, yarın başka bir ifade. Model.
- Sabah bırakılacak özet. Doğal dil, sabit kalıp yok. Model.
- Fark 5.000 $’ı geçerse gece nöbetçisini ara. Eşik karşılaştırması. Kod — ve bedeli geri alınamaz olduğu için sınırı da kod tutar, model değil.
Üç desen
1. Zincir: sıra belli
Adımlar ve sıraları sabit; her adım bir öncekinin çıktısını alır. Mutabakat işi bu. Model iki adımda var, diğerlerinde yok.
# akis.py - sira kodda yazili, modelde degil
def gece_mutabakati(tarih):
dosya = banka_dosyasi_oku(tarih) # kod
kayit = islem_listesi(tarih) # kod
fark = eslestir(dosya, kayit, tolerans=0.01) # kod: JOIN
if not fark:
return "Fark yok."
etiket = model_sinifla(fark) # model: 13 satir, serbest metin
if fark.toplam > 5000:
nobetci_ara(fark) # kod: esik karari
return model_ozet(fark, etiket) # model: dogal dil
Buradaki model_sinifla ve model_ozet birer agent değil, birer
çağrı: döngü yok, tool yok, girdi sınırlı. Beş adımlık işin üçü zaten kod; kalan ikisi de
tek turluk.
2. Yönlendirici: giriş tipi belirsiz
Chat ekranına gelen sorunun ne olduğu belli değil: rapor sorusu mu, mutabakat isteği mi, KYC sorgusu mu? Burada model bir kere karar verir — hangi akışa gideceğine — sonra akış devralır.
- Yönlendirici tek turdur ve çıktısı kapalı bir kümedendir:
rapor,mutabakat,kyc,bilinmiyor. - “Bilinmiyor” gerçek bir seçenek olmalı. Yoksa model en yakın kutuya zorla atar; bizde ilk hafta 3 soru yanlış akışa gitti, üçü de kapalı küme dar olduğu için.
- Yönlendirici yanlış seçerse bedel bir adımdır, tüm koşu değil: akış “bu veri bende yok” deyip geri döner.
3. Planlayıcı–işçi: adım sayısı girdiye bağlı
“Geçen ay reddedilen tüm çekimleri sebep sebep incele” dediğinde kaç adım gerektiğini önceden bilemezsin: 4 sebep de olabilir, 40 da. Burada model bir plan üretir, kod planı çalıştırır.
- Plan bir veri yapısıdır, serbest metin değil: adım listesi, her adımda tool adı ve argümanlar.
- Kod planı doğrular: tool var mı, argümanlar tipinde mi, adım sayısı sınırın altında mı (bizde 12). Geçersiz plan çalıştırılmaz, modele bir kez geri verilir.
- İşçiler planı çalıştırır; paralel çalıştırmanın ne zaman kazandırdığı ayrı yazının konusu.
- Plan koşu başında kaydedilir. Koşu yarıda kalırsa kaldığı adımdan devam eder, en baştan başlamaz.
| Desen | Ne zaman | Modelin rolü | Risk |
|---|---|---|---|
| Zincir | Sıra sabit | 1–2 adımda, tek tur | Yok denecek kadar az |
| Yönlendirici | Giriş tipi belirsiz | Tek seçim, kapalı küme | Yanlış kutu; bedeli bir adım |
| Planlayıcı–işçi | Adım sayısı girdiye bağlı | Plan üretir, çalıştırmaz | Uzayan plan, artan maliyet |
| Serbest agent | Keşif, tek seferlik analiz | Her turda akışı seçer | Tekrarlanamaz koşu, sınırsız maliyet |
Son satırı silmedim, çünkü serbest agent yanlış bir şey değil. Yanlış olan onu gece işinde kullanmak. Keşif yaparken — “bu veride ne var?” — başımda dururken serbest agent iyi çalışıyor. Her gece 02:40’ta kimse başında değil.
Dört fren
Yönlendirilmiş akış da bir yerde modele soruyor; model de yanlış cevaplayabiliyor. Frenler bu yüzden akışın kendisinde durur, model prompt’unda değil.
ADIM_TUR_SINIRI = 3 # bir adim icinde model kac kez tool isteyebilir
KOSU_TUR_SINIRI = 8 # tum kosuda toplam tur
KOSU_TOKEN_BUTCE = 120000 # asilirsa kosu durur
ADIM_TIMEOUT_SN = 45 # tek adim icin
# tekrar korumasi: ayni tool + ayni argumanlar
# 2. cagri -> onbellekten don, tur sayma
# 3. cagri -> adimi hata ile bitir
Dördü birlikte çalışır, çünkü her biri başka bir çöküşü yakalar:
- Tur sınırı döngüyü keser. Tek başına yetmez: 8 tur içinde 400 bin token yakabilirsin.
- Token bütçesi maliyeti keser. Tek başına yetmez: 3 turda 2 dakika bekleyen bir tool zinciri bütçeyi aşmadan geceyi yer.
- Adım zaman aşımı asılı kalmayı keser. Tek başına yetmez: hızlı ve yanlış dönen döngüyü görmez.
- Tekrar koruması aynı yere üçüncü kez gitmeyi keser. O gece 9–12. turlarda iki birebir aynı çağrı vardı; bu fren onları tek çağrıya indirirdi.
Fren devreye girdiğinde koşu sessizce bitmez. Kaydedilen üç şey: o ana kadarki kısmi sonuç, hangi frenin yakaladığı, son adım ve argümanları. Sabah gelen mesaj “beceremedim” değil, “3. adımda tur sınırına takıldım, elimde şu 13 kayıt var” oluyor.
Sahadan: aynı iş, dört adım
Akışı yazdıktan sonraki hâli. Aynı gece işi, aynı model, aynı tool’lar:
| Adım | Kim | Süre | Not |
|---|---|---|---|
| 1. Dosya + kayıt çek | Kod | 6 sn | Tarih aralığı kodda; tartışma yok |
| 2. Eşleştir | Kod | 0,4 sn | 2.300 × 2.287, tolerans 0,01; 13 eşleşmeyen |
| 3. Sınıflandır | Model | 21 sn | 13 kayıt, tek tur, kapalı etiket kümesi (5 etiket + diger) |
| 4. Özet yaz | Model | 11 sn | Girdi: 13 kayıt + etiketler. Ham 2.300 satır modele hiç girmedi |
| Toplam | — | 38 sn | 2 model turu; 9 dk 12 sn → 38 sn |
İki hafta boyunca her gece koştu. 14 koşunun 13’ü aynı 4 adımı izledi; biri 3. adımda zaman aşımına düştü (model sunucusu yeniden başlamıştı), kısmi sonuç kaydedildi, sabah 2 dakikada elle bitirdim. Asıl kazanç süre değil: artık “dün neden yavaştı” sorusunun cevabı var, çünkü karşılaştırılacak sabit bir akış var.
- Akışı kodda yaz; modele yalnızca kuralı yazılamayan adımları ver.
- Model çıktısını kapalı kümeye zorla: etiket listesi, JSON şeması, enum.
- Her koşuya bir kimlik ver; adımları, süreleri ve token’ı kaydet.
- Frenleri koda koy, prompt’a değil. Dördünü birden.
- Kısmi sonucu sakla; yarıda kalan koşu kaldığı adımdan devam etsin.
- Geri alınamaz adımı (para, mail, silme) insan onayına bağla.
- “Sırayla şunları yap” diye prompt’a adım listesi yazmak. Sıra koda aittir.
- 2.300 satır ham veriyi modele göndermek. Eşleştirme kod işi.
- Tur sınırını tek fren sanmak.
- Gece çalışan bir işi serbest agent’a bırakmak.
- Modelin ürettiği planı doğrulamadan çalıştırmak.
- Fren yakalayınca koşuyu sessizce bitirmek.
Ne izlemeli?
- Koşu başına tur sayısı (p50 / p95). Dağılım genişse akış yazılı değil demektir. Bizde 2 / 3.
- Adım başına model çağrısı. 1’in üstüne çıkan adım aslında iki adımdır; böl.
- Fren tetiklenme oranı. %0 ise frenler gevşek, kimse fark etmeden pahalanıyorsundur; %10’u geçiyorsa akış yanlış.
- Aynı girdiye aynı yol oranı. Tekrarlanabilirliğin tek sayısı. Bizde 13/14.
- Koşu başına token ve süre. Görev başı maliyetin girdisi; adım kırılımıyla tut.
- İnsana düşen koşu oranı. Artıyorsa modelden fazla şey isteniyordur; azalan bir eğri beklenir.
Kontrol listesi
- Bu işin adımlarını kâğıda yazabiliyor muyum? Yazamıyorsam model de yazamaz.
- Her adım için üç soruyu sordum mu: girdi sonlu mu, kural tek cümle mi, bedel geri alınabilir mi?
- Modele giden adımların çıktısı kapalı bir kümede mi, serbest metin mi?
- Hangi deseni kullanıyorum: zincir, yönlendirici, planlayıcı–işçi? Neden diğeri değil?
- Yönlendiricide “bilinmiyor” seçeneği var mı?
- Dört fren de kodda mı: tur, bütçe, zaman aşımı, tekrar?
- Fren yakalayınca ne kaydediliyor? Sabah bakan kişi nereden devam edecek?
- Aynı girdiyle iki koşu aynı yolu izliyor mu? İzlemiyorsa hangi adım belirsiz?
- Geri alınamaz adım hangisi? Onu kim onaylıyor?
- Koşu yarıda kalırsa baştan mı başlıyor, kaldığı yerden mi?
Sonuç
O gece 17 tur döndü, 9 dakika harcadı ve yanlış bir özet bıraktı. Model kötü olduğu için değil; ona görev yerine boş bir oda verdiğimiz için. “Mutabakat farkını bul” bir cümle, beş adım. Beş adımın üçünün kuralı belliydi ve biz o üçünü de modele sordurduk.
Yönlendirilmiş akışta aynı iş 38 saniye sürüyor, iki model turu içeriyor ve her gece aynı yolu izliyor. Hızlanması güzel; asıl değişen, ölçülebilir olması. Yanlış çıkarsa hangi adımda yanlış çıktığını biliyorum ve o adımı düzeltiyorum. Serbest agent’ta düzeltecek bir adım yoktu.
Akılda kalacak cümle şu: agent’ın zekâsı, akışı yazdıktan sonra başlar. Kuralını yazabildiğin her şeyi koda yaz, kalanını modele bırak; frenleri de modele değil akışa koy. Geriye kalan boşluk, modelin gerçekten iyi olduğu yerdir.