Ana Sayfa/Hatalar
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
- Yalnızca 429, 503 ve taşıma hatalarını yeniden deneyin; 400, 401, 403, 404 ve 402'leri kök nedende düzeltin.
- Hatalar, kod ve mesaj içeren bir hata nesnesiyle JSON olarak gelir; bu nedenle önce duruma göre dallanma yapın, sonra koda.
- Saniyede 5 token yenileyen bir token havuzu, bir anahtarı dakikada 300 istek altında tutar ve sunucu geri bildirimine gerek kalmaz.
- 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
| Durum | Kod | Tipik neden | Yeniden dene? | Eylem |
|---|---|---|---|---|
| 400 | geçersiz istek | Bozuk JSON veya istem tokenları ile max_tokens 100.000'in üzerinde | Hayır | Veri yükünü düzeltin; geçmişi kısaltın veya max_tokens'u düşürün |
| 401 | geçersiz anahtar | Eksik başlık, yazım hatası veya yenilenmiş bir anahtar | Hayır | Anahtarı gizli depolamanızdan yeniden yükleyin |
| 402 | no_credit | Bakiye doldu veya ücretsiz deneme süresi doldu | Hayır | Ön ödemeli bakiyeyi yükleyin, ardından devam edin |
| 403 | content_blocked | İstem, ergenleri içeren cinsel içeriğe dokunuyor | Hayır | Yeniden göndermeyin; kendi politika mesajınızı gösterin |
| 404 | bulunamadı | Yanlış yol, örneğin eksik /v1 ön eki | Hayır | Temel URL'yi kontrol edin |
| 429 | hız limiti | Bir anahtar üzerinde bir dakikada 300'den fazla istek | Evet | Titreşimle geri çekilme; istemci hız kesme ekleyin |
| 503 | upstream_busy | Geçici kapasite baskısı | Evet | Birkaç 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.
- 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.
- 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.
- 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.
- 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. - 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)
raiseProaktif 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_tokensdeğ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.