Omnilude के ai-service में Agent इस तरह काम करते हैं
शुरू करने से पहले
यह लेख Omnilude के ai-service ने Assistant / Thread / Run संरचना क्यों चुनी का अगला भाग है। पिछले लेख में मैंने assistant, thread, और run की भूमिका समझाई थी। इस बार मैं बताना चाहता हूँ कि उसी संरचना के ऊपर agent वास्तव में कैसे काम करता है।
जब मैं इस संरचना को समझाता हूँ, तो सबसे पहले एक गलतफ़हमी हटाना चाहता हूँ। Omnilude का AiAgent कोई जादुई ब्लैक बॉक्स नहीं है। यह assistants को किसी बिल्कुल अलग चीज़ में बदल देने वाली परत भी नहीं है। सच तो यह है कि यह उसके उलट है। AiAgent एक ऐसी संरचना है जो कई assistants को nodes के रूप में जोड़ती है और उनके execution order को workflow के रूप में सहेजती है।
इसे थोड़ा और सरल तरीके से कहें तो:
अगर
AiAssistantएक individual LLM preset है, तोAiAgentउन presets को जोड़ने वाला workflow है।
इस लेख में मैं समझाने की कोशिश करूँगा कि यह flow कोड में कैसे implement किया गया है, और वह भी जितना हो सके उतनी आसान भाषा में।
Agent कोई अलग AI नहीं, बल्कि workflow है
सबसे पहले AiAgent entity को देखना चाहिए। इसमें नाम, विवरण और type भी है, लेकिन असली केंद्र workflow field है। यह value किसी अलग table में नहीं, बल्कि JSONB के रूप में store होती है।
यानी Omnilude में agent को "एक ऐसा object जो model को और समझदारी से बुलाए" की तरह देखने से ज़्यादा सही होगा कि उसे nodes और edges से बने execution graph की तरह देखा जाए।
उदाहरण के लिए, एक agent ऐसा दिख सकता है:
- start node पर input लेता है।
generate-textnode एक assistant का उपयोग करके text बनाता है।routernode अगला path तय करता है।- आख़िरी
finishnode result को व्यवस्थित करता है।
इसे देखने के बाद assistant और agent का अंतर काफ़ी साफ़ हो जाता है।
- assistant एक single inference के लिए preset है।
- agent वह workflow है जो तय करता है कि वे inferences किस क्रम और किन शर्तों में जुड़ेंगे।
Agent कोई अलग AI नहीं, बल्कि workflow है (टेक्स्ट संदर्भ)
AiAssistant
- एक single LLM call के लिए preset
- कौन सा model/provider/instructions इस्तेमाल होगा, यह तय करता है
AiAgent
- कई nodes को जोड़ने वाला workflow
- हर node assistant का उपयोग कर सकता है या tool की तरह behave कर सकता है
- असली बात "एक call" नहीं, बल्कि "execution order और connection" है
Request आते ही execution शुरू नहीं होती
Omnilude में AiAgent execution आमतौर पर एक synchronous function call पर खत्म नहीं होती। यहाँ महत्वपूर्ण भूमिका DTE (Distributed Task Executor) निभाता है।
कुल flow लगभग ऐसा है:
- client या backoffice agent execution का अनुरोध करता है।
- server उसे तुरंत process नहीं करता, बल्कि DTE job में बदल देता है।
- queue में गया job
WorkflowTaskHandlerउठाता है। - उसके बाद
SingleWorkflowExecutorवास्तविक workflow execution संभालता है। - अंदर
BasicWorkflowEnginenodes को एक-एक करके आगे बढ़ाता है।
यह संरचना इसलिए महत्वपूर्ण है क्योंकि agent execution अक्सर लंबी चल सकती है, streaming के साथ आ सकती है, बीच का state रखना पड़ सकता है, और कभी-कभी इसे background में भी चलना चाहिए। अगर यह सब एक साधारण request-response में ठूँस दिया जाए, तो संरचना जल्दी अस्थिर हो जाती है। Execution को job की तरह संभालना ज़्यादा मज़बूत तरीका है।
Request आते ही execution शुरू नहीं होती (टेक्स्ट संदर्भ)
Controller
-> AiAgentExecutor
-> DistributedTaskQueue
-> WorkflowTaskHandler
-> SingleWorkflowExecutor
-> BasicWorkflowEngine
मुख्य बिंदु
- execution को job की तरह handle किया जाता है
- streaming और background processing आसान हो जाती है
- long-running execution को एक ही संरचना में manage किया जा सकता है
शुरुआत एक start node से होती है
Workflow होने का मतलब यह नहीं कि engine शुरुआत से अंत तक list को क्रम से पढ़ता जाए। BasicWorkflowEngine पहले उस node को ढूँढता है जहाँ startNode=true हो और type -input पर खत्म होता हो। फिर वही initial input लेकर execution शुरू करता है।
मुझे यह हिस्सा काफ़ी पसंद है। यह agent को "एक command line" की तरह नहीं, बल्कि स्पष्ट entry point वाले execution graph की तरह देखता है।
उदाहरण के लिए, text-input node user द्वारा दिया गया string तैयार करता है और उसे अगले node तक भेजता है। फिर generate-text node वही value लेकर LLM call trigger करता है। उसके बाद output edge के साथ अगले node तक propagate होता है।
दूसरे शब्दों में, agent कोई बहुत बड़ा function नहीं है। यह छोटे-छोटे execution units का जुड़ा हुआ flow है।
Nodes को वास्तव में चलाने का काम NodeExecutor करता है
यहाँ सबसे महत्वपूर्ण layer NodeExecutor है। हर node के पास एक type string होती है, और NodeExecutorFactory उस type के हिसाब से executor ढूँढता है। वहीं NodeExecutorRegistry @NodeType annotation को scan करके यह auto-register करता है कि कौन सा executor किस type को handle करेगा।
इस संरचना की वजह से नया node जोड़ते समय पूरे engine को बदलने की ज़रूरत नहीं पड़ती। एक node बनाइए, उसका type घोषित कीजिए, provider जोड़िए, और वह runtime में शामिल हो जाता है।
इस लेख में समझने लायक चार प्रमुख nodes हैं:
TextInputNode: शुरुआती input तैयार करता है।GenerateTextNode: assistant का उपयोग करके वास्तविक text बनाता है।RouterNode: LLM की मदद से अगला path तय करता है।FinishNode: अंतिम result इकट्ठा करता है और execution समाप्त करता है।
इन चार nodes को समझ लेने से Omnilude की agent संरचना का काफ़ी हिस्सा समझ में आ जाता है।
Agent के अंदर भी वास्तविक inference assistants ही करते हैं
यहीं यह लेख पिछले लेख से दोबारा जुड़ता है।
AiAgent होने का मतलब यह नहीं कि agent खुद सीधे model को call करता है। वास्तविक LLM call node के अंदर होती है, और उसी समय AiAssistantService फिर से सामने आता है।
उदाहरण के लिए, GenerateTextNode अपनी config से aiAssistantId पढ़ता है। फिर उसी id से assistant को लोड करता है, AiModel, AiProvider, और AiApiKey को जोड़ता है, और RunnableAiAssistant बनाता है। उसके बाद ही असली chat model call होती है।
यानी इस संरचना को ऐसे समझना ज़्यादा सही है:
- assistants inference के लिए components हैं
- agents वे workflows हैं जो तय करते हैं कि ये components किस क्रम में चलेंगे
एक बार यह बात समझ में आ जाए, तो assistant और agent को एक-दूसरे के competitor की तरह देखने की ज़रूरत नहीं रहती। वे alternatives नहीं हैं। वे अलग-अलग layers हैं।
Agent के अंदर भी वास्तविक inference assistants ही करते हैं (टेक्स्ट संदर्भ)
AiAgent
- workflow रखने वाली ऊपरी execution unit
Node
- ज़रूरत पड़ने पर assistant चुनता है और call करता है
RunnableAiAssistant
- assistant + model + provider + key से बना वास्तविक executable object
/ai-runs path में agent conversation context के ऊपर चलता है
एक और दिलचस्प हिस्सा /ai-runs path है। यह कोई ऐसा API नहीं है जो stored agent को सीधे execute कर दे। यह पहले thread के messages को पढ़ता है, फिर उसी context के ऊपर एक specific AiAgent workflow चलाता है।
मौजूदा implementation में ChatAgentTaskHandler AiAgentType.USING_WEB_SEARCH_TOOL जैसे किसी agent type को चुनता है और उसे SingleWorkflowExecutor को सौंप देता है। यानी इस बिंदु पर run सिर्फ़ एक साधारण LLM call नहीं रह जाता। यह conversation context के ऊपर agent workflow शुरू करने वाला command बन जाता है।
यही उन कारणों में से एक है जिनसे Omnilude का ai-service सिर्फ़ model wrapper की बजाय एक platform जैसा महसूस होता है। वही inference structure, जब thread/message/run interface के ऊपर रखा जाता है, तो उसका product-level अर्थ बदल जाता है।
इस लेख में मैं जानबूझकर multiagent को बाहर रख रहा हूँ
अगर आप कोड पढ़ेंगे तो multiagent package भी दिखाई देगा। लेकिन उसका स्वभाव यहाँ समझाए जा रहे AiAgent workflow से थोड़ा अलग है। वह ज़्यादा एक अलग orchestration layer जैसा है, जो multiple agents, dynamic routing, retries, और human review जैसी बड़ी समस्याओं को संभालता है।
सबसे महत्वपूर्ण बात यह है कि अभी उसमें कुछ हिस्से प्रगति पर हैं। इसलिए मैं उसे मौजूदा AiAgent runtime के बिल्कुल उसी स्तर पर समझाना नहीं चाहता। इसीलिए मैंने उसे इस लेख से जानबूझकर बाहर रखा है। इस लेख की सीमा सिर्फ़ इतनी है कि assistants को जोड़कर एक agent workflow कैसे चलाया जाता है।
इस तरह scope को सीमित रखने से लेख समझना आसान होता है और व्याख्या भी धुंधली नहीं पड़ती।
मुझे यह संरचना काफ़ी व्यावहारिक लगती है
फिर से देखें तो Omnilude के ai-service में agent कोई अलग, बड़े नाम वाली AI नहीं है। यह assistants के ऊपर लिपटी एक और wrapper भी नहीं है। अगर कुछ है, तो यह ज़्यादा व्यावहारिक है।
- execution flow
AiAgent.workflowमें store होता है - वास्तविक execution DTE job के रूप में सौंपी जाती है
- engine start node से edge के सहारे आगे बढ़ता है
- हर node ज़रूरत पड़ने पर assistant को बुलाकर LLM का उपयोग करता है
मुझे यह संरचना इसलिए अच्छी लगती है क्योंकि यह extensibility को बढ़ा-चढ़ाकर पेश नहीं करती। assistant, thread, run और agent सबकी अलग भूमिका है, और हर एक की जिम्मेदारी की सीमा अपेक्षाकृत साफ़ है।
मेरा मानना है कि जैसे-जैसे AI features किसी product के अंदर गहराई से जाते हैं, वैसी संरचना और भी महत्वपूर्ण हो जाती है। लंबे समय तक जो चीज़ टिकती है, वह सिर्फ़ यह नहीं कि आपने model को एक बार अच्छी तरह call किया, बल्कि यह है कि आपने किस unit में चीज़ों को store किया, किस interface से execute किया, और किस flow से जोड़ा।
समापन
अगर पिछले लेख में assistant / thread / run Omnilude के execution platform की बुनियादी अवधारणाएँ थीं, तो इस लेख में agent उसके ऊपर रखा गया composition layer है। AiAgent कोई अलग AI नहीं, बल्कि workflow को store करने वाली entity है, और उसका execution DTE -> WorkflowExecutor -> NodeExecutor के flow से गुजरता है।
और वास्तविक inference आज भी assistants ही करते हैं। अंततः Omnilude का ai-service assistants और agents को आमने-सामने खड़ा करके नहीं बढ़ता, बल्कि assistants को components की तरह इस्तेमाल करके agents बनाता है।
अगले लेख में मैं इसे एक कदम और व्यावहारिक दिशा में ले जाऊँगा और concrete examples के साथ दिखाऊँगा कि मैं वास्तविक workflow JSON और node composition को कैसे design करता हूँ।