Hata Gövdesi Formatı ve Okuma Sırası
Tüm başarısız yanıtlar aynı yapıdadır:
{"error":{"code":"...","message":"..."}}
Okuma sırası sabit üç adımdan oluşur:
- HTTP durum kodu: Büyük kategoriyi belirler;
error.code: Belirli nedeni belirler; kodda dallandırma için kullanılır;error.message: İnsanlar için okunur, günlüğe kaydedilir. Metin eşleştirme için kullanmayın.
Öncelikle şu ayrımı netleştirin: tekrar denemelerle çözülebilen (429, 503 ve ağ zaman aşımı) ile değişiklik gerektiren (diğerleri). Bu iki durumu karıştırmak, üretim ortamı sorunlarının en yaygın nedenidir; örneğin 402 için sürekli tekrar denemek ve saniyede onlarca geçersiz istek göndermek gibi.
Günlüklerde dört alanı sabit olarak kaydedin: zaman, durum kodu, error.code ve bu istek için tahmini prompt token sayısı. Sorunlar aniden arttığında veya genel başarısızlıklar olduğunda bunu hemen fark edersiniz. 402 hatası bir kez bile oluşursa hemen uyarı verin çünkü bu hizmetin kullanıcılar için kullanılamaz olduğu anlamına gelir. 429 hatası için oranlara bakın; arada bir oluşması sorun değil, sürekli oluşması eşzamanlı istekler tasarımında sorun olduğunu gösterir.
Durum Kodları Hızlı Başvuru
| Durum Kodu | error.code | Anlam | Tekrar? |
|---|---|---|---|
| 400 | — | İstek geçersiz; örneğin prompt ve max_tokens toplamı 100k'ı aşıyor. | Hayır |
| 401 | — | Geçersiz veya eksik anahtar | Hayır |
| 402 | no_credit | Bakiye tükendi veya deneme süresi doldu. | Hayır |
| 403 | content_blocked | İçerik engellendi | Hayır |
| 404 | — | Uç nokta bulunamadı | Hayır |
| 429 | — | Hız limitine takıldı | Evet, geri çekilme |
| 503 | upstream_busy | Hizmet geçici olarak meşgul. | Evet, birkaç saniye sonra |
Tablodaki "—" simgesi, özel olarak ele almanız gereken sabit bir code dizesi olmadığını gösterir; durum koduna göre dallandırmanız yeterlidir.
4xx: İsteği Düzelt, Tekrarlama
400 Geçersiz İstek
- Neden 1: JSON format hatası, genellikle manuel dize yazarken tırnak işaretlerinin kaçış karakteri olarak kullanılmamasından kaynaklanır.
- Neden 2: prompt + max_tokens 100.000'i aştı. Uzun konuşmalar en sık bu hatayı tetikler.
- Neden 3: İstek gövdesi 8 MB'ı aştı.
- Düzeltme: JSON kütüphanesi ile seri hale getirin; göndermeden önce token sayısını tahmin edin, aşılırsa geçmişi kısaltın veya max_tokens değerini düşürün. Uzun Bağlam Pratiği rehberine bakın.
401 Anahtar Sorunu
- Header eksik veya
Bearerön eki eksik. - Anahtar yeniden oluşturuldu; eski anahtar hemen geçersiz hale geldi, ancak bir makine hala eski değeri kullanıyor.
- Ortam değişkenleri konteynıra veya zamanlanmış görevlere aktarılmadı.
402 no_credit
Bakiye tükendi veya 7 günlük deneme süresi doldu. hesap sayfası üzerinden ön ödemeli bakiye yükleyerek hizmeti tekrar aktif hale getirebilirsiniz. Kendi hizmetlerinizin bakiyesini izlemesini öneririz; kullanıcılar hata vermeden önce bakiyenin bitmesini beklemeyin.
403 content_blocked
İçerik engellendi. Yetişkinlere yönelik yasal içerikler, kurgusal ve tartışmalı konular reddedilmez. Ancak reşit olmayanların cinsel içeriklerini içeren her şey engellenir; bu kural romanlar ve rol yapma içerikleri için de geçerlidir. 403 hatası alırsanız, içeriği değiştirip yeniden denemek yerine girdide veya geçmişte bu tür içerik olup olmadığını kontrol edin.
404 uç nokta bulunamadı
Sadece iki uç nokta vardır: POST /v1/chat/completions ve GET /v1/models. /v1 yolunun eksik olması, fazladan eğik çizgi eklenmesi, yazım hatası yapılması veya desteklenmeyen embeddings veya resim gibi uç noktaların istek edilmesi 404 hatasına neden olur.
400 hatası içinde sıkça yanlış anlaşılan bir durum vardır: Uzun sohbetlerde token sayısı her adımda artar. Gündüz testleri sorunsuz çalışır ancak onlarca adım sonra aniden 400 hatası almaya başlarsınız. Bu API'nin kararsızlığından değil, bağlam penceresinin dolmasından kaynaklanır. Çözüm olarak geçmiş için bir sınır belirleyin; eşik aşıldığında en eski adımları atın veya eski içerikleri özetleyin. Hata vermesini beklemeyin; istek göndermeden önce token sayısını tahmin edin.
401 hata ayıklamasında küçük bir ipucu: Anahtarın ilk ve son dört karakterini günlüklere yazdırın, tamamını yazdırmayın ve hesap sayfasında görünenle karşılaştırın. Bu sayede, özellikle konteyner ve zamanlanmış görev ortamlarında ortam değişkenlerinin eksik olması veya eski değerin okunması gibi yaygın nedenler nedeniyle, süreçte okunan değerin gerçekten sizin sandığınız anahtar olup olmadığını doğrulayabilirsiniz.
429 ve 503: Yeniden deneme yapılması gereken iki hata kodu
429 hız limiti
Her anahtar için dakikada 300 istek. Toplu işler, birden fazla örneğin tek bir anahtar paylaşması veya yeniden deneme fırtınaları bu sınırı tetikler. İki katmanlı bir düzeltme uygulanmalıdır: İstemci tarafında öncelikle hız limiti uygulanmalı (aşağıdaki koda bakınız) ve 429 için geri çekilme yeniden denemeleri yapılmalıdır.
503 upstream_busy
Hizmet geçici olarak meşgul. Birkaç saniye sonra tekrar deneyin. Hemen ardışık istek göndermeyin veya bir saniye içinde on kez tekrar denemeyin; bu durumu daha da kötüleştirir.
Ağ zaman aşımı
Uzun metin üretimi uzun sürer, bu nedenle zaman aşımı süresini çok kısa ayarlamayın; örnekte 120 saniye kullanılmıştır. Zaman aşımından sonra yeniden deneme yaparken dikkat edin: Önceki istek sunucu tarafında zaten işlenmiş olabilir ve tekrar çağrı yapmak bakiyeden gereksiz yere düşürülmesine neden olabilir. Bu nedenle üretim isteklerinde yeniden deneme sayısını azaltın; tek seferlik bekleme süresini kılmak için akış modunu kullanmanız daha iyidir.
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"])Özet: Geri çekilme formülü min(cap, base × 2^n) × rastgele katsayı şeklindedir; rastgele dalgalanma (jitter), istemcilerin aynı anda yeniden deneme yapmasını engeller. FATAL kümesindeki hata kodlarında hiç yeniden deneme yapılmaz.
İstemci hız limiti ve teşhis istekleri
429 hatasını bekleyip geri çekilmek yerine, önceden hız limiti uygulamak daha iyidir. Aşağıdaki küçük araç, bir dakikadaki istek sayısını belirlenen değerin altında tutar ve çok iş parçacıklı güvenli çalışır:
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))Hata ayıklama sırasında en temiz yöntem, iş kodundan bağımsız olarak curl ile minimum bir istek göndermektir. -i bayrağı durum satırını ve yanıt başlıklarını aynı anda görmenizi sağlar:
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 çalışıyor ama iş kodu çalışmıyorsa sorun kodunuzda veya ortamınızda (proxy, ortam değişkenleri, kodlama) vardır; curl de çalışmıyorsa anahtarı, bakiyeyi ve ağı kontrol edin.
Neden hız limiti 300 yerine 240 olarak ayarlandı? Çoklu örnekle dağıtım yapıldığında her örneğin kendi hız limitine sahip olması nedeniyle toplam hız limiti aşılabilir. Ayrıca yeniden denemeler ek kota tüketir. %20 pay bırakmak daha güvenli bir yaklaşımdır. Birden fazla örneğiniz varsa, toplam limiti örnekler arasında eşit şekilde paylaşın veya ortak bir sayaç kullanarak merkezi bir kontrol uygulayın.
Hata ayıklama kontrol listesi
- Yalnızca durum koduna bakmayın, gövdedeki
error.codedeğerini okuyun. - 401: Anahtar ön eki, ortam değişkenleri, anahtarın yeniden oluşturulup oluşturulmadığı.
- 400: JSON geçerli mi, prompt + max_tokens 100.000'i aşıyor mu, istek gövdesi 8 MB'ı aşıyor mu.
- 402: Bakiye ve deneme süresi geçerliliği.
- 403: Girdide ve geçmişte yasaklı içerik var mı.
- 404: Yol /v1/chat/completions veya /v1/models mi.
- 429: Birden fazla örnek tek bir anahtar mı paylaşıyor, istemci hız limiti uygulandı mı.
- 503: Geri çekilme yeniden denemesi uygulandı mı, aralık en az birkaç saniye mi.
- Zaman aşımı: Zaman aşımı süresi yeterli mi, akış moduna geçilebilir mi.
- Yukarıdakilerin tümü elendiyse: curl ile minimum istek göndererek sorunu tekrarlayın.
Yeni entegrasyon yapıyorsanız, önce entegrasyon kılavuzuna bakın. Diğer parametreler belgelerde yer alır.
Liste kullanımı: Sorunlar ortaya çıktığında yukarıdan aşağıya doğru sırayla eleme yapın, atlayarak okumayın. Çoğu 'garip' arıza ilk dört maddeyle çözülür.
Ek bir deneyim kuralı: Her hata ayıklama sonucunu ekip belgelerine geri yazın; böylece aynı hata bir sonraki seferde doğrudan eşleştirilebilir.