Sorun gidermeKılavuz
HTTP 200'den sonra akış başarısız oldu: Python'da akış ortası hataları yakalayın
Bir akış 200 durumundan sonra neden bozulabilir, event: error nasıl fark edilir ve yanıtı kopyalamadan kısmi metni koruyan bir Python yeniden denemesi.

Bu sayfada
Sohbet arayüzünüz yarım bir yanıt akıttı, dondu ve günlük 200 OK diyor. Bu bir çelişki değil: 200 yalnızca akışın başladığını söyler, bittiğini değil. Sonradan bir şey bozulursa, sunucu hatayı ancak akışın içinde gönderebilir, bu yüzden durum kodu kontrolü bunu asla görmez. Çözüm, bir akışı yalnızca bitiş sinyaliyle sona erdiğinde başarılı saymak ve sona ermediğinde temiz bir arabellekten yeniden denemektir.
Bu sayfanın geri kalanı bozuk akışın nasıl göründüğünü, iki Python işleyicisini (Anthropic Messages ve OpenAI SDK) ve yanıtın başlangıcını iki kez yazdırmayan bir yeniden denemeyi gösterir. Her iki işleyici de API uç noktası olarak CheapTokens kullanır: dokümanlar temel URL'leri içerir ve örnek model DeepSeek-V4-Flash'tir (id deepseek-, 380K bağlam, yanıt başına 32.768'e kadar çıktı token'ı, her saatte tek fiyat — model sayfasına bakın).
200 gerçekte neyi vaat eder#
Kapıda kargo için imza atan bir kuryeyi düşünün: imza onun geldiğini kanıtlar, paketin sağlam olduğunu değil. HTTP de aynı şekilde çalışır. Sunucu önce durum satırını ve başlıkları gönderir, sonra gövde parça parça gelir. Model arka ucu işin ortasında aşırı yüklenirse, durum satırı çoktan gitmiştir.
Anthropic'in API hataları sayfası (1 Kasım 2026'da kontrol edildi) bunu doğrudan söyler: SSE üzerinden akış yanıtı aldığınızda, API 200 döndürdükten sonra bir hata oluşabilir ve bu durumda standart hata işleme geçerli olmaz. Akış dokümanları bu olayın şeklini verir:
event: error
data: {"type": "error", "error": {"type": "overloaded_error", "message": "Overloaded"}}overloaded_error normalde akışsız bir çağrıda HTTP 529'a karşılık gelir (yüksek trafikten kaynaklanan geçici aşırı yük). Aynı sayfa 500 api_error (üstel geri çekilmeyle yeniden dene) ve 504 timeout_error (uzun istekler için akış kullan) listeler. Kablo üzerinde bozuk bir akış şöyle görünür:

Dokümanlar ayrıca yeni olay türlerinin eklenebileceği konusunda uyarır, bu yüzden kodunuz bilinmeyen olayları zarifçe işlemelidir. Bu nedenle aşağıdaki işleyiciler her hata baytını tanımaya çalışmaz. Tek bir soru sorarlar: akış bitiş sinyaliyle sona erdi mi?
- Anthropic Messages: son olay
message_stop'dir vemessage_deltaiçindekistop_reasonneden bittiğini söyler (end_turn,max_tokens,stop_sequence). - OpenAI Chat Completions: son parça boş olmayan bir
finish_reasontaşır (stop,length, …).
Bitiş sinyali yoksa veya yolda bir istisna varsa — durum ne derse desin yanıt eksiktir.
Python'da yakalayın#
Tarayıcıya yanıt akıtan bir destek botu alın. Döngü metni bir arabelleğe toplar ve üç şeyi bildirir: şu ana kadarki metin, akışın bitip bitmediği ve varsa hata. Kullandığınız SDK'nın sekmesini seçin.
Tek işleyici, iki SDK
Anthropic SDK
import os
import anthropic
client = anthropic.Anthropic(
base_url='https://api.cheaptokens.dev', # no /v1 for the Anthropic SDK
api_key=os.environ['CHEAPTOKENS_API_KEY'],
)
MODEL = 'deepseek-ai/DeepSeek-V4-Flash-0731'
def ask_once(prompt, on_text=lambda t: None):
parts, finished = [], False
try:
with client.messages.stream(
model=MODEL,
max_tokens=1024,
messages=[{'role': 'user', 'content': prompt}],
) as stream:
for event in stream:
if event.type == 'content_block_delta' and event.delta.type == 'text_delta':
parts.append(event.delta.text)
on_text(event.delta.text)
elif event.type == 'message_stop':
finished = True
except anthropic.APIError as err:
return ''.join(parts), False, err
return ''.join(parts), finished, NoneOpenAI SDK
import os
import openai
client = openai.OpenAI(
base_url='https://api.cheaptokens.dev/v1',
api_key=os.environ['CHEAPTOKENS_API_KEY'],
)
MODEL = 'deepseek-ai/DeepSeek-V4-Flash-0731'
def ask_once(prompt, on_text=lambda t: None):
parts, finish = [], None
try:
stream = client.chat.completions.create(
model=MODEL,
max_tokens=1024,
stream=True,
messages=[{'role': 'user', 'content': prompt}],
)
for chunk in stream:
if not chunk.choices:
continue
choice = chunk.choices[0]
if choice.delta.content:
parts.append(choice.delta.content)
on_text(choice.delta.content)
if choice.finish_reason:
finish = choice.finish_reason
except openai.APIError as err:
return ''.join(parts), False, err
return ''.join(parts), finish is not None, Noneİki ayrıntı ikinci bir bakışı hak ediyor. Birincisi, her iki işleyici de SDK'nın temel hata sınıfını yakalar (anthropic., openai.APIError), böylece SDK'nın belirli bir hata için hangi alt sınıfı fırlattığı önemli değildir. İkincisi, finished bayrağı istisnadan ayrıdır: bir akış hiç istisna olmadan da erken bitebilir ve bu durum da başarısızlık sayılmalıdır.
openai-python README'si OpenAI tarafında ne bekleneceğini ekler (1 Kasım 2026'da kontrol edildi): bir akışta okuma zaman aşımı APITimeoutError fırlatır, diğer HTTPX hataları orijinal istisnayla birlikte APIConnectionError fırlatır (__cause__ içinde). Akış başarısız olmak yerine takılırsa, OpenAI Python SDK'da zaman aşımları ve yeniden denemeler sayfasına bakın.
Yanıtı iki kez yazdırmadan yeniden deneyin#
İşte gönderilmesi kolay bir hata. İlk deneme "İade politikası şudur…" yazdırır, ölür, yeniden deneme baştan başlar ve "İade politikası şudur…" tekrar yazdırır — şimdi kullanıcı başlangıcı iki kez görür veya bir cümle kendi yeniden başlangıcına yapışır. Bunun olağan nedeni tek bir paylaşılan arabellektir: answer += text denemenin dışında yaşar, bu yüzden ikinci deneme birincinin üzerine ekler.
Çözüm sıkıcıdır. Bir deneme bir arabelleğe sahiptir, başarısız bir denemenin metni atılır (veya yalnızca günlük için saklanır) ve yeniden deneme sıfırdan başlar:
import time
def ask_with_retry(prompt, attempts=3, on_text=lambda t: None, on_restart=lambda: None):
for attempt in range(attempts):
text, finished, err = ask_once(prompt, on_text)
if finished:
return text
status = getattr(err, 'status_code', None)
if status is not None and 400 <= status < 500 and status not in (408, 409, 429):
raise err # a 400/401/404 will not fix itself
print(f'attempt {attempt + 1} failed after {len(text)} chars: {err!r}')
if attempt == attempts - 1:
break
on_restart() # clear the message box in your UI
time.sleep(2 ** attempt) # 1 s, 2 s
raise RuntimeError('stream failed after all attempts')on_restart kopyayı durduran kısımdır. Bir web arayüzünde, sonraki deneme akarken mesaj balonunu boşaltır. Düz bir terminalde yazdırmayı geri alamazsınız, bu yüzden ya yalnızca finished doğru olduktan sonra yazdırın ya da görünür bir --- retrying --- satırı yazdırın. Sıfırdan yeniden denemek tüm istemi yeniden gönderir, bu yüzden girdi yeni deneme için tekrar faturalandırılır; çoğu sohbet yanıtı için bu, temiz bir yanıt için makul bir bedeldir.
Sıraya koy
Yeniden deneme adımlarını kodunuzun çalıştırması gereken sıraya koyun
Öğeleri sürükle veya okları kullan
- Bozuk akışı okumayı durdurun ve kısmi metnini günlük için saklayın
- Hatayı kontrol edin: 408, 409 ve 429 dışındaki bir 4xx, yeniden deneme değil durma anlamına gelir
- Mesaj kutusunu temizleyin ve yeni bir arabellek başlatın
- Üstel geri çekilmeyle bekleyin (1 sn, sonra 2 sn)
- Tam isteği yeniden gönderin ve yalnızca yeni yanıtı gösterin
Anthropic'in SDK'sı geçici hataları — bağlantı hataları, hız sınırları, 5xx — üstel geri çekilmeyle zaten yeniden dener, varsayılan olarak 2 kez, retry-after değerine uyar ve max_retries bunu değiştirir. Bu isteği kapsar. 200'den sonra ölen bir akış başka bir hikayedir: dokümanlar standart hata işlemenin orada geçerli olmadığını söyler, bu yüzden yukarıdaki döngü sizin sorumluluğunuzdadır. Yalnızca 429 için ayrı bir adım adım kılavuz var: 429 Too Many Requests: geri çekilmeyle yeniden denemeler.
Her erken duruş bir hata değildir#
Yeniden denemeden önce yanıtın neden bittiğini kontrol edin. stop_ (Anthropic) veya finish_ (OpenAI) ile biten bir akış bitmiştir — yalnızca sizin belirlediğiniz sınıra ulaşmıştır. Bunu yeniden denemek aynı kesilmiş metni ve aynı faturayı getirir. Bunun yerine sınırı yükseltin; kesilmiş yanıt kılavuzu bunu adım adım anlatır.
Üçüncü bir grup var: ağ. Boşta bağlantılar yolda düşebilir, bu da bağlantı hatası veya hiçbir olay olmadan duran bir akış olarak görünür. Bunu akış ortası hatayla aynı şekilde ele alın ve sık sık oluyorsa yaygın bağlantı hataları sayfasına bakın. Uzun üretimler için Anthropic, devasa akışsız bir max_tokens yerine akış kullanmayı önerir, yani zaten bunun doğru tarafındasınız.
Göndermeden önce#
Her başarısız denemenin istek kimliğini kaydedin. Anthropic hata gövdeleri bir request_id alanı ve bir request-id yanıt başlığı taşır ve Python SDK'sı message.'yi açığa çıkarır; bu kimlikle bir başarısızlık anekdot değil izlenebilir olur.
Kontrol listesi
Akış hata işleme, doğru yapılmış
İşleyicinin çalıştığını görmek isterseniz, kendi anahtarınıza yönlendirin: dokümanlarda bir API anahtarı oluşturun, CHEAPTOKENS_ ayarlayın ve ask_ çağırın. Python'da akışın temelleri için Python'da akış yanıtları ile başlayın; Anthropic tarafı CheapTokens ile Anthropic Python SDK sayfasında ele alınmıştır.




