Bloga dön

Sorun gidermeKılavuz

AI yanıtı kesildi mi? finish_reason "length" ve max_tokens sorununu düzeltin

API yanıtınız cümle ortasında mı duruyor ya da bozuk JSON mu döndürüyor? finish_reason alanını kontrol edin, max_tokens değerini sınır içinde yükseltin ve bir devam adımı ekleyin.

Yazan: CheapTokens TeamYayınlanma tarihi: 5 dk okuma

Bir API yanıtında finish_reason length değerini gösteren terminal tarzı kapak
Bu sayfada
  1. Kesilmiş bir yanıt ekranda nasıl görünür
  2. Adım 1: size söyleyen alanı okuyun
  3. Adım 2: max_tokens değerini yükseltin, ama tavanı aşmayın
  4. Adım 3: yarıda duran JSON
  5. Adım 4: modelin devam etmesine izin verin
  6. Uzun bir yanıtın maliyeti
  7. Yayına almadan önce: kısa bir kontrol listesi

Betiğiniz çalıştı, model yanıt verdi ve fonksiyon bir satırın ortasında bitiyor. Ya da JSON ayrıştırıcısı tamamen normal görünen bir yanıtta hata fırlatıyor. Çoğu zaman model başarısız olmadı: sizin belirlediğiniz (ya da hiç görmediğiniz bir varsayılan) max_tokens sınırına takıldı ve API onu kelimenin ortasında durdurdu.

Hızlı çözüm: yanıttaki finish_reason alanını okuyun. "length" ise (OpenAI uyumlu API) ya da stop_reason değeri "max_tokens" ise (Anthropic Messages), yanıt kesilmiştir. max_tokens değerini modelin çıktı sınırına kadar yükseltin ya da modelden devam etmesini isteyin. Bu sayfanın geri kalanı her ikisini de kopyalayıp yapıştırabileceğiniz kodla gösteriyor.

Bunun neden olduğunun sade bir dille anlatımını istiyorsanız, bir AI yanıtı neden cümle ortasında durur yazısıyla başlayın. Bu sayfa hata ayıklama sürümüdür.

Kesilmiş bir yanıt ekranda nasıl görünür#

Belirtiler ne istediğinize göre değişir, ama neden aynıdır. Bunları gördüklerinizle eşleştirmeyi deneyin:

Eşleştir

Belirtiyi olası nedeniyle eşleştirin

  • Bir fonksiyon return resu ile bitiyorKod yanıtı satır ortasında max_tokens sınırına takıldı
  • json.loads "Unterminated string" veya "Expecting ',' delimiter" hatasıyla başarısız oluyorJSON yarıda kesildi
  • Bir çeviri metnin ilk yarısından sonra duruyorÇıktı sınırı çeviriden küçük
  • Yanıt tam ve alan stop diyorModel kendi kendine bitirdi; başka yere bakın

Son satır önemli. finish_reason değeri stop ise sorununuz sınır değildir ve max_tokens değerini yükseltmek hiçbir şeyi değiştirmez.

Adım 1: size söyleyen alanı okuyun#

Her yanıt üretimin neden sona erdiğini söyler. OpenAI uyumlu bir yanıtta bu alan choices[0].finish_reason: model bitirdiğinde "stop", tokenları tükendiğinde "length". Anthropic Messages API'sinde alan stop_reason ve kesilme değeri "max_tokens". Anthropic'in stop-reason kılavuzu (28 Ekim 2026'da kontrol edildi) tam olarak aşağıdaki iki düzeltmeyi öneriyor: max_tokens değerini yükseltin ya da yanıta devam edin.

Aynı kontrol üç biçimde. Temel URL, OpenAI SDK için https://api.cheaptokens.dev/v1 ve Anthropic SDK için https://api.cheaptokens.dev (/v1 olmadan). max_tokens=200 kasıtlı olarak küçük, böylece kesilmeyi kendiniz görebilirsiniz.

Tek kontrol, üç yol

Python (OpenAI SDK)

python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.cheaptokens.dev/v1",
    api_key=os.environ["CHEAPTOKENS_API_KEY"],
)

resp = client.chat.completions.create(
    model="deepseek-ai/DeepSeek-V4-Flash-0731",
    max_tokens=200,
    messages=[{"role": "user", "content": "Write a Python class for a todo list with tests."}],
)

choice = resp.choices[0]
if choice.finish_reason == "length":
    print("Cut off at the token limit")
print(choice.message.content)
print(resp.usage.completion_tokens)

Python (Anthropic SDK)

python
import os
import anthropic

client = anthropic.Anthropic(
    base_url="https://api.cheaptokens.dev",
    api_key=os.environ["CHEAPTOKENS_API_KEY"],
)

msg = client.messages.create(
    model="deepseek-ai/DeepSeek-V4-Flash-0731",
    max_tokens=200,
    messages=[{"role": "user", "content": "Write a Python class for a todo list with tests."}],
)

if msg.stop_reason == "max_tokens":
    print("Cut off at the token limit")
print(msg.content[0].text)

curl

bash
curl https://api.cheaptokens.dev/v1/chat/completions \
  -H "Authorization: Bearer $CHEAPTOKENS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-ai/DeepSeek-V4-Flash-0731",
    "max_tokens": 200,
    "messages": [{"role": "user", "content": "Write a Python class for a todo list with tests."}]
  }'

Geri gelen JSON'da "finish_reason": "length" alanına bakın.

Bir teşhis olarak çalıştığında şu çifti görürsünüz: düşük bir sınır length verir, geniş bir sınır stop verir.

Düşük ve yüksek max_tokens ile aynı istek: finish_reason length'ten stop'a değişiyor
En sık karşılaşacağınız iki finish_reason değeri

Adım 2: max_tokens değerini yükseltin, ama tavanı aşmayın#

Bariz düzeltme daha büyük bir sayıdır. İşin püf noktası: her modelin yanıt için kendi üst sınırı vardır. Bunun üzerinde bir değer ayarlamayın: sınır modele özgüdür, bu yüzden önce aşağıdaki tabloya bakın. Bunlar CheapTokens'teki yanıt başına sınırlardır (bilgiler 28 Ekim 2026'da kontrol edildi):

Model Yanıt başına maksimum çıktı Bağlam
DeepSeek-V4-Flash 32.768 token 380K
GLM-5.3-Flash 8.192 token 390K
MiniMax-M2.7 8.192 token 180K

9.000 token'lık bir çeviri, yanıt başına sınırı daha büyük bir model gerektirir — DeepSeek-V4-Flash yanıt başına 32.768 token'a kadar alır. Uzun kod, uzun JSON veya bütün bir belge için deepseek-ai/DeepSeek-V4-Flash-0731 en fazla alana sahiptir: yanıt başına 32.768 token'a kadar, günün her saatinde tek fiyat. Sağlayıcılar bunları farklı adlandırdığı için tam model kimliklerini CheapTokens belgelerinden ve modeller sayfasından alın.

Pratik bir kural: max_tokens değerini kabul edeceğiniz en uzun yanıta ayarlayın, maksimuma değil. Modelin gerçekte yazdığı tokenlar için ödeme yaparsınız, bu yüzden yanıtlar kısa olduğunda yüksek bir tavan hiçbir maliyet getirmez.

Adım 3: yarıda duran JSON#

Kesilmiş bir JSON yanıtı en kötü durumdur, çünkü metin ayrıştırıcı sona ulaşana kadar doğru görünür. Tek bir çağrıda 40 faturadan alan çıkardığınızı ve bir dizi istediğinizi varsayalım. Model 31 nesne yazar, sınıra ulaşır ve dizi hiç kapanmaz.

Token sınırında kesilmiş bir dizide json.loads hatası
Ayrıştırıcıda kesilmiş bir JSON dizisi nasıl görünür

Dizeyi ]} ekleyerek onarmaya çalışmayın. Eksik kayıtlarla geçerli JSON elde edersiniz, bu da bir hatadan daha kötüdür. Önce finish_reason alanını kontrol edin; length ise ya sınırı yükseltip çağrıyı yeniden çalıştırın ya da girdiyi daha küçük gruplara bölün. Biçimi zorlamanın kendisi için bir LLM API'sinden geçerli JSON yazısına bakın.

Adım 4: modelin devam etmesine izin verin#

Bazen yanıt gerçekten herhangi bir sınırdan uzundur: bir kitap bölümü, büyük bir yeniden düzenleme. O zaman elinizdekini geri besleyin ve modelden devam etmesini isteyin. Aşağıdaki döngü şu ana kadarki metni tutar, geri kalanını ister ve bir hata sonsuza kadar dönmesin diye birkaç turdan sonra vazgeçer.

python
def complete(base_messages, model, max_tokens=4096, rounds=4):
    text = ""
    for _ in range(rounds):
        messages = list(base_messages)
        if text:
            messages += [
                {"role": "assistant", "content": text},
                {"role": "user", "content": "Continue exactly where you stopped. Do not repeat anything."},
            ]
        r = client.chat.completions.create(model=model, max_tokens=max_tokens, messages=messages)
        choice = r.choices[0]
        text += choice.message.content or ""
        if choice.finish_reason != "length":
            return text, True   # finished on its own
    return text, False          # still cut after all rounds

İki alışkanlık bunu dürüst tutar. True/False bayrağını döndürün ve yarım bir belgeyi tamamlanmış gibi sunmak yerine False durumunda kullanıcıya bir uyarı gösterin. Ve her turun önceki metni girdi olarak yeniden gönderdiğini unutmayın, bu yüzden devam ettirilen bir yanıt tek büyük yanıttan daha pahalıdır. Yapılandırılmış veriler için devam ettirmek yerine daha büyük bir sınırı veya daha küçük grupları tercih edin.

Uzun bir yanıtın maliyeti#

Uzun bir yanıtın 2.000 token girdi ve 8.000 token çıktı olduğunu varsayalım. DeepSeek-V4-Flash'te bu istek bugünkü fiyatla $0.00083 tutar ve girdi ile çıktı birlikte sayıldığında toplamda OpenRouter'dan daha ucuzdur. Sayıları kendi yükünüze göre değiştirin:

Maliyet hesaplayıcı

Günde 50 uzun yanıt

İstek başına giriş token'ı: 2.000 · İstek başına çıkış token'ı: 8.000 · Günlük istek sayısı: 50

ModelGünlükAylık
GLM-5.3-Flash$0.018$0.54
DeepSeek-V4-Flash$0.0415$1.25
MiniMax-M2.7$0.065$1.95

Çıkarım: bu senaryoda çıktı tarafı baskındır, bu yüzden max_tokens içindeki pay, yeniden çalıştırmaya karşı ucuz bir sigortadır. Yeniden üretmeniz gereken kesilmiş bir yanıtın bedeli iki kez ödenir. Faturanın iki tarafı hakkında arka plan bilgisi girdi ve çıktı tokenları yazısında, fiyatlarıyla birlikte tam model listesi ise fiyatlandırma sayfasında.

Yayına almadan önce: kısa bir kontrol listesi#

Kontrol listesi

Kodunuz için kesilme kontrol listesi