Alejandro Rioja.
AI Agents Operations

मल्टी-एजेंट ऑर्केस्ट्रेशन पैटर्न: क्यू, स्टेट और हैंडऑफ़

Alejandro Rioja
Alejandro Rioja
8 मिनट पढ़ें
TL;DR

भरोसेमंद मल्टी-एजेंट सिस्टम चतुर प्रॉम्प्ट से नहीं बनते — वे डिस्ट्रिब्यूटेड सिस्टम के उबाऊ अनुशासन से बनते हैं: एजेंटों के बीच टिकाऊ क्यू, मॉडल के बाहर रखा गया स्टेट, और ऐसे आइडम्पोटेंट हैंडऑफ़ जो रीट्राई झेल जाते हैं। मॉडल वर्कर है; क्यू रीढ़ की हड्डी है।

मुफ़्त न्यूज़लेटर

हर बुधवार। 28,400+ पाठक। बिना फालतू बात।

विषय-सूची

जून 2026 में अपडेट किया गया।

संक्षेप में: भरोसेमंद मल्टी-एजेंट सिस्टम चतुर प्रॉम्प्ट से नहीं जीते जाते — वे डिस्ट्रिब्यूटेड सिस्टम के उबाऊ अनुशासन से जीते जाते हैं। एजेंटों के बीच एक टिकाऊ क्यू रखें, स्टेट को मॉडल के बाहर रखें, और हर हैंडऑफ़ को आइडम्पोटेंट बनाएँ ताकि कोई रीट्राई दोबारा कार्रवाई न कर सके। मॉडल वर्कर है; क्यू रीढ़ की हड्डी है। इन तीनों को सही कर लें और ऑर्केस्ट्रेशन डरावना नहीं रह जाता।

ऑपरेटर का नज़रिया: मेरे 100 से ज़्यादा एजेंटों में अधिकतर सिंगल-स्टेप हैं। जो नहीं हैं — वे पाइपलाइन जो पहले क्लासिफ़ाई करती हैं, फिर एनरिच करती हैं, फिर कार्रवाई करती हैं — वे तभी भरोसेमंद बनीं जब मैंने “प्रॉम्प्ट चेन” सोचना बंद किया और “LLM वर्कर वाली जॉब क्यू” सोचना शुरू किया। यह आर्किटेक्चर है, प्रॉम्प्ट इंजीनियरिंग नहीं।

“मल्टी-एजेंट” सुनने में ऐसा लगता है जैसे एजेंट आपस में बात करते हों। व्यवहार में, भरोसेमंद संस्करण इसका उलटा है: एजेंट सीधे संवाद करते ही नहीं। वे एक क्यू पर संदेश छोड़ते हैं और एक क्यू से काम उठाते हैं, और ऑर्केस्ट्रेशन उनके बीच की पाइपलाइन (प्लंबिंग) में बसता है। ये वे पैटर्न हैं जो प्रोडक्शन में टिके रहते हैं।

पैटर्न 1: हर एजेंट के बीच एक टिकाऊ क्यू रखें

पहली प्रवृत्ति होती है एजेंट A के भीतर से सीधे एजेंट B को कॉल करना। ऐसा न करें। सीधी कॉल दोनों को जोड़ देती हैं: अगर B धीमा है, A रुक जाता है; अगर B विफल होता है, A का काम खो जाता है; अगर आपको B को स्केल करना है, तो A को छुए बिना नहीं कर सकते।

इसके बजाय, A अपना काम पूरा करता है और B के लिए एक संदेश क्यू में डालता है। B एक अलग वर्कर है जो क्यू को अपनी गति से खाली करता है।

typescript
// एजेंट A समाप्त करता है और क्यू के ज़रिए हैंडऑफ़ करता है — B को कोई सीधी कॉल नहीं
await env.ENRICH_QUEUE.send({
  traceId,
  type: "enrich",
  payload: classifierResult,
});
// A का काम पूरा हुआ। B इसे स्वतंत्र रूप से उठाएगा।

Cloudflare पर मैं ठीक इसी के लिए Workers Queues इस्तेमाल करता हूँ — वही प्रिमिटिव जो जिस एजेंट स्टैक का मैं इस्तेमाल करता हूँ के पीछे हैं। क्यू आपको मुफ़्त में चार चीज़ें देती है: बफ़रिंग (B बंद हो सकता है फिर भी काम नहीं खोता), रीट्राई (विफल संदेश दोबारा भेजे जाते हैं), बैकप्रेशर (बढ़ोतरी क्रैश की बजाय क्यू में जमा होती है), और डिकपलिंग (A को छुए बिना B को स्केल या रीडिप्लॉय करें)। इनमें से हर एक वह चीज़ है जिसे वरना आपको हाथ से बनाना पड़ता और गलती करनी पड़ती।

पैटर्न 2: स्टेट को हमेशा मॉडल के बाहर रखें

सबसे आम मल्टी-एजेंट बग यह मान लेना है कि मॉडल को चरणों के बीच कुछ याद रहता है। नहीं रहता। हर मॉडल कॉल स्टेटलेस है; एकमात्र स्मृति वही है जो आप प्रॉम्प्ट में डालते हैं। इसलिए “यह जॉब पाइपलाइन में कहाँ है” के लिए सत्य का स्रोत एक डेटाबेस में बसना चाहिए, बातचीत में नहीं।

मैं एक ही जॉब रिकॉर्ड रखता हूँ जिसे हर एजेंट पढ़ता और अपडेट करता है:

typescript
interface JobState {
  traceId: string;
  stage: "classified" | "enriched" | "acted" | "done" | "failed";
  data: Record<string, unknown>;
  attempts: number;
  updatedAt: number;
}

हर एजेंट वही लूप चलाता है: जॉब स्टेट पढ़ो, अपना काम करो, नया स्टेट लिखो, अगला चरण क्यू में डालो। मॉडल कभी स्टेट नहीं रखता — वह संबंधित हिस्सा इनपुट के रूप में पाता है और एक परिणाम लौटाता है। यही सिस्टम को रीस्टार्ट-योग्य बनाता है: अगर कोई वर्कर जॉब के बीच मर जाए, तो स्टेट रिकॉर्ड अब भी ठीक-ठीक बताता है कि चीज़ें कहाँ थीं, और दोबारा भेजा गया क्यू संदेश वहीं से आगे बढ़ाता है। यह डिबगिंग को भी संभालने लायक बनाता है, क्योंकि स्टेट टेबल हर जॉब की यात्रा का एक क्वेरी-योग्य रिकॉर्ड है — वही इंस्ट्रूमेंटेशन मानसिकता जो मैं कैसे मापता हूँ कि कोई एजेंट सचमुच काम कर रहा है या नहीं में है।

पैटर्न 3: हर हैंडऑफ़ को आइडम्पोटेंट बनाएँ

क्यू कम-से-कम-एक-बार डिलीवरी की गारंटी देती हैं, ठीक एक बार की नहीं। इसका मतलब है कि एक संदेश दो बार पहुँच सकता है — नेटवर्क झटके, रीट्राई, रीडिप्लॉय। अगर आपके एजेंट की कार्रवाई आइडम्पोटेंट नहीं है, तो दोहरी डिलीवरी दोहरी कार्रवाई करती है: दो पुष्टि-ईमेल, दो बुकिंग, दो चार्ज। यह ऑर्केस्ट्रेशन बग की सबसे बुरी श्रेणी है, और यही वह है जिसे टीमें प्रोडक्शन में खोजती हैं।

हल यह है कि कार्रवाइयों को एक की (key) से आइडम्पोटेंट बनाया जाए:

typescript
async function handleEnrich(msg: QueueMessage, env: Env) {
  const job = await getJob(env, msg.traceId);
  if (job.stage !== "classified") {
    // इस चरण से आगे पहले ही प्रोसेस हो चुका — यह डुप्लिकेट डिलीवरी है। छोड़ दें।
    return;
  }
  const result = await enrich(job.data);
  await advanceJob(env, msg.traceId, "enriched", result);
  await env.ACT_QUEUE.send({ traceId: msg.traceId, type: "act" });
}

चरण-जाँच ऑपरेशन को दो बार चलाने के लिए सुरक्षित बना देती है: दूसरी डिलीवरी देखती है कि जॉब पहले ही आगे बढ़ चुका है और कुछ नहीं करती। बाहरी साइड-इफ़ेक्ट (ईमेल भेजना, कार्ड चार्ज करना) के लिए, डाउनस्ट्रीम API को एक आइडम्पोटेंसी की पास करें ताकि वह भी डीडुप्लिकेट करे। मान लें कि हर संदेश दो बार पहुँचेगा और इस तरह डिज़ाइन करें कि वह हानिरहित हो — क्योंकि आख़िरकार ऐसा होगा।

पैटर्न 4: ऑर्केस्ट्रेटर बनाम कोरियोग्राफ़ी — सोच-समझकर चुनें

फ़्लो को जोड़ने के दो तरीके हैं, और सही चुनाव जटिलता पर निर्भर करता है।

कोरियोग्राफ़ी (जो मैं डिफ़ॉल्ट रूप से अपनाता हूँ): हर एजेंट केवल अगला चरण जानता है और उसे क्यू में डालता है। फ़्लो श्रृंखला से उभरता है। सरल, विकेंद्रित, बढ़ाने में आसान — एक क्यू डालकर एक चरण जोड़ें। नुकसान यह है कि कोई एक जगह पूरे फ़्लो का वर्णन नहीं करती, इसलिए एक जटिल पाइपलाइन के बारे में सोचना कठिन हो सकता है।

ऑर्केस्ट्रेशन (एक केंद्रीय समन्वयक): एक ऑर्केस्ट्रेटर फ़्लो का स्वामी होता है, हर एजेंट को बारी-बारी से कॉल करता है, और परिणामों के आधार पर तय करता है कि आगे क्या। पूरा फ़्लो एक पठनीय जगह में बसता है और ब्रांचिंग लॉजिक स्पष्ट होता है। कीमत है एक केंद्रीय घटक जिसे स्वयं टिकाऊ होना चाहिए — अगर ऑर्केस्ट्रेटर का अपना स्टेट बाहर नहीं रखा गया (पैटर्न 2), तो वह एकल विफलता-बिंदु बन जाता है।

मेरा नियम: जब तक ब्रांचिंग जटिल न हो जाए तब तक कोरियोग्राफ़ी, फिर एक टिकाऊ ऑर्केस्ट्रेटर। एक रैखिक तीन-चरण पाइपलाइन कोरियोग्राफ़ी है। शर्तीय रूटिंग, समानांतर फ़ैन-आउट, और जॉइन वाले फ़्लो को एक ऐसा ऑर्केस्ट्रेटर चाहिए जिसका स्टेट डेटाबेस में बसता हो ताकि वह क्रैश के बाद फिर से शुरू हो सके।

पैटर्न 5: टुकड़े खोए बिना फ़ैन-आउट, फ़ैन-इन

जब एक जॉब N समानांतर उप-कार्य जन्म देता है (50 रिकॉर्ड एनरिच करना, 20 दस्तावेज़ सारांशित करना) और जारी रखने से पहले आपको उन सबका इंतज़ार करना होता है, तो आपको एक जॉइन चाहिए। तरकीब है जॉब स्टेट में एक काउंटर:

  1. पैरेंट N चाइल्ड संदेश क्यू में डालता है और जॉब रिकॉर्ड में expected: N, completed: 0 लिखता है।
  2. हर चाइल्ड अपना काम करता है और completed को परमाणविक रूप से बढ़ाता है।
  3. जो चाइल्ड completed को expected के बराबर तक पहुँचाता है, वह अगला चरण क्यू में डालता है।

परमाणविक वृद्धि भार-वहन करने वाली है — इसके बिना, एक साथ ख़त्म होने वाले दो चाइल्ड दोनों सोच सकते हैं कि वे आख़िरी नहीं हैं, और जॉइन कभी ट्रिगर नहीं होता। ऐसा काउंटर इस्तेमाल करें जिसे डेटास्टोर परमाणविक रूप से बढ़ा सके, या एक ट्रांज़ैक्शन। यह पैटर्न आपको पाइपलाइन के महँगे बीच के हिस्से को समानांतर करने देता है (अक्सर Haiku-सस्ता काम — देखें Haiku बनाम Sonnet की लागत-गणित) जबकि अंत में एक साफ़ जॉइन बनाए रखता है।

जो मैं छोड़ दूँगा

इनमें से कुछ भी करने के लिए आपको एक भारी-भरकम एजेंट फ़्रेमवर्क की ज़रूरत नहीं है। क्यू, एक स्टेट टेबल, और आइडम्पोटेंसी कीज़ ऐसी प्रिमिटिव हैं जो हर प्लेटफ़ॉर्म के पास पहले से हैं। मैंने टीमों को विस्तृत मल्टी-एजेंट फ़्रेमवर्क की ओर हाथ बढ़ाते देखा है ताकि वे वे सुविधाएँ पा सकें जो एक क्यू मुफ़्त देती है, और एक ऐसा ब्लैक बॉक्स विरासत में पा लेते हैं जिसे डिबग करना उस पाइपलाइन से कठिन है जिसे उसने बदला। उबाऊ प्रिमिटिव से शुरू करें। किसी फ़्रेमवर्क की ओर तभी हाथ बढ़ाएँ जब आपने कोई ठोस दर्द महसूस किया हो जिसे वह हल करता है।

सारांश: एजेंट स्टेटलेस वर्कर हैं, क्यू टिकाऊ रीढ़ की हड्डी हैं, स्टेट एक डेटाबेस में बसता है, और हर हैंडऑफ़ दो बार चलाने के लिए सुरक्षित है। बस यही पूरा खेल है।

अक्सर पूछे जाने वाले प्रश्न

क्या एजेंटों को एक-दूसरे को सीधे कॉल करना चाहिए या क्यू से गुज़रना चाहिए?

क्यू से। सीधी कॉल एजेंटों को जोड़ देती हैं — एक की विफलता या सुस्ती दूसरे तक फैलती है, और आप स्वतंत्र रूप से स्केल या रीडिप्लॉय नहीं कर सकते। एक टिकाऊ क्यू आपको बफ़रिंग, रीट्राई, बैकप्रेशर, और डिकपलिंग मुफ़्त में देती है।

मल्टी-एजेंट स्टेट कहाँ बसना चाहिए?

मॉडल के बाहर, एक डेटाबेस में, एक जॉब रिकॉर्ड के रूप में जिसे हर एजेंट पढ़ता और अपडेट करता है। मॉडल कॉल स्टेटलेस होती हैं, इसलिए पाइपलाइन प्रगति के लिए सत्य का स्रोत बाहरी होना चाहिए — यही सिस्टम को क्रैश के बाद रीस्टार्ट-योग्य बनाता है।

मैं किसी एजेंट को एक ही जॉब पर दो बार कार्रवाई करने से कैसे रोकूँ?

हैंडऑफ़ को आइडम्पोटेंट बनाएँ। कार्रवाई से पहले जॉब का चरण जाँचें और अगर वह पहले ही आगे बढ़ चुका हो तो कुछ न करें, और बाहरी API को आइडम्पोटेंसी कीज़ पास करें। क्यू कम-से-कम-एक-बार डिलीवर करती हैं, इसलिए मान लें कि हर संदेश दो बार आ सकता है और इस तरह डिज़ाइन करें कि डुप्लिकेट हानिरहित हों।

क्या मुझे एक मल्टी-एजेंट फ़्रेमवर्क चाहिए?

आमतौर पर नहीं। टिकाऊ क्यू, एक स्टेट टेबल, और आइडम्पोटेंसी कीज़ अधिकांश प्रोडक्शन ज़रूरतों को उन प्रिमिटिव से पूरा कर देती हैं जो आपका प्लेटफ़ॉर्म पहले से देता है। फ़्रेमवर्क तभी अपनाएँ जब आप किसी ठोस समस्या से टकराएँ जिसे वह अनोखे ढंग से हल करता है, डिफ़ॉल्ट रूप से नहीं।

पढ़ते रहें

AI प्लेबुक अपने इनबॉक्स में पाएं

हर बुधवार। 28,400+ पाठक। बिना फालतू बात।

↵ सभी परिणाम देखें esc esc बंद करें