त्रुटि बॉडी फॉर्मेट और पढ़ने का क्रम
सभी विफल प्रतिक्रियाएँ एक ही संरचना का पालन करती हैं:
{"error":{"code":"...","message":"..."}}
पढ़ने का क्रम तीन निश्चित चरणों में है:
- HTTP स्टेटस कोड, जो श्रेणी निर्धारित करता है;
error.codeविशिष्ट कारण निर्धारित करता है; प्रोग्राम में इसे शाखा (branch) के लिए उपयोग करें;error.message, इंसानों के लिए; लॉग में लिखें, लेकिन स्ट्रिंग मैचिंग के लिए उपयोग न करें।
सबसे पहले एक सीमा स्पष्ट करें: पुनः प्रयास से हल होने वाले (429, 503, और नेटवर्क टाइमआउट) और संशोधन से हल होने वाले (शेष)। दोनों को मिला देना ऑनलाइन दुर्घटनाओं का सबसे आम कारण है, जैसे 402 के लिए लगातार पुनः प्रयास करना, जिससे प्रति सेकंड कई अमान्य अनुरोध भेजे जाते हैं।
लॉग में चार फ़ील्ड्स स्थिर रूप से रिकॉर्ड करने की सलाह दी जाती है: समय, स्थिति कोड, error.code, और इस अनुरोध के लिए प्रॉम्प्ट टोकन का अनुमान। समस्या आने पर, यह तुरंत पता चलता है कि क्या किसी एक प्रकार की त्रुटि अचानक बढ़ी है या समग्र विफलता हुई है। एक अलर्ट नियम जोड़ें: 402 एक बार आते ही तुरंत सूचित करें, क्योंकि इसका मतलब है कि सेवा उपयोगकर्ताओं के लिए अनुपलब्ध है; 429 के लिए अनुपात देखें, यदि यह कभी-कभी आता है तो उसे नज़रअंदाज़ करें, यदि लगातार आता है तो इसका मतलब है कि समानांतरता डिज़ाइन में समस्या है।
स्टेटस कोड त्वरित संदर्भ
| स्टेटस कोड | error.code | अर्थ | रिट्राई? |
|---|---|---|---|
| 400 | — | अमान्य अनुरोध, जैसे prompt + max_tokens > 100k | नहीं |
| 401 | — | अमान्य या अनुपलब्ध कुंजी | नहीं |
| 402 | no_credit | बैलेंस खत्म या ट्रायल समाप्त | नहीं |
| 403 | content_blocked | कंटेंट अवरोधित | नहीं |
| 404 | — | एंडपॉइंट मौजूद नहीं | नहीं |
| 429 | — | रेट लिमिट सक्रिय | हाँ, बैकऑफ़ |
| 503 | upstream_busy | सेवा अस्थायी रूप से व्यस्त | हाँ, कुछ सेकंड बाद |
तालिका में '—' का अर्थ है कि कोई विशेष fixed code स्ट्रिंग नहीं है; स्टेटस कोड के आधार पर शाखा बनाएं।
4xx: अनुरोध संशोधित करें, पुनः प्रयास न करें
400 अमान्य अनुरोध
- कारण 1: JSON फॉर्मेट त्रुटि, अक्सर स्ट्रिंग मैन्युअल लिखते समय क्वोट्स को एस्केप न करने के कारण।
- कारण 2: प्रॉम्प्ट और max_tokens का योग 100,000 से अधिक हो जाता है। लंबी चैट में यह सबसे आम है।
- कारण 3: अनुरोध बॉडी > 8 MB।
- संशोधन: JSON लाइब्रेरी का उपयोग करके serialize करें; भेजने से पहले टोकन का अनुमान लगाएं, यदि सीमा पार हो जाए तो इतिहास काटें या max_tokens कम करें; लंबे कॉन्टेक्स्ट के लिए व्यावहारिक गाइड देखें।
401 कुंजी समस्या
- हेडर गायब है, या
Bearerप्रिफिक्स गायब है। - कुंजी (key) को पुनर्जनित किया गया है, पुरानी कुंजी तुरंत अमान्य हो जाती है, लेकिन कुछ मशीनें अभी भी पुरानी कुंजी का उपयोग कर रही हैं।
- एनवायरनमेंट वेरिएबल्स कंटेनर या टास्क में नहीं पहुँचे।
402 no_credit
क्रैडिट खत्म या 7 दिन का ट्रायल समाप्त।खाता पृष्ठ पर जाकर प्रीपेड क्रेडिट टॉप-अप करें। बैलेंस मॉनिटर करें ताकि यूज़र से पहले पता चल जाए।
403 content_blocked
सामग्री ब्लॉक हो गई। वयस्क-अनुमत सामग्री, काल्पनिक और विवादास्पद विषयों को अस्वीकार नहीं किया जाता, लेकिन अल्पवयकों से संबंधित यौन सामग्री को पूरी तरह से ब्लॉक किया जाता है, जिसमें उपन्यास और भूमिका निभाना भी शामिल है। यदि 403 त्रुटि मिले, तो इनपुट और इतिहास में ऐसी सामग्री तो नहीं है, यह जांचें, शब्द बदलकर दोबारा प्रयास करने के बजाय।
404 एंडपॉइंट नहीं मिला
केवल दो एंडपॉइंट हैं: POST /v1/chat/completions और GET /v1/models। पाथ में /v1 छूट गया हो, अतिरिक्त स्लैश हो, या गलत वर्तनी हो, या एम्बेडिंग्स, इमेज आदि जैसे असमर्थित इंटरफ़ेस को कॉल किया गया हो, तो 404 मिलता है।
400 त्रुटि में एक और भ्रामक स्थिति है: लंबी बातचीत में टोकन की संख्या चरणों के साथ रैखिक रूप से बढ़ती है। दिन में परीक्षण सामान्य रहता है, लेकिन कई चरणों के बाद अचानक 400 त्रुटि आने लगती है। यह इंटरफ़ेस की अस्थिरता नहीं है, बल्कि कॉन्टेक्स्ट विंडो भर गई है। समाधान यह है कि इतिहास की लंबाई पर सीमा लगाएं और थ्रेशोल्ड पार होने पर सबसे पुराने चरण हटा दें, या पुरानी सामग्री को सारांश में बदल दें। त्रुटि आने का इंतज़ार न करें, अनुरोध भेजने से पहले ही अनुमान लगा लें।
401 की जाँच का एक टिप: कुंजी (key) के पहले और आखिरी चार अंक लॉग में प्रिंट करें, पूरा कंटेंट नहीं, और खाता पृष्ठ पर दिखाए गए से तुलना करें। इससे यह पुष्टि होती है कि प्रोग्राम में पढ़ी गई कुंजी वही है या नहीं, खासकर कंटेनर और टास्क एनवायरनमेंट में, जहाँ एनवायरनमेंट वेरिएबल्स की कमी या पुरानी कुंजी पढ़ना सबसे आम कारण है।
429 और 503: पुनः प्रयास करने योग्य दो स्थितियाँ
429 रेट लिमिट
प्रति कुंजी प्रति मिनट 300 अनुरोध। बैच टास्क, कई इंस्टेंस एक ही कुंजी साझा करना, या पुनः प्रयास का तूफ़ान, इसे ट्रिगर कर सकता है। संशोधन के दो स्तर हैं: पहले क्लाइंट-साइड रेट लिमिट (नीचे कोड देखें), फिर 429 के लिए बैकऑफ़ पुनः प्रयास।
503 upstream_busy
सर्विस अस्थायी रूप से व्यस्त है। कुछ सेकंड बाद रीट्राई करें। तुरंत लगातार रिक्वेस्ट न भेजें, और एक सेकंड में दस बार रीट्राई न करें, इससे स्थिति और खराब होगी।
नेटवर्क टाइमआउट
लंबे टेक्स्ट जनरेशन में समय लगता है, इसलिए टाइमआउट बहुत कम न सेट करें, उदाहरण में 120 सेकंड का उपयोग किया गया है। टाइमआउट के बाद पुनः प्रयास करते समय ध्यान दें: पिछला अनुरोध सर्वर पर निष्पादित हो चुका हो सकता है, दोहरा कॉल करने से क्रेडिट दो बार खर्च हो सकता है, इसलिए जनरेशन अनुरोधों के लिए पुनः प्रयास की संख्या कम रखें, बेहतर होगा कि स्ट्रीमिंग आउटपुट के साथ एकल प्रतीक्षा समय कम करें।
import os
import random
import time
import requests
URL = "https://api.wushenchaapi.com/v1/chat/completions"
HEADERS = {
"Authorization": "Bearer " + os.environ["API_KEY"],
"Content-Type": "application/json",
}
RETRYABLE = {429, 503} # 只重试这两类
FATAL = {400, 401, 402, 403, 404}
class ApiError(Exception):
def __init__(self, status, code, message):
super().__init__(f"{status} {code}: {message}")
self.status, self.code = status, code
def call(payload, max_retries=5, base=1.0, cap=30.0):
for attempt in range(max_retries + 1):
try:
r = requests.post(URL, headers=HEADERS, json=payload, timeout=120)
except (requests.ConnectionError, requests.Timeout):
r = None # 网络层失败,按可重试处理
if r is not None and r.ok:
return r.json()
if r is not None:
try:
err = r.json().get("error", {})
except ValueError:
err = {}
if r.status_code in FATAL or r.status_code not in RETRYABLE:
raise ApiError(r.status_code, err.get("code"), err.get("message"))
if attempt == max_retries:
raise ApiError(r.status_code if r is not None else 0, "retry_exhausted", "重试次数用尽")
delay = min(cap, base * (2 ** attempt)) * random.uniform(0.5, 1.0)
time.sleep(delay)
if __name__ == "__main__":
out = call({"model": "uncensored", "max_tokens": 100,
"messages": [{"role": "user", "content": "回复一个字:好"}]})
print(out["choices"][0]["message"]["content"])मुख्य बात: रिकॉवरी सूत्र min(cap, base × 2^n) × गुणांक है; यादृच्छिक गुणांक यह सुनिश्चित करता है कि कई क्लाइंट एक साथ रिकॉवर न करें; FATAL सेट में दिए गए स्टेटस कोड के लिए एक भी बार रिकॉवर नहीं किया जाता।
क्लाइंट रेट लिमिट और डायग्नोस्टिक रिक्वेस्ट
429 आने का इंतज़ार करने के बजाय, पहले रेट लिमिट लगाएं। नीचे दिया गया टूल यह सुनिश्चित करता है कि रिक्वेस्ट की संख्या प्रति मिनट निर्धारित वैल्यू से कम रहे, और यह मल्टी-थ्रेड सेफ़ है:
import threading
import time
class RateGate:
"""简单的客户端限速:保证一分钟内请求数不超过 limit。"""
def __init__(self, limit=240): # 留出余量,低于 300/分钟
self.limit, self.stamps, self.lock = limit, [], threading.Lock()
def wait(self):
while True:
with self.lock:
now = time.time()
self.stamps = [t for t in self.stamps if now - t < 60]
if len(self.stamps) < self.limit:
self.stamps.append(now)
return
sleep_for = 60 - (now - self.stamps[0])
time.sleep(max(sleep_for, 0.05))डीबगिंग के दौरान, सबसे साफ़ तरीका यह है कि बिज़नेस कोड से बाहर निकलकर, curl से एक न्यूनतम अनुरोध भेजें, -i से स्थिति लाइन और रिस्पॉन्स हेडर दोनों दिखाई देते हैं:
curl -i https://api.wushenchaapi.com/v1/chat/completions \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"uncensored","max_tokens":20,"messages":[{"role":"user","content":"ping"}]}'curl काम करता है लेकिन बिज़नेस कोड नहीं, इसका मतलब है समस्या आपके कोड या एनवायरनमेंट (प्रॉक्सी, एनवायरनमेंट वेरिएबल्स, एन्कोडिंग) में है; curl भी काम नहीं करता, तो कुंजी, बैलेंस और नेटवर्क देखें।
रेट लिमिट 300 की जगह 240 क्यों सेट करें: मल्टी-इंस्टेंस डिप्लॉयमेंट में, प्रत्येक इंस्टेंस अपना रेट लिमिट सेट करता है, लेकिन उनका योग कुल सीमा से अधिक हो सकता है; इसके अलावा रिकॉवररी से अतिरिक्त क्वोटा खर्च होता है। 20% सुरक्षा मार्जिन छोड़ना अधिक सुरक्षित है। यदि आपके पास कई इंस्टेंस हैं, तो प्रत्येक इंस्टेंस के लिए क्वोटा को कुल संख्या से समान रूप से बांटें, या एक साझा काउंटर से समानांतर अनुरोधों को एकत्रित रूप से प्रबंधित करें।
डिबगिंग चेकलिस्ट
- बॉडी में
error.codeपढ़ें, केवल स्टेटस कोड पर भरोसा न करें। - 401: key प्रिफ़िक्स, एनवायरनमेंट वेरिएबल्स, और क्या key रीजेनरेट की गई है।
- 400: क्या JSON वैध है, prompt + max_tokens 100,000 टोकन से अधिक तो नहीं, और रिक्वेस्ट बॉडी 8 MB से अधिक तो नहीं।
- 402: बैलेंस और ट्रायल वैलिडिटी।
- 403: इनपुट और हिस्ट्री में ब्लॉक्ड कंटेंट तो नहीं है।
- 404: क्या पथ /v1/chat/completions या /v1/models है।
- 429: क्या मल्टी-इंस्टेंस एक key शेयर कर रहे हैं, और क्लाइंट साइड रेट लिमिट लगाया गया है या नहीं।
- 503: क्या बैकऑफ़ पुनः प्रयास किया गया है, और अंतराल कम से कम कुछ सेकंड है या नहीं।
- टाइमआउट: क्या टाइमआउट पर्याप्त है, और क्या स्ट्रीमिंग पर स्विच किया जा सकता है।
- यदि ऊपर सब ठीक है: curl से न्यूनतम रिक्वेस्ट भेजकर समस्या को रीप्रोड्यूस करें।
नई एकीकरण के लिएइंटीग्रेशन ट्यूटोरियल देखें। अन्य पैरामीटरदस्तावेज़ में हैं।
चेकलिस्ट का उपयोग: समस्या आने पर ऊपर से नीचे तक क्रम से जांचें, बीच में न छलांग लगाएं। अधिकांश 'अजीब' समस्याएं पहले चार बिंदुओं में ही मिल जाती हैं।
एक अतिरिक्त अनुभव: हर डिबगिंग निष्कर्ष को टीम डॉक्यूमेंटेशन में लिखें। अगली बार उसी एरर के लिए तुरंत समाधान मिल जाएगा।