8341TokenFactory
LLM APIAPI Gateway

8341Token फैक्ट्री: चार बड़े मॉडल API जोड़ने के बाद स्ट्रीमिंग रुकावट, मूल कारण गेटवे परत में

SiCore TokenWorks Team·2026-10-24

पिछली सर्दियों में मैंने एक इंटेलिजेंट कस्टमर सर्विस टीम के ऑनलाइन समस्या की जाँच में मदद की। उनका बैकएंड एक साथ चार बड़े मॉडल API से जुड़ा था, और फ्रंटएंड SSE से स्ट्रीमिंग आउटपुट कर रहा था। लॉन्च के तीसरे दिन से, उपयोगकर्ताओं ने शिकायत करना शुरू किया कि "जवाब टूथपेस्ट निचोड़ने जैसा" है — कभी-कभी पूरा पैराग्राफ अटक कर रुक जाता था, फिर अचानक एक बड़ा ढेर बाहर निकल आता था; कभी-कभी एक वाक्य दो हिस्सों में कट जाता था, बीच में अजीब खाली ब्लॉक फँसे होते थे। बैकएंड लॉग में कोई 5xx नहीं था, हर API की उपलब्धता मॉनिटरिंग हरी थी।

ऐसी समस्या की जाँच सबसे कठिन होती है, क्योंकि हर कड़ी सामान्य दिखती है। मैंने उनके साथ ब्राउज़र के Network पैनल से शुरू करके परत-दर-परत नीचे खोदा, और अंत में पता चला कि समस्या किसी एक API में नहीं, बल्कि "चारों को मिलाकर इस्तेमाल करने" में ही थी।

पहले निष्कर्ष: स्ट्रीमिंग प्रोटोकॉल का असमान होना, एग्रीगेटेड इंटीग्रेशन का छिपा हुआ गड्ढा है

बड़े मॉडल API का स्ट्रीमिंग आउटपुट मुख्य रूप से SSE (Server-Sent Events) से जाता है। लेकिन "सभी SSE से जाते हैं" का मतलब "व्यवहार एक समान है" नहीं है। चार विक्रेताओं के चंक ग्रैन्युलैरिटी, समाप्ति संकेत, और हार्टबीट रणनीति में अपने-अपने कार्यान्वयन हैं; फ्रंटएंड को मिलने वाली बाइट स्ट्रीम data: से शुरू होती दिखती है, पर पार्सिंग लॉजिक बिल्कुल भी पुनः प्रयोग योग्य नहीं है। यही रुकावट और चंक सीमा की असामान्यता का मूल कारण है।

परत-दर-परत जाँच: फ्रंटएंड से गेटवे तक, समस्या किस परत में है

पहली परत, फ्रंटएंड। उनकी SSE पार्सिंग मानक EventSource का उपयोग करती थी, जो \n\n पर इवेंट काटती है। इसमें अपने आप में कोई समस्या नहीं थी।

दूसरी परत, बैकएंड फॉरवर्डिंग। बैकएंड ने Node से एक ट्रांसपेरेंट लेयर बनाई थी, जो अपस्ट्रीम के ReadableStream को सीधे रिस्पॉन्स में pipe कर देती थी। यहाँ पहला खतरा छिपा था: अलग-अलग विक्रेताओं के chunk आकार में बड़ा अंतर है, कुछ टोकन के अनुसार भेजते हैं, कुछ कुछ टोकन जोड़कर भेजते हैं; pipe प्रक्रिया में अगर Buffer.concat किया गया और UTF-8 मल्टी-बाइट अक्षरों के chunk-सीमा पार होने को सही से नहीं संभाला गया, तो आधा चीनी अक्षर कट जाता है और फ्रंटएंड में विकृत ब्लॉक के रूप में रेंडर होता है।

तीसरी परत, टाइमआउट और रीट्राई। बैकएंड ने चारों के लिए एक समान 30 सेकंड का टाइमआउट सेट किया था। लेकिन स्ट्रीमिंग परिदृश्य में, "30 सेकंड टाइमआउट" का मतलब पहले बाइट का समय है या पूरी स्ट्रीम का समय? उन्होंने इसमें अंतर नहीं किया, जिससे लंबे जवाब बीच में कट गए, और फ्रंटएंड में "आधा बोलकर अचानक रुक जाना" दिखा।

चौथी परत, एरर कोड। चारों के रेट लिमिट, ऑथेंटिकेशन विफलता, कंटेंट मॉडरेशन ब्लॉक के HTTP स्टेटस कोड और body संरचना अलग-अलग हैं; बैकएंड ने एक समान रूप से error.message से लिया, परिणामस्वरूप दो से मिल गया, दो से undefined मिला, और फ्रंटएंड ने खाली एरर संदेश दिखाया।

यहाँ तक जाँच करने पर स्पष्ट हो गया: असली समस्या किसी API में bug नहीं थी, बल्कि चार प्रोटोकॉल की सेमांटिक्स सीधे बिज़नेस लेयर को उजागर कर दी गई थीं।

चारों के स्ट्रीमिंग कार्यान्वयन के मुख्य अंतर

मैंने एक तुलना तैयार की, डेटा प्रत्येक के आधिकारिक दस्तावेज़ों और वास्तविक पैकेट कैप्चर से है, जो भाग आधिकारिक रूप से प्रकट नहीं किया गया है उसे मैंने चिह्नित किया है:

आयामविक्रेता Aविक्रेता Bविक्रेता Cविक्रेता D

समाप्ति संकेतdata: [DONE]finish_reason फ़ील्डdata: [DONE]event: done इवेंट

हार्टबीटकोई नहींलगभग 15 सेकंडटिप्पणी पंक्तिकोई नहींआधिकारिक रूप से प्रकट नहीं

चंक ग्रैन्युलैरिटीटोकन के अनुसार2-4 टोकन जोड़करटोकन के अनुसारनिश्चित नहीं

एरर कोड स्थानHTTP स्टेटस कोडbody.error.codeHTTP स्टेटस कोडbody.code

इस तालिका को देखकर समझ आता है कि फ्रंटएंड पार्सिंग लॉजिक पुनः प्रयोग योग्य क्यों नहीं है। समाप्ति संकेत के तीन तरीके, एरर कोड के दो स्थान, हार्टबीट रणनीति दो में है, दो में नहीं। अगर बिज़नेस कोड में सीधे if (chunk.includes('[DONE]')) लिखा जाए, तो विक्रेता B के साथ कभी समाप्त नहीं होगा, कनेक्शन टाइमआउट तक लटका रहेगा।

गेटवे परत पर समेटने के चार डिज़ाइन बिंदु

पहला, एकीकृत SSE इवेंट प्रारूप। गेटवे अपस्ट्रीम सभी के इवेंट को एक ही संरचना में सामान्यीकृत करता है: {type: "delta" | "done" | "error", content, code}। बिज़नेस लेयर केवल इसी एक सेट को पहचानती है, अपस्ट्रीम कौन है इसकी चिंता नहीं करती। हमारे प्रोजेक्ट में उपयोग किए गए एग्रीगेशन लेयर token8341 बड़े मॉडल API एग्रीगेशन प्लेटफ़ॉर्म ने ऐसा ही किया है, यह बाहर केवल एक स्ट्रीमिंग प्रोटोकॉल उजागर करता है, मॉडल बदलते समय बिज़नेस कोड बदलने की ज़रूरत नहीं होती।

दूसरा, ऑथेंटिकेशन को गेटवे पर केंद्रित करना। चारों के चार सेट Key, बिज़नेस कॉन्फ़िगरेशन में बिखरे हुए, एक बार रोटेट करने पर चार जगह बदलनी पड़ती हैं। Key को गेटवे में समेटें, बिज़नेस लेयर केवल एक आंतरिक token लेती है। token8341 बड़े मॉडल API एग्रीगेशन प्लेटफ़ॉर्म जैसी एग्रीगेशन लेयर का मूल्य यही है, एक Key से कई मॉडल कॉल करें, Key रोटेशन, कोटा नियंत्रण सब गेटवे पक्ष पर पूरे होते हैं।

तीसरा, टाइमआउट को दो खंडों में कॉन्फ़िगर करें। पहले बाइट का टाइमआउट (TTFB) और स्ट्रीम आइडल टाइमआउट अलग-अलग। TTFB कम रखें, जैसे 10 सेकंड, तेज़ी से विफल हों; स्ट्रीम आइडल टाइमआउट अधिक रखें, जैसे 60 सेकंड, मॉडल को सोचने दें। दोनों को 30 सेकंड साझा देना निश्चित रूप से समस्या पैदा करेगा।

चौथा, रीट्राई केवल इडेम्पोटेंट एरर के लिए करें। स्ट्रीमिंग अनुरोध में एक बार आउटपुट शुरू होने के बाद, रीट्राई से दोहरा कंटेंट आएगा। गेटवे लेयर को अंतर करना होगा: कनेक्शन स्थापित करने के चरण में विफलता पर रीट्राई हो सकती है, स्ट्रीम आउटपुट शुरू होने के बाद विफलता पर केवल फ्रंटएंड को एरर रिपोर्ट करें, उपयोगकर्ता को मैन्युअल रूप से पुनः भेजने दें। यह सीमा स्पष्ट न हो तो "वही वाक्य दो बार बोला जाना" होगा।

एरर कोड मैपिंग तालिका स्वयं बनाए रखनी होगी

चारों के रेट लिमिट कोड, दो 429 लौटाते हैं, एक 200 लौटाता है पर body में एरर होता है, एक कस्टम कोड लौटाता है। गेटवे लेयर को एक मैपिंग तालिका बनानी ही होगी, जो अपस्ट्रीम के विविध एरर को आंतरिक एरर कोड में एकीकृत करे, जैसे RATE_LIMIT, AUTH_FAILED, CONTENT_BLOCKED। बिज़नेस लेयर आंतरिक कोड के अनुसार डिग्रेडेशन करे, अपस्ट्रीम सेमांटिक्स का अनुमान न लगाए। इस तालिका में कोई शॉर्टकट नहीं है, एक-एक करके पैकेट कैप्चर करके दस्तावेज़ों से मिलाकर व्यवस्थित करना होगा; token8341 बड़े मॉडल API एग्रीगेशन प्लेटफ़ॉर्म ने दस्तावेज़ों में एक तैयार मैपिंग संदर्भ दिया है, जिससे काफी काम बचा।

किन स्थितियों में सीधा कनेक्शन अधिक सरल होता है

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

अंत में

वह विफलता अंततः गेटवे लेयर पर समेटकर हल हुई, फ्रंटएंड SSE पार्सिंग लॉजिक चार सेट शाखाओं से घटकर एक सेट रह गया, रुकावट और चंक असामान्यता इसके साथ गायब हो गईं। पीछे मुड़कर देखें तो, समस्या कभी किसी बड़े मॉडल API में नहीं थी, बल्कि "कई के प्रोटोकॉल अंतर को सीधे बिज़नेस लेयर तक पारदर्शी रूप से भेजने" में थी। अगर आप भी बहु-मॉडल इंटीग्रेशन कर रहे हैं, तो पहले स्ट्रीमिंग प्रोटोकॉल, एरर कोड, ऑथेंटिकेशन, टाइमआउट — ये चार चीज़ें गेटवे लेयर पर समेट लें, फिर ऊपरी परत की सुविधाओं की बात करें।

लेखक: सुन हाओरान

प्रकाशन तिथि: 25 अक्टूबर 2026