यह लेख Onyx का परिचय देता है, जो प्रोग्रामेबल एजेंट ऑर्केस्ट्रेशन के लिए हमारा VM है। और विस्तार से, एक रनटाइम जो ऑर्केस्ट्रेशन को सॉफ्टवेयर इंजीनियरिंग में बदल देता है। इस लेख के अंत तक, आप VM के निर्माण में शामिल बाधाओं और डिज़ाइन निर्णयों को समझ जाएंगे, साथ ही अपने स्वयं के प्रोग्राम बनाने और अपने एजेंट सिस्टम को आर्किटेक्ट करने का तरीका भी जान जाएंगे।
परिचय
एजेंट स्वाभाविक रूप से गैर-नियतात्मक (non-deterministic) होते हैं। यही पूरा मुद्दा है। अगर आप नियतत्ववाद (determinism) चाहते, तो आप सॉफ्टवेयर लिख रहे होते।
लेकिन रास्ते में कहीं, एजेंट का उपयोग करने वाले सभी लोग सामूहिक रूप से उन्हें और आगे धकेलना चाहते थे। हमने सीखा कि निष्पादन को संरचित चरणों में तोड़ने से प्रदर्शन में मदद मिलती है: योजना बनाएं, कार्यान्वित करें, समीक्षा करें, QA आदि। फिर हमने स्पष्ट रूप से प्रत्येक एजेंट को चलाने, उनके बीच संदर्भ साझा करने और उन्हें सुरक्षित रखने के लिए स्क्रिप्ट, टूल और कौशल लिखने पर सहमति व्यक्त की। फिर हम एजेंटों के बीच टेक्स्ट को पाइप करके इन स्क्रिप्ट्स को एक साथ जोड़ते हैं, और क्योंकि हम सिर्फ टेक्स्ट पास कर रहे हैं, यह कुछ हद तक काम करता है।
यदि आपने समस्या पर पर्याप्त समय बिताया और विशेष रूप से चतुर थे, तो आपने यह पता लगा लिया होगा कि अपने सिस्टम से गारंटी कैसे प्राप्त करें ताकि आप किसी दिए गए स्थिति के आधार पर सशर्त निष्पादन कर सकें। और आप शायद उस स्थिति को अपनी bash स्क्रिप्ट को चलाने के लिए एक पार्स करने योग्य मार्कअप फ़ाइल या फ़ाइलों के सेट में संग्रहीत करेंगे। हो सकता है कि आपने अपने एजेंटों के उपयोग के लिए एक कस्टम CLI भी बनाया हो।
इंजीनियरों के रूप में यह परिचित है, हम सॉफ्टवेयर इंजीनियरिंग करते समय स्क्रिप्ट का उपयोग करते हैं। हालाँकि, आधुनिक सॉफ्टवेयर bash स्क्रिप्ट और CLI टूल को जोड़कर नहीं बनाया जाता है। इसके बजाय, हमारे पास प्रोग्रामिंग भाषाएँ, रनटाइम और टूल चेन हैं जो हमें अपने सिस्टम को इंजीनियर करने में मदद करते हैं। हम प्रोग्रामिंग भाषाओं में सॉफ्टवेयर लिखते हैं क्योंकि वे एक मानक लाइब्रेरी, स्पष्ट सिमैंटिक्स और एक निष्पादन मॉडल के साथ आती हैं जिस पर हम भरोसा कर सकते हैं। उनके पास हमारी सभी जरूरतों के लिए टूलचेन के साथ समृद्ध पारिस्थितिकी तंत्र हैं।
वे हमें अपने सिस्टम के बारे में जो गारंटी देते हैं, वे हमें उच्च स्तर के अमूर्तन पर तर्क करने की अनुमति देते हैं।
लेकिन एजेंट सिस्टम को इंजीनियर करने के लिए कोई समकक्ष नहीं है। सिस्टम बनाने के लिए, एजेंट ऑर्केस्ट्रेशन को आधुनिक सॉफ्टवेयर की तरह ही प्रोग्रामेबल होने की आवश्यकता है।
आज, हम PROGRAMS (*.program.ts) के लिए स्पेक और Onyx पेश कर रहे हैं, जो नियतात्मक एजेंट ऑर्केस्ट्रेशन के लिए बनाया गया हमारा VM है। यह लेख एजेंट ऑर्केस्ट्रेशन के इतिहास, एक VM के स्टैटिक और रनटाइम सिमैंटिक्स की पड़ताल करता है जो एक प्रोग्राम चला सकता है, और इस क्षेत्र के भविष्य के लिए इसके निहितार्थों की।
यह महंगा लगता है, लेकिन वास्तव में ऐसा नहीं है। मैं इस लेख में बाद में इसकी व्याख्या करता हूँ।
जो लोग उत्सुक हैं, उनके लिए यह Andrej Karpathy का Autoresearch एक प्रोग्राम के रूप में कैसा दिखता है:

एजेंट ऑर्केस्ट्रेशन में अनसुलझी समस्याएँ
यह समझने के लिए कि एजेंट ऑर्केस्ट्रेशन के लिए रनटाइम में क्या शामिल होना चाहिए, हमें एजेंटों की सीमाओं को समझने की आवश्यकता है।
एक LLM एजेंट को एक JSON स्ट्रीम जनरेटर के रूप में सोचा जा सकता है, जिसे एक पार्सर में डाला जाता है, जो फिर एक लूप में एनवायरनमेंट में टूल कॉल भेजता है।
प्रत्येक टूल कॉल का बिल्कुल एक ही बाहरी स्कीमा आकार होता है, लेकिन इस आउटपुट स्ट्रीम की सामग्री नियतात्मक नहीं होती है।
नियतत्ववाद और गैर-नियतत्ववाद के संयोजन ने ही एजेंटों को इतना मूल्यवान बनाया है। वे अद्वितीय तरीकों से क्रियाओं के अनुक्रमों को श्रृंखलित करने के लिए पर्याप्त लचीले हैं, लेकिन टूल कॉल के माध्यम से कंप्यूटर के साथ बातचीत करने के लिए पर्याप्त नियतात्मक हैं।
यदि आप इस आवश्यकता को छोड़ने को तैयार हैं कि उस स्ट्रीम की सामग्री टाइप की गई हो, तो संयोजनीयता (composability) लगभग मुफ्त है। मॉडल उन रेलों के भीतर टेक्स्ट को अंदर और बाहर पाइप करने के लिए पर्याप्त अच्छे हैं जो हम उन्हें प्रदान करते हैं: प्रॉम्प्ट, संदेश और टूल कॉल।
यह एक बहुत ही संयोजनीय इंटरफ़ेस उजागर करता है: टेक्स्ट
टेक्स्ट एक सार्वभौमिक इंटरफ़ेस है। कंप्यूटर पर सब कुछ टेक्स्ट में क्रमबद्ध किया जा सकता है, भले ही वह सिर्फ मशीन कोड ही क्यों न हो। यदि आपके पास इस सार्वभौमिक इंटरफ़ेस के माध्यम से टेक्स्ट को इनपुट और आउटपुट करने वाला LLM हो सकता है, तो आपको टेक्स्ट स्ट्रीम पर संयोजनीयता मिलती है।
इसका मतलब है कि आपके एजेंट व्यवहार की विश्वसनीयता सीधे मॉडल से आउटपुट की स्थिरता से संबंधित है। उच्च आउटपुट परिवर्तनशीलता का मतलब अधिक अनियमित एजेंट व्यवहार है।
एक बार जब आपके पास टुकड़ों को एक साथ जोड़ने के लिए एक इंटरफ़ेस होता है, तो अगली बाधा जिसकी आप परवाह करते हैं वह है स्टीयरेबिलिटी (steerability) :
आप एजेंट से क्या करवाना चाहते हैं, और आप लगातार उससे वह कैसे करवाते हैं
हम एजेंटों को उस वितरण को स्थानांतरित करके चलाते हैं जिससे वे नमूना लेते हैं, दूसरे शब्दों में, प्रॉम्प्टिंग।
2022 में, ReAct आया और इसने मूल रूप से एजेंट स्टीयरेबिलिटी की शुरुआत की। वास्तव में, हम यहाँ तक कह सकते हैं कि इसने एजेंटों को जैसा हम जानते हैं एक चीज़ बना दिया। अगला कदम उठाने से पहले टूल आउटपुट के बारे में सोचना और तर्क करना ही लूप को सुसंगत रखता है।

हमें अभी भी एजेंटों के अधिक स्मार्ट होने की आवश्यकता थी। @OpenAI के O-सीरीज़ मॉडल द्वारा उत्पादित, टेस्ट टाइम कंप्यूट स्केलिंग के उपयोग ने मॉडल लैब्स को बेहतर एजेंट व्यवहार को शामिल करने की क्षमता दी [[11]](http://localhost:5173/blog/onyx#ref-11)। टूल को कॉल करने से पहले अधिक टोकन आउटपुट करने से मॉडल को उस आउटपुट वितरण से बचने की अनुमति मिलती है जिसमें वह फंस गया होता यदि वह रीज़निंग आउटपुट लंबाई पर विवश होता। आप चुन सकते हैं कि मॉडल अपने आउटपुट वितरण परिदृश्य को कैसे पार करता है, और इसलिए आपको अपने इच्छित कार्यों पर स्पष्ट एजेंटिक व्यवहार में प्रशिक्षित करने की स्वतंत्रता है।
जैसे-जैसे संदर्भ लंबाई असीमित रूप से बढ़ती है, एजेंट को चलाना मुश्किल हो जाता है और कार्य पूरा होने की संभावना कम हो जाती है। यहां तक कि एक रीज़निंग मॉडल के साथ भी, रिकवरी की कोई गारंटी नहीं है, और एजेंट वहीं मर जाता है। एजेंट अपनी संदर्भ सीमा तक पहुँच सकता है, जल्दी पूरा होने की घोषणा कर सकता है, एक लूप में फंस सकता है, आदि।
एक गैर-नियतात्मक प्रणाली से गारंटी निकालना
इसके समाधान विविध थे, लेकिन एक सबसे अलग है: द राल्फ लूप (The Ralph Loop) , @GeoffreyHuntley द्वारा बनाया गया। [[3]](http://localhost:5173/blog/onyx#ref-3
उन्होंने यह विचार पेश किया कि आप एजेंट निष्पादन को सीमित कर सकते हैं, और फिर कार्य पूरा होने के बारे में तर्क करने के लिए उन सीमाओं का उपयोग कर सकते हैं। यह राल्फ लूप को कुछ जादुई करने की अनुमति देता है: यह कुछ ऐसा प्रदान करता है जिस पर आप एक गैर-नियतात्मक प्रणाली में भरोसा कर सकते हैं।
नियतत्ववाद की एक चिंगारी।
स्लॉट मशीन का लीवर एक बार और खींचने से बेहतर है कि विफलता की गारंटी दी जाए और धीरे-धीरे सही की ओर बढ़ा जाए। यह परिभाषित सीमा आपको तर्क करने के लिए कुछ ठोस देती है और एक बार जब आप किसी चीज़ की सीमाओं के बारे में तर्क कर सकते हैं, तो आप उससे एक सिस्टम बना सकते हैं।
संदर्भ लंबाई की सीमाओं से लड़ना
एक समस्या है, हालांकि, एक नया एजेंट रनों के बीच सुसंगतता खो देता है, लेकिन एक एकल एजेंट पर्याप्त समय दिए जाने पर संदर्भ से बाहर हो जाता है।
यहाँ RLM आता है @lateinteraction @a1zhang द्वारा। RLM ने हमें एक संरचित तरीके से लंबे संदर्भ (यानी एक एजेंट रन) के साथ बातचीत करने की अवधारणा दी [[4]](http://localhost:5173/blog/onyx#ref-4)। RLM CodeAct से प्रेरित था, 2024 का एक पेपर जिसने ऑपरेशन को ऑर्केस्ट्रेट करने के लिए कोड के उपयोग का प्रदर्शन किया [[5]](http://localhost:5173/blog/onyx#ref-5)। एजेंट स्क्रिप्ट लिखता है जो एक REPL के अंदर ऑपरेशन को ऑर्केस्ट्रेट करता है ताकि आउटपुट प्राप्त किया जा सके। RLM उसी तरह से काम करता है, इस अतिरिक्त शर्त के साथ कि यह संदर्भ को संग्रहीत करने और उस संदर्भ पर संचालन करने के लिए वेरिएबल का उपयोग करता है। यह अतिरिक्त रूप से REPL में पुनरावर्ती LLM कॉल की अनुमति देता है। हो सकता है कि आप कुछ प्रतिक्रियाशीलता खो दें जो अन्य लूप में है, लेकिन आप प्रोग्रामेटिक रूप से संदर्भ के साथ काम करने की क्षमता प्राप्त करते हैं। यहाँ मुख्य बात यह है कि REPL में स्क्रिप्ट क्षणिक (ephemeral) होती हैं। आपको एक स्क्रिप्टिंग रनटाइम और संदर्भ प्रबंधन मिलता है, लेकिन कोई पुन: प्रयोज्यता या संयोजनीयता नहीं है। बस स्क्रिप्ट लिखें, इसे चलाएँ, और यह गायब हो जाती है। सिस्टम बनाने के संदर्भ में, यह एजेंटों और मार्कडाउन फ़ाइलों को bash स्क्रिप्ट के साथ एक साथ जोड़ने से सख्ती से बदतर है क्योंकि आप दृढ़ता (persistence) और बाउंडेड निष्पादन खो देते हैं।
व्यक्तिगत लूप से स्केलिंग ऑर्केस्ट्रेशन की ओर बढ़ना
OpenAI का Deep research[[6]](http://localhost:5173/blog/onyx#ref-6) एक नियतात्मक वर्कफ़्लो के शुरुआती उदाहरणों में से एक था जिसमें एक सामान्य निष्पादन आकार या स्कीमा था जिसमें रन-दर-रन आधार पर छोटी परिवर्तनशीलता थी। यह जिस तरह से काम करता है वह प्रश्नों के एक बैच की योजना बनाकर, उन्हें वेब पर चलाकर, परिणामों की समीक्षा करके और प्रश्नों के अगले बैच की योजना बनाकर है। प्रत्येक बैच समस्या स्थान में गहराई से जांच करता है।

Cursor ने नियतत्ववाद के विचार को और आगे बढ़ाया जब @wilsonzlin ने एक हार्नेस का प्रदर्शन किया जिसने एक ब्राउज़र बनाने के लिए एजेंटों को ऑर्केस्ट्रेट किया। उन्होंने समानांतर प्लानर एजेंटों और टास्क एजेंटों का उपयोग करके बड़ी मात्रा में काम के समन्वय के लिए एक बेस्पोक हार्नेस बनाया [[7]](http://localhost:5173/blog/onyx#ref-7)। यहाँ प्रासंगिक बात यह है कि हार्नेस के प्रत्येक भाग के बीच संबंध निश्चित है। प्लानर हैं, जो वर्तमान सिस्टम स्थिति का पता लगाते हैं और कार्य उत्पन्न करते हैं, और निष्पादक हैं, जो कार्य लेते हैं और उन्हें समानांतर में लागू करते हैं। एजेंटों के बीच निश्चित गार्डरेल और सूचना संप्रेषित करने के लिए निश्चित चैनल हैं। समन्वय को अच्छी तरह से करने के लिए, आपको इंटरफेस पर गारंटी की आवश्यकता है।
बाउंडेड निष्पादन के लिए समाप्ति शर्तों का उपयोग करना
मई में, Codex ने एक लक्ष्य (goal) का विचार पेश किया जो किसी कार्य के पूरा होने तक किसी वांछित अंतिम स्थिति के खिलाफ हिलक्लाइम्ब करने के लिए एक वेरिफायर लूप का उपयोग करता है। आप इसे राल्फ लूप का एक उत्पादन-तैयार संस्करण मान सकते हैं, जो Codex में बनाया गया है। यह आपको एक उद्देश्य निर्दिष्ट करने की अनुमति देता है, और इसमें एक स्वचालित लूप है जो निष्पादित और समीक्षा करता है, जो इसमें बनाया गया है।

Karpathy का autoresearch[[9]](http://localhost:5173/blog/onyx#ref-9) Codex के /goal और राल्फ लूप के समान है। यह लक्ष्य की सत्यापन योग्य समाप्ति शर्त को पुनरावृत्तियों पर राल्फ लूप के निष्पादन बाउंडिंग के साथ जोड़ता है, जिससे यह लगातार एक लक्ष्य की ओर बढ़ सकता है। यह विचार स्थान की खोज करके प्रगति करता है, समय के साथ पुनरावृत्त रूप से सुधार करता है।

इस बिंदु तक, वे सभी समाधान जो एजेंट के बाहर ऑर्केस्ट्रेशन को बाहरी बनाते हैं, अपने निष्पादन ग्राफ आकार में निश्चित होते हैं। वे एक हस्तलिखित पैटर्न का उपयोग करके चलते हैं, और उनके पास अनुमत आकृतियों के लिए एक प्रकार की स्कीमा होती है जिसमें वे काम कर सकते हैं। वे प्रति कार्य अनुकूलित नहीं होते हैं या उनके पास निष्पादन ग्राफ आकार अवधि पर मजबूत गारंटी नहीं होती है।
ऑर्केस्ट्रेशन को लचीला बनाना
इस वर्ष मार्च में, हमने Slate पेश किया, जो RLM की शैली में लाइव सबएजेंट ऑर्केस्ट्रेशन के लिए कोड का उपयोग करने वाला पहला कोडिंग एजेंट है। यह अभी भी एकमात्र अच्छी तरह से उपयोग किया जाने वाला कोडिंग एजेंट है जो लाइव एजेंट ऑर्केस्ट्रेशन करने के लिए कोड का उपयोग करता है। Slate में, थ्रेड को वास्तविक समय में स्पॉन, रोका, फिर से शुरू और चलाया जा सकता है। मुख्य एजेंट गहराई से समझता है कि सभी चल रहे सबएजेंटों को कैसे ऑर्केस्ट्रेट किया जाए ताकि आपको न करना पड़े। हालाँकि, RLM के समान, हम अभी भी सबएजेंटों और क्षणिक स्क्रिप्टिंग में स्थिति साझा करने की चुनौती का सामना कर रहे थे, जो कि कुछ ऐसा नहीं है जो आप bash स्क्रिप्ट और मार्कडाउन फ़ाइल का उपयोग करते समय सामना करेंगे।
फिर भी, यदि मॉडल ही ऑर्केस्ट्रेशन कर रहा है, तो आप इसे कैसे चलाते हैं? क्या आप इसे अपना ऑर्केस्ट्रेशन कोड एक विशिष्ट तरीके से लिखने के लिए कहते हैं? आप क्या करते हैं?
हमारा प्रारंभिक समाधान (Onyx रनटाइम जारी करने से पहले एक पैच के रूप में) ऑर्केस्ट्रेशन स्किल्स कहलाता था [[13]](http://localhost:5173/blog/onyx#ref-13)। विचार सरल था, उपयोगकर्ता को एजेंट के ऑर्केस्ट्रेशन के दृष्टिकोण को चलाने के लिए एक कौशल प्रदान करने की अनुमति देना। बस इतना ही। यह ठीक काम करता था, लेकिन इसमें बहुत सारी समस्याएँ थीं।
अर्थात्, एक कौशल एक बाध्यकारी व्यवहार अनुबंध नहीं है। आप टेक्स्ट से गारंटी प्राप्त नहीं कर सकते।
इसका मतलब है कि ऑर्केस्ट्रेटर को वांछित निष्पादन पैटर्न का पालन नहीं करना था क्योंकि इसे लागू करने का कोई वास्तविक तरीका नहीं था। Onyx रनटाइम के सबसे बड़े लाभों में से एक यह है कि हमने इस समस्या को हल किया।
उल्लिखित प्रणालियों में से किसी के पास बाध्यकारी व्यवहार अनुबंध नहीं हैं।
ठीक है, तो क्या होगा यदि एजेंट प्रति कार्य एक स्क्रिप्ट के लिए अपना ऑर्केस्ट्रेशन कोड लिख सके ताकि निष्पादन ग्राफ तय हो? यही Claude डायनेमिक वर्कफ़्लो है।[[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 और Slate के समान ही, सबएजेंटों को ऑर्केस्ट्रेट करने के लिए कोड लिखकर, डायनेमिक वर्कफ़्लो Claude को वर्कफ़्लो आकार लिखने और सहेजने की अनुमति देता है। यह विशिष्ट पैटर्न पर लूप करने में सक्षम होने के लिए /loop के साथ जुड़ता है। यह एजेंटों के एक सेट के व्यवहार के लिए एक घोषणात्मक अनुबंध प्रदान करता है। यह अभी भी सॉफ्टवेयर लिखने जैसा नहीं है क्योंकि इसमें कार्यात्मक संरचना जैसी चीजों का अभाव है, लेकिन आपको दृढ़ता और एक मजबूत गारंटी मिलती है कि कार्य कैसे निष्पादित किया जाएगा। वे किसी दिए गए कार्य के लिए तदर्थ रूप से गतिशील रूप से लिखे गए वर्कफ़्लो स्क्रिप्ट हैं।[[12]](http://localhost:5173/blog/onyx#ref-12) और चूंकि वे डिस्क पर बने रहते हैं, उनका एक अतिरिक्त लाभ है: उन्हें फिर से चलाया जा सकता है और /loop जैसे ऑर्केस्ट्रेशन गोंद के साथ लपेटा जा सकता है।

यदि आप ध्यान देंगे, तो उपरोक्त सभी समाधान एक ही चीज़ के लिए प्रयास कर रहे हैं: यह नियंत्रित करने का एक नियतात्मक तरीका कि एजेंट समय के साथ कैसे निष्पादित होते हैं।
यह एक ऐसी कहानी है जिसे हमने पहले भी सॉफ्टवेयर इंजीनियरिंग में एक क्षेत्र के रूप में सामने आते देखा है। हमने असमान प्रणालियों और स्क्रिप्टिंग जॉब्स को एक साथ जोड़कर शुरू किया, और फिर हमारी भाषाएँ अधिक लचीली और शक्तिशाली होती गईं। हमने मजबूत पारिस्थितिकी तंत्र के साथ इंजीनियरिंग प्रक्रिया पर अधिक से अधिक लाभ प्राप्त किया, जिससे हमें उच्च अमूर्त स्तरों पर अधिक विश्वसनीय सिस्टम बनाने की अनुमति मिली।
अभी, एजेंट उसी प्रक्षेपवक्र पर हैं, और आज हम उस प्रक्षेपवक्र के साथ अगला कदम जारी कर रहे हैं ताकि आप उन सिस्टमों को इंजीनियर कर सकें जो आपके एजेंटों को चलाते हैं। प्रोग्रामिंग भाषाएँ अक्सर संसाधनों को स्वचालित रूप से शेड्यूल करने के लिए इंटरप्रेटर या VM का उपयोग करती हैं। यही वह चीज़ है जो आपको भाषा का उपयोग करने वाले इंजीनियर के रूप में लाभ देती है।
यदि VM एजेंट ऑर्केस्ट्रेशन के लिए समझ में आता है, तो आपको कुछ चीज़ों की आवश्यकता होगी:
- स्थायी स्थिति प्रबंधन: हमें स्थिति को परिभाषित करने, नाम से संदर्भित करने, इसे बनाए रखने और प्रोग्रामेटिक रूप से हेरफेर करने में सक्षम होना चाहिए।
- प्रकार की गारंटी। हमें परिभाषित इनपुट और आउटपुट आकृतियों का सम्मान करना चाहिए और उनका पालन करना चाहिए, और उन पर भरोसा करने में सक्षम होना चाहिए।
- नियंत्रण प्रवाह आदिम, अधिमानतः प्रसिद्ध जिन्हें LLM समझेगा।
- त्रुटि प्रबंधन के लिए स्पष्ट संरचना (जैसे try-catch)।
- संसाधन प्रबंधन: एजेंट समानता, लागत, कौन से मॉडल चल रहे हैं आदि जैसे संसाधनों पर परिभाषित नियंत्रण।
- निष्पादन अलगाव: किसी दिए गए चल रहे एजेंट या प्रोग्राम को दूसरे से अलग किया जाना चाहिए जब तक कि स्थिति स्पष्ट रूप से साझा न की जाए।
- जीवनचक्र नियंत्रण: एक एजेंट प्रोग्राम कैसा दिखता है और चलाने, रद्द करने और चलाने के लिए सिमैंटिक्स। इसके बिना, आपके पास सफाई का कोई स्पष्ट रास्ता नहीं है और जीवनचक्र प्रबंधन को नियंत्रित नहीं कर सकते हैं।
- संयोजनीयता: प्रोग्राम को एक दूसरे में शामिल किया जाना चाहिए और परिभाषित इनपुट और आउटपुट प्रकारों के साथ कॉल करने योग्य होना चाहिए।
- दृश्यता: हमें यह जानने में सक्षम होना चाहिए कि क्या चला, कब, और स्रोत में निष्पादन विफलता का पता लगाने में सक्षम होना चाहिए।
- स्थायित्व: हमारे पास एक स्पष्ट मॉडल होना चाहिए कि हम क्रैश से कैसे उबर सकते हैं और फिर से शुरू कर सकते हैं।
इनमें से प्रत्येक एक ऐसी समस्या है जिसे दशकों पहले प्रोग्रामिंग भाषाओं द्वारा पहले ही हल कर लिया गया था। एजेंट ऑर्केस्ट्रेशन पहली बार उन सभी को फिर से हिट कर रहा है।
वास्तव में इसके लिए सॉफ्टवेयर लिखने में सक्षम होने के लिए, एक "program.ts" प्रोग्राम को एक रनटाइम में लिखा जाना चाहिए जो उपरोक्त सभी का समर्थन करता है, ताकि हम तर्क कर सकें कि जब कोई प्रोग्राम काम नहीं करता है तो क्या होगा और विफलता के आसपास इंजीनियर कर सकें।
यही कारण है कि हमने Onyx बनाया। यह एक एजेंट ऑर्केस्ट्रेशन VM है जिसे स्थायी रचनात्मक प्रोग्राम और एक व्याख्या की गई स्क्रिप्टिंग परत दोनों का समर्थन करने के लिए डिज़ाइन किया गया है। यहाँ बताया गया है कि यह कैसे काम करता है, और एक "program.ts" संगत रनटाइम को क्या समर्थन देने की आवश्यकता है।
रनटाइम डिज़ाइन करना
जब हम एक भाषा और उस भाषा के लिए एक रनटाइम डिज़ाइन करते हैं, तो हमें उन बाधाओं के बारे में सोचने की ज़रूरत होती है जिनके बारे में हम तर्क करने में सक्षम होना चाहते हैं, और हम किस बारे में आसानी से व्यक्त करने योग्य होने की परवाह करते हैं। फिर हम परिणामी सिमैंटिक्स को दो श्रेणियों में विभाजित कर सकते हैं: स्टैटिक सिमैंटिक्स और रनटाइम सिमैंटिक्स।
स्टैटिक सिमैंटिक्स वे सभी चीज़ें हैं जिन्हें केवल देखकर किसी प्रोग्राम के बारे में अनुमान लगाया जा सकता है। वे चीज़ें जो एक कंपाइलर या टाइप चेकर किसी दिए गए प्रोग्राम के बारे में जानता है।
रनटाइम सिमैंटिक्स परिभाषित करते हैं कि कोड का वास्तव में क्या अर्थ है और प्रोग्राम वास्तव में कैसे चलता है। इसमें अंतर्निहित संसाधन आवंटन और शेड्यूलिंग यांत्रिकी शामिल है।
एजेंटों के लिए रनटाइम के साथ हमारा लक्ष्य ऑर्केस्ट्रेशन नियंत्रण प्रवाह को कोड में बदलना है, और हम निष्पादन स्थिति को स्थायी और टाइप किया हुआ बनाना चाहते हैं ताकि हम ऑर्केस्ट्रेशन को चलाने के लिए इसका विश्वसनीय रूप से उपयोग कर सकें।
कुछ VM आवश्यकताएँ
सामान्य TypeScript निष्पादन जैसी चीज़ों से परे, हम 3 VM-विशिष्ट चीज़ों की परवाह करते हैं।
- एक एजेंट ऑर्केस्ट्रेशन रनटाइम के रूप में, इसे एजेंटों को ऑर्केस्ट्रेट करने में सक्षम होना चाहिए। इसका मतलब है उन्हें बनाना, उनके जीवनचक्र को ट्रैक करना आदि। हम चाहते हैं कि रनटाइम उन्हें ब्लॉकिंग या नॉन-ब्लॉकिंग तरीके से चलाने और उन्हें सही ढंग से शेड्यूल करने में सक्षम हो।
- हम एजेंटों के आउटपुट आकार पर नियंत्रण चाहते हैं और सख्त आउटपुट अनुबंध प्रवर्तन चाहते हैं।
- हम मॉडल और लागत जैसे बाहरी संसाधनों पर रनटाइम नियंत्रण चाहते हैं।
एजेंट और प्रोग्राम चलाना
एक एजेंट चलाने के लिए, हमने दो बुनियादी क्रियाएँ चुनीं: run और spawn। Run अग्रभूमि में एक ब्लॉकिंग एजेंट चलाता है। Spawn पृष्ठभूमि में एक एजेंट चलाता है। यह posix_spawn जैसे spawn की सामान्य समझ के अनुरूप है, जिससे मॉडल के लिए हमारी नई क्रियाओं को समझना आसान हो जाता है क्योंकि वे अवधारणात्मक रूप से प्रशिक्षण डेटा में हैं। Spawn और run आपको डिस्क से पढ़े गए एजेंटों और प्रोग्रामों को सीधे लागू करने की अनुमति देते हैं, जो एक निष्पादन हैंडल के लिए पर्याप्त जानकारी लौटाते हैं।
Run कुछ चीज़ों का भी समर्थन करता है। यह @colinhacks के माध्यम से zod के माध्यम से सीधे लागू किए गए आउटपुट प्रकारों का समर्थन करता है, और यह प्रत्यक्ष मॉडल ओवरराइड का समर्थन करता है, जिससे उन प्रोग्रामों को लिखना और चलाना आसान हो जाता है जहाँ किसी कार्य के विभिन्न समाधानों या विभिन्न चरणों के लिए कई अलग-अलग मॉडलों में फैलना समझ में आता है।
1function run<S extends z.ZodType>(2 name: string,3 options: ...4): Promise<z.infer<S>>
Run आपको सीधे इनलाइन सबएजेंटों को श्रृंखलित करने की अनुमति देता है।
1// सादा एजेंट रन2const out = await run({ type: "read", prompt: () => "Reply with: ok" })3// नामित रन (string = child workflowId)4const review = await run("reviewer", {5 type: "general",6 prompt: () => "Review the diff",7})8// संरचित आउटपुट (टाइप किया गया परिणाम)9const Verdict = z.object({ risk: z.enum(["low", "high"]), why: z.string() })10const v = await run({11 type: "general",12 prompt: () => "Assess risk",13 output: Verdict,14})
Spawn run के समान है लेकिन पृष्ठभूमि में एक एजेंट बनाता है। स्पॉन किए गए सबएजेंटों की प्रतीक्षा नहीं की जाती है और नियंत्रण प्रवाह बस आगे बढ़ता है। Spawn कई नॉन-ब्लॉकिंग निष्पादन एजेंटों को चालू करने के लिए बहुत उपयोगी है।
1// पृष्ठभूमि एजेंट2const h = await spawn("worker", { type: "general", prompt: "Long task" })
चल रहे एजेंटों के साथ बातचीत करना
हम चल रहे एजेंटों पर दो प्रकार के संचालन करने में सक्षम होना चाहते हैं: स्टीयरिंग और स्टॉपिंग।
एक स्टीयरिंग संदेश एजेंट को भेजा गया एक संदेश है जो LLM को चलने के दौरान प्राप्त होगा ताकि उसे एक दिशा में धकेला जा सके। यह वर्कर को तोड़े बिना एजेंट के कार्य संदर्भ को अपडेट करने के लिए उपयोगी है।
रद्दीकरण भी महत्वपूर्ण है, हम एक सबएजेंट को सक्रिय रूप से नीचे लाने में सक्षम होना चाहते हैं यदि उसे नहीं चलना चाहिए।
लाइव REPL और पूर्व-लेखक प्रोग्राम दोनों से इन संचालनों को चलाने में सक्षम होना Slate को वास्तविक समय में सब कुछ ऑर्केस्ट्रेट करने की क्षमता देता है। यह गतिशील रूप से रनटाइम पर ऑर्केस्ट्रेशन के आकार को परिभाषित कर सकता है, या यह ऑर्केस्ट्रेशन करने के लिए वास्तविक सॉफ्टवेयर लिख और पुनरावृत्त कर सकता है।
Slate .program.ts फ़ाइलों में प्रोग्राम लिखने में सक्षम है। एक प्रोग्राम फ़ाइल में कुछ चीज़ें होती हैं: इसका नाम (Slate इसी से जानता है कि यह क्या है), एक JSDoc विवरण, और फिर वास्तविक प्रोग्राम बॉडी*। एक प्रोग्राम घोषणा इस तरह दिखती है:
1program(async (ctx) => {2 // खोज के लिए सस्ता मॉडल — इसे सिर्फ फ़ाइलें ढूंढनी हैं3 const findings = await run("search", {4 type: "read",5 prompt: "Find all authentication-related files",6 model: "codex/gpt-4.1-mini", // आपकी बिल्ट-इन codex कुंजी का उपयोग करता है7 })8})
प्रोग्राम उसी async निष्पादन मॉडल का पालन करते हैं जो हमें एक प्रोग्राम को अग्रभूमि और पृष्ठभूमि दोनों में चलाने और चलने के दौरान उसके साथ बातचीत करने की अनुमति देता है।
1// पृष्ठभूमि एजेंट2const h = await spawn("worker", { type: "general", prompt: "Long task" })3await h.notify("focus on the parser first") // चल रहे एजेंट को स्टीयर संदेश4const result = await h.result() // बाद में पूरा होने की प्रतीक्षा करें5// फैलाएँ, फिर इकट्ठा करें6const a = await spawn({ prompt: "task A" })7const b = await spawn({ prompt: "task B" })8const [ra, rb] = [await a.result(), await b.result()]9// एक प्रोग्राम को पृष्ठभूमि में चलाएँ10import Audit from "deep-audit"11const ah = await spawn(Audit, { input: { pr: 42 } })12const auditResult = await ah.result()
संरचित आउटपुट और स्थिति
यह आज तक की हर दूसरी प्रणाली की प्राथमिक सीमा है। स्थिति, अन्य सभी प्रणालियों में, खराब तरीके से बाहरीकृत होती है और सुरक्षित रूप से पृथक नहीं होती है। यदि यह सिस्टम पर एक फ़ाइल है, तो आप कोई भ्रष्टाचार नहीं होने की गारंटी नहीं दे सकते। यदि आप कर सकते हैं, तो भी आप पार्सेबिलिटी की गारंटी नहीं दे सकते। आप संचालन चलाने के लिए स्थिति परिवर्तनों की सदस्यता नहीं ले सकते, और आप प्रकार के पालन की गारंटी नहीं दे सकते।
याद है कैसे हम स्थायी स्थिति चाहते थे जो संरचित भी हो और संदर्भित की जा सके?
Onyx में, स्थिति अलग है। स्थिति नामस्थान घोषित किए जाते हैं, सीधे नामित होते हैं और समय के साथ बने रहते हैं। इसका मतलब है कि एक स्थिति स्टोर का बार-बार पुन: उपयोग किया जा सकता है, जिससे आप वास्तविक डेटा के साथ लंबे समय तक चलने वाले एजेंट सिस्टम बना सकते हैं।
एजेंट और कोड दोनों स्थिति पढ़ते हैं, और हम जो नियतत्ववाद चाहते थे वह एक रनटाइम से इसी से निकलता है। एजेंट एक समर्पित टूल के माध्यम से स्थिति पढ़ते हैं जो उन्हें हमेशा सुरक्षित रूप से संरचित तरीके से इसके साथ बातचीत करने की अनुमति देता है। एजेंट और प्रोग्राम दोनों उपभोक्ता हैं जिन्हें स्थिति को संशोधित करने के लिए चलाया जा सकता है जो रनटाइम को ऑर्केस्ट्रेशन चलाने के लिए स्थिति ऑब्जेक्ट पर भरोसा करने देता है।
स्थिति, और स्कीमा का पालन, सबएजेंट के पूरा होने को नियंत्रित करता है। इस वजह से, स्थिति पूरे प्रोग्राम को चलाने के लिए एक एकीकृत सतह प्रदान करती है।
स्थिति ऑब्जेक्ट को मुख्य एजेंट के साथ साझा किए गए चाइल्ड सेशन में रनटाइम वेरिएबल के रूप में भी पास किया जा सकता है। एजेंट पदानुक्रम में यह पास-बाय-रेफरेंस एक्सेस (जो अपने आप में एक पहली बात है) एक साझा स्थिति चैनल के माध्यम से क्रॉस-एजेंट संचार की अनुमति देता है।

लंबे समय तक चलने वाले लूप
कुछ प्रोग्रामों को चल रहे सिस्टम की तरह अधिक कार्य करने की आवश्यकता होती है। उदाहरण के लिए openclaw को लें। आप वास्तव में सही आदिम दिए जाने पर openclaw को एक प्रोग्राम के रूप में प्रस्तुत कर सकते हैं। इसके लिए, हम दो आदिम का उपयोग करते हैं: sleep और checkpoint।
Sleep वही करता है जिसकी आप अपेक्षा करते हैं, यह सोता है।
अब बात यह है, मान लीजिए कि आप पृष्ठभूमि में कुछ लंबे समय तक चलने वाला कार्य प्रबंधन चाहते हैं। एक पूर्वनिर्धारित निष्पादन ग्राफ फंस सकता है या टूट सकता है, और इसलिए यह महत्वपूर्ण है कि मुख्य एजेंट प्रोग्राम की स्थिति से अवगत हो।
इसे समर्थन देने के लिए, हम checkpoint आदिम पेश करते हैं।
एक checkpoint कुछ भी हो सकता है, लेकिन इसे checkpoint नाम देने का कारण यह है कि यह मुख्य एजेंट को एक निश्चित आकार की वस्तु के साथ सूचित करता है। यह मुख्य एजेंट को कार्य प्रगति जैसी चीज़ों को ट्रैक करने और सीधे प्रोग्राम स्थिति में परिवर्तन के बारे में सूचित होने की अनुमति देता है। बदले में, मुख्य एजेंट तब एक चल रहे प्रोग्राम को अधिक प्रभावी ढंग से प्रबंधित कर सकता है।
Onyx Openclaw जैसा एजेंट लूप बनाने का समर्थन करता है, यानी एक दिल की धड़कन वाला एक स्थायी एजेंट।
यह वास्तव में बहुत अच्छा है, आप केवल while लूप, sleep और चेकपॉइंट का उपयोग करके प्रिमिटिव को पूरी तरह से अलग प्रकार के एजेंट में बदल सकते हैं।
Openclaw को केवल एक प्रोग्राम फ़ाइल के रूप में दर्शाया जा सकता है!
1// एक लंबे समय तक चलने वाले ऑटो-रिसर्च लूप को चलाने का प्रोग्राम2for (let i = 0; i < maxExperiments; i++) {3 const idea = await run("propose", { ... })4 const result = await run("train", { ... })5 checkpoint({ message: `experiment ${i}`, data: { idea, result } })6 await sleep(30_000) // प्रयोगों के बीच कूल डाउन7}89// एक openclaw शैली के स्थायी एजेंट को चलाने का प्रोग्राम10while(true) {11 const status = await run("status_check", { ...insert cheap model here... })if(status.pending_tasks) {checkpoint({ tasks: status.pending_tasks }) // महत्वपूर्ण स्थिति लौटाएं और मुख्य एजेंट को जगाएं}12 await sleep(30_000) // प्रयोगों के बीच कूल डाउन13}
रचना (Composition)
Onyx के साथ, Slate आपके लिए एक *.program.ts लिख सकता है। यह स्थायी होता है और इसे सामान्य कोड की तरह ही माना जाना चाहिए (और होना भी चाहिए)। इसमें बॉक्स से बाहर टाइप्स आते हैं, यह रनटाइम ग्लोबल्स से रहित रनटाइम में चलता है, और यह सिर्फ टाइपस्क्रिप्ट है, इसलिए इसकी रचना मॉडल सिर्फ दूसरे प्रोग्राम को इम्पोर्ट करना और कॉल करना है।
क्योंकि यह सिर्फ टाइपस्क्रिप्ट है, आपको समानांतरता (Promise.all) और लूप मुफ्त में मिलते हैं।
यहां बताया गया है कि आप एक प्रोग्राम को कैसे इम्पोर्ट करेंगे और दूसरे में इसका उपयोग करेंगे:
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", ... audit output) // यह चलेगा और ऑडिट प्रोग्राम आउटपुट को ठीक करेगा।4})
त्रुटि अर्थशास्त्र (Error semantics)
आदर्श VM में, त्रुटियां जोर से फेंकी जाती हैं। इन्हें रनटाइम सिंटैक्स समस्याओं, एजेंट विफलताओं, क्रैश आदि पर फेंका जाना चाहिए।
विशेष रूप से, हम ऑर्केस्ट्रेशन त्रुटियों को इस प्रकार परिभाषित करते हैं:
- एक एजेंट किसी कार्य पर अवरुद्ध है
- एक एजेंट किसी कार्य को पूरा करने में विफल रहा
- एक एजेंट किसी कार्य के लिए चरणों या बजट से बाहर हो गया
- एक प्रोग्राम एक रन के लिए बजट से बाहर हो गया
- ऑर्केस्ट्रेशन मॉडल वाक्यात्मक रूप से सही कोड लिखने में विफल रहा
- एक अवैध स्थिति संशोधन किया जा रहा है
ये सभी विशिष्ट त्रुटि मामले रनटाइम अर्थशास्त्र को परिभाषित करते हैं। वे कहते हैं, "आप इस रनटाइम से त्रुटि फेंकने की उम्मीद कर सकते हैं, क्योंकि हम एजेंट निष्पादन विफलता को उसी तरह देखते हैं जैसे हम कोड में त्रुटि देखते हैं"। यह पहली बार में कष्टप्रद लग सकता है, लेकिन यह जोरदार विफलता तंत्र आपको बदले में कुछ देता है: विफलताओं के आसपास तैयारी और प्रोग्राम करने का एक स्पष्ट तरीका। तो वास्तव में यह आपको अधिक नियंत्रण देता है, कम नहीं।
1// त्रुटियाँ try/catch हैं — किसी भी TypeScript प्रोग्राम के समान2program(async (ctx) => {3 try {4 const result = await run("risky-refactor", {5 type: "general",6 prompt: "प्रमाणीकरण मॉड्यूल को रीफैक्टर करें",7 model: "claude-sonnet",8 maxSteps: 20,9 })10 } catch (err) {11 // एजेंट विफल रहा — लेकिन हम जानते हैं कि वास्तव में क्यों।12 // ट्रेस में हर टूल कॉल, हर मॉडल अनुरोध,13 // हर स्थिति लेखन है जो यहां ले गया।1415 // एक अलग मॉडल के साथ पुनः प्रयास करें16 const result = await run("risky-refactor-retry", {17 type: "general",18 prompt: `पिछला प्रयास विफल रहा: ${err.message}. एक अलग दृष्टिकोण आज़माएं।`,19 model: "claude-opus",20 maxSteps: 30,21 })22 }23})
मॉडल चयन, बजट प्रवर्तन, और BYOK
मॉडल चयन का निर्मित होना आपको और भी सटीक नियंत्रण रखने की अनुमति देता है। /models स्किल Slate को उपलब्ध मॉडलों की सूची तक पूर्ण पहुंच प्रदान करता है, जिससे Slate को कई अलग-अलग मॉडलों के साथ प्रोग्राम लिखने की अनुमति मिलती है जो विभिन्न कार्य कर रहे हैं। चाहते हैं कि Fable योजनाकार हो, लेकिन GLM 5.2 एक नियतात्मक हार्नेस के अंदर कार्यान्वित करे? बिल्कुल। एक प्रश्न को Gemini, GPT 5.5, और DeepSeek में फैलाना चाहते हैं? वह भी काम करता है।
इसके अतिरिक्त, रनटाइम प्रोग्राम के लिए दो प्रकार के कॉन्फ़िग ओवरराइड का समर्थन करता है:
- एजेंट निष्पादन के लिए उपयोग किए जाने वाले डिफ़ॉल्ट वैश्विक मॉडल
- प्रोग्राम चलाने का बजट
आप किसी दिए गए लूप के लिए खर्च को सीमित करने के लिए सीधे रन बजट सेट कर सकते हैं।
इसके अतिरिक्त, रनटाइम आपके मौजूदा OpenAI और Github Copilot सब्सक्रिप्शन का उपयोग करने का समर्थन करता है।
1program(async (ctx) => {2 // खोज के लिए सस्ता मॉडल — इसे केवल फ़ाइलें ढूंढनी हैं3 const findings = await run("search", {4 type: "read",5 prompt: "सभी प्रमाणीकरण-संबंधित फ़ाइलें खोजें",6 model: "codex/gpt-4.1-mini", // आपकी निर्मित codex कुंजी का उपयोग करता है7 })89 // कठिन भाग के लिए तर्क मॉडल — इसे सोचने की आवश्यकता है10 const plan = await run("architect", {11 type: "general",12 prompt: `इसके आधार पर एक फिक्स डिज़ाइन करें: ${findings.output}`,13 model: "openai/o3", // अंत में API क्रेडिट का उपयोग करता है14 output: z.object({15 approach: z.string(),16 files: z.array(z.string()),17 risk: z.enum(["low", "medium", "high"]),18 }),19 })2021 // कार्यान्वयन के लिए मध्य-स्तरीय मॉडल — इसे केवल संपादित करने की आवश्यकता है22 const handles = await Promise.all(23 plan.files.map(f => spawn("fix-" + f, {24 type: "general",25 prompt: `${f} पर यह फिक्स लागू करें: ${plan.approach}`,26 model: "anthropic/claude-sonnet-5",27 maxSteps: 15,28 }))29 )30 await Promise.all(handles.map(h => h.result()))31})
लेखन सतह को परिभाषित करना
प्रोग्राम के लिए लेखन सतह को डिजाइन करने में दो मुख्य कारक थे: एक एजेंट के लिए इसे समझना कितना आसान है, और एक मानव के लिए इसे पढ़ना कितना आसान है। हमने अपेक्षाकृत सरल क्रियाओं को चुना जो अंग्रेजी की तरह पढ़ी जाती हैं, और स्पष्ट रूप से निर्णय लिया कि हम ऑर्केस्ट्रेशन को घोषणात्मक के बजाय प्रक्रियात्मक रूप से मॉडल करना चाहते हैं।
भाषा के रूप में TypeScript का चयन भी महत्वपूर्ण था। जंगली में इतना प्रक्रियात्मक TypeScript कोड है कि एक मॉडल पोस्ट-ट्रेनिंग के बिना भी TypeScript अर्थशास्त्र को स्पष्ट रूप से समझ जाएगा।

हमारे सॉफ्टवेयर फैक्ट्री के इंजीनियरिंग भाग
अगला उत्तर देने वाला प्रश्न है: यह सब आपको क्या खरीदता है?
यह आपको अपने एजेंट ऑर्केस्ट्रेशन के लिए वास्तविक सॉफ्टवेयर लिखने की क्षमता खरीदता है। अब आप अपने स्वयं के एजेंट ऑर्केस्ट्रेशन को अंत से अंत तक इंजीनियर कर सकते हैं।
आप फैक्ट्री को इंजीनियर कर सकते हैं।
उदाहरण के लिए, आप एक प्रोग्राम बना सकते हैं जो एक लूप में Github की निगरानी करता है, और एक अलग प्रोग्राम जो समीक्षा के लिए QA एजेंट के साथ एक कार्यान्वयन एजेंट चलाता है। दोनों व्यक्तिगत रूप से उपयोगी पैटर्न हैं जो आपको जंगली में मिल सकते हैं। फिर आप उन्हें एक साथ रखकर एक ऐसी प्रणाली बना सकते हैं जो PR पर टिप्पणियों को सुनती है, उन टिप्पणियों को संबोधित करने के लिए एक कार्यान्वयनकर्ता को स्पॉन करती है, और फिर यह सुनिश्चित करने के लिए एक QA एजेंट को स्पॉन करती है कि फिक्स मान्य है।
फिर आप इस प्रोग्राम का उपयोग टास्क क्यू से जुड़े हुए अपने कोडबेस पर काम को सौंपने और मॉनिटर करने के लिए कर सकते हैं, और इसे स्वचालित रूप से PR टिप्पणियों का जवाब दे सकते हैं।
और आप यह सब तेज़ ओपन वेट मॉडल का उपयोग करके कर सकते हैं। क्योंकि यह सिर्फ कोड है, पहली बार लिखे जाने के बाद आपको ऑर्केस्ट्रेशन के माध्यम से सोचने के लिए एक शक्तिशाली LLM की आवश्यकता नहीं है।
अब मजेदार हिस्से के लिए, उन कुछ प्रोग्रामों को साझा करने का समय है जिनका उपयोग हमने भारी आउटपुट वृद्धि के लिए किया है।
गहन कोडबेस अनुसंधान (Deep Codebase Research)
हम कार्यों के दायरे को निर्धारित करने में मदद के लिए इस प्रोग्राम का उपयोग करते हैं। यह हमारे मोनोरेपो की स्थिति पर गहन शोध करता है, और एक कार्यान्वयनकर्ता के संदर्भ के लिए एक शोध पैकेट तैयार करता है। हम इसका हर समय उपयोग करते हैं। यह महंगा लगता है, लेकिन वास्तव में ऐसा नहीं है। आप इस प्रोग्राम को Slate में DeepSeek V4 Flash के साथ चला सकते हैं और शोध प्रक्रिया गहन लेकिन बहुत सस्ती है।

लक्ष्य-समीक्षा-PR (Goal-Review-PR)
यह वह है जिसका उपयोग हम एक बार शोध पूरा हो जाने के बाद किसी कार्य को लागू करने के लिए करते हैं। सौभाग्य से, जब तक शोध लक्ष्य प्रोग्राम तक पहुंचता है, अधिकांश कार्य अस्पष्टता हल हो चुकी होती है, जिससे कार्य को निष्पादित करना और भी तेज हो जाता है। एक हल्के OSS मॉडल के साथ शोध को फ्रंट-लोड करने से हमारे लिए एक महंगे मॉडल जैसे Opus का उपयोग करना आसान हो जाता है जो मायने रखता है: वास्तव में अच्छा कोड लिखना और सिस्टम की स्थिति को सत्यापित करना। आप Opus 4.8 के काम की प्रतिकूल समीक्षा करने के लिए GPT 5.5 का उपयोग करने के लिए प्रोग्राम को संशोधित भी कर सकते हैं।

एक प्रोग्राम के रूप में ऑटोरिसर्च (Autoresearch as a Program)
Autoresearch[[9]](http://localhost:5173/blog/onyx#ref-9) मूल रूप से पूरी तरह से LLM-संचालित था। एक एजेंट को program.md प्रॉम्प्ट पर निर्देशित करें और यह तय करता है कि क्या प्रयास करना है और कैसे आगे बढ़ना है।
कोई आश्चर्य नहीं, Autoresearch वास्तव में सिर्फ एक प्रोग्राम है।
एजेंट प्रोग्राम आपको इसे उलटने और नियंत्रण प्रवाह को रनटाइम में रखने की अनुमति देते हैं। प्रोग्राम नियंत्रण प्रवाह का मालिक है जबकि एजेंट साइड-इफेक्टिंग कार्य (कोड संपादित करना, git चलाना, रिमोट GPU पर SSH करना, प्रशिक्षण) करते हैं। ऑटोरिसर्च प्रोग्राम के लिए, रखने/वापस लाने का निर्णय नियतात्मक कोड है:
1kept = status === "ok" && valBpb != null && valBpb < best
हमारे मामले में, प्रोग्राम एक नया रेपो तैयार करने और रिमोट A100 तक पहुंच की पुष्टि करने के लिए एक सेटअप एजेंट चलाता है। यदि सेटअप विफल हो जाता है, तो यह एक टाइप किए गए मान के आधार पर एक साफ निकास के साथ जल्दी वापस आ जाता है। अन्यथा यह प्रयोग लूप में प्रवेश करता है।
प्रत्येक प्रयोग को एक नया एजेंट मिलता है। एजेंट को वर्तमान सर्वश्रेष्ठ कॉन्फ़िग और पिछले विचारों और परिणामों का इतिहास दिया जाता है, ताकि वह खुद को दोहराए नहीं और जो रखा गया था उस पर निर्माण कर सके। यह एक बदलाव प्रस्तावित करता है, train.py को संपादित करता है, कमिट करता है, रिमोट मशीन पर rsync करता है, प्रशिक्षित करता है, और परिणाम को वर्गीकृत करता है।
एजेंट और प्रोग्राम स्थिति साझा करते हैं। एजेंट स्थिति में डेटा लिखता है, और प्रोग्राम नियंत्रण प्रवाह के लिए स्थिति का मूल्यांकन करता है। परिणाम के आधार पर, एक रिकॉर्डर एजेंट results.tsv को अपडेट करता है, और यदि प्रोग्राम ने प्रयोग को त्यागने का निर्णय लिया तो वैकल्पिक रूप से रन को रीसेट करता है। यह git HEAD को हमेशा प्रयोग वृक्ष की वर्तमान सर्वश्रेष्ठ शाखा की ओर इंगित करता है।
ध्यान देने योग्य दो मुख्य अंतर हैं: 1) यह एक प्रोग्राम में चलता है इसलिए हम प्रति प्रयोग एक नया एजेंट स्पॉन कर सकते हैं और 2) हम लाइव प्रोग्राम स्थिति के आधार पर तय कर सकते हैं कि एजेंट को कौन सा कार्य करना चाहिए।


और यह कोड में इस तरह दिखता है:
1// ---------- प्रोग्राम ----------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: `सेटअप विफल: ${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 // एजेंट ने त्रुटि दी/अवरुद्ध हो गया — क्रैश के रूप में मानें, रेपो को सर्वश्रेष्ठ पर पुनर्स्थापित करें, जारी रखें।32 exp = {33 description: `प्रयोग ${i} एजेंट त्रुटि`,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: `exp ${i}/${total}: ${exp.status}${kept ? " KEPT" : ""} val_bpb=${exp.valBpb ?? "n/a"} (best=${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})
भविष्य का कार्य (Future work)
एकमात्र शेष VM आवश्यकता जिसे हमने अभी तक परिभाषित नहीं किया है, वह प्रोग्राम के लिए स्थायित्व मॉडल है। यह स्पष्ट नहीं है कि प्रोग्राम के जीवनचक्र को फिर से शुरू करने और संभालने के लिए सही मॉडल क्या है, और रनटाइम पर नियंत्रण का कौन सा स्तर उजागर किया जाना चाहिए।
इसके अलावा, बहुत सी रोमांचक चीजें हैं जिन्हें हम विभिन्न कार्यभार और कार्य आकृतियों का समर्थन करने के लिए जोड़ेंगे, ताकि हम एजेंटों को बेहतर ढंग से ऑर्केस्ट्रेट करने के लिए वास्तविक सॉफ्टवेयर लिख सकें। हमें विश्वास है कि कई पैटर्न लोगों द्वारा अपने दम पर रचनात्मक तरीकों से प्रोग्राम का उपयोग करने से सामने आएंगे।
हम वास्तव में यह देखने के लिए इंतजार नहीं कर सकते कि आप क्या बनाते हैं।
- RL टीम
संदर्भ (References)
- Yao et al., "ReAct: Synergizing Reasoning and Acting in Language Models," 2022
- Geoffrey Huntley, "The Ralph Loop"
- Geoffrey Huntley, "everything is a ralph loop," January 2026
- Zhang, Kraska, Khattab, "Recursive Language Models," December 2025
- Wang et al., "Executable Code Actions Elicit Better LLM Agents," ICML 2024
- OpenAI, "Introducing Deep Research," February 2025
- Cursor, "Scaling Agents," January 2026
- OpenAI, "Using Goals in Codex"
- Andrej Karpathy, "autoresearch"
- Anthropic, "Introducing Dynamic Workflows in Claude Code"
- OpenAI, "Learning to Reason with LLMs," September 2024
- Anthropic, "A harness for every task: dynamic workflows in Claude Code"
- Random Labs, "Skill Chaining"





