क्यों कई एजेंटिक सिस्टम प्रोडक्शन में असफल होते हैं और स्टेट‑मशीन, स्पष्ट टूल कॉन्ट्रैक्ट्स, रिट्राई नीतियाँ और गहरी ऑब्ज़र्वेबिलिटी के साथ विश्वसनीय एजेंट कैसे डिज़ाइन करें।

एजेंटिक सिस्टम वे एप्लिकेशन हैं जहाँ एक LLM केवल प्रॉम्प्ट का उत्तर नहीं देता, बल्कि आगे क्या करना है तय करता है: कौन से टूल कॉल करने हैं, कौन सा डेटा लाना है, कौन से स्टेप चलाने हैं और कब काम पूरा हुआ माना जाए। ये एक मॉडल, टूल्स (APIs, डेटाबेस, सेवाएँ), एक प्लानिंग/एक्सेक्यूशन लूप, और उन सबको जोड़ने वाली इन्फ्रास्ट्रक्चर का संयोजन होते हैं।
डेमो में यह जादुई लगता है: एक एजेंट योजना बनाता है, कुछ टूल कॉल करता है, और एक परिपूर्ण परिणाम लौटाता है। हैप्पी‑पाथ छोटा होता है, लैटेंसी कम होती है, और कुछ भी एक साथ फेल नहीं होता।
असल वर्कलोड में वही एजेंट उन तरहों से तनाव में आता है जो डेमो ने कभी नहीं देखे:
परिणाम: फ़्लैकी व्यवहार जिसे पुनःप्रजनन करना कठिन है, चुप्पी से हुए डेटा करप्शन, और उपयोगकर्ता फ्लोज़ जो कभी‑कभी हैंग या अनंत लूप में पड़ जाते हैं।
फ़्लैकी एजेंट केवल “डिलाइट” को चोट नहीं पहुँचाते। वे:
यह लेख इंजीनियरिंग पैटर्न्स के बारे में है, "बेहतर प्रॉम्प्ट्स" के बारे में नहीं। हम स्टेट मशीनें, स्पष्ट टूल कॉन्ट्रैक्ट्स, रिट्राई और विफलता‑हैंडलिंग रणनीतियाँ, मेमोरी और समवर्तीता नियंत्राण, और वे ऑब्ज़र्वेबिलिटी पैटर्न देखेंगे जो एजेंटिक सिस्टम्स को लोड के तहत पूर्वानुमेय बनाते हैं — न कि सिर्फ़ मंच पर प्रभावित करने वाले।
अधिकांश एजेंट सिस्टम एकल हैप्पी‑पाथ डेमो में ठीक लगते हैं। वे तब विफल होते हैं जब ट्रैफ़िक, टूल्स और एज‑केसेस साथ आते हैं।
नैव ऑर्केस्ट्रेशन मानता है कि मॉडल एक या दो कॉल में "सही" करेगा। असली उपयोग में, आप निम्न पैटर्न बार‑बार देखते हैं:
बिना स्पष्ट स्टेट्स और समाप्ति शर्तों के ये व्यवहार अनिवार्य हैं।
LLM सैंपलिंग, लेटेंसी वैरिएबिलिटी, और टूल टाइमिंग छिपे हुए नॉन‑डिटरमिनिज़्म पैदा करते हैं। वही इनपुट अलग‑अलग ब्रांच से गुज़र सकता है, अलग टूल्स को कॉल कर सकता है, या टूल परिणामों को अलग तरह से इंटरप्रेट कर सकता है।
स्केल पर, टूल समस्याएँ प्रमुख हो जाती हैं:
इनमें से हर एक स्प्यूरियस लूप्स, रिट्राईज़, या गलत अंतिम उत्तर में बदल जाता है।
10 RPS पर दुर्लभ जो टूटता है, 1,000 RPS पर लगातार टूटेगा। समवर्तीता प्रकट करती है:
उत्पादन टीमें अक्सर निर्धारक वर्कफ़्लो, स्पष्ट SLA, और ऑडिटेबिलिटी की उम्मीद करती हैं। एजेंट, बिना सीमाओं के छोड़े जाएँ, प्रोबैबिलिस्टिक, बेस्ट‑एफ़र्ट व्यवहार देते हैं जिनमें कमजोर गारंटियाँ होती हैं।
जब आर्किटेक्चर इस मिसमैच को नज़रअंदाज़ करते हैं—एजेंट्स को पारंपरिक सेवाओं की तरह मानते हुए न कि स्टोकेस्टिक प्लानर्स की तरह—तो सिस्टम सबसे ज़रूरीReliability की जरूरतों में अनिश्चित व्यवहार करने लगते हैं।
प्रोडक्शन‑रेडी एजेंट्स "स्मार्ट प्रॉम्प्ट्स" से अधिक अनुशासित सिस्टम डिज़ाइन के बारे में होते हैं। एक उपयोगी सोच यह है कि उन्हें छोटे, पूर्वानुमेय मशीनों के रूप में सोचें जो कभी‑कभी LLM को कॉल करते हैं, न कि रहस्यमयी LLM ब्लॉबस के रूप में जो कभी‑कभी आपके सिस्टमों को छूते हैं।
चार गुण सबसे ज़्यादा मायने रखते हैं:
ये गुण केवल प्रॉम्प्ट्स से नहीं मिलते; आपको संरचना चाहिए।
कई टीमें जो पैटर्न यूज़ करती हैं वह है: “while not done, call the model, let it think, maybe call a tool, repeat”. यह प्रोटोटाइप करने में आसान है पर ऑपरेट करने में कठिन।
एक सुरक्षित पैटर्न यह है कि एजेंट को एक स्पष्ट वर्कफ़्लो के रूप में प्रदर्शित करें:
COLLECTING_INPUT, PLANNING, EXECUTING_STEP, WAITING_ON_HUMAN, DONE).यह एजेंट को एक स्टेट मशीन में बदल देता है जहाँ हर चरण निरीक्षण योग्य, परीक्षण योग्य और रिप्लेबल होता है। फ्री‑फॉर्म लूप्स लचीले लगते हैं, पर स्पष्ट वर्कफ़्लोज़ ही होते हैं जो इंस्टेंन्ट्स को डिबग्गेबल और व्यवहार को ऑडिटेबल बनाते हैं।
मोनोलिथिक एजेंट जो "सब कुछ" करते हैं आकर्षक होते हैं, पर वे असंबंधित जिम्मेदारियों के बीच कड़ी कपलिंग पैदा करते हैं: प्लानिंग, रिट्रीवल, बिज़नेस लॉजिक, UI ऑर्केस्ट्रेशन इत्यादि।
बदले में, छोटे, अच्छी तरह परिभाषित एजेंट्स/स्किल्स तैयार करें:
हर स्किल अपनी स्टेट मशीन, टूल्स और सुरक्षा नियम रख सकती है। कम्पोज़िशन लॉजिक तब एक उच्च‑स्तरीय वर्कफ़्लो बन जाता है, न कि एक एकल एजेंट के अंदर बढ़ता हुआ प्रॉम्प्ट।
यह मॉड्यूलैरिटी हर एजेंट को सरल रखने में मदद करती है और आपको एक क्षमता को बिना बाकी को प्रभावित किए विकसित करने देती है।
एक उपयोगी मानसिक मॉडल एजेंट को तीन लेयर्स में विभाजित करना है:
निर्णय नीति (LLM प्रॉम्प्ट्स + मॉडल)
यह encapsulate करता है कि एजेंट अगला एक्शन कैसे चुनता है, सख्त प्रतिबंधों के तहत। आपको मॉडल बदलने, टेम्परेचर समायोजित करने, या प्रॉम्प्ट परिष्कृत करने में सक्षम होना चाहिए बिना सिस्टम वायरिंग को छेड़े।
स्टेट मशीन / वर्कफ़्लो इंजन
यह नियंत्रित करता है कि आप प्रक्रिया में कहाँ हैं, कौन‑से ट्रांज़िशन संभव हैं, और प्रगति कैसे परसिस्ट की जाती है। नीति एक मूव सुझाव देती है; स्टेट मशीन उसे वैध ठहराती और लागू करती है।
टूलिंग लेयर
यह धरती पर क्या हो सकता है वह लागू करता है: APIs, डेटाबेस, क्यूज़, बाहरी सेवाएँ। टूल्स संकुचित, अच्छी‑टाइप्ड कॉन्ट्रैक्ट्स एक्सपोज़ करें और प्राधिकरण, रेट‑लिमिट्स और इनपुट वैलिडेशन लागू करें।
इस विभाजन से आप प्रॉम्प्ट्स या टूल विवरणों में बिज़नेस लॉजिक छिपाने की गलती से बचते हैं। LLM एक स्पष्ट, निर्धारित खोल के अंदर एक निर्णय घटक बनकर काम करता है, न कि खुद खोल बन जाता है।
सबसे भरोसेमंद एजेंटिक सिस्टम सबसे शानदार डेमो नहीं होते—वे वे होते हैं जिनके व्यवहार आप वाइटबोर्ड पर समझा सकते हैं।
व्यवहारिक रूप से:
छोटे, कंपोज़ेबल और सुव्यवस्थित एजेंट्स की यह प्रवृत्ति सिस्टम को उसकी जटिलता के कारण ढहने से रोकती है और स्कोप के साथ सुरक्षित रूप से बढ़ने देती है।
अधिकांश एजेंट कार्यान्वयन एक LLM कॉल के चारों ओर "सोचो, काम करो, अवलोकन करो" लूप के रूप में शुरू होते हैं। यह डेमो के लिए ठीक है, पर जल्दी ही यह अस्पष्ट और नाज़ुक बन जाता है। एक बेहतर दृष्टिकोण है कि एजेंट को एक स्पष्ट स्टेट मशीन के रूप में माना जाए: सीमित स्टेट्स का सेट, जिनमें टाइप्ड इवेंट्स द्वारा ट्रांज़िशन होते हैं।
मॉडल को यह तय करने देने की बजाय कि आगे क्या करना है, एक छोटा स्टेट डायाग्राम परिभाषित करें:
इन स्टेट्स के बीच ट्रांज़िशन टाइप्ड इवेंट्स द्वारा ट्रिगर होते हैं जैसे UserRequestReceived, ToolCallSucceeded, ToolValidationFailed, TimeoutExceeded, या HumanOverride. हर इवेंट और वर्तमान स्टेट मिलकर अगला स्टेट और कार्रवाई तय करते हैं।
यह रिट्राईज़ और टाइमआउट्स को सरल बनाता है: आप व्यक्तिगत स्टेट्स (उदा., CALL_TOOL 3 बार एक्सपोनेंशियल बैकऑफ़ के साथ रिट्राई कर सकता है, पर PLAN शायद बिल्कुल रिट्राई न करे) पर नीतियाँ संलग्न करते हैं, बजाय इसके कि रिट्राई लॉजिक को कोडबेस भर में बिखेर दें।
वर्तमान स्टेट और न्यूनतम संदर्भ को बाहरी स्टोर (डेटाबेस, क्यू, या वर्कफ़्लो इंजन) में परसिस्ट करें। एजेंट तब एक शुद्ध फ़ंक्शन बन जाता है:
next_state, actions = transition(current_state, event, context)
यह सक्षम बनाता है:
स्टेट मशीन के साथ, एजेंट के व्यवहार का हर चरण स्पष्ट होता है: वह किस स्टेट में था, कौन‑सा इवेंट आया, कौन‑सा ट्रांज़िशन फायर हुआ, और कौन‑से साइड‑इफेक्ट्स उत्पन्न हुए। यह स्पष्टता डिबगिंग को तेज बनाती है, घटना जाँच को सरल करती है, और अनुपालन समीक्षाओं के लिए स्वाभाविक ऑडिट ट्रेल बनाती है। आप लॉग्स और स्टेट इतिहास से यह प्रमाणित कर सकते हैं कि कुछ जोखिमपूर्ण क्रियाएँ केवल विशिष्ट स्टेट्स और परिभाषित शर्तों के तहत ही उठाई जाती हैं।
जब टूल्स "प्रॉम्प्ट में छिपे APIs" की तरह नहीं बल्कि स्पष्ट गारंटी देने वाले इंटरफेस की तरह दिखते हैं, तो एजेंट अधिक पूर्वानुमेय रूप से व्यवहार करते हैं।
हर टूल का कॉन्ट्रैक्ट निम्न को कवर करना चाहिए:
InvalidInput, NotFound, RateLimited, TransientFailure) साफ़ अर्थों के साथ।इस कॉन्ट्रैक्ट को मॉडल के पास संरचित दस्तावेज़ के रूप में एक्सपोज़ करें, न कि लंबे टेक्स्ट की दीवार के रूप में। एजेंट प्लानर को पता होना चाहिए कि कौन‑सी त्रुटियाँ रिट्राय‑योग्य हैं, किसके लिए उपयोगकर्ता हस्तक्षेप चाहिए, और किससे वर्कफ़्लो रोका जाना चाहिए।
टूल I/O को किसी भी अन्य प्रोडक्शन API की तरह ट्रीट करें:
यह प्रॉम्प्ट्स को सरल बनाता है: विस्तृत निर्देशों की बजाय स्कीमा‑ड्रिवन मार्गदर्शन पर निर्भर करें। स्पष्ट प्रतिबंध हलुसिनेटेड आर्ग्यूमेंट्स और निरर्थक टूल अनुक्रमों को कम कर देते हैं।
टूल्स समय के साथ विकसित होते हैं; एजेंट हर बार टूटना नहीं चाहिए:
v1, v1.1, v2) और एजेंट्स को एक वर्शन पर पिन करें।ताकि प्लानिंग लॉजिक अलग‑अलग परिपक्वता वाले एजेंट्स और टूल्स को सुरक्षित रूप से मिलाकर इस्तेमाल कर सके।
कॉन््ट्रैक्ट्स को आंशिक विफलता को ध्यान में रखकर डिज़ाइन करें:
फिर एजेंट अनुकूलित कर सकता है: सीमित कार्यक्षमता के साथ वर्कफ़्लो जारी रखें, उपयोगकर्ता से पुष्टिकरण माँगें, या किसी फ़ॉलबैक टूल पर स्विच करें।
टूल कॉन्ट्रैक्ट्स सुरक्षा सीमाओं को कोडित करने के लिए प्राकृतिक स्थान हैं:
confirm: true)।इन्हें सर्वर‑साइड चेक्स के साथ मिलाएँ; कभी केवल मॉडल पर भरोसा न करें कि वह "ठीक" रहेगा।
जब टूल्स के पास स्पष्ट, वैलिडेटेड, वर्शनड कॉन्ट्रैक्ट्स होते हैं तो प्रॉम्प्ट्स छोटे हो जाते हैं, ऑर्केस्ट्रेशन लॉजिक सरल होता है, और डिबगिंग काफी आसान हो जाती है। आप जटिलता को नाज़ुक नैचुरल‑लैंग्वेज इंस्ट्रक्शन्स से deterministic स्कीम्स और नीतियों में शिफ्ट कर देते हैं, जिससे हलुसिनेटेड टूल कॉल और अनपेक्षित साइड‑इफेक्ट्स घटते हैं।
भरोसेमंद एजेंटिक सिस्टम मान लेते हैं कि सब कुछ कभी‑न‑कभी फेल होगा: मॉडल्स, टूल्स, नेटवर्क, यहाँ तक कि आपका समन्वय लेयर भी। लक्ष्य यह नहीं है कि विफलता से बचा जाए, बल्कि इसे सस्ता और सुरक्षित बनाया जाए।
इडेम्पोटेंसी का मतलब है: उसी अनुरोध को दोहराने से बहिर्मुख रूप से वही प्रभाव होगा जैसा एक बार करने से होता। यह LLM एजेंट्स के लिए महत्वपूर्ण है, जो आंशिक विफलताओं या अस्पष्ट प्रतिक्रियाओं के बाद अक्सर टूल कॉल दोहराते हैं।
टूल्स को इस प्रकार बनायें कि वे इडेम्पोटेंट हों:
request_id हो। टूल इसे स्टोर करे और वही परिणाम लौटाये यदि यह ID फिर से देखा गया।ट्रांज़िएंट विफलताओं (टाइमआउट, रेट‑लिमिट्स, 5xx) के लिए संरचित रिट्राईज़ का उपयोग करें: एक्सपोनेंशियल बैकऑफ़, थिर्र (jitter) ताकि थंडरिंग हर्ड्स से बचा जा सके, और सख्त मैक्स अटेम्प्ट्स। हर प्रयास को कॉरिलेशन IDs के साथ लॉग करें ताकि आप एजेंट व्यवहार को ट्रेस कर सकें।
स्थायी त्रुटियों (4xx, वैलिडेशन एरर्स, बिज़नेस रूल उल्लंघन) के लिए रिट्राई न करें। एक संरचित एरर एजेंट नीति तक पहुँचाएँ ताकि वह योजना संशोधित करे, उपयोगकर्ता से पूछे, या अलग टूल चुने।
एजेंट और टूल लेयर दोनों पर सर्किट ब्रेकर्स लागू करें: बार‑बार विफलता होने पर उस टूल को अस्थायी रूप से ब्लॉक करें और फेल‑फास्ट करें। इसे स्पष्ट फ़ॉलबैक्स से जोड़ें: डिग्रेडेड मोड, कैश्ड डेटा, या वैकल्पिक टूल्स।
एजेंट लूप से अंधाधुंध रिट्राईज़ से बचें। बिना इडेम्पोटेंट टूल्स और स्पष्ट फेल्यर क्लासेस के, आप केवल साइड‑इफेक्ट्स, लेटेंसी और लागत को गुणा कर देंगे।
भरोसेमंद एजेंट स्पष्ट सोच से शुरू होते हैं कि "कौन‑सा स्टेट है" और "यह कहाँ रहता है"।
एजेंट को ऐसे समझें जैसे आप एक अनुरोध हैंडल करने वाली सेवा को समझते हैं:
इनको मिलाने से भ्रम और बग होते हैं — उदाहरण के लिए, अस्थायी टूल परिणामों को "मेमोरी" में डाल देने से एजेंट भविष्य की बातचीत में stale संदर्भ दुबारा उपयोग कर सकता है।
आपके पास तीन मुख्य विकल्प हैं:
एक अच्छा नियम: LLM एक स्पष्ट स्टेट ऑब्जेक्ट पर स्टेटलेस फ़ंक्शन है। वह ऑब्जेक्ट मॉडल के बाहर परसिस्ट करें और उससे प्रॉम्प्ट्स पुनर्निर्मित करें।
एक सामान्य विफलता पैटर्न है बातचीत लॉग्स, ट्रेसेस, या रॉ प्रॉम्प्ट्स को डि‑फैक्टो मेमोरी बना देना।
समस्याएँ:
इसके बजाय, संरचित मेमोरी स्कीम्स परिभाषित करें: user_profile, project, task_history आदि। लॉग्स को स्टेट से व्युत्पन्न करें, विपरीत नहीं।
जब कई टूल्स या एजेंट्स एक ही एंटिटी को अपडेट करते हैं (उदा., CRM रिकॉर्ड या टास्क स्टेट), तो आपको बुनियादी कन्सिस्टेंसी नियंत्रण चाहिए:
उच्च‑मूल्य ऑपरेशंस के लिए, एक संवादी लॉग से अलग निर्णय लॉग रिकॉर्ड करो: क्या बदला, क्यों, और किस इनपुट्स के आधार पर।
क्रैश, डिप्लॉइस और रेट‑लिमिटिंग से बचने के लिए, वर्कफ़्लोज़ को रिज़्यूमेबल बनाना चाहिए:
यह "टाइम‑ट्रैवल डिबगिंग" भी सक्षम बनाता है: आप उस सटीक स्टेट का निरीक्षण और रिप्ले कर सकते हैं जिसने खराब निर्णय को जन्म दिया।
मेमोरी एक संपत्ति जितनी कि एक दायित्व है। प्रोडक्शन एजेंट्स के लिए:
मेमोरी को एक उत्पाद सतह की तरह डिज़ाइन, वर्शन और शासित करें — सिर्फ़ एजेंट से चिपका हुआ एक बढ़ता हुआ टेक्स्ट डंप नहीं।
एजेंट्स श्वेतपट पर क्रमिक दिखते हैं पर असली लोड में वितरित सिस्टम की तरह व्यवहार करते हैं। जैसे ही कई समवर्ती उपयोगकर्ता, टूल्स और बैकग्राउंड जॉब्स आते हैं, आप रेस कंडीशंस, डुप्लिकेट काम, और ऑर्डरिंग समस्याओं से जूझते हैं।
सामान्य विफलता मोड:
इन्हें रोका जा सकता है इडेम्पोटेंट टूल कॉन्ट्रैक्ट्स, स्पष्ट वर्कफ़्लो स्टेट, और डेटालेयर पर ऑप्टिमिस्टिक/पेसीमिस्टिक लॉकिंग से।
सिंक अनुरोध–प्रतिक्रिया फ्लोज़ सरल पर नाज़ुक हैं: हर निर्भरता उप, रेट‑लिमिट के भीतर, और तेज होनी चाहिए। जब एजेंट कई टूल्स या पैरेलल सब‑टास्क में फैले, तो लंबे चलने वाले या साइड‑इफ़ेक्ट वाले स्टेप्स को क्यू के पीछे ले जाएँ।
क्यू‑आधारित ऑर्केस्ट्रेशन आपको सक्षम बनाता है:
एजेंट्स सामान्यतः तीन प्रकार की सीमाओं से टकराते हैं:
आपको एक स्पष्ट रेट‑लिमिट लेयर चाहिए जिसमें प्रति‑उपयोगकर्ता, प्रति‑टेनेंट, और ग्लोबल थ्रॉटल्स हों। पॉलिसी लागू करने के लिए टोकन बकेट या लीकी बकेट का उपयोग करें, और स्पष्ट एरर टाइप एक्सपोज़ करें (उदा., RATE_LIMIT_SOFT, RATE_LIMIT_HARD) ताकि एजेंट शांतिपूर्वक बैक ऑफ कर सके।
बैकप्रेशर सिस्टम को तनाव के दौरान खुद को बचाने का तरीका है। रणनीतियाँ शामिल हैं:
क्यू डैप्थ, वर्कर उपयोग, मॉडल/टूल एरर रेट्स, और लेटेंसी प्रतिशतILES की निगरानी करें। बढ़ती कतारें और बढ़ती लेटेंसी या 429/503 एरर्स शुरुआती चेतावनी हैं कि एजेंट्स अपने वातावरण को ओवररन कर रहे हैं।
अगर आप इन दो प्रश्नों का उत्तर जल्दी नहीं दे सकते: उसने क्या किया? और उसने ऐसा क्यों किया?—तो आप एजेंट को भरोसेमंद बना नहीं सकते। एजेंटिक सिस्टम्स के लिए ऑब्ज़र्वेबिलिटी का मतलब है उन उत्तरों को सस्ता और सटीक बनाना।
डिज़ाइन ऐसा करें कि एक ही टास्क का ट्रेस निम्न चीज़ों से गुज़रे:
उस ट्रेस में महत्वपूर्ण निर्णयों के लिए संरचित लॉग्स और वॉल्यूम/हेल्थ के लिए मैट्रिक्स जोड़ें।
एक उपयोगी ट्रेस आमतौर पर शामिल करता है:
प्रॉम्प्ट्स, टूल इनपुट्स और आउटपुट्स को संरचित रूप में लॉग करें, पर उन्हें पहले एक रेडक्शन लेयर से गुज़ारें:
रॉ कंटेंट को लोअर एन्वाइरनमेंट में फीचर फ्लैग्स के पीछे रखें; प्रोडक्शन में डिफ़ॉल्ट रूप से रेडैक्टेड व्यू रखें।
कम से कम ट्रैक करें:
घटनाओं के दौरान, अच्छे ट्रेसेस और मैट्रिक्स आपको "एजेंट फ़्लैकी लग रहा है" से एक सटीक कथन तक पहुँचाने देते हैं जैसे: “P95 टास्क ToolSelection में 2 रिट्राई के बाद फेल कर रहे हैं क्योंकि billing_service में नया स्कीमा आया है,” जिससे निदान घंटे के बजाय मिनटों में हो सके और आपको व्यवहार संशोधित करने के ठोस लीवर मिलें।
एजेंट्स का परीक्षण उन टूल्स और उन फ्लोज़ दोनों का परीक्षण करना होता है जो उन्हें जोड़ते हैं। इसे केवल प्रॉम्प्ट ट्वीक करने की तरह न मानें—इसे वितरण प्रणाली के टेस्ट जैसा मानें।
शुरुआत टूल बॉउन्ड्री पर यूनिट टेस्ट्स से करें:
ये टेस्ट्स कभी LLM पर निर्भर नहीं होने चाहिए। आप टूल को सीधे सिंथेटिक इनपुट्स के साथ कॉल करें और सटीक आउटपुट या एरर कॉन्ट्रैक्ट का असर्ट करें।
इंटीग्रेशन टेस्ट्स एजेंट वर्कफ़्लो को एंड‑टू‑एंड पर परखते हैं: LLM + टूल्स + ऑर्केस्ट्रेशन।
इन्हें सीनारियो‑आधारित टेस्ट्स के रूप में मॉडल करें:
ये टेस्ट्स यह असर्ट करें कि कौन‑से टूल्स कॉल हुए, किस आर्ग्युमेंट्स के साथ, किस क्रम में, और एजेंट ने किस अंतिम स्टेट/परिणाम तक पहुँचा।
टेस्ट्स को रिप्रोड्यूसिबल रखने के लिए LLM रिस्पॉन्स और टूल आउटपुट फिक्स्चर करें:
एक सामान्य पैटर्न:
with mocked_llm(fixtures_dir="fixtures/llm"), mocked_tools():
result = run_agent_scenario(input_case)
assert result.state == "COMPLETED"
हर प्रॉम्प्ट या स्कीमा परिवर्तन पर एक अनिवार्य रिग्रेशन रन रखें:
कोई नया मॉडल, नीति, या राउटिंग रणनीति सीधे प्रोडक्शन ट्रैफ़िक पर मत भेजें।
इसके बजाय:
ऑफ़लाइन गेट्स पास करने के बाद ही नया वेरिएंट प्रोडक्शन पर जाए, आदर्श रूप से फीचर फ्लैग्स और क्रमिक रोलआउट के पीछे।
एजेंट लॉग्स अक्सर संवेदनशील उपयोगकर्ता डेटा रखते हैं। परीक्षण में इसका सम्मान करें:
इन नियमों को CI पाइपलाइन का हिस्सा बनाएं ताकि कोई भी टेस्ट आर्टिफैक्ट बिना अनोनिमाइजेशन के जनरेट या स्टोर न हो सके।
प्रोडक्शन में एजेंट्स चलाना स्थिर मॉडल भेजने जैसा नहीं है; यह एक विकसित होते हुए सेवा को चलाने जैसा है। आपको रोलआउट कंट्रोल्स, स्पष्ट विश्वसनीयता लक्ष्य, और अनुशासित परिवर्तन प्रबंधन चाहिए।
नए एजेंट या व्यवहार को धीरे‑धीरे परिचित कराएँ:
इन सबका समर्थन फीचर फ्लैग्स और कॉन्फ़िग‑ड्रिवन नीतियों से करें: राउटिंग नियम, सक्षम टूल्स, टेम्परेचर, सुरक्षा सेटिंग्स। बदलाव को कोड नहीं बल्कि कॉन्फ़िग से deploy और रीवर्ट करें।
ऐसे SLOs परिभाषित करें जो सिस्टम हेल्थ और उपयोगकर्ता वैल्यू दोनों को दर्शाते हों:
इन्हें अलर्ट में बाँधें और घटनाओं को उसी तरह संभालें जैसे किसी भी प्रोडक्शन सेवा को: स्पष्ट मालिक, ट्रायेज रनबुक, और मानक शमन कदम (रोलबैक फ्लैग, ट्रैफ़िक ड्रेन, सेफ़‑मोड)।
लॉग्स, ट्रेसेस, और ट्रांसक्रिप्ट्स का उपयोग करके प्रॉम्प्ट्स, टूल्स और नीतियों को परिष्कृत करें। हर परिवर्तन को वर्शनड आर्टिफैक्ट मानें जिसमें समीक्षा, अनुमोदन और रोलबैक क्षमता हो।
चुपके से प्रॉम्प्ट या टूल परिवर्तन करने से बचें। बिना परिवर्तन‑नियंत्रण के, आप रिग्रेशन्स को किसी विशेष एडिट से नहीं जोड़ पाएँगे और घटना प्रतिक्रिया अनुमान पर निर्भर कर जाएगी बजाय इंजीनियरिंग के।
एक प्रोडक्शन‑रेडी एजेंटिक सिस्टम स्पष्ट जिम्मेदारियों के पृथक्करण से लाभान्वित होता है। लक्ष्य यह है कि एजेंट निर्णयों में स्मार्ट रहे, पर इन्फ्रास्ट्रक्चर में मूर्ख (dumb) रहे।
1. गेटवे / API एज
क्लाइंट्स (ऐप्स, सर्विसेज, UIs) के लिए सिंगल एंट्री पॉइंट। यह संभालता है:
2. ऑर्केस्ट्रेटर
ऑर्केस्ट्रेटर "ब्रेनस्टेम" है, न कि पूरा ब्रेन। यह समन्वय करता है:
LLMs ऑर्केस्ट्रेटर के पीछे रहते हैं, प्लानर और उन विशेष टूल्स द्वारा उपयोग किए जाते हैं जिन्हें भाषा समझ की आवश्यकता होती है।
3. टूलिंग और स्टोरेज लेयर
बिज़नेस लॉजिक मौजूदा माइक्रोसर्विसेज, क्यूज़ और डेटा सिस्टमों में रहता है। टूल्स पतले रैपर होते हैं जो:
ऑर्केस्ट्रेटर टूल्स को सख्त कॉन्ट्रैक्ट्स के माध्यम से कॉल करता है, जबकि स्टोरेज सिस्टम्स सत्यता का स्रोत बने रहते हैं।
गेटवे पर ऑथ और कोटास लागू करें; ऑर्केस्ट्रेटर में सुरक्षा, डेटा एक्सेस और नीति लागू करें। सभी कॉल्स (LLM और टूल्स) संरचित टेलीमेट्री इमिट करें जो पाइपलाइन को खिलाती है और वह पाइपलाइन आगे चलकर देती है:
सरल वास्तुकला (गेटवे → एकल ऑर्केस्ट्रेटर → टूल्स) ऑपरेशन में आसान है; अलग‑अलग प्लानर्स, पॉलिसी इंजन और मॉडल गेटवे जोड़ना लचीलापन बढ़ाता है पर समन्वय, लेटेंसी और ऑपरेशनल जटिलता भी बढ़ाता है।
अब आपके पास वे मुख्य सामग्री हैं जिनसे एजेंट लोड के तहत पूर्वानुमेय व्यवहार करेंगे: स्पष्ट स्टेट मशीनें, स्पष्ट टूल कॉन्ट्रैक्ट्स, अनुशासित रिट्राईज़, और गहरी ऑब्ज़र्वेबिलिटी। अंतिम कदम इन विचारों को आपकी टीम के लिए एक दोहराने योग्य अभ्यास में बदलना है।
प्रत्येक एजेंट को एक स्टेटफुल वर्कफ़्लो के रूप में सोचें:
जब ये टुकड़े एक साथ आते हैं, तो आपको ऐसे सिस्टम मिलते हैं जो एज‑केसेस में धीरे‑धीरे degrade करते हैं बजाय इसके कि ढह जाएँ।
प्रोटोटाइप एजेंट को असली उपयोगकर्ताओं पर भेजने से पहले सुनिश्चित करें:
यदि कोई आइटम गायब है, तो आप अभी भी प्रोटोटाइप मोड में हैं।
एक स्थायी सेटअप आमतौर पर अलग करता है:
यह उत्पाद टीमों को तेज़ी से बदलने देता है जबकि प्लेटफ़ॉर्म टीमें विश्वसनीयता, सुरक्षा और लागत नियंत्रण सुनिश्चित करती हैं।
एक बार नींव स्थिर हो जाए, आप इनका अन्वेषण कर सकते हैं:
यहाँ प्रगति क्रमिक होनी चाहिए: नए लर्निंग घटकों को फीचर फ्लैग्स के पीछे लाएँ, ऑफ़लाइन मूल्यांकन और मजबूत गार्डरेल्स के साथ।
सारे सिद्धांत एक ही विषय से बंधे हैं: विफलता के लिए डिज़ाइन करें, चतुराई पर स्पष्टता को प्राथमिकता दें, और जहाँ आप ऑब्ज़र्व कर सकते हैं और तुरंत रोलबैक कर सकते हैं वहाँ क्रमिक रूप से इटरेशन करें। इन प्रतिबंधों के साथ, एजेंटिक सिस्टम डरावने प्रोटोटाइप नहीं रह जाते बल्कि ऐसा इन्फ्रास्ट्रक्चर बन जाते हैं जिस पर आपकी संस्था निर्भर कर सकती है।
एक एजेंटिक सिस्टम वह एप्लिकेशन है जहाँ एक LLM केवल एक प्रॉम्प्ट का उत्तर नहीं देता बल्कि आगे क्या करना है तय करता है: कौन से टूल कॉल करने हैं, कौन सा डेटा लाना है, वर्कफ़्लो का कौन सा स्टेप चलाना है और कब काम समाप्त हुआ माना जाए.
एक साधारण चैट कंप्लीशन के उलट, एक एजेंटिक सिस्टम निम्न चीज़ों का संयोजन होता है:
प्रोडक्शन में, LLM पूरे सिस्टम का केंद्र नहीं रहता बल्कि एक निर्णय घटक बनकर एक बड़े, निर्धारित खोल के अंदर काम करता है।
डेमो आमतौर पर एक ही हैप्पी‑पाथ पर चलते हैं: एक उपयोगकर्ता, आदर्श टूल व्यवहार, कोई टाइमआउट नहीं, कोई स्कीमा ड्रिफ्ट नहीं और छोटे संवाद। प्रोडक्शन लोड में एजेंटों को निम्न समस्याओं का सामना करना पड़ता है:
यदि स्पष्ट वर्कफ़्लो, कॉन्ट्रैक्ट और विफलता‑हैंडलिंग न हों, तो ये कारक लूप, स्टॉल, आंशिक काम और चुप्पी से हुई त्रुटियाँ पैदा करते हैं जो डेमो वातावरण में दिखाई नहीं देतीं।
LLM को एक फ़्री‑फॉर्म लूप के भीतर छोड़ने के बजाय उसे एक स्पष्ट संरचना के अंदर चलाएँ:
एजेंट को एक वर्कफ़्लो के रूप में मॉडल करें जिसमें नामित स्टेट्स और टाइप्ड इवेंट्स हों, न कि while not done: call LLM जैसा लूप।
सामान्य स्टेट्स हो सकते हैं:
टूल्स को प्रॉम्प्ट के prose की तरह नहीं बल्कि सही प्रोडक्शन APIs की तरह डिज़ाइन करें। हर टूल को निम्न कॉन्ट्रैक्ट होना चाहिए:
मान लीजिए कि हर बाहरी कॉल कभी‑न‑कभी फेल होगी और उसी के चारों ओर डिज़ाइन करें.
मुख्य पैटर्न्स:
LLM के पास स्वयं कोई स्थायी राज्य नहीं होना चाहिए — स्पष्ट रूप से शॉर्ट‑टर्म स्टेट और लॉन्ग‑टर्म मेमोरी अलग रखें।
LLM को एक स्पष्ट स्टेट ऑब्जेक्ट के ऊपर स्टेटलेस फ़ंक्शन के रूप में व्यवहार करें: प्रासंगिक स्टेट लोड करें, प्रॉम्प्ट बनायें, मॉडल कॉल करें, फिर अपडेटेड स्टेट परसिस्ट करें।
एजेंट्स पर असल दुनिया में कई समवर्ती अनुरोध आने पर वे एक वितरित सिस्टम की तरह व्यवहार करते हैं। भेदभाव के बिना:
इनकी रोकथाम के लिए इडेम्पोटेंट टूल कॉन्ट्रैक्ट्स, स्पष्ट वर्कफ़्लो स्टेट और डेटालेयर में ऑप्टिमिस्टिक/पेसीमिस्टिक लॉकिंग का उपयोग करें।
आपको यह जल्दी सटीकता से उत्तर देना चाहिए: "उसने क्या किया?" और "उसने ऐसा क्यों किया?"— किसी भी टास्क के लिए. ऑब्ज़र्वेबिलिटी को ऐसे डिजाइन करें कि एक ही टास्क का ट्रेस निम्न बातों को कवर करे:
ट्रेस के भीतर स्ट्रक्चर्ड लॉग्स जोड़ें (मुख्य निर्णय, प्लान संशोधन, गार्डरेल ट्रिगर) और वॉल्यूम व हेल्थ के लिए मैट्रिक्स।
उपयोगी ट्रेस में सामान्यतः ये शामिल होते हैं:
एजेंट टेस्टिंग का मतलब है उन टूल्स का और उन फ्लोज़ का टेस्ट करना जो उन्हें जोड़ते हैं। इसे डिस्ट्रिब्यूटेड सिस्टम टेस्टिंग की तरह मानें, केवल प्रॉम्प्ट ट्वीकिंग नहीं।
योजना:
प्रोडक्शन में एजेंट्स चलाना एक विकसित होते हुए डिस्ट्रिब्यूटेड सिस्टम की तरह है—रोलआउट, विश्वसनीयता लक्ष्य और बदलाव नियंत्रण की ज़रूरत होती है।
सुरक्षित रोलआउट के तरीके:
इससे आप व्यवहार को चरण-दर-चरण समझा, टेस्ट और डिबग कर पाएँगे, बजाय इसके कि अस्पष्ट “एजेंट सोच” वाले लूप का पीछा करना पड़े।
PLAN – अनुरोध को समझना और स्टेप‑बाय‑स्टेप योजना बनानाCALL_TOOL – किसी विशेष टूल या बैच को कॉल करनाVERIFY – आउटपुट्स को सरल नियमों या द्वितीयक मॉडल चेक से जाँचनाRECOVER – त्रुटियों को रिट्राई, फ़ॉलबैक या एस्केलेशन द्वारा संभालनाDONE / FAILED – टर्मिनल नतीजेइवेंट्स (जैसे ToolCallSucceeded, TimeoutExceeded) और वर्तमान स्टेट मिलकर अगला स्टेट तय करते हैं। इससे रिट्राई, टाइमआउट और त्रुटि‑हैंडलिंग स्पष्ट बन जाते हैं, बजाय इसके कि वे प्रॉम्प्ट या ग्लू‑कोड में छिपे रहें।
InvalidInput, NotFound, RateLimited, TransientFailureकॉल करने से पहले इनपुट्स और कॉल के बाद आउटपुट्स वैलिडेट करें। टूल कॉन्ट्रैक्ट्स को वर्शन करें और एजेंट्स को किसी वर्शन पर पिन करें ताकि स्कीमा बदलाव चुपके से फ्लो नहीं तोड़ें।
request_id या बिज़नेस की स्वीकार करें और वही परिणाम दोहराने पर वापस करें।इससे विश्वसनीयता ऊँची रहती है बिना रनअवे लूप्स, डुप्लिकेट साइड‑इफेक्ट्स या अनियंत्रित लागत के।
कच्चे लॉग्स या संवादी इतिहास को मेमोरी के रूप में उपयोग करने से बचें; इसके बजाय उनसे संरचित सारांश बनाकर रखें और रिटेंशन/प्राइवेसी नीतियाँ लागू करें।
लंबे चलने वाले या साइड‑इफ़ेक्ट वाले स्टेप्स को क्यू के पीछे रखें ताकि आप कनकरेंसी को कंट्रोल कर सकें और रिट्राई/डेडुप्लिकेशन केंद्रीकृत कर सकें।
लॉग करने से पहले PII और सीक्रेट्स को रेडैक्ट करें, बड़े पेलोड को ट्रंकेट करें और कॉरिलेशन के लिए हैश रखें। प्रोडक्शन में डिफ़ॉल्ट रूप से रेडैक्टेड व्यू रखें।
कम से कम ट्रैक करें:
अच्छे ट्रेस और मैट्रिक्स से आप समस्या को घटकों तक सीमित कर पाएँगे और निदान को मिनटों में कर सकेंगे।
यूनिट टेस्ट्स: टूल बॉउन्ड्री पर फ़ोकस करें — स्कीमा, इडेम्पोटेंसी, त्रुटि सेमैटिक्स। ये टेस्ट्स LLM पर निर्भर नहीं होने चाहिए; सीधे टूल को सिंथेटिक इनपुट के साथ कॉल करें और अपेक्षित आउटपुट/एरर असर्ट करें।
इंटीग्रेशन टेस्ट्स: एजेंट वर्कफ़्लो एंड‑टू‑एंड — LLM + टूल्स + ऑर्केस्ट्रेशन। सीनारियो‑आधारित परीक्षण चलाएँ: हैप्पी‑पाथ, एज केस (मिसिंग डेटा, आंशिक टूल फ़ेल्यर, टाइमआउट्स, रेट‑लिमिट्स), और क्रॉस‑टूल इंटरेक्शन। ये टेस्ट्स टोकन‑लेवल आउटपुट नहीं पर स्टेट ट्रांज़िशन और टूल कॉल अनुक्रम असर्ट करें।
डिटर्मिनिस्टिक फिक्स्चर: LLM रिस्पॉन्स और टूल आउटपुट फिक्स्चर रखें ताकि टेस्ट रिप्रोड्यूसिबल रहें। मॉडल के लिए सीड और फ़िक्स्ड‑टेम्परेचर का उपयोग करें।
रिग्रेशन सूट्स: हर प्रॉम्प्ट या स्कीमा बदलाव पर अनिवार्य रिग्रेशन रन चलाएँ—कर्ल्ड इनपुट्स और अपेक्षित स्टेट/टूल ट्रेस को गोल्डन फ़ाइल में लॉक करें और किसी भी ड्रिफ्ट को मैन्युअली अप्रूव या रोलबैक करें।
ऑफ़लाइन इवैल्यूएशन: कोई नया मॉडल/रूटिंग स्ट्रैटेजी डायरेक्ट प्रोडक्शन में न भेजें। पहले रिग्रेशन कॉर्पस पर चलाएँ, हिस्टोरिकल इंटरेक्शन पर रिप्ले करें और ऑटो‑मैट्रिक्स व ह्यूमन सैंपल रेटिंग्स लें।
टेस्ट डेटा प्रबंधन: टेस्ट डाटासेट्स को अनोनिमाइज़ या सिंथेटिक बनायें; पहचान और PII को हटाएँ/हैश करें; CI पाइपलाइन में अनामिकरण चेक्स को कोडाइफी करें।
सभी बदलाव फीचर फ्लैग्स और कॉन्फ़िग‑ड्रिवन पॉलिसियों के पीछे करें: राउटिंग नियम, सक्षम टूल्स, टेम्परेचर, और सुरक्षा सेटिंग्स। बदलाव को कोड नहीं बल्कि कॉन्फ़िग से रीवर्ट करने योग्य रखें।
SLOs और incident वर्कफ़्लो:
इनको अलर्ट्स में बाँधें, रनबुक रखें और ट्रायेज़/मिटिगेशन के लिए स्पष्ट मालिकाना रखें (रोलबैक फ्लैग, ट्रैफ़िक ड्रेन, सेफ़‑मोड)।
लगातार सुधार और परिवर्तन नियंत्रण: