ID ▾

API LLM tanpa sensor yang kompatibel dengan OpenAIuncensoredapis.com

BerandaKesalahan

Kesalahan dan Batas Laju: Panduan Praktis untuk Uncensored API

Kode produksi menghabiskan lebih banyak waktu pada jalur kegagalan daripada jalur sukses. Panduan ini mencantumkan setiap kode status yang dikembalikan oleh Uncensored API, menjelaskan mana yang layak untuk dicoba lagi, dan memberikan pembatasan laju di sisi klien untuk batas 300 permintaan per menit pada Python asyncio dan Node, serta cara tenang untuk menampilkan 402 kepada pengguna Anda sendiri.

Diperbarui

Poin kunci

  1. Hanya coba ulang 429, 503 dan kegagalan transport; perbaiki 400, 401, 403, 404 dan 402 pada penyebabnya.
  2. Kesalahan dikirim sebagai JSON dengan objek error yang berisi kode dan pesan, jadi lakukan percabangan berdasarkan status terlebih dahulu, lalu kode.
  3. Tongga token yang mengisi ulang 5 token per detik menjaga satu kunci tetap di bawah 300 permintaan per menit tanpa penolakan server.
  4. 402 berarti saldo prabayar habis atau masa uji coba berakhir; perlakukan ini sebagai status produk, bukan sebagai kegagalan.

Amplop kesalahan

Setiap kegagalan mengembalikan tubuh JSON dengan satu objek error di tingkat atas. Dua bidang penting: code, string mesin pendek, dan message, teks yang dimaksudkan untuk log dan manusia.

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

Putuskan dengan urutan ini. Lihat status HTTP terlebih dahulu karena status itu menunjukkan kelas masalah. Gunakan code hanya untuk memisahkan kasus yang memiliki status sama, dan jangan pernah mem-parsing message untuk logika karena kata-katanya dapat berubah. Untuk bentuk respons sukses, lihat referensi API.

Kode status, penyebab dan tindakan

StatusKodePenyebab khasCoba ulang?Tindakan
400permintaan burukJSON tidak valid, atau token prompt ditambah max_tokens di atas 100.000TidakPerbaiki payload; pangkas riwayat atau turunkan max_tokens
401kunci tidak validHeader hilang, salah ketik, atau kunci yang telah dibuat ulangTidakMuat ulang kunci dari tempat penyimpanan rahasia Anda
402no_creditSaldo habis atau uji coba gratis berakhirTidakIsi saldo prabayar, lalu lanjutkan
403content_blockedPermintaan menyentuh konten seksual yang melibatkan anak di bawah umurTidakJangan kirim ulang; tampilkan pesan kebijakan Anda sendiri
404tidak ditemukanJalur salah, seperti awalan /v1 yang hilangTidakPeriksa URL dasar
429batas lajuLebih dari 300 permintaan dalam satu menit pada satu kunciYaTunda dengan jitter; tambahkan throttling sisi klien
503upstream_busyTekanan kapasitas sementaraYaCoba ulang setelah beberapa detik

403 memerlukan penekanan: ini adalah keputusan kebijakan, bukan kesalahan sementara. Mencoba lagi permintaan yang sama sia-sia kuota dan akan mengembalikan jawaban yang sama. Kasus 400 yang paling mengejutkan orang adalah jumlah konteks. Prompt 60.000 token dengan max_tokens sebesar 8.000 meluap sebesar 4.000 dan gagal meskipun setiap angka valid secara terpisah.

Kebijakan pengulangan yang berperilaku

Gunakan kebijakan kecil dan terbatas, dan terapkan hanya di tempat pengulangan dapat membantu.

  1. Daftar putih kegagalan yang dapat dicoba lagi: 429, 503, reset koneksi, dan waktu tunggu. Semua yang lain melempar segera.
  2. Backoff eksponensial dengan jitter: tunggu 1, 2, 4, 8 detik ditambah fraksi detik acak, dibatasi hingga 30. Jitter mencegah banyak pekerja mencoba lagi secara serentak.
  3. Batasi upaya hingga lima. Di luar itu, gangguan lebih mungkin terjadi daripada keberuntungan buruk, dan pekerjaan yang mengantri harus gagal secara terlihat.
  4. Nonaktifkan percobaan ulang otomatis SDK (max_retries=0) saat Anda menjalankan loop sendiri, jika tidak upaya akan berlipat ganda dan pembatas laju Anda kehilangan jumlah.
  5. Coba ulang stream dari awal. Stream yang gagal di tengah tidak dapat dilanjutkan; buang teks parsial dan keluarkan permintaan lagi, atau simpan dan minta kelanjutan.

Untuk 503, panduan adalah menunggu beberapa detik, jadi mulai penundaan pertama Anda sekitar satu atau dua detik daripada membanjiri segera. Untuk 429, obatnya adalah memperlambat, yang mengotomatisasi bagian berikutnya.

Tetap di bawah 300 permintaan per menit

Batasnya adalah 300 permintaan per menit per kunci, yang merupakan lima per detik rata-rata. Tongga token memberlakukan persis itu: ia menahan hingga ledakan kecil token, mengisi ulang pada lima per detik, dan membuat setiap permintaan mengambil satu token. Jika tongga kosong, pemanggil menunggu hingga token ada.

Versi Python menggunakan asyncio. Semua dua puluh tugas berbagi satu tongga dan kunci, sehingga korutin konkuren tidak dapat melebihi batasnya. Perhatikan bahwa tongga menghitung setiap upaya, termasuk percobaan ulang.

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())

Jalankan dengan API_KEY diekspor. Dua puluh permintaan muat dalam ledakan ditambah beberapa detik pengisian ulang, jadi Anda akan melihatnya selesai dengan cepat; naikkan jumlah menjadi 600 dan jalannya memanjang menjadi sekitar dua menit, yang merupakan batas melakukan tugasnya.

Versi Node, menggunakan paket resmi dalam modul ES, merangkai akuisisi melalui antrian janji sehingga pemanggil dilayani secara berurutan.

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

Ukur ledakan secara konservatif. Ledakan 10 memungkinkan lonjakan pendek sementara laju berkelanjutan tetap pada lima per detik. Jika beberapa proses berbagi satu kunci, bagikan laju di antaranya, misalnya 100 per menit masing-masing di tiga pekerja, atau alirkan semua lalu lintas melalui satu antrian.

Menangani 402 dengan baik di produk Anda

402 dengan kode no_credit berarti saldo prabayar mencapai nol atau masa uji coba gratis berakhir. Ini adalah satu kesalahan yang tidak boleh dilihat oleh pengguna akhir Anda sebagai jejak tumpukan, dan biasanya menandakan sesuatu yang hanya Anda yang dapat perbaiki: mengisi ulang.

Bangun tiga lapisan. Pertama, detect secara terpusat dalam satu pembungkus sehingga tidak ada situs panggilan yang harus mengingat. Kedua, translate: browser atau aplikasi seluler menerima status netral seperti capacity_paused dan menampilkan layar ramah, bukan pesan hulu. Ketiga, alert diri Anda sendiri, karena setiap pengguna terpengaruh sekaligus; kirimkan pemberitahuan ke pemilik akun dan balikkan bendera fitur sehingga UI berhenti mengirim permintaan.

# 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

Tambahkan juga perlindungan proaktif. Jumlahkan usage.total_tokens per permintaan ke buku besar Anda sendiri dan beri peringatan pada ambang batas yang Anda pilih, sehingga pengisian ulang terjadi sebelum pengguna diblokir. Ingat bahwa kredit uji coba adalah $0,50 dan berlangsung 7 hari, sehingga prototipe dapat mencapai 402 hanya dari kadaluarsa dengan uang yang belum dibelanjakan. Tingkat untuk perencanaan ada di halaman harga.

Setelah saldo positif lagi, putar ulang pekerjaan yang Anda antri saat dijeda. Pembungkus Anda harus menghapus flag dijeda pada keberhasilan pertama.

Apa yang harus dicatat dan diberi peringatan

Catatan yang baik membuat insiden singkat. Log, per permintaan: id permintaan Anda sendiri, penyelesaian id saat ada, status HTTP, error code, nomor upaya, dan penggunaan token. Jangan pernah log header Authorization atau prompt penuh yang membawa data pribadi.

Pemberitahuan yang berguna, berdasarkan urutan prioritas: 402 apa pun (segera), rantai berkelanjutan 401 (kunci yang dibuat ulang tidak diterapkan di mana-mana), laju 429 di atas beberapa persen panggilan (pembatas laju Anda salah ukuran), dan klaster 503 (mundur lebih luas, pertimbangkan antrian). Dasbor jumlah status per menit membuat keempatnya terlihat sekilas. Ditangani dengan baik, kode-kode ini menjadi sinyal rutin daripada gangguan.

Menguji jalur kegagalan Anda sebelum peluncuran

Penanganan kesalahan yang belum pernah dijalankan adalah tebakan. Anda dapat melatih sebagian besar percabangan tanpa menunggu gangguan nyata, menggunakan permintaan murah dan double uji coba Anda sendiri.

  • 401: panggil GET /v1/models dengan kunci yang sengaja salah dan konfirmasi bahwa aplikasi Anda menunjukkan kesalahan konfigurasi kepada operator, bukan kepada pelanggan.
  • 404: permintaan /v1/chat/completion (tunggal) sekali dan konfirmasi bahwa baris log menamai jalur, sehingga salah ketik di URL dasar jelas dalam hitungan menit.
  • 400: kirim max_tokens sebesar 32.000 dengan prompt yang diisi hingga sekitar 50.000 token. Jumlahnya melebihi 100.000, dan Anda dapat melihat jalur validasi terpicu.
  • 429 dan 503: Anda tidak dapat memanggil ini sesuai permintaan, jadi stub mereka. Bungkus klien HTTP Anda dalam palsu yang melempar status untuk dua panggilan pertama, lalu berhasil, dan assert bahwa loop Anda tidur, mencoba lagi, dan mengembalikan jawaban akhir.
  • 402: stub juga, dan konfirmasi bahwa UI menampilkan layar jeda, pemberitahuan terpicu dan tidak ada yang mencoba lagi dalam loop ketat.

Tulis ini sebagai pengujian otomatis yang berjalan dalam integrasi berkelanjutan. Pengujian berbasis tabel dengan satu baris per status dari tabel di atas membutuhkan waktu beberapa menit untuk ditulis dan melindungi kebijakan dari refaktor yang bermaksud baik. Terakhir, jalankan pengujian beban singkat terhadap throttle Anda sendiri dengan API disembunyikan: kirimkan 1.000 akuisisi dan pastikan bahwa tidak ada jendela 60 detik yang berisi lebih dari 300 pemberian ditambah burst. Itu membuktikan aritmetika sebelum lalu lintas nyata bergantung pada itu. Ketika Anda nanti membaca panduan loop agen, gunakan pembungkus yang sama di sana, karena agen melipatgandakan jumlah permintaan dan mencapai batas ini lebih dulu.

Tanya jawab

Apakah 429 dihitung terhadap saldo saya?

Periksa angka penggunaan di buku besar Anda sendiri daripada mengasumsikan. Bagaimanapun, solusinya adalah memperlambat dan mengulang dengan penundaan.

Haruskah saya mengulang respons 403 content_blocked?

Tidak. Ini adalah blokir kebijakan dan permintaan yang identik mengembalikan hasil yang sama. Tampilkan pesan Anda sendiri dan lanjutkan.

Kunci saya tiba-tiba mengembalikan 401. Apa yang berubah?

Paling sering kunci dibuat ulang, yang membatalkan yang lama sekaligus. Salin kunci baru dari akun Anda dan terapkan kembali.

Berapa banyak pekerja yang dapat berbagi satu kunci?

Semua berbagi batas 300 permintaan per menit. Bagi laju di antara pekerja atau cor panggilan melalui satu antrian.

Kunci Anda hanya selangkah lagi dari satu formulir

Buat akun, salin kunci, ubah URL dasar. Itu saja seluruh pengaturan.