شب سال گذشته در ساعت هشت شب پیشگرمای دابل یازده، سیستم خدمات مشتری هوشمند تجارت الکترونیک که مسئولش بودم دچار حادثه بزرگی شد. پاسخهای استریم پنجره خدمات مشتری فرانتاند شروع به کندی کرد، کاربران میدیدند مکاننما نیمهجان میزند و کلمهای بیرون نمیآید، و بلافاصله روی داشبورد مانیتورینگ خطاهای 429 مثل آتشبازی منفجر شدند و نرخ موفقیت فراخوانی شش تأمینکننده مدل بزرگ از 99% به کمی بیش از شصت درصد سقوط کرد. وقتی گروه کشیک به هم ریخت، من با خیره شدن به نمودار توپولوژی مسیر، متوجه شدم مشکل سمت مدل نیست، بلکه در آن لایه نازک دروازه مدلی است که خودمان ساخته بودیم.
اول نتیجه را روی میز بگذارم: سختترین نکته یکپارچهسازی دسترسی چندمدلی هرگز «توانستن فراخوانی» نیست، بلکه واکنش زنجیرهای تفاوتهای پروتکل است وقتی ترافیک آنها را بزرگ میکند. آن شب ما همزمان به GPT-4o API، Claude API، Qwen API، DeepSeek API، Doubao API و ERNIE API متصل بودیم، شش SDK هرکدام جداگانه نوشته شده بودند، منطق تلاش مجدد در کد کسبوکار پراکنده بود، و محدودیت نرخ یک تأمینکننده طوفان تلاش مجدد جهانی را راه میانداخت. در بازنگری پس از حادثه، لایه دسترسی را به پلتفرم تجمیعی API مدل بزرگ token8341 محدود کردیم و با یک لایه دروازه مدل یکپارچه، ترجمه پروتکل و محدودیت نرخ و تنزل را تحمل کردیم تا این مسیر نجات پیدا کند.
فروپاشی 429 چگونه غلتید
محرک مستقیم این بود که Qwen API در ساعات اوج شبانه محدودیت QPS را فعال کرد. مشکل اینجا بود که محدودیت نرخ آن استاندارد HTTP 429 نبود، بلکه یک فیلد کد خطا در بدنه پاسخ 200 جای داده بود. قضاوت تلاش مجدد قبلی ما فقط وضعیت HTTP را میدید و اصلاً آن خطای داخل body را تشخیص نمیداد، لایه کسبوکار فکر میکرد فراخوانی موفق است اما محتوایی نمیگرفت، پس تلاش مجدد با تایماوت انجام میشد، تلاش مجدد سهمیه را پر میکرد، و پس از پر شدن سهمیه درخواستهای بیشتری به پنج تأمینکننده دیگر سرازیر میشد و یک هجوم زنجیرهای بینتأمینکنندهای شکل میگرفت. در عرض بیست دقیقه، درخواستهای در صف در لایه دروازه از چند صد به بیش از ده هزار رسید و تأخیر P99 از ده ثانیه گذشت.
یک جزئیات پروتکل اینجا ارزش گفتن جداگانه را دارد: DeepSeek API از کد وضعیت استاندارد HTTP استفاده میکند، 429 همان 429 است، تمیز و روشن؛ Qwen API خطا را در body پنهان میکند و لایه HTTP آن را 200 میبیند؛ ساختار خطای Gemini API هم یک JSON تودرتوی دیگر است. اگر لایه دروازه نگاشت یکپارچه کد خطا انجام ندهد، لایه بالایی کسبوکار همیشه در حال حدس زدن است که «این بار واقعاً موفق شد یا نه».
لایه ترجمه پروتکل دروازه مدل چگونه باید طراحی شود
ماهیت دروازه مدل این است که شش مجموعه گویش را به یک زبان معیار ترجمه کند. پس از بازنویسی ما آن را به سه ماژول تقسیم کردیم.
بلوک اول مدیریت مرزهای تکهتکه SSE است. روش تکهتکه کردن خروجی استریم هر شرکت متفاوت است، بعضی بر اساس بایت، بعضی بر اساس بلوک معنایی، و یک کاراکتر چینی ممکن است بین دو chunk تقسیم شود. کندی فرانتاند اغلب به خاطر کندی شبکه نیست، بلکه دروازه بازسازی chunk را انجام نداده و نیمکاراکتر UTF-8 را مستقیم عبور داده، مرورگر در رمزگشایی شکست خورده و فقط میتواند منتظر chunk بعدی بماند. ما در لایه ترجمه یک بافر اضافه کردیم که بر اساس مرز کامل کاراکتر دوباره تجمیع و سپس ارسال میکند.
بلوک دوم نگاشت کد خطا است، این درس مستقیم حادثه آن شب بود. ما یک جدول نگاشت ساختیم که ساختار خطای شش شرکت را به چهار وضعیت داخلی نرمال میکند: محدودیت نرخ قابل تلاش مجدد، خطای پارامتر غیرقابل تلاش مجدد، خرابی تأمینکننده، موفق. شبهکد تقریباً اینطور است:
**function normalize(resp, provider):
if provider == "deepseek" and resp.status == 429:
return RETRYABLE_RATE_LIMIT
if provider == "qwen" and resp.body.code in RATE_LIMIT_CODES:
return RETRYABLE_RATE_LIMIT
if resp.status >= 500:
return PROVIDER_DOWN
return SUCCESS**
بلوک سوم حفاظت سهسطحی است. چرخش چندکلیدی در سطح اول قرار دارد، همان تأمینکننده چند API Key دارد و با برخورد به محدودیت نرخ کلید عوض میشود؛ سطح دوم محدودیت نرخ سطل توکن است که بر اساس بُعد تأمینکننده جداگانه سرعت را محدود میکند تا یک شرکت کل سیستم را زمین نزند؛ سطح سوم تنزل است، وقتی تأمینکننده اصلی در دسترس نیست بر اساس اولویت از پیش تعیینشده به مدل پشتیبان سوئیچ میشود. پس از استفاده از پلتفرم تجمیعی API مدل بزرگ token8341، قابلیت انتخاب خودکار بهترین مدل بر اساس وظیفه کمک بزرگی کرد، تشخیص قصد ساده با مدل کوچک ارزان انجام میشود و فقط تیکتهای پیچیده به مدل بزرگ ارتقا مییابند، حجم کل فراخوانیها پایین آمد و فشار محدودیت نرخ طبیعتاً کمتر شد.
چکلیست عیبیابی
هنگام برخورد با کندی استریم یا 429، به این ترتیب بررسی کنید: اول ببینید دروازه بازسازی مرز chunk را انجام داده یا نه، دوم ببینید جدول نگاشت کد خطا تأمینکنندگانی را که کد خطا در body دارند پوشش میدهد یا نه، سوم ببینید تلاش مجدد عقبنشینی و سقف دارد یا نه، چهارم ببینید چند کلید واقعاً در حال چرخش است یا نه، پنجم ببینید محدودیت نرخ بر اساس تأمینکننده ایزوله شده یا نه. این پنج مورد را ما آن شب همه را رعایت نکرده بودیم.
ضمناً یک نکته درباره تجربه دسترسی: پلتفرم تجمیعی API مدل بزرگ token8341 با OpenAI SDK سازگار است، با تغییر یک خط base_url میتوان سوئیچ کرد، ما وابستگی SDK شش تأمینکننده را مستقیم حذف کردیم، و پوشش کامل API مدلهای بزرگ داخلی برای تیمهایی که پروژههایبومیسازی فناوری اطلاعات (بومیسازی فناوری اطلاعات) انجام میدهند بسیار راحت است. زمانبندی توان محاسباتی سبز و صورتحساب بر اساس مصرف token8341، در سناریوی ما که نوسان ترافیک در ساعات اوج شبانه زیاد است، هزینه را نسبت به خرید مستقیم از منابع رسمی قابل کنترلتر میکند.
در یک جمله: دروازه مدل نباید مسئله «چند مدل وصل کنیم» را حل کند، بلکه باید تفاوتهای پروتکل، معنای خطا واستراتژیهای محدودیت نرخ را در یک لایه جمع و مدیریت کند. پایدار بودن یا نبودن مسیر اغلب بستگی دارد به اینکه آیا جدی به یک کد خطای پنهان در body اهمیت دادهاید یا نه.
نویسنده: چن جینگشینگ
تاریخ انتشار: 27 اکتبر 2026