Orkas Orkas
Ana sayfa Blog Mimari
Mimari

Uygulamada Çok Ajanlı Orkestrasyon: Orkas Ana Ajanı ve Alt Ajanlarını Nasıl Çalıştırır?

Orkas'ın çok ajanlı orkestrasyonunun içinde: Ana ajan tek bir isteği plana dönüştürür, alt ajanları bağımlılıklara göre görevlendirir, adımlar arasında bağlam aktarır ve hatalardan toparlanır.

Buradaki önceki makale tek bir ajanı güvenilir kılmayı ele alıyordu: çalışma döngüsü, araç yönlendirme, bağlam sıkıştırma ve çökmeye dayanıklı oturumlar. Bu katman, "tek bir ajan bir görevi aksaklık yaşamadan nasıl tamamlar?" sorusunu yanıtlıyor. Bu makale ise onun üzerindeki katmanla ilgili: tek bir ajan yetmediğinde ve işin bir ekibe dağıtılması gerektiğinde neler olduğu; yani bir ekip.

İnsanların genellikle şu ifadeyle kastettiği budur: çok ajanlı orkestrasyon: konuşmayı yöneten bir lider ajan, isteği parçalara ayırır, her parçayı uzman bir alt ajana devreder, sonraki işe başlamadan önce gerekli ajanların bitirmesini bekler, sonuçları sonraki adımlara aktarır ve bir adım başarısız olduğunda tüm sürecin yolunda kalmasını sağlar. Orkas, bunların tamamını kullanıcının kendi bilgisayarında yürütür. Aşağıda bu orkestrasyon katmanının nasıl kurulduğu anlatılıyor. Kod ayıklanıp genelleştirildi, ancak yapı gerçektir.

Kısa özet Tek bir çalışma alanında bir lider ajan ve alt ajanları Orkas bugün işleri böyle dağıtıyor: Commander uzmanları görevlendiriyor, onları paralel veya sıralı çalıştırıyor; siz de olup biteni izliyorsunuz.
Orkas'ı indirin — ücretsiz

Lider ajan ve alt ajanlar

Bunu net bir komuta zinciri olan küçük bir ekip olarak düşünebilirsiniz. Bir lider ajan (biz ona commander diyoruz) konuşmayı ve genel bağlamı yönetir. Bütün işi kendisi yapmaz; görevi şuna karar vermektir: neyin, hangi sırayla ve kim tarafından yapılması gerektiğine. Diğer üyeler, alt ajanlar ise uzmandır; her biri kendi sistem istemi, izin verilen araçları ve becerileriyle yapılandırılır. Bir alt ajan işin belirli bir bölümünde iyidir ve o bölüm gündeme geldiğinde çağrılır.

Bunu moda bir terim olmaktan çıkaran iki şey var. Birincisi, alt ajanlar ve beceriler birinci sınıf birimlerdir, istem hileleri değildir: alt ajan gerçekten ayrı yapılandırılmış bir ajandır ve ona iş atamak, kendi bağlamı olan gerçek bir devir işlemidir. İkincisi, koordinasyon modelin iyi niyetine bırakılmaz; doğruluğunu modelin değil sistemin koruduğu açık bir yapı tarafından yönetilir. Bu yapı plandır.

Plan bir betik değil, bir graftır

Lider ajan, bir isteğin birden fazla adım gerektirdiğine karar verdiğinde bir planyazar. Plan serbest biçimli bir metin veya doğrusal bir kontrol listesi değildir; küçük bir bağımlılık grafıdır (DAG). Her düğüm bir adımdır ve her adım, orkestratörün onu görevlendirmek için ihtiyaç duyduğu her şeyi taşır:

interface PlanStep {
  index: number;            // 1-based, stable, never renumbered
  title: string;            // human-readable, shown in the UI
  assignee: string;         // who runs it: "user" | "commander" | a sub-agent
  input?: string;           // the dispatch payload — a template (see below)
  wait_for?: number[];      // upstream step indexes; defaults to [index - 1]
  on_failure?: "abort_plan" | "continue" | "ask_commander";

  // --- runtime state, owned by the orchestrator, NOT written by the model ---
  status: "pending" | "in_progress" | "done" | "failed" | "skipped" | "blocked";
  output_summary?: string;  // short summary of what the step produced
  output_files?: string[];  // files the step produced
  failure_reason?: string;
}

Buradaki wait_for alanı, bir listeyi grafa dönüştüren şeydir. Varsayılan olarak bir adım kendinden öncekini bekler (basit bir zincir), ancak bir adım daha önceki birkaç adıma bağlı olduğunu belirtebilir. Örneğin "özetle", hem "pazarı araştır" hem de "rakipleri incele" adımlarını bekleyebilir. Bu bir çizgi değil, elmas biçiminde bir yapıdır ve orkestratör de onu böyle ele alır.

Gerçek durumun sahibi model değil, orkestratördür

Bu yapıdaki ayrıma yeniden bakın. Model, planı ilk yazdığında niyeti — başlıkları, görevlileri, girdileri, bağımlılıkları — doldurur. Ancak şu konudaki her şey: yürütme durumu — status, output_summary, failure_reason — yalnızca orkestratörün kontrolündedir. Model planı bir kez önerir; kendi adımlarını hiçbir zaman "tamamlandı" olarak işaretleyemez.

Bu ayrım bilinçlidir ve tüm tasarımdaki en önemli karardır. Bir dil modeli, 3. adım hata verdiğinde neşeyle "3. adım tamamlandı" diyebilir veya uzun bir konuşmanın ortasında hangi adımların hâlâ beklediğini unutabilir. Durum modelin zihninde tutulsaydı, plan gerçeklikten uzaklaşırdı. Durumu yalnızca yürütücünün yazdığı ve ancak bir adım gerçekten bittiğinde güncellediği yapılandırılmış bir kayıt hâline getirmek, planın gerçekte olup biteni doğru yansıtmasını sağlar. İşin biçimine model karar verir; ilerlemesine ilişkin gerçeği ise çalışma zamanı belirler.

Hazır adımları görevlendirme

Bir plan oluştuğunda küçük bir motor, yani yürütücü, onu ilerletir. Temel işlem "hazır adımları bul ve görevlendir"dir. Bir adım şu durumda hazırdır : hâlâ şu durumdaysa: pending ve beklediği her adım yeterince başarılı sayılan bir son duruma ulaşmışsa:

function findReadySteps(plan): PlanStep[] {
  return plan.steps.filter((s) => {
    if (s.status !== "pending") return false;
    const deps = s.wait_for ?? (s.index > 1 ? [s.index - 1] : []);
    return deps.every((d) => isTerminal(plan.step(d).status)); // done or skipped
  });
}

Bu işlem bir zamanlayıcıyla değil, olaylara yanıt olarak çalışır. Bir adım her bittiğinde — bir alt ajan geri döndüğünde veya commander bir sentez turunu tamamladığında — yürütücü durumu uzlaştırır: az önce biten adımın sonucunu kaydeder, ardından bunun sonucunda hazır hâle gelen adımları yeniden tarar ve görevlendirir. Orkestrasyon, geriye hiç adım kalmayana kadar tekrar tekrar işleyen bu uzlaştırma döngüsüdür.

Görevlendirme yan kanaldan değil, aynı sohbet üzerinden yapılır

Sistemin gerçeğe bağlı kalmasını sağlayan bir tercih var: bir adımı görevlendirmek için gizli bir RPC kanalı kullanılmaz. Kullanıcının izlediği grup konuşmasının tam içine bir mesaj gönderilir, lider ajan tarafından, alt ajan @ ile etiketlenerek. Alt ajan açısından görevlendirilmek, sohbette kendisine seslenilmesinden farksızdır; normal turunu çalıştırır. İlk yürütme yoluyla eşzamanlı tutulması gereken ikinci bir yol yoktur.

Görevli üç türden biri olabilir ve her biri biraz farklı şekilde görevlendirilir:

  • Bir alt ajan — en yaygın durum. Yürütücü, ajanın adını kimliğine dönüştürür ve şu mesajı gönderir: @<agent> <rendered input> commander adına. Alt ajan mesajı alır ve tam bir ajan turu çalıştırır.
  • Kullanıcı — bir adım gerçekten insan girdisi gerektirdiğinde forma dönüşür ve planı duraklatır (aşağıda daha ayrıntılı ele alınıyor). Kullanıcı yanıt verene kadar sonraki hiçbir adım ilerlemez.
  • Commander'ın kendisi — sentez veya karar adımları için ("yukarıdakilerin tamamını oku ve özeti yaz"). Bu, kullanıcıya gereksiz bir mesaj göstermeyen dahili bir uyandırmadır; lider ajan, toplanan bağlamı kullanarak bir tur yürütür.

Bağlamı bir adımdan diğerine aktarma

Bir ekip ancak üyeleri arasında iş akışı varsa faydalıdır. Bunu sağlayan mekanizma input şablonudur. Lider ajan bir adım yazdığında, girdi sabit bir metin değildir; önceki sonuçlara başvurabilir ve yürütücü bu başvuruları görevlendirme anında işler:

// step 3.input, as written by the lead agent
"Using the findings below, draft the launch note.\n\n{{step_1.output_summary}}"

// what the sub-agent actually receives at dispatch time
"Using the findings below, draft the launch note.\n\n- Market is growing ~20% YoY; two incumbents…"

Sonraki adımlara ne aktarıldığına dikkat edin: output_summary, bir kısa bir özet; tamamlanan her adımın tüm konuşma dökümü değil. Bu bir bütçe kararıdır ve ajan yürütme altyapısının bağlam sıkıştırmasıyla aynı düşünceye dayanır. Sonraki her adım, kendinden önceki her şeyin token token tüm geçmişini devralsaydı, yalnızca birkaç aktarımın ardından bağlam şişer ve maliyet patlardı. Özetler her devrin maliyetini düşük tutar ve her alt ajanın, önceki adımların sonuca nasıl ulaştığına dalmak yerine gerçekten ihtiyaç duyduğu bilgilere odaklanmasını sağlar. İlk kullanıcı mesajı ve varsa ekler de taşınır; böylece zincirde üç aktarım ilerideki bir adım bile asıl isteği bilir.

Varsayılan olarak sıralı — peki neden?

Birkaç adım aynı anda hazır olduğunda — örneğin elmas biçimli yapının iki dalı — orkestratörün hepsini paralel başlatmasını bekleyebilirsiniz. Bunu yapabilir; ancak bugün her seferinde tek bir hazır adımı görevlendirir, indeks sırasına göre en öndekini seçer ve diğerlerini sonraki uzlaştırmayı beklemeye bırakır. Bütün bir ekibi kesin biçimde tek tek çalıştırmak bilinçli, temkinli bir tercihtir ve nedenini açıkça anlatmak gerekir.

Sebep, eşzamanlılık altında doğruluğu korumaktır. İki alt ajanın neredeyse aynı anda bittiğini düşünün. Her iki tamamlanma da bir uzlaştırmayı tetikler; iki uzlaştırma da planı okur; ikisi de sonraki aynı adımın hâlâ şu durumda olduğunu görür: pending — ve ikisi de onu görevlendirir. Böylece aynı adım iki kez çalışır. Bunu olanaksız kılmak için belirli bir konuşmadaki her okuma-değiştirme-görevlendirme döngüsü, konuşmaya özel bir kilitle sıralı yürütülür:

// all state-changing paths for one conversation run under one mutex
planLock(uid, cid).runExclusive(async () => {
  const plan = await readPlan(uid, cid);
  applyOutcomeOfFinishedStep(plan);   // mark done / failed / skipped
  await dispatchReady(plan);          // dispatch the next ready step
});

Kilit, "neyin bittiğini kaydet" ve "sırada ne olduğuna karar ver" işlemlerinin bölünmez tek bir birim olarak gerçekleşmesini garanti eder; böylece sonraki bir adım asla iki kez görevlendirilemez. Bu kilit mevcutken adımları tek tek görevlendirmek, doğruluğu açıkça görülen en basit çözümdür. Gerçek paralel dallanma, bu temel üzerine eklenebilecek uygulanabilir bir genişletmedir. Ancak temel, sıralı çalışan ve yarış koşullarından arınmış bir yürütücüdür; asıl mesele de bu öncelik sırasıdır: önce doğru, sonra hızlı.

Bir adımda işler ters gittiğinde

Gerçek bir bilgisayarda harici model API'leriyle çalışırken hata olağandır. Orkestratör de her hatayı aynı şekilde ele almak yerine birkaç duruma ayırır.

Önce hatanın yalnızca şu nitelikte olup olmadığını değerlendirir: geçici — kopan bir bağlantı, istek sınırı, kısa bir aksaklık. Öyleyse ve adım küçük yeniden deneme hakkını henüz tüketmediyse, sessizce şu duruma geri alınır: pending ve sonraki uzlaştırma onu yeniden görevlendirir. (Bu mekanizma üzerinde yer alır ajan yürütme altyapısının çalışma içindeki yeniden denemelerinin; plan ancak ajanın kendi denemeleri tükendikten sonra yeniden görevlendirme yapar ve gerçekten bozuk bir adımın sonsuza kadar döngüye girmemesi için kesin bir üst sınır uygular.)

Hata kalıcıysa, adımın tanımlanmış on_failure politikası ekibin bundan sonra ne yapacağını belirler:

  • abort_plan — bu adım o kadar önemlidir ki onsuz sonraki adımların anlamı kalmaz. Adımı başarısız olarak işaretle ve zincirleme uygula: hâlâ bekleyen her adım şu şekilde işaretlenir: skipped. Plan, eksik bir temel üzerine inşa etmek yerine düzgün biçimde durur.
  • continue — bu adım isteğe bağlıydı. Şu şekilde işaretle: skipped ve sonraki adımların, bu adım hiçbir şey üretmemiş gibi ilerlemesine izin ver.
  • ask_commander (varsayılan) — ne körü körüne iptal et ne de körü körüne devam et. Başarısız olarak işaretle ve ne olduğunu inceleyip karar vermesi için lider ajanı uyandır: farklı biçimde yeniden denesin, başka bir yol izlesin veya durup kullanıcıya sorsun.

Özellikle belirtilmesi gereken altıncı bir durum var: blocked. Bir alt ajan, adımın ortasında yalnızca kullanıcının sağlayabileceği bir şeye ihtiyaç duyduğunu fark edip bir form veya soru gösterebilir. Adım başarısız olmaz; şu duruma geçer: blockedve bütün plan duraklar. Kullanıcı yanıt verdiği anda yürütücü durumu uzlaştırır ve ekip tam kaldığı yerden devam eder. Engellenmiş bir plan bozuk değil, duraklatılmış bir plandır.

Her adım tam bir ajan çalıştırmasıdır

Burada önceki makaleyle bağlantıyı tamamlamakta fayda var. Orkestratör bir adımı alt ajana atadığında, o alt ajan kısıtlanmış bir yordam çalıştırmaz; şunu çalıştırır: ajan yürütme altyapısının tam döngüsünü: kendi akışlı çalışma döngüsünü, kendi araç çağrılarını, sıkıştırma destekli kendi bağlam penceresini ve çökmeye dayanıklı kendi oturumunu. Orkestrasyon açıkça üzerinde yer alır tek ajanlı çalışma zamanının; onun içine asla müdahale etmez. Lider ajan işin biçimine ve devirlerin sırasına karar verir; her alt ajan ise kendisine payı verildiğinde başlı başına eksiksiz bir ajandır.

İki makalenin birbirini tamamlamasının nedeni bu katmanlı yapıdır. Ajan yürütme altyapısı, tek bir ajanı tek bir görev için güvenilir kılar. Orkestratör ise birkaç güvenilir ajanı, herhangi biri için fazla büyük veya fazla çeşitli bir görevi üstlenebilecek bir ekibe dönüştürür.

Fark yaratan birkaç karar

Yürütme durumu orkestratöre, niyet modele aittir. Model planı önerir; adımları tamamlandı, başarısız veya atlandı olarak yalnızca çalışma zamanı işaretler ve bunu ancak gerçekten bir şey olduğunda yapar. Bu tek sınır, planın modelin iyimser tahmini yerine gerçekliğin doğru bir yansıması olarak kalmasını sağlar.

Görevlendirmeyi yan kanaldan değil, aynı konuşma üzerinden yapın. Görevlendirilmiş bir adım, lider ajandan alt ajana gönderilmiş bir mesajdan ibarettir. Tek bir yürütme yolu vardır, eşzamanlılığını kaybedebilecek gizli bir süreç yoktur ve kullanıcı ekibin çalışmasını zaten okuduğu aynı konuşmada izleyebilir.

Adımlar arasında konuşma dökümleri değil, özetler. Her devir, önceki adımların çıktısının kısa bir özetini taşır. Bu, uzun zincirler boyunca bağlam bütçelerini makul tutar ve her alt ajanın önceki ajanın sonuca nasıl ulaştığına değil, ihtiyaç duyduğu bilgilere odaklanmasını sağlar.

Paralellikten önce doğruluk. Konuşmaya özel bir kilit, her okuma-değiştirme-görevlendirme döngüsünü sıralı yürütür ve adımlar tek tek görevlendirilir. Kesin sıralı yürütme, çift görevlendirmeye yol açan yarış koşullarından arınmış olduğu açıkça görülen sürümdür; paralel dallanma ise zaten doğru çalışan bir temelin üzerine eklenecek optimizasyondur.

Sonuç

Orkas'ın orkestrasyon katmanının merkezinde sıra dışı bir algoritma yoktur. Değeri, kararlılıkla korunan birkaç sınırdan gelir: betik yerine bağımlılık grafı olan bir plan; modele değil çalışma zamanına ait yürütme durumu; kullanıcının izlediği aynı sohbet üzerinden yapılan görevlendirme; adımlar arasında özetler hâlinde taşınan bağlam ve doğruluğu eşzamanlılığın önüne koyan bir yürütücü. Her biri kendi başına basittir. Bir araya geldiklerinde tek bir güvenilir ajanı, iş bölümü yapan, işi sonraki adımlara aktaran ve bir parçada sorun çıktığında toparlanan bir ekibe dönüştürürler.

Bu katmanın altındakini merak ediyorsanız şu yazıyı okuyun: tek bir ajanın güvenilir çalışacak şekilde nasıl tasarlandığı. Her ajanın kullanıldıkça gelişmesini sağlayan katmanı merak ediyorsanız şu yazıyı okuyun: Orkas ajanlarının kendi çalışmalarından nasıl öğrendiği. Bu katmanı geliştirmek yerine yönetmek istiyorsanız Orkas bunu şu biçimde sunuyor: açık kaynaklı yapay zekâ ajan orkestrasyonu ve kendi bilgisayarınızda çalışıyor.