Bu makale, programlanabilir ajan orkestrasyonu için VM'imiz olan Onyx'i tanıtıyor. Ve bunun bir uzantısı olarak, orkestrasyonu yazılım mühendisliğine dönüştüren bir çalışma zamanını. Bu makalenin sonunda, VM'i oluştururken yapılan kısıtlamaları ve tasarım kararlarını ve ayrıca kendi programlarınızı nasıl oluşturacağınızı ve ajan sistemlerinizi nasıl mimari edeceğinizi anlayacaksınız.
Giriş
Ajanlar doğası gereği deterministik değildir. Bütün mesele bu. Determinizm isteseydiniz, yazılım yazıyor olurdunuz.
Ama yol boyunca bir yerde, ajanları kullanan herkes toplu olarak onları daha da ileriye taşımak istedi. Yürütmeyi yapılandırılmış adımlara ayırmanın performansa yardımcı olduğunu öğrendik: Planla, Uygula, İncele, QA vb. Ardından, her bir ajana yön vermek, aralarında bağlam paylaşmak ve onları güvenlik altına almak için komut dosyaları, araçlar ve beceriler yazmakta görünüşte anlaştık. Daha sonra bu komut dosyalarını ajanlar arasında metin aktararak birbirine yamalıyoruz ve sadece metin aktardığımız için bir şekilde çalışıyor.
Sorun üzerinde yeterince zaman harcadıysanız ve özellikle zekiyseniz, belirli bir duruma dayalı koşullu yürütmeye sahip olabilmeniz için sisteminizden nasıl garantiler alacağınızı çözmüş olurdunuz. Ve muhtemelen bu durumu, bash komut dosyalarınıza yön vermek için ayrıştırılabilir bir işaretleme dosyasında veya dosya grubunda saklardınız. Ajanlarınızın kullanması için özel bir cli bile oluşturmuş olabilirsiniz.
Mühendisler olarak bu bize tanıdık geliyor, yazılım mühendisliği yaparken komut dosyaları kullanıyoruz. Ancak modern yazılım, bash komut dosyalarını ve cli araçlarını zincirleyerek oluşturulmuyor. Bunun yerine, sistemlerimizi mimari etmemize yardımcı olacak programlama dillerine, çalışma zamanlarına ve araç zincirlerine sahibiz. Yazılımı programlama dilleriyle yazıyoruz çünkü bunlar standart bir kitaplık, net bir anlambilim ve güvenebileceğimiz bir yürütme modeliyle birlikte gelir. Tüm ihtiyaçlarımız için araç zincirleriyle zengin ekosistemlere sahiptirler.
Sistemlerimiz hakkında bize verdikleri garantiler, daha yüksek soyutlama seviyelerinde akıl yürütmemizi sağlar.
Ancak ajan sistemlerini mühendislik etmek için eşdeğer bir şey yok. Sistemler oluşturmak için, Ajan orkestrasyonunun, modern yazılımla tamamen aynı şekilde programlanabilir olması gerekir.
Bugün, PROGRAMLAR (*.program.ts) ve deterministik ajan orkestrasyonu için oluşturulmuş VM'imiz Onyx için spesifikasyonu tanıtıyoruz. Bu makale, bir ajan orkestrasyonu tarihçesini, bir programı çalıştırabilen bir VM'in statik ve çalışma zamanı anlambilimini ve bunun alanın nereye gittiği üzerindeki etkilerini araştırıyor.
Kulağa pahalı geliyor, ama aslında öyle değil. Bunu makalenin ilerleyen kısımlarında açıklıyorum.
Merak edenler için, Andrej Karpathy'nin Autoresearch projesinin bir program olarak görünümü şöyle:

Ajan Orkestrasyonunda Çözülmemiş Problemler
Bir ajan orkestrasyonu çalışma zamanının neleri içermesi gerektiğini anlamak için, ajanların sınırlamalarını anlamamız gerekir.
Bir llm ajanı, bir döngü içinde bir ayrıştırıcıya beslenen ve ardından araç çağrılarını bir ortama gönderen bir json akışı oluşturucu olarak düşünülebilir.
Her araç çağrısı tamamen aynı dış şema şekline sahiptir, ancak bu çıktı akışının içeriği deterministik değildir.
Determinizm ve deterministik olmamanın birleşimi, ajanları bu kadar değerli kılan şeydir. Eylem dizilerini benzersiz şekillerde zincirleyecek kadar esnektirler, ancak araç çağrıları aracılığıyla bir bilgisayarla etkileşime girecek kadar deterministiktirler.
Bu akışın içeriğinin türlendirilmesi gerekliliğinden vazgeçmeye istekliyseniz, birleştirilebilirlik neredeyse ücretsizdir. Modeller, onlara sağladığımız raylar (istemler, mesajlar ve araç çağrıları) içinde metin girip çıkarmak için yeterince iyidir.
Bu, çok birleştirilebilir bir arayüzü ortaya çıkarır: metin
Metin evrensel bir arayüzdür. Bir bilgisayardaki her şey, sadece makine kodu olsa bile metne serileştirilebilir. Bir llm'den bu evrensel arayüz aracılığıyla metin girişi ve çıkışı alabiliyorsanız, metin akışları üzerinde birleştirilebilirlik elde edersiniz.
Bu, ajan davranışınızın güvenilirliğinin, modelden gelen çıktının tutarlılığıyla doğrudan ilişkili olduğu anlamına gelir. Yüksek çıktı değişkenliği, daha düzensiz ajan davranışı anlamına gelir.
Parçaları birleştirecek bir arayüze sahip olduğunuzda, dikkate almanız gereken bir sonraki kısıtlama yönlendirilebilirliktir :
ajanın ne yapmasını istediğiniz ve onu istediğinizi yapması için nasıl tutarlı bir şekilde sağlarsınız
Ajanları, örneklem aldığı dağılımı değiştirerek, yani istemleyerek yönlendiririz.
2022'de ReAct ortaya çıktı ve esasen ajan yönlendirilebilirliğine öncülük etti. Aslında, bildiğimiz şekliyle ajanları bir şey haline getirdiğini söyleyebiliriz. Sonraki bir adımı atmadan önce bir araç çıktısı hakkında düşünmek ve akıl yürütmek, döngüyü tutarlı tutan şeydir.

Hala ajanların daha akıllı olmasına ihtiyacımız vardı. @OpenAI tarafından üretime alınan test zamanı hesaplama ölçeklendirmesinin kullanımı, model laboratuvarlarına daha iyi ajan davranışı yerleştirme yeteneği verdi [[11]](http://localhost:5173/blog/onyx#ref-11). Bir aracı çağırmadan önce daha fazla token çıktısı almak, modelin, akıl yürütme çıktı uzunluğu konusunda kısıtlanmış olsaydı takılıp kalacağı çıktı dağılımından kaçmasına olanak tanır. Modelin çıktı dağılımı manzarasında nasıl gezindiğini eğitmeyi seçebilir ve bu nedenle önemsediğiniz görevlerde daha net ajan benzeri davranışlar konusunda eğitim özgürlüğüne sahip olabilirsiniz.
Bağlam uzunluğu sınırsız bir şekilde büyüdükçe, ajanı yönlendirmek zorlaşır ve görevin tamamlanma olasılığı azalır. Bir akıl yürütme modeliyle bile, kurtarma garantisi yoktur ve ajan tam orada ölür. Ajan, bağlam sınırına ulaşabilir, erken tamamlama bildirebilir, bir döngüye takılıp kalabilir, vb.
Deterministik Olmayan Bir Sistemden Garantiler Çıkarmak
Bunun için çözümler çeşitliydi, ancak bir tanesi öne çıkıyor: Ralph Döngüsü, @GeoffreyHuntley tarafından yapıldı. [[3]](http://localhost:5173/blog/onyx#ref-3
Ajan yürütmesini sınırlayabileceğiniz ve ardından görev tamamlama hakkında akıl yürütmek için bu sınırları kullanabileceğiniz fikrini ortaya attı. Bu, Ralph Döngüsü'nün büyülü bir şey yapmasını sağlar: deterministik olmayan bir sistemde güvenebileceğiniz bir şey sağlar.
Bir determinizm kıvılcımı.
Bir kere daha slot makinesi kolunu çekmektense, başarısızlığı garanti etmek ve kademeli olarak doğruya doğru ilerlemek daha iyidir. Bu tanımlanmış sınır, size üzerinde düşünebileceğiniz somut bir şey verir ve bir şeyin sınırları hakkında akıl yürütebildiğinizde, ondan bir sistem yapabilirsiniz.
Bağlam Uzunluğunun Sınırlarıyla Mücadele
Bir sorun var ama, yeni bir ajan çalıştırmalar arasında tutarlılığını kaybederken, tek bir ajan yeterli zaman verildiğinde bağlamı tüketir.
@lateinteraction @a1zhang tarafından RLM ile tanışın. RLM bize uzun bağlamla (yani bir ajan çalıştırmasıyla) yapılandırılmış bir şekilde nasıl etkileşim kuracağımız konusunda bir konsept verdi [[4]](http://localhost:5173/blog/onyx#ref-4). RLM, işlemleri düzenlemek için kod kullanımını gösteren 2024 tarihli bir makale olan CodeAct'ten ilham aldı [[5]](http://localhost:5173/blog/onyx#ref-5). Ajan, bir REPL içinde işlemleri düzenleyen ve ardından bir çıktı almak için çalıştırılan komut dosyaları yazar. RLM, bağlamı depolamak ve bu bağlam üzerinde işlemler yapmak için değişkenler kullanması ek koşuluyla aynı şekilde çalışır. Ayrıca REPL'de özyinelemeli LLM çağrılarına izin verir. Diğer döngülerin sahip olduğu bazı tepkiselliği kaybedebilirsiniz, ancak bağlamla programlı bir şekilde çalışma yeteneği kazanırsınız. Buradaki kilit nokta, REPL'deki komut dosyalarının geçici olmasıdır. Bir komut dosyası çalıştırma zamanı ve bağlam yönetimi elde edersiniz, ancak yeniden kullanılabilirlik veya birleştirilebilirlik yoktur. Sadece komut dosyasını yazın, çalıştırın ve kaybolur. Sistemler oluşturma açısından bu, kalıcılık ve sınırlı yürütme kaybettiğiniz için ajanları ve işaretleme dosyalarını bash komut dosyalarıyla birbirine zincirlemekten kesinlikle daha kötüdür.
Bireysel Döngülerden Orkestrasyonu Ölçeklendirmeye Geçiş
OpenAI'ın Deep research[[6]](http://localhost:5173/blog/onyx#ref-6), çalıştırma başına küçük değişkenlikle genel bir yürütme şekline veya şemasına sahip deterministik bir iş akışının en erken örneklerinden biriydi. Çalışma şekli, bir dizi sorgu planlamak, bunları web'de çalıştırmak, sonuçları incelemek ve bir sonraki sorgu grubunu planlamaktır. Her grup, problem alanının daha derinlerine iner.

Cursor, @wilsonzlin bir tarayıcı oluşturmak için ajanları düzenleyen bir koşum takımı gösterdiğinde determinizm fikrini çok daha ileri götürdü. Paralel planlayıcı ajanlar ve görev ajanları kullanarak büyük miktarda işi koordine etmek için özel bir koşum takımı oluşturdu [[7]](http://localhost:5173/blog/onyx#ref-7). Burada önemli olan, koşum takımının her bir parçası arasındaki ilişkinin sabit olmasıdır. Mevcut sistem durumunu keşfeden ve görevler oluşturan planlayıcılar ve görevleri alıp paralel olarak uygulayan yürütücüler vardır. Ajanlar arasında sabit güvenlik korkulukları ve bilgi iletmek için sabit kanallar vardır. Koordinasyonu iyi yapmak için arayüzlerde garantilere ihtiyacınız vardır.
Sınırlı Yürütme için Sonlandırma Koşullarını Kullanma
Mayıs ayında Codex, bir görev tamamlanana kadar istenen bazı son duruma karşı tepe tırmanışı yapmak için bir doğrulayıcı döngüsü kullanan bir hedef fikrini tanıttı. Bunu, codex'in içine yerleştirilmiş, Ralph döngüsünün üretime hazır bir versiyonu olarak düşünebilirsiniz. Bir hedef belirlemenize olanak tanır ve yerleşik, yürüten ve inceleyen otomatik bir döngüye sahiptir.

Karpathy'nin autoresearch[[9]](http://localhost:5173/blog/onyx#ref-9) projesi, Codex'in /goal'ine ve Ralph döngüsüne benzer. Goal'in doğrulanabilir sonlandırma koşulunu, Ralph döngüsünün yinelemeler üzerindeki yürütme sınırlamasıyla birleştirerek sürekli olarak bir hedefe doğru ilerlemesini sağlar. Fikir alanını arayarak, zaman içinde yinelemeli olarak iyileştirerek ilerleme kaydeder.

Bu noktaya kadar, orkestrasyonu ajanın dışına çıkaran tüm çözümler, yürütme grafiği şekillerinde sabittir. Elle yazılmış bir desen kullanarak çalışırlar ve çalışabilecekleri izin verilen şekiller için bir tür şemaya sahiptirler. Görev başına uyum sağlamazlar veya yürütme grafiği şekli üzerinde güçlü garantilere sahip değildirler.
Orkestrasyonu Esnek Hale Getirmek
Bu yılın Mart ayında, canlı alt ajan orkestrasyonu için RLM tarzında kod kullanan ilk kodlama ajanı olan Slate'i tanıttık. Hala canlı ajan orkestrasyonu için kod kullanan, iyi kullanılan tek kodlama ajanıdır. Slate'te, iş parçacıkları gerçek zamanlı olarak oluşturulabilir, duraklatılabilir, devam ettirilebilir ve yönlendirilebilir. Ana ajan, çalışan tüm alt ajanları nasıl düzenleyeceğini derinlemesine anlar, böylece sizin yapmanıza gerek kalmaz. Bununla birlikte, RLM'ye benzer şekilde, hala alt ajanlar arasında durum paylaşımı ve geçici komut dosyası oluşturma zorluğuyla karşı karşıyaydık, ki bu bir bash komut dosyası ve bir işaretleme dosyası kullanırken karşılaşacağınız bir şey değildir.
Yine de, orkestrasyonu yapan modelse, onu nasıl yönlendirirsiniz? Orkestrasyon kodunu belirli bir şekilde yazmasını mı söylersiniz? Ne yaparsınız?
(Onyx çalışma zamanını yayınlamadan önce bir yama olarak) ilk çözümümüz orkestrasyon becerileri olarak adlandırıldı [[13]](http://localhost:5173/blog/onyx#ref-13). Fikir basitti, kullanıcının ajana orkestrasyonuna nasıl yaklaşacağı konusunda yön vermek için bir beceri sağlamasına izin vermek. Bu kadar. İyi çalıştı, ancak birçok sorunu vardı.
Yani, bir beceri bağlayıcı bir davranış sözleşmesi değildir. Metinden garanti alamazsınız.
Bu, orkestratörün istenen yürütme modelini takip etmek zorunda olmadığı anlamına geliyordu çünkü bunu uygulamanın gerçek bir yolu yoktu. Onyx çalışma zamanının en büyük faydalarından biri, bu sorunu çözmüş olmamızdır.
Bahsedilen sistemlerin hiçbirinde bağlayıcı davranış sözleşmeleri yoktur.
Peki ya ajan, orkestrasyon kodunu görev başına bir komut dosyasına yazabilseydi, böylece yürütme grafiği sabitlenmiş olurdu? Claude dinamik iş akışları budur.[[10]]([http://localhost:5173/blog/onyx#ref-10)[[12]](http://localhost:5173/blog/onyx#ref-12](http://localhost:5173/blog/onyx#ref-10)[[12]](http://localhost:5173/blog/onyx#ref-12) RLM ve Slate ile aynı tarzda, alt ajanları düzenlemek için kod yazarak, dinamik iş akışları Claude'un iş akışı şekillerini yazmasına ve kaydetmesine olanak tanır. Bu, belirli modeller üzerinde döngü yapabilmek için /loop ile birleşir. Bir dizi ajanın davranışı için bildirimsel bir sözleşme sağlar. Yine de, işlevsel kompozisyon gibi şeylerden yoksun olduğu için yazılım yazmakla aynı şey değildir, ancak kalıcılık ve görevin nasıl yürütüleceği konusunda güçlü bir garanti elde edersiniz. Bunlar, belirli bir görev için geçici olarak dinamik olarak yazılmış iş akışı komut dosyalarıdır.[[12]](http://localhost:5173/blog/onyx#ref-12) Ve diske kaydedildikleri için ek bir faydaları daha vardır: yeniden çalıştırılabilirler ve /loop gibi orkestrasyon yapıştırıcısıyla sarılabilirler.

Fark ederseniz, yukarıdaki çözümlerin tümü aynı şeyi hedefliyor: ajanların zaman içinde nasıl yürütüleceğini kontrol etmenin deterministik bir yolu.
Bu, yazılım mühendisliği alanında daha önce yaşanmış bir hikaye. Farklı sistemleri birbirine yapıştırarak ve işleri komut dosyalarıyla yazarak başladık ve ardından dillerimiz daha esnek ve güçlü hale geldi. Daha güçlü ekosistemlerle mühendislik süreci üzerinde giderek daha fazla kaldıraç elde ettik ve bu da daha yüksek soyutlama seviyelerinde daha güvenilir sistemler kurmamızı sağladı.
Şu anda, ajanlar aynı yörüngede ve bugün, ajanlarınızı çalıştıran sistemleri mühendislik etmenize izin vermek için bu yörüngedeki bir sonraki adımı yayınlıyoruz. Programlama dilleri, kaynakları otomatik olarak planlamak için genellikle yorumlayıcılar veya VM'ler kullanır. Dili kullanan bir mühendis olarak size kaldıraç sağlayan şey budur.
Bir VM'in ajan orkestrasyonu için anlamlı olması için birkaç şeye ihtiyacınız olurdu:
- Kalıcı durum yönetimi: durumu tanımlayabilmeli, ada göre referans alabilmeli, kalıcı hale getirebilmeli ve programlı olarak değiştirebilmeliyiz.
- Tür garantileri. Tanımlanmış girdi ve çıktı şekillerine saygı göstermeli ve bunları takip etmeli ve onlara güvenebilmeliyiz.
- Kontrol akışı temelleri, tercihen bir LLM'nin anlayacağı iyi bilinenler.
- Hata işleme için net yapı (ör. dene-yakala).
- Kaynak yönetimi: ajan paralelliği, maliyet, hangi modellerin çalıştığı vb. gibi kaynaklar üzerinde tanımlanmış kontroller.
- Yürütme Yalıtımı: Çalışan belirli bir ajan veya program, durum açıkça paylaşılmadıkça diğerinden izole edilmelidir.
- Yaşam döngüsü kontrolü: bir ajan programının neye benzediği ve çalıştırma, iptal etme ve yönlendirme anlambilimi. Bu olmadan, temizlik için net bir yolunuz olmaz ve yaşam döngüsü yönetimini kontrol edemezsiniz.
- Birleştirilebilirlik: Programlar birbirleriyle birleşebilmeli ve tanımlanmış girdi ve çıktı türleriyle çağrılabilmelidir.
- Görünürlük: Ne zaman neyin çalıştığını bilmeli ve kaynaktaki bir yürütme hatasını geriye doğru izleyebilmeliyiz.
- Dayanıklılık: Çökmelerden nasıl kurtulabileceğimiz ve devam edebileceğimiz konusunda net bir modele sahip olmalıyız.
Bunların her biri, onlarca yıl önce programlama dilleri tarafından zaten çözülmüş bir problemdir. Ajan orkestrasyonu, ilk kez hepsine tekrar çarpıyor.
Bunun için gerçekten yazılım yazabilmek için, bir "program.ts" programı, yukarıdakilerin tümünü destekleyen bir çalışma zamanında yazılmalıdır, böylece bir program çalışmadığında ne olacağı hakkında akıl yürütebilir ve başarısızlığın etrafından mühendislik yapabiliriz.
Bu yüzden Onyx'i oluşturduk. Hem kalıcı birleştirilebilir programları hem de yorumlanmış bir komut dosyası katmanını desteklemek için hassas bir şekilde tasarlanmış bir ajan orkestrasyonu VM'idir. İşte nasıl çalıştığı ve bir "program.ts" uyumlu çalışma zamanının neleri desteklemesi gerektiği.
Çalışma Zamanını Tasarlamak
Bir dil ve o dil için bir çalışma zamanı tasarladığımızda, üzerinde akıl yürütebilmek istediğimiz kısıtlamaları ve kolayca ifade edilebilir olmasını önemsediğimiz şeyleri düşünmemiz gerekir. Ardından, ortaya çıkan anlambilimi iki kategoriye ayırabiliriz: statik anlambilim ve çalışma zamanı anlambilimi.
Statik anlambilim, bir programa sadece bakarak çıkarılabilecek tüm şeylerdir. Bir derleyicinin veya tür denetleyicisinin belirli bir program hakkında bildiği şeyler.
Çalışma zamanı anlambilimi, kodun gerçekte ne anlama geldiğini ve programın gerçekte nasıl çalıştığını tanımlar. Bu, temel kaynak tahsisi ve planlama mekaniğini içerir.
Ajanlar için bir çalışma zamanı hedefimiz, orkestrasyon kontrol akışını koda dönüştürmek ve yürütme durumunu kalıcı ve türlü hale getirmek istiyoruz, böylece orkestrasyonu yönlendirmek için güvenilir bir şekilde kullanabiliriz.
Birkaç VM Gereksinimi
Normal TypeScript yürütmesinin ötesinde, önemsediğimiz VM'e özgü 3 şey vardır.
- Bir ajan orkestrasyonu çalışma zamanı olarak, ajanları düzenleyebilmelidir. Bu, onları oluşturmak, yaşam döngülerini takip etmek vb. anlamına gelir. Çalışma zamanının, onları bloke eden veya bloke etmeyen bir şekilde çalıştırabilmesini ve doğru şekilde planlayabilmesini istiyoruz.
- Ajanların çıktı şekilleri üzerinde kontrole sahip olmak ve sıkı çıktı sözleşmesi uygulaması istiyoruz.
- Modeller ve maliyet gibi harici kaynaklar üzerinde çalışma zamanı kontrolüne sahip olmak istiyoruz.
Ajanları ve Programları Çalıştırma
Bir ajana çalıştırmak için iki temel fiil seçtik: run ve spawn. Run, ön planda bloke eden bir ajanı çalıştırır. Spawn, arka planda bir ajanı çalıştırır. Bu, posix_spawn gibi spawn'ın yaygın anlayışlarıyla uyumludur ve modelin yeni fiillerimizi anlamasını kolaylaştırır çünkü kavramsal olarak eğitim verilerinde bulunurlar. Spawn ve run, ajanları ve diskten okunan programları doğrudan çağırmanıza olanak tanır ve bir yürütme tanıtıcısı için yeterli bilgiyi döndürür.
Run ayrıca birkaç şeyi destekler. Zod @colinhacks aracılığıyla doğrudan uygulanan çıktı türlerini ve doğrudan model geçersiz kılmalarını destekler; bu, farklı çözümler veya bir görevin farklı adımları için birden çok farklı modele dallanmanın mantıklı olduğu programlar yazmayı ve çalıştırmayı kolaylaştırır.
1function run<S extends z.ZodType>(2 name: string,3 options: ...4): Promise<z.infer<S>>
Run, alt ajanları satır içinde doğrudan zincirlemenize olanak tanır.
1// düz ajan çalıştırması2const out = await run({ type: "read", prompt: () => "Şununla yanıtla: ok" })3// adlandırılmış çalıştırma (string = alt iş akışı kimliği)4const review = await run("reviewer", {5 type: "general",6 prompt: () => "Farkı incele",7})8// yapılandırılmış çıktı (türlendirilmiş sonuç)9const Verdict = z.object({ risk: z.enum(["low", "high"]), why: z.string() })10const v = await run({11 type: "general",12 prompt: () => "Riski değerlendir",13 output: Verdict,14})
Spawn, run'a benzer ancak arka planda bir ajan oluşturur. Oluşturulan alt ajanlar beklenmez ve kontrol akışı ileriye doğru devam eder. Spawn, birkaç bloke etmeyen yürütme ajanı başlatmak için çok kullanışlıdır.
1// arka plan ajanı2const h = await spawn("worker", { type: "general", prompt: "Uzun görev" })
Çalışan Ajanlarla Etkileşim
Çalışan ajanlar üzerinde iki tür işlem yapabilmek istiyoruz: yönlendirme ve durdurma.
Bir yönlendirme mesajı, çalışırken llm'nin alacağı ve onu bir yöne itmek için ajana gönderilen bir mesajdır. Bu, işçiyi yok etmeye gerek kalmadan ajanın görev bağlamını güncellemek için kullanışlıdır.
İptal de önemlidir, çalışmaması gereken bir alt ajanı aktif olarak yok edebilmek istiyoruz.
Bu işlemleri hem canlı REPL'den hem de önceden yazılmış bir programdan çalıştırabilmek, Slate'e her şeyi gerçek zamanlı olarak düzenleme yeteneği verir. Çalışma zamanında orkestrasyonun şeklini dinamik olarak tanımlayabilir veya orkestrasyonu yapmak için gerçek yazılım yazabilir ve üzerinde yineleme yapabilir.
Slate, \.program.ts dosyalarına programlar yazabilir. Bir program dosyası birkaç şeye sahiptir: adı (Slate'in ne olduğunu bu şekilde bilir), bir JSDoc açıklaması ve ardından gerçek program gövdesi*. Bir program bildirimi şöyle görünür:
1program(async (ctx) => {2 // arama için ucuz model — sadece dosyaları bulması gerekiyor3 const findings = await run("search", {4 type: "read",5 prompt: "Kimlik doğrulama ile ilgili tüm dosyaları bul",6 model: "codex/gpt-4.1-mini", // yerleşik codex anahtarınızı kullanır7 })8})
Programlar, bir programı hem ön planda hem de arka planda çalıştırmamıza ve çalışırken onunla etkileşime girmemize olanak tanıyan aynı async yürütme modelini izler.
1// arka plan ajanı2const h = await spawn("worker", { type: "general", prompt: "Uzun görev" })3await h.notify("önce ayrıştırıcıya odaklan") // çalışan ajana yönlendirme mesajı4const result = await h.result() // daha sonra tamamlanmayı bekle// dallan, sonra topla5const a = await spawn({ prompt: "görev A" })6const b = await spawn({ prompt: "görev B" })7const [ra, rb] = [await a.result(), await b.result()]// bir programı arka plana al8import Audit from "deep-audit"9const ah = await spawn(Audit, { input: { pr: 42 } })10const auditResult = await ah.result()
Yapılandırılmış Çıktı ve Durum
Bu, bugüne kadarki diğer tüm sistemlerin birincil sınırlamasıdır. Diğer tüm sistemlerde durum, zayıf bir şekilde dışsallaştırılmıştır ve güvenli bir şekilde izole edilmemiştir. Sistemde bir dosyaysa, bozulma olmayacağını garanti edemezsiniz. Garanti edebilseniz bile, ayrıştırılabilirliği garanti edemezsiniz. İşlemleri yönlendirmek için durum değişikliklerine abone olamazsınız ve tür uyumluluğunu garanti edemezsiniz.
Yapılandırılmış ve referans alınabilir, kalıcı durum istediğimizi hatırlayın.
Onyx'te durum farklıdır. Durum ad alanları bildirilir, doğrudan adlandırılır ve zaman içinde kalıcı hale getirilir. Bu, bir durum deposunun tekrar tekrar kullanılabileceği ve gerçek verilerle uzun süreli ajan sistemleri oluşturmanıza olanak tanıdığı anlamına gelir.
Hem ajanlar hem de kod durumu okur ve bir çalışma zamanından istediğimiz determinizm bundan kaynaklanır. Ajanlar, durumu her zaman güvenli bir şekilde yapılandırılmış bir şekilde etkileşime girmelerini sağlayan özel bir araç aracılığıyla okur. Ajanlar ve programların her ikisi de, çalışma zamanının orkestrasyonu yönlendirmek için durum nesnesine güvenmesini sağlayacak şekilde durumu değiştirmeye yönlendirilebilen tüketicilerdir.
Durum ve şema uyumu, alt ajan tamamlamasını koşullandırır. Bu nedenle durum, tüm programı yönlendirmek için birleşik bir yüzey sağlar.
Durum nesneleri ayrıca, ana ajanla paylaşılan alt oturumlara çalışma zamanı değişkenleri olarak aktarılabilir. Ajan hiyerarşisi boyunca (kendi türünde bir ilk olan) bu referansla geçiş erişimi, paylaşılan bir durum kanalı aracılığıyla ajanlar arası iletişime olanak tanır.

Uzun Süreli Döngüler
Bazı programların daha çok çalışan sistemler gibi işlev görmesi gerekir. Örneğin openclaw'u ele alalım. Doğru temeller verildiğinde openclaw'u aslında bir program olarak temsil edebilirsiniz. Bunun için iki temel kullanıyoruz: sleep ve checkpoint.
Sleep, beklendiği gibi uyur.
Şimdi olay şu, diyelim ki arka planda uzun süreli bir görev yönetimi istiyorsunuz. Önceden tanımlanmış bir yürütme grafiği takılıp kalabilir veya bozulabilir ve bu nedenle ana ajanın programın durumundan haberdar olması önemlidir.
Bunu desteklemek için checkpoint temelini tanıtıyoruz.
Bir checkpoint herhangi bir şey olabilir, ancak checkpoint olarak adlandırılmasının nedeni, ana ajana sabit şekilli bir nesne ile bildirimde bulunmasıdır. Bu, ana ajanın görev ilerlemesi gibi şeyleri takip etmesine ve program durumundaki değişiklikler hakkında doğrudan bilgilendirilmesine olanak tanır. Buna karşılık, ana ajan daha sonra çalışan bir programı daha etkili bir şekilde yönetebilir.
Onyx, Openclaw gibi bir ajan döngüsü yapmayı, yani kalp atışı olan kalıcı bir ajanı destekler.
Bu gerçekten çok havalı, ilkelleri tamamen farklı bir ajan türünde birleştirebiliyorsunuz, sadece bir while döngüsü, bir uyku ve bir kontrol noktası kullanarak.
Openclaw basitçe bir program dosyası olarak temsil edilebilir!
1// Uzun süreli otomatik araştırma döngüsü çalıştırmak için bir program2for (let i = 0; i < maxExperiments; i++) {3 const idea = await run("propose", { ... })4 const result = await run("train", { ... })5 checkpoint({ message: `deney ${i}`, data: { idea, result } })6 await sleep(30_000) // deneyler arasında soğuma süresi7}89// Openclaw tarzı kalıcı bir ajan çalıştırmak için bir program10while(true) {11 const status = await run("status_check", { ...buraya ucuz modeli ekleyin... })if(status.pending_tasks) {checkpoint({ tasks: status.pending_tasks }) // önemli durumu döndür ve ana ajana uyanmasını söyle}12 await sleep(30_000) // deneyler arasında soğuma süresi13}
Kompozisyon
Onyx ile Slate sizin için bir *.program.ts yazabilir. Bu kalıcıdır ve normal kod gibi ele alınmalıdır (ve ele alınmalıdır). Kutudan çıktığı gibi gelen türleri vardır, çalışma zamanı globallerinden arındırılmış bir çalışma zamanında çalışır ve sadece typescript olduğu için kompozisyon modeli, başka bir programı içe aktarmak ve çağırmaktır.
Sadece typescript olduğu için paralellik (Promise.all) ve döngüler gibi şeyleri ücretsiz olarak elde edersiniz.
İşte bir programı nasıl içe aktarıp başka bir programda kullanacağınız:
1import Audit from "deep-audit"program (() => {const ah = await spawn(Audit, { input: { pr: 42 } })2 const auditResult = await ah.result()3 const fixer = await run("fixer", ... denetim çıktısı) // bu çalışır ve denetim programı çıktısını düzeltir.4})
Hata Anlambilimi
Hatalar, ideal VM'de, yüksek sesle fırlatılır. Bunlar, çalışma zamanı sözdizimi sorunları, ajan hataları, çökmeler vb. durumlarda fırlatılmalıdır.
Spesifik olarak, orkestrasyon hatalarını şu şekilde tanımlarız:
- Bir ajan bir görevde bloke oldu
- Bir ajan bir görevi tamamlayamadı
- Bir ajan bir görev için adım veya bütçeyi tüketti
- Bir program bir çalıştırma için bütçeyi tüketti
- Orkestrasyon modeli sözdizimsel olarak doğru kod yazamadı
- Yasa dışı bir durum değişikliği yapıldı
Tüm bu spesifik hata durumları, çalışma zamanı anlambilimini tanımlar. "Bu çalışma zamanının hata fırlatmasını bekleyebilirsiniz, çünkü bir ajan yürütme hatasını, koddaki bir hatayla aynı şekilde görüyoruz" derler. İlk başta sinir bozucu görünebilir, ancak bu yüksek sesli hata mekanizması size karşılığında bir şey verir: hatalara karşı hazırlanmak ve programlamak için açık bir yol. Yani gerçekte size daha az değil, daha fazla kontrol sağlar.
1// hatalar try/catch'tir — herhangi bir TypeScript programıyla aynı2program(async (ctx) => {3 try {4 const result = await run("risky-refactor", {5 type: "general",6 prompt: "Auth modülünü yeniden düzenle",7 model: "claude-sonnet",8 maxSteps: 20,9 })10 } catch (err) {11 // ajan başarısız oldu — ama nedenini tam olarak biliyoruz.12 // iz, buraya götüren her araç çağrısını, her model isteğini,13 // her durum yazımını içerir.1415 // farklı bir modelle yeniden dene16 const result = await run("risky-refactor-retry", {17 type: "general",18 prompt: `Önceki deneme başarısız oldu: ${err.message}. Farklı bir yaklaşım dene.`,19 model: "claude-opus",20 maxSteps: 30,21 })22 }23})
Model seçimi, bütçe zorlaması ve BYOK
Model seçiminin yerleşik olması, daha da hassas kontrole sahip olmanızı sağlar. /models becerisi, Slate'e mevcut modellerin listesine tam erişim sağlayarak Slate'in farklı işler yapan birden çok farklı modelle programlar yazmasına olanak tanır. Fable'ın planlayıcı olmasını, ancak GLM 5.2'nin deterministik bir koşum içinde uygulama yapmasını mı istiyorsunuz? Sorun değil. Bir soruyu Gemini, GPT 5.5 ve DeepSeek arasında yaymak mı istiyorsunuz? Bu da işe yarar.
Ek olarak, çalışma zamanı programlar için iki tür yapılandırma geçersiz kılmayı destekler:
- Ajan yürütme için kullanılan varsayılan global modeller
- Bir programı çalıştırma bütçesi
Belirli bir döngü için harcamayı sınırlamak üzere doğrudan bir çalıştırma bütçesi belirleyebilirsiniz.
Ayrıca çalışma zamanı, mevcut OpenAI ve Github Copilot aboneliklerinizi kullanmayı da destekler.
1program(async (ctx) => {2 // arama için ucuz model — sadece dosyaları bulması gerekiyor3 const findings = await run("search", {4 type: "read",5 prompt: "Kimlik doğrulama ile ilgili tüm dosyaları bul",6 model: "codex/gpt-4.1-mini", // yerleşik codex anahtarınızı kullanır7 })89 // zor kısım için akıl yürütme modeli — düşünmesi gerekiyor10 const plan = await run("architect", {11 type: "general",12 prompt: `Şuna dayalı bir düzeltme tasarla: ${findings.output}`,13 model: "openai/o3", // API kredilerini kullanır14 output: z.object({15 approach: z.string(),16 files: z.array(z.string()),17 risk: z.enum(["low", "medium", "high"]),18 }),19 })2021 // uygulama için orta seviye model — sadece düzenleme yapması gerekiyor22 const handles = await Promise.all(23 plan.files.map(f => spawn("fix-" + f, {24 type: "general",25 prompt: `Bu düzeltmeyi ${f} dosyasına uygula: ${plan.approach}`,26 model: "anthropic/claude-sonnet-5",27 maxSteps: 15,28 }))29 )30 await Promise.all(handles.map(h => h.result()))31})
Yazma yüzeyini tanımlama
Programlar için yazma yüzeyini tasarlarken iki ana faktör vardı: bir ajanın onu anlamasının ne kadar kolay olduğu ve bir insanın onu okumasının ne kadar kolay olduğu. İngilizce gibi okunan nispeten basit fiiller seçtik ve orkestrasyonu bildirimsel olarak değil, yordamsal olarak modellemek istediğimize açıkça karar verdik.
Bir dil olarak TypeScript'in seçilmesi de önemliydi. Vahşi doğada o kadar çok yordamsal TypeScript kodu var ki, bir model, sonradan eğitim olmadan bile TypeScript anlambilimini örtük olarak anlayacaktır.

Yazılım fabrikamızın mühendislik parçaları
Cevaplanması gereken bir sonraki soru şu: tüm bunlar size ne kazandırıyor?
Size ajan orkestrasyonunuz için gerçek yazılım yazma yeteneği kazandırır. Artık kendi ajan orkestrasyonunuzu uçtan uca mühendislikle tasarlayabilirsiniz.
Fabrikayı mühendislikle tasarlayabilirsiniz.
Örneğin, Github'ı bir döngüde izleyen bir program ve inceleme için bir QA ajanı ile bir uygulama ajanı çalıştıran ayrı bir program yapabilirsiniz. Her ikisi de vahşi doğada karşılaşabileceğiniz bireysel olarak kullanışlı kalıplardır. Daha sonra bunları bir araya getirerek bir PR'deki yorumları dinleyen, bu yorumları ele almak için bir uygulayıcı başlatan ve ardından düzeltmenin geçerli olduğundan emin olmak için bir QA ajanı başlatan bir sistem yapabilirsiniz.
Daha sonra bu programı bir görev kuyruğuna bağlı olarak kod tabanınızda işleri devretmek ve izlemek ve PR yorumlarına otomatik olarak yanıt vermesini sağlamak için kullanabilirsiniz.
Ve tüm bunları hızlı açık ağırlık modellerini kullanarak yapabilirsiniz. Çünkü bu sadece koddur, ilk kez yazıldıktan sonra orkestrasyonu düşünmek için güçlü bir LLM'ye ihtiyacınız yoktur.
Şimdi eğlenceli kısma geçelim, büyük çıktı artışları için kullandığımız programlardan bazılarını paylaşma zamanı.
Derin Kod Tabanı Araştırması
Görevlerin kapsamını belirlemeye yardımcı olmak için bu programı kullanıyoruz. Monorepomuzun durumu hakkında derinlemesine araştırma yapar ve bir uygulayıcının başvurması için bir araştırma paketi hazırlar. Her zaman kullanırız. Kulağa pahalı geliyor, ama aslında değil. Bu programı Slate'te DeepSeek V4 Flash ile çalıştırabilirsiniz ve araştırma süreci kapsamlı ama çok ucuzdur.

Hedef-İnceleme-PR
Bu, araştırma tamamlandıktan sonra bir görevi uygulamak için kullandığımız programdır. Neyse ki, araştırma hedef programa ulaştığında, görev belirsizliğinin çoğu çözülmüş olur, bu da görevi yürütmeyi daha da hızlandırır. Hafif bir OSS modeliyle araştırmayı ön yüklemek, önemli olan şeyler için Opus gibi pahalı bir modeli kullanmamızı kolaylaştırır: gerçekten iyi kod yazmak ve sistemin durumunu doğrulamak. Programı, Opus 4.8'in çalışmasını olumsuz bir şekilde incelemek için GPT 5.5 kullanacak şekilde bile değiştirebilirsiniz.

Bir Program Olarak Otomatik Araştırma
Autoresearch[[9]](http://localhost:5173/blog/onyx#ref-9) başlangıçta tamamen LLM odaklıydı. Bir ajana program.md istemine yönlendirin ve ne deneyeceğine ve nasıl ilerleyeceğine karar verir.
Şaşırtıcı olmayan bir şekilde, Otomatik Araştırma aslında sadece bir programdır.
Ajan programları, bunu tersine çevirmenize ve kontrol akışını çalışma zamanına koymanıza olanak tanır. Program kontrol akışına sahipken, ajanlar yan etki yaratan işleri yapar (kodu düzenleme, git çalıştırma, uzak GPU'ya SSH ile bağlanma, eğitim). Otomatik araştırma programı için, tutma/geri alma kararı deterministik koddur:
1kept = status === "ok" && valBpb != null && valBpb < best
Bizim durumumuzda, program yeni bir repo hazırlamak ve uzaktaki A100'e erişilebilir olduğunu doğrulamak için bir kurulum ajanı çalıştırır. Kurulum başarısız olursa, yazılı bir değere dayanarak temiz bir çıkışla erken döner. Aksi takdirde deney döngüsüne girer.
Her deney yeni bir ajan alır. Ajana mevcut en iyi yapılandırma ve önceki fikirlerin ve sonuçların geçmişi verilir, böylece kendini tekrar etmez ve tutulanların üzerine inşa edebilir. Bir değişiklik önerir, train.py dosyasını düzenler, commit yapar, uzak makineye rsync yapar, eğitir ve sonucu sınıflandırır.
Ajan ve program durumu paylaşır. Ajan duruma veri yazar ve program kontrol akışı için durumu değerlendirir. Sonuca bağlı olarak, bir kaydedici ajan results.tsv dosyasını günceller ve program deneyi atmaya karar verirse isteğe bağlı olarak çalıştırmayı sıfırlar. Bu, git HEAD'in her zaman deney ağacının mevcut en iyi dalını göstermesini sağlar.
Dikkat edilmesi gereken iki temel fark vardır: 1) bu bir programda çalışır, bu nedenle deney başına yeni bir ajan başlatabiliriz ve 2) ajanın ne yapması gerektiğine canlı program durumuna göre karar verebiliriz.


Ve kodda şöyle görünür:
1// ---------- Program ----------23program(async (ctx) => {4 const c = cfg(ctx.input)5 const total = ctx.input?.maxExperiments ?? 2067 const setup = await run("ar-setup", {8 prompt: setupPrompt(c),9 type: "general",10 maxSteps: 40,11 output: SetupResult,12 })13 if (!setup.ready) {14 return { aborted: true, reason: `kurulum başarısız oldu: ${setup.note}`, setup }15 }1617 let best = c.baselineValBpb18 let bestCommit = setup.baselineCommit19 const history = []2021 for (let i = 1; i <= total; i++) {22 let exp23 try {24 exp = await run(`ar-exp-${i}`, {25 prompt: experimentPrompt(c, i, total, best, historyText(history)),26 type: "general",27 maxSteps: 80,28 output: ExperimentResult,29 })30 } catch (err) {31 // Ajan hata verdi/bloke oldu — çökme olarak ele al, repoyu en iyi duruma geri yükle, devam et.32 exp = {33 description: `deney ${i} ajan hatası`,34 commit: "error",35 status: "crash",36 valBpb: null,37 peakVramMb: null,38 numSteps: null,39 exitCode: -1,40 retries: 0,41 note: String(err?.message ?? err).slice(0, 200),42 }43 }4445 const kept = exp.status === "ok" && exp.valBpb != null && exp.valBpb < best4647 await run(`ar-record-${i}`, {48 prompt: recordPrompt(c, exp, kept, bestCommit),49 type: "general",50 maxSteps: 20,51 output: RecordResult,52 })5354 if (kept) {55 best = exp.valBpb56 bestCommit = exp.commit57 }5859 history.push({60 idx: i,61 description: exp.description,62 status: exp.status,63 valBpb: exp.valBpb,64 kept,65 commit: exp.commit,66 retries: exp.retries,67 })6869 await checkpoint({70 name: `experiment-${i}`,71 message: `deney ${i}/${total}: ${exp.status}${kept ? " TUTULDU" : ""} val_bpb=${exp.valBpb ?? "yok"} (en iyi=${best})`,72 data: { i, total, status: exp.status, valBpb: exp.valBpb, kept, best, bestCommit },73 })74 }7576 const kepts = history.filter((h) => h.kept)77 return {78 baselineValBpb: c.baselineValBpb,79 bestValBpb: best,80 bestCommit,81 improvement: c.baselineValBpb - best,82 experimentsRun: history.length,83 kept: kepts.length,84 crashes: history.filter((h) => h.status === "crash").length,85 infraFails: history.filter((h) => h.status === "infra_fail").length,86 localRepo: c.localRepo,87 branch: c.branch,88 history,89 }90})
Gelecek çalışmalar
Henüz tanımlamadığımız tek kalan VM gereksinimi, programlar için dayanıklılık modelidir. Bir programın yaşam döngüsünü sürdürmek ve yönetmek için doğru modelin ne olduğu ve çalışma zamanında ne düzeyde kontrolün açığa çıkarılması gerektiği net değildir.
Bunun ötesinde, farklı iş yüklerini ve görev şekillerini desteklemek için ekleyeceğimiz o kadar heyecan verici şey var ki, ajanları daha iyi orkestre etmek için gerçek yazılımlar yazabilelim. Kalıpların çoğunun, insanların programları kendi başlarına yaratıcı yollarla kullanmalarından ortaya çıkacağından eminiz.
Ne inşa edeceğinizi görmek için gerçekten sabırsızlanıyoruz.
- RL Ekibi
Referanslar
- Yao ve diğerleri, "ReAct: Synergizing Reasoning and Acting in Language Models," 2022
- Geoffrey Huntley, "The Ralph Loop"
- Geoffrey Huntley, "everything is a ralph loop," Ocak 2026
- Zhang, Kraska, Khattab, "Recursive Language Models," Aralık 2025
- Wang ve diğerleri, "Executable Code Actions Elicit Better LLM Agents," ICML 2024
- OpenAI, "Introducing Deep Research," Şubat 2025
- Cursor, "Scaling Agents," Ocak 2026
- OpenAI, "Using Goals in Codex"
- Andrej Karpathy, "autoresearch"
- Anthropic, "Introducing Dynamic Workflows in Claude Code"
- OpenAI, "Learning to Reason with LLMs," Eylül 2024
- Anthropic, "A harness for every task: dynamic workflows in Claude Code"
- Random Labs, "Skill Chaining"





