TR ▾

OpenAI uyumlu sansürsüz LLM APIuncensoredapis.com

Ana SayfaHatalar

Hatalar ve Hız Limitleri: Uncensored API İçin Pratik Kılavuz

Üretim kodu, başarılı yoldan daha fazla zamanı hata yollarında geçirir. Bu rehber, Uncensored API'ın döndürdüğü her durum kodunu listeler, hangilerinin yeniden denemeye değer olduğunu belirtir ve dakikada 300 istek sınırı için Python asyncio ve Node'da istemci tarafı hız kesme sağlar, ayrıca 402'yi kullanıcılarınıza sunmanın sakin bir yolunu verir.

Güncelleme tarihi:

Anahtar noktalar

  1. Yalnızca 429, 503 ve taşıma hatalarını yeniden deneyin; 400, 401, 403, 404 ve 402'leri kök nedende düzeltin.
  2. Hatalar, kod ve mesaj içeren bir hata nesnesiyle JSON olarak gelir; bu nedenle önce duruma göre dallanma yapın, sonra koda.
  3. Saniyede 5 token yenileyen bir token havuzu, bir anahtarı dakikada 300 istek altında tutar ve sunucu geri bildirimine gerek kalmaz.
  4. 402, ön ödemeli bakiyenin bittiğini veya denemenin sona erdiğini gösterir; bunu bir çökme olarak değil, bir ürün durumu olarak ele alın.

Hata zarfı

Her hata, tek bir üst düzey error nesnesi içeren bir JSON gövdesi döndürür. İki alan önemlidir: code, kısa bir makine dizisi; ve message, günlükler ve insanlar için metin.

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

Bu sırayla karar verin. Önce HTTP durumuna bakın, çünkü sorun sınıfını belirtir. Sadece aynı duruma sahip durumları ayırmak için code'u kullanın ve mantık için message'i asla ayrıştırmayın, çünkü ifade biçimi değişebilir. Başarılı yanıtların yapısı için API referansı'na bakın.

Durum kodları, nedenler ve eylemler

DurumKodTipik nedenYeniden dene?Eylem
400geçersiz istekBozuk JSON veya istem tokenları ile max_tokens 100.000'in üzerindeHayırVeri yükünü düzeltin; geçmişi kısaltın veya max_tokens'u düşürün
401geçersiz anahtarEksik başlık, yazım hatası veya yenilenmiş bir anahtarHayırAnahtarı gizli depolamanızdan yeniden yükleyin
402no_creditBakiye doldu veya ücretsiz deneme süresi dolduHayırÖn ödemeli bakiyeyi yükleyin, ardından devam edin
403content_blockedİstem, ergenleri içeren cinsel içeriğe dokunuyorHayırYeniden göndermeyin; kendi politika mesajınızı gösterin
404bulunamadıYanlış yol, örneğin eksik /v1 ön ekiHayırTemel URL'yi kontrol edin
429hız limitiBir anahtar üzerinde bir dakikada 300'den fazla istekEvetTitreşimle geri çekilme; istemci hız kesme ekleyin
503upstream_busyGeçici kapasite baskısıEvetBirkaç saniye sonra yeniden deneyin

403 durum koduna vurgu yapılmalıdır: bu bir politika kararındandır, geçici bir arıza değildir. Aynı isteği tekrar etmek kota harcar ve aynı yanıtı döndürür. İnsanları en çok şaşırtan 400 durumu bağlam toplamıdır. 60.000 token'lık bir istem ve max_tokens değeri 8.000 olduğunda, toplam 4.000 token taşma yapar ve her sayı tek başına geçerli olsa bile istek başarısız olur.

Davranan bir yeniden deneme politikası

Küçük, sınırlı bir politika kullanın ve yalnızca tekrar etmenin fayda sağlayacağı yerlerde uygulayın.

  1. Yeniden denenebilir hataları beyaz listeye alın: 429, 503, bağlantı sıfırlamaları ve zaman aşımı. Diğer her şey hemen yükseltilir.
  2. Jitter (rastgelelik) ile üstel geri çekilme: 1, 2, 4, 8 saniye bekleyin ve saniyenin rastgele bir kesrini ekleyin; maksimum süre 30 saniye ile sınırlıdır. Jitter, birçok işçinin senkronize bir şekilde tekrar etmesini engeller.
  3. Deneme sayısını beşle sınırlayın. Bundan sonra bir arıza, şanssızlıktan daha olasıdır ve kuyruktaki işler görünür bir şekilde başarısız olmalıdır.
  4. Kendi döngünüzü çalıştırıyorsanız SDK'nın otomatik tekrarlarını devre dışı bırakın (max_retries=0), aksi takdirde denemeler katlanır ve hız limitiniz sayısını kaybeder.
  5. Akışları baştan tekrar edin. Ortada kesilen bir akış sürdürülemez; kısmi metni atın ve isteği yeniden gönderin veya metni koruyarak bir devam isteğinde bulunun.

503 durumu için yönerge birkaç saniye beklemektir, bu nedenle ilk gecikmeyi hemen vurmak yerine bir veya iki saniye civarında başlatın. 429 durumu için çözüm hızı azaltmaktır; bu, bir sonraki bölümde otomatikleştirilir.

Dakikada 300 isteğin altında kalmak

Limit, anahtar başına dakikada 300 istektir; bu da saniyede ortalama beş istek demektir. Bir token kovanı bunu tam olarak uygular: küçük bir token patlamasına izin verir, saniyede beş token hızında yeniler ve her istek bir token harcar. Kovan boş olduğunda çağırıcı, bir token oluşana kadar bekler.

Python sürümü asyncio kullanır. Yirmi görevin tamamı tek bir havuzu ve bir kilit paylaşır, böylece eşzamanlı koroutinler havuzu aşamaz. Havuzun her denemeyi, yeniden denemeler dahil olmak üzere saydığını unutmayın.

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 ortam değişkeni olarak ayarlanmışken çalıştırın. Yirmi istek, patlama süresi ve birkaç saniyelik yenileme süresi içinde sığar, bu yüzden işlemin hızlıca tamamlandığını görürsünüz; sayıyı 600'e çıkarırsanız çalıştırma süresi yaklaşık iki dakikaya uzar; bu, limitin işini yaptığı andır.

Resmi paketi ES modülü olarak kullanan Node sürümü, edinmeleri bir promise kuyruğu üzerinden zincirler, böylece çağırıcılar sırayla sunulur.

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]);

Patlamayı muhafazakar şekilde boyutlandırın. 10'luk bir patlama, sürdürülebilir hızın saniyede beş olduğu bir kısa dalgalanmaya izin verir. Birden fazla işlem tek bir anahtarı paylaşıyorsa, hızı bunlar arasında bölün; örneğin üç işçi için dakikada 100'ü paylaşın veya tüm trafiği tek bir kuyruk üzerinden yönlendirin.

Ürününüzde 402 durumunu zarifçe yönetmek

Kodu no_credit olan bir 402 durumu, ön ödemeli bakiyenin sıfıra ulaşması veya ücretsiz deneme kredisinin süresinin dolması anlamına gelir. Bu, son kullanıcılarınızın yığın izleme (stack trace) olarak görmemesi gereken tek hatadır ve genellikle yalnızca sizin düzeltebileceğiniz bir durumu işaret eder: bakiye yüklemek.

Üç katman oluşturun. İlk olarak, detect tek bir sarmalayıcıda merkezi olarak yapın, böylece hiçbir çağrı noktasının hatırlaması gerekmez. İkinci olarak, translate: tarayıcı veya mobil uygulama, capacity_paused gibi nötr bir durum alır ve üst mesajı değil, dostça bir ekran gösterir. Üçüncü olarak, alert: çünkü her kullanıcı aynı anda etkilenir; hesap sahibine bir bildirim gönderin ve UI'nın istek göndermesini durdurmak için bir özellik bayrağını kapatın.

# 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

Proaktif koruma da ekleyin. Her istek için usage.total_tokens değerini kendi defterinize toplayın ve seçtiğiniz bir eşiğe ulaştığınızda uyarı verin, böylece bir kullanıcı engellenmeden önce bakiye yüklemesi yapılır. Deneme kredisinin $0.50 olduğunu ve 7 gün sürdüğünü unutmayın; bu nedenle bir prototip, harcanmamış para olsa bile yalnızca sürenin dolması nedeniyle 402 hatası alabilir. Planlama için oranlar fiyatlandırma sayfasında yer almaktadır.

Bakiye tekrar pozitif olduğunda, duraklatma sırasında kuyruğa aldığınız işleri yeniden oynatın. Sarmalayıcınız, ilk başarıda duraklatma bayrağını temizlemelidir.

Ne loglanmalı ve hangi durumlarda uyarı verilmeli

İyi kayıtlar, olayların kısa sürmesini sağlar. İstek başına şunları loglayın: kendi istek kimliğiniz, varsa completion id, HTTP durumu, hata code, deneme sayısı ve token kullanımı. Yetkilendirme başlığını veya kişisel veri içeren tam istemleri asla loglamayın.

Öncelik sırasına göre yararlı uyarılar: herhangi bir 402 (hemen), 401'lerin sürekli serisi (yeniden oluşturulan anahtar her yere dağıtılmadı), çağrıların birkaç yüzdesinin üzerindeki 429 hızı (hız kesme ayarı yanlış), ve 503 kümeleri (daha geniş geri baskı uygulayın, bir kuyruk düşünün). Dakikada durum sayıları için bir gösterge paneli, dört uyarıyı da bir bakışta görünür kılar. İyi yönetildiğinde, bu kodlar rutin sinyallere dönüşür.

Yayına başlamadan önce hata yollarınızı test etmek

Hiç çalışmamış hata yönetimi bir tahmindir. Gerçek bir arızayı beklemeksizin, uygun maliyetli istekler ve kendi test sahte nesneleriniz kullanarak çoğu dalı çalıştırabilirsiniz.

  • 401: kasıtlı olarak yanlış bir anahtarla GET /v1/models çağrısı yapın ve uygulamanızın operatörlere yapılandırma hatası gösterdiğini, müşterilere değil, onaylayın.
  • 404: /v1/chat/completion (tekil) isteğini bir kez gönderin ve log satırının yolu adlandırdığını onaylayın, böylece temel URL'deki bir yazım hatası dakikalar içinde belirgin hale gelir.
  • 400: Yaklaşık 50.000 token ile doldurulmuş bir istemle max_tokens değerini 32.000 olarak gönderin. Toplam 100.000'i geçer ve doğrulama yolunun tetiklendiğini izleyebilirsiniz.
  • 429 ve 503: bunları talep edemezsiniz, bu yüzden taklit edin. HTTP istemcinizi, ilk iki çağrı için durumu yükselten ve ardından başarılı olan bir sahteyle sarın ve döngünüzün uyuması, yeniden denemesi ve nihai yanıtı döndürdüğünü doğrulayın.
  • 402: Bunu da sahte nesne ile simüle edin ve UI'nın duraklatma ekranını gösterdiğini, uyarının tetiklendiğini ve sık bir döngüde hiçbir şeyin tekrar edilmediğini onaylayın.

Bunları sürekli entegrasyonda çalışan otomatik testler olarak yazın. Yukarıdaki tablodan bir satırlık tablo tabanlı bir test yazmak dakikalar sürer ve politikayı iyi niyetli refaktörlerden korur. Son olarak, API taklit edilerek kendi hız kesme sisteminize kısa bir yük testi çalıştırın: 1.000 edinme başlatın ve 60 saniyelik bir pencerenin 300 izn artı patlamadan daha fazla içermediğini doğrulayın. Bu, gerçek trafik buna bağlı olmadan önce aritmetiği kanıtlar. Daha sonra ajan döngüsü kılavuzunu okuduğunuzda, ajanların istek sayılarını katlayıp bu limitlere ilk ulaşanlar olduğu için aynı sarmalayıcıyı orada yeniden kullanın.

Sorular ve cevaplar

Bir 429 benim bakiyeme sayılır mı?

Varsayımda bulunmak yerine kendi defterinizdeki kullanım figürlerini kontrol edin. Her iki durumda da çözüm hızı azaltmak ve geri çekilme ile tekrar etmektir.

Bir 403 content_blocked yanıtını tekrar etmeli miyim?

Hayır. Bu bir politika engellemesidir ve aynı istek aynı sonucu döndürür. Kendi mesajınızı gösterin ve devam edin.

Anahtarımdan aniden 401 hatası alıyorum. Ne değişti?

En sık olarak anahtar yeniden oluşturulmuştur, bu da eski anahtarı derhal geçersiz kılar. Yeni anahtarı hesabınızdan kopyalayın ve yeniden dağıtın.

Bir anahtarı kaç işçi paylaşabilir?

Hepsi dakikada 300 istek limitini paylaşır. Hızı işçiler arasında bölün veya çağrıları tek bir kuyruk üzerinden yönlendirin.

Anahtarınız tek bir formun uzağında

Bir hesap oluşturun, anahtarı kopyalayın, temel URL'yi değiştirin. Kurulumun tamamı budur.