HI ▾

OpenAI-संगत बिना सेंसर LLM APIuncensoredapis.com

होमत्रुटियाँ

Uncensored API के लिए त्रुटियाँ और रेट लिमिट: एक व्यावहारिक प्लेबुक

प्रोडक्शन कोड में विफलता मार्ग पर खुशहाल मार्ग की तुलना में अधिक समय लगता है। यह प्लेबुक प्रत्येक स्टेटस कोड की सूची बनाता है जिसे Uncensored API लौटाता है, बताता है कि किनका पुनः प्रयाम करना चाहिए, और Python asyncio और Node में प्रति मिनट 300 अनुरोध सीमा के लिए क्लाइंट-साइड थ्रॉटलिंग देता है, साथ ही अपने उपयोगकर्ताओं के लिए 402 को प्रदर्शित करने का एक सुव्यवस्थित तरीका।

अपडेट किया गया

मुख्य बिंदु

  1. केवल 429, 503 और ट्रांसपोर्ट विफलताओं का रीट्राई करें; 400, 401, 403, 404 और 402 को कारण पर ठीक करें।
  2. त्रुटियाँ JSON के रूप में आती हैं, एक त्रुटि ऑब्जेक्ट जिसमें कोड और संदेश होता है, इसलिए पहले स्टेटस पर शाखा बनाएं, फिर कोड पर।
  3. प्रति सेकंड 5 टोकन रिफ़िल करने वाला एक टोकन बकेट एक कुंजी को सर्वर पुशबैक के बिना प्रति मिनट 300 अनुरोध के अंदर रखता है।
  4. 402 का अर्थ है कि प्रीपेड बैलेंस खत्म हो गया है या ट्रायल समाप्त हो गया है; इसे एक क्रैश की बजाय उत्पाद स्थिति मानें।

त्रुटि एनवलप

प्रत्येक विफलता एक JSON बॉडी लौटाती है जिसमें एक अकेला टॉप-लेवल error ऑब्जेक्ट होता है। दो फ़ील्ड महत्वपूर्ण हैं: code, एक छोटा मशीन स्ट्रिंग, और message, लॉग और मानवों के लिए टेक्स्ट।

{
  "error": {
    "code": "no_credit",
    "message": "Balance used up or trial expired."
  }
}

इस क्रम में निर्णय लें। पहले HTTP स्टेटस देखें, क्योंकि यह समस्या की श्रेणी बताता है। code का उपयोग केवल उन मामलों को अलग करने के लिए करें जिनका स्टेटस समान है, और लॉजिक के लिए message को पार्स न करें, क्योंकि शब्दावली बदल सकती है। सफल प्रतिक्रियाओं के आकार के लिए, API संदर्भ देखें।

स्टेटस कोड, कारण और क्रियाएँ

स्टेटसकोडआम कारणरीट्राई?क्रिया
400बैड रिक्वेस्टदोषपूर्ण JSON, या प्रॉम्प्ट टोकन plus max_tokens 100,000 से अधिकनहींपेलोड ठीक करें; इतिहास कम करें या max_tokens कम करें
401अमान्य कुंजीहैडर की कमी, टाइपो, या एक कुंजी जिसे पुनः उत्पन्न किया गया थानहींअपने सीक्रेट स्टोर से कुंजी रीलोड करें
402no_creditबैलेंस खत्म या मुफ़्त ट्रायल समाप्तनहींप्रीपेड बैलेंस टॉप-अप करें, फिर जारी रखें
403content_blockedअनुरोध किशोरों के साथ यौन सामग्री को छूता हैनहींदुबारा भेजें नहीं; अपना पॉलिसी संदेश दिखाएं
404नहीं मिलागलत पथ, जैसे /v1 प्रीफिक्स की कमीनहींबेस URL जाँचें
429रेट लिमिटएक कुंजी पर एक मिनट में 300 से अधिक अनुरोधहाँजिटर के साथ बैकऑफ़; क्लाइंट थ्रॉटलिंग जोड़ें
503upstream_busyअस्थायी क्षमता दबावहाँकुछ सेकंड बाद रीट्राई करें

403 पर जोर देना चाहिए: यह एक नीति निर्णय है, न कि अस्थायी त्रुटि। समान अनुरोध का पुनः प्रयाम करने से क्रेडिट बर्बाद होता है और वही उत्तर मिलता है। 60,000-टोकन प्रॉम्प्ट के साथ max_tokens 8,000 होने पर 4,000 ओवरफ्लो होता है और विफल हो जाता है, भले ही प्रत्येक संख्या अकेले मान्य हो।

एक पुनः प्रयाम नीति जो सही ढंग से काम करती है

एक छोटी, सीमित नीति का उपयोग करें और केवल वहां लागू करें जहां रीट्राई मदद कर सकता है।

  1. रीट्राई योग्य विफलताओं को व्हाइटलिस्ट करें: 429, 503, कनेक्शन रिसेट और टाइमआउट। बाकी सब तुरंत फेल करें।
  2. जिटर के साथ एक्सपोनेंशियल बैकऑफ़: 1, 2, 4, 8 सेकंड इंतज़ार करें, एक सेकंड के यादृच्छिक अंश को जोड़ें, 30 पर सीमित करें। जिटर कई वर्कर को एक साथ रीट्राई करने से रोकता है।
  3. प्रयाम को पांच पर सीमित करें। इसके बाद, खराबी की संभावना भाग्य की खराबी से अधिक होती है, और कतारबद्ध कार्य स्पष्ट रूप से विफल होने चाहिए।
  4. अपने लूप को चलाने पर SDK ऑटो-रीट्राइज़ अक्षम करें (max_retries=0), अन्यथा प्रयास बढ़ जाएंगे और आपका थ्रॉटल गिनती खो देगा।
  5. स्ट्रीम को शुरुआत से रीट्राई करें। एक स्ट्रीम जो बीच में फेल हो जाए, उसे फिर से शुरू नहीं किया जा सकता; आंशिक पाठ को छोड़ दें और अनुरोध दोबारा भेजें, या इसे रखें और कंटिन्यूएशन के लिए पूछें।

503 के लिए, मार्गदर्शन एक सेकंड या दो सेकंड के लिए प्रतीक्षा करने का है, इसलिए तुरंत हथौड़ा मारने के बजाय अपनी पहली देरी एक या दो सेकंड के पास शुरू करें। 429 के लिए, इलाज गति धीमी करना है, जिसे अगला अनुभाग स्वचालित करता है।

प्रति मिनट 300 अनुरोधों से कम रहना

प्रति कुंजी प्रति मिनट 300 अनुरोध की सीमा है, जो औसतन प्रति सेकंड पांच है। एक टोकन बकेट बिल्कुल वही लागू करता है: यह टोकन के एक छोटे बर्स्ट को रखता है, प्रति सेकंड पांच की दर से रिफिल होता है, और प्रत्येक अनुरोध के लिए एक टोकन लेता है। यदि बकेट खाली है, तो कॉलर एक टोकन उपलब्ध होने तक सो जाता है।

पायथन संस्करण asyncio का उपयोग करता है। सभी बीस टास्क एक बकेट और एक लॉक साझा करते हैं, इसलिए समकालीन कोरूटीन इसे ओवरड्रो नहीं कर सकते। ध्यान दें कि बकेट प्रत्येक प्रयास को गिनता है, रीट्राइज़ सहित।

import asyncio, os, random, time
from openai import AsyncOpenAI, APIStatusError, APIConnectionError

class TokenBucket:
    """Allows `rate` acquisitions per `per` seconds, with a small burst."""
    def __init__(self, rate=300, per=60.0, burst=10):
        self.fill = rate / per          # tokens added per second (5.0)
        self.cap = burst
        self.tokens = burst
        self.stamp = time.monotonic()
        self.lock = asyncio.Lock()

    async def acquire(self):
        async with self.lock:
            while True:
                now = time.monotonic()
                self.tokens = min(self.cap, self.tokens + (now - self.stamp) * self.fill)
                self.stamp = now
                if self.tokens >= 1:
                    self.tokens -= 1
                    return
                await asyncio.sleep((1 - self.tokens) / self.fill)

client = AsyncOpenAI(base_url="https://api.uncensoredapis.com/v1",
                     api_key=os.environ["API_KEY"], max_retries=0)
bucket = TokenBucket()

RETRYABLE = {429, 503}

async def ask(prompt, attempts=5):
    for n in range(attempts):
        await bucket.acquire()
        try:
            r = await client.chat.completions.create(
                model="uncensored",
                messages=[{"role": "user", "content": prompt}],
                max_tokens=200,
            )
            return r.choices[0].message.content
        except APIStatusError as e:
            if e.status_code not in RETRYABLE or n == attempts - 1:
                raise
        except APIConnectionError:
            if n == attempts - 1:
                raise
        await asyncio.sleep(min(30, 2 ** n) + random.uniform(0, 1))

async def main():
    prompts = [f"Give one-line fact number {i} about tides." for i in range(1, 21)]
    results = await asyncio.gather(*(ask(p) for p in prompts))
    print(len(results), "answers; first:", results[0])

asyncio.run(main())

इसे API_KEY निर्यात करके चलाएं। बीस्ट के भीतर 20 अनुरोध और कुछ सेकंड का रीफिल फिट होता है, इसलिए आप इसे जल्दी समाप्त होते देखेंगे; गिनती को 600 तक बढ़ाएं और रन लगभग दो मिनट तक फैल जाता है, जो सीमा अपना काम कर रही है।

नोड संस्करण, आधिकारिक पैकेज का उपयोग करके एक ES मॉड्यूल में, प्रॉमिस कतार के माध्यम से अधिग्रहण को चेन करता है ताकि कॉलर्स को क्रम में सेवा दी जा सके।

import OpenAI from "openai";

class TokenBucket {
  constructor(rate = 300, perMs = 60000, burst = 10) {
    this.fillPerMs = rate / perMs;
    this.cap = burst;
    this.tokens = burst;
    this.stamp = Date.now();
    this.queue = Promise.resolve();
  }
  acquire() {
    // Serialize callers so the bucket math never races.
    this.queue = this.queue.then(async () => {
      for (;;) {
        const now = Date.now();
        this.tokens = Math.min(this.cap, this.tokens + (now - this.stamp) * this.fillPerMs);
        this.stamp = now;
        if (this.tokens >= 1) { this.tokens -= 1; return; }
        await new Promise((r) => setTimeout(r, Math.ceil((1 - this.tokens) / this.fillPerMs)));
      }
    });
    return this.queue;
  }
}

const client = new OpenAI({
  baseURL: "https://api.uncensoredapis.com/v1",
  apiKey: process.env.API_KEY,
  maxRetries: 0,
});
const bucket = new TokenBucket();

async function ask(prompt, attempts = 5) {
  for (let n = 0; n < attempts; n++) {
    await bucket.acquire();
    try {
      const r = await client.chat.completions.create({
        model: "uncensored",
        messages: [{ role: "user", content: prompt }],
        max_tokens: 200,
      });
      return r.choices[0].message.content;
    } catch (err) {
      const retryable = err.status === 429 || err.status === 503 || err.status === undefined;
      if (!retryable || n === attempts - 1) throw err;
      await new Promise((r) => setTimeout(r, Math.min(30000, 2 ** n * 1000) + Math.random() * 1000));
    }
  }
}

const prompts = Array.from({ length: 20 }, (_, i) => `Give one-line fact number ${i + 1} about tides.`);
const answers = await Promise.all(prompts.map((p) => ask(p)));
console.log(answers.length, "answers; first:", answers[0]);

बीस्ट को संयम से सेट करें। 10 का बीस्ट एक छोटी चोट की अनुमति देता है जबकि स्थिर दर प्रति सेकंड पांच रहती है। यदि कई प्रक्रियाएं एक कुंजी साझा करती हैं, तो दर को उनके बीच विभाजित करें, उदाहरण के लिए तीन वर्कर के लिए प्रति मिनट 100, या सभी ट्राफिक को एक कतार के माध्यम से रूट करें।

अपने उत्पाद में 402 को सहजता से संभालना

कोड no_credit के साथ 402 का अर्थ है कि प्रीपेड शेष शून्य हो गया है या मुफ़्त ट्रायल समाप्त हो गया है। यह वह एक त्रुटि है जिसे आपके अंत-उपयोगकर्ताओं को स्टैक ट्रेस के रूप में कभी नहीं देखना चाहिए, और यह आमतौर पर कुछ संकेत देता है जिसे केवल आप ठी कर सकते हैं: टॉप-अप करना।

तीन परतें बनाएं। पहले, detect इसे केंद्रीय रूप से एक व्रैपर में करें ताकि कोई कॉल साइट याद रखने की आवश्यकता न हो। दूसरा, translate करें: ब्राउज़र या मोबाइल ऐप एक तटस्थ स्थिति प्राप्त करता है जैसे capacity_paused और एक उपयोगकर्ता-अनुकूल स्क्रीन दिखाता है, कभी भी अपस्ट्रीम संदेश नहीं। तीसरा, alert खुद को, क्योंकि हर उपयोगकर्त एक साथ प्रभावित होता है; खाता मालिक को सूचना भेजें और एक फीचर फ्लिप करें ताकि UI अनुरोध सबमिट करना बंद कर दे।

# server side: translate the upstream 402 into a product state
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from openai import AsyncOpenAI, APIStatusError
import os

app = FastAPI()
client = AsyncOpenAI(base_url="https://api.uncensoredapis.com/v1", api_key=os.environ["API_KEY"])

@app.post("/api/reply")
async def reply(body: dict):
    try:
        r = await client.chat.completions.create(
            model="uncensored", messages=body["messages"], max_tokens=400)
        return {"text": r.choices[0].message.content}
    except APIStatusError as e:
        if e.status_code == 402:
            # Tell the client app to show a "temporarily unavailable" screen,
            # and page yourself to top up the prepaid balance.
            return JSONResponse({"state": "capacity_paused"}, status_code=503)
        if e.status_code == 429 or e.status_code == 503:
            return JSONResponse({"state": "busy_retry"}, status_code=503)
        raise

प्रोएक्टिव सुरक्षा भी जोड़ें। प्रत्येक अनुरोध में usage.total_tokens को अपने लेजर में जोड़ें और एक सीमा पर चेतावनी दें जिसे आप चुनते हैं, ताकि टॉप-अप एक उपयोगकर्ता के ब्लॉक होने से पहले हो जाए। याद रखें कि ट्रायल क्रेडिट $0.50 है और 7 दिनों तक चलता है, इसलिए एक प्रोटोटाइप अकेले समाप्ति से 402 तक पहुंच सकता है, भले ही पैसा अभी भी अनखर्च हो। योजना के लिए दरें pricing page पर हैं।

एक बार शेष धनात्मक हो जाए, तो रुके हुए समय में आपकी कतारबद्ध कार्य को फिर से चलाएं। आपका व्रैपर पहली सफलता पर paused फ्लैग साफ करना चाहिए।

लॉग और अलर्ट करने के लिए क्या

अच्छे रिकॉर्ड आप आपातकालीन स्थितियों को छोटा बनाते हैं। प्रत्येक अनुरोध के लिए लॉग करें: अपना अनुरोध id, समाप्ति id (जब उपलब्ध हो), HTTP स्थिति, त्रुटि code, प्रयास संख्या, और टोकन उपयोग। Authorization हेडर या व्यक्तिगत डेटा वाले पूर्ण प्रॉम्प्ट कभी लॉग न करें।

उपयोगी अलर्ट, प्राथमिकता क्रम में: कोई भी 402 (तत्काल), 401s की एक स्थिर धाव (एक पुनः उत्पन्न कुंजी हर जगह तैनात नहीं की गई थी), कॉल के कुछ प्रतिशत से ऊपर 429 रेट (आपका थ्रॉटल गलत आकार का है), और 503 क्लस्टर (बैक ऑफ़ चौड़ा करें, एक कतार पर विचार करें)। प्रति मिनट स्थिति गणना का एक डैशबोर्ड सभी चार को एक नज़रे में दिखाता है। अच्छी तरह से संभाला गया, ये कोड विच्छेद के बजाय रूटीन संकेत बन जाते हैं।

लॉन्च से पहले अपनी विफलता पथों का परीक्षण करना

त्रुटि हैंडलिंग जो कभी नहीं चली है, एक अनुमान है। आप सस्ते अनुरोध और अपने टेस्ट डबल्स का उपयोग करके अधिकांश शाखाओं को व्यायाम कर सकते हैं, वास्तविक बाधा का इंतज़ार किए बिना।

  • 401: कॉल GET /v1/models एक जानबूझकर गलत कुंजी के साथ और पुष्टि करें कि आपका ऐप ऑपरेटरों को कॉन्फ़िगरेशन त्रुटि दिखाता है, ग्राहकों को नहीं।
  • 404: अनुरोध /v1/chat/completion (एकवचन) एक बार और पुष्टि करें कि लॉग लाइन पथ का नाम बताती है, ताकि बेस URL में टाइपो मिनटों में स्पष्ट हो।
  • 400: 32,000 में से max_tokens भेजें और प्रॉम्प्ट को लगभग 50,000 टोकन तक पैड करें। योग 100,000 से अधिक हो जाता है, और आप देख सकते हैं कि सत्यापन पथ सक्रिय हो रहा है।
  • 429 और 503: आप इन्हें मांग पर नहीं ला सकते, इसलिए इन्हें स्टब करें। अपने HTTP क्लाइंट को एक फेक में लपेटें जो पहले दो कॉल के लिए स्थिति बढ़ाता है, फिर सफल होता है, और यह पुष्टि करें कि आपका लूप सोता है, पुनः प्रयास करता है और अंतिम उत्तर लौटाता है।
  • 402: इसे स्टब भी करें, और पुष्टि करें कि UI paused स्क्रीन दिखाता है, अलर्ट फायर होता है और कुछ भी तंग लूप में रीट्राई नहीं करता।

इनकी रचना ऐसे स्वचालित टेस्ट के रूप में करें जो निरंतर इंटीग्रेशन में चले। एक टेबल-ड्राइव टेस्ट जिसमें ऊपर की तालिका से प्रत्येक स्थिति के लिए एक पंक्ति होती है, लिखने में मिनट लेता है और नीति को अच्छे इरादों वाले रिफैक्टर्स से बचाता है। अंत में, API को स्टब करके अपने थ्रॉटल के खिलाफ एक छोटा लोड टेस्ट चलाएं: 1,000 अधिग्रहण फायर करें और पुष्टि करें कि कोई भी 60-सेकंड का विंडो 300 ग्रांट्स और बर्स्ट से अधिक नहीं रखता है। यह गणित को साबित करता है कि असली ट्राफिक इस पर निर्भर होने से पहले। जब आप बाद में agent loop guide पढ़ते हैं, तो वहां उसी व्रैपर को पुनः उपयोग करें, क्योंकि एजेंट अनुरोध गिनती को बढ़ाते हैं और इन सीमाओं को पहले हिट करते हैं।

प्रश्न और उत्तर

क्या 429 मेरे बैलेंस के खिलाफ गिना जाता है?

अनुमान लगाने के बजाय अपने लेजर में उपयोग आंकड़ों की जाँच करें। किसी भी स्थिति में, समाधान गति धीमी करना और बैकऑफ़ के साथ पुनः प्रयाम करना है।

क्या मुझे 403 content_blocked प्रतिक्रिया का रीट्राई करना चाहिए?

नहीं। यह एक नीति ब्लॉक है और एक समान अनुरोध वही परिणाम लौटाता है। अपना संदेश दिखाएं और आगे बढ़ें।

मेरी कुंजी अचानक 401 लौटाती है। क्या बदला है?

अक्सर कुंजी को पुनः उत्पन्न किया गया था, जिससे पुरानी कुंजी तुरंत अमान्य हो जाती है। अपनी खाता से नई कुंजी कॉपी करें और इसे पुनः तैनात करें।

एक कुंजी कितने वर्कर साझा कर सकते हैं?

सभी प्रति मिनट 300 अनुरोध सीमा साझा करते हैं। रेट को वर्कर्स में बाँटें या कॉल को एक कतार के माध्यम से भेजें।

आपकी कुंजी बस एक फ़ॉर्म दूर है

एक खाता बनाएं, कुंजी कॉपी करें, बेस URL बदलें। यह सेटअप का पूरा हिस्सा है।