Назад в блог

AI для новичковИнструкция

Почему ответ ИИ обрывается на полуслове? max_tokens, контекстное окно и finish_reason

Ответ ИИ оборвался на полуслове — сработал лимит. Смотрим finish_reason, отличаем max_tokens от заполненного контекста, сверяем лимиты моделей.

Автор: CheapTokens TeamОпубликовано Обновлено 5 мин чтения

Тёмная обложка с логотипом cheaptokens: слова max_tokens, finish_reason и length в рамках и заголовок «Ответ обрывается на полуслове?»
Содержание
  1. Три лимита, которые обрезают ответ
  2. Сначала смотрим finish_reason
  3. Исправление 1: поднять max_tokens
  4. Исправление 2: когда заполнено контекстное окно
  5. Исправление 3: получить длинный ответ частями
  6. Когда finish_reason равен stop
  7. Выбор модели по длине ответа

Ответ, который оборвался на полуслове, почти всегда остановил лимит. Модель не потеряла мысль: в запросе кончилось место. Какой именно лимит сработал, видно в ответе — в поле finish_reason. length значит, что упёрлись в лимит. stop — модель закончила сама.

Длину ответа ограничивают три вещи. Когда понятно, какая из них сработала, исправить это можно за минуту.

Три лимита, которые обрезают ответ#

  • max_tokens — потолок, который вы задаёте в запросе. Ответ дорастает до него, и генерация останавливается, пусть даже посреди слова. В справочнике DeepSeek API параметр описан как максимальное число токенов, которое модель сгенерирует в ответе.
  • Лимит вывода модели — потолок для одного ответа конкретной модели. Он принадлежит модели, поэтому max_tokens держите не выше него. Цифры для наших моделей — в таблице ниже.
  • Контекстное окно — место под весь обмен: ваш ввод и ответ вместе. По справочнику DeepSeek, входные и сгенерированные токены вместе ограничены длиной контекста модели.

Если токены пока что-то расплывчатое, сначала прочитайте Что такое токен в ИИ. Здесь считается, что вы это уже знаете.

Сначала смотрим finish_reason#

В каждом варианте ответа (choice) чат-API есть finish_reason. Рядом лежит usage: сколько токенов ушло на вход и на выход.

Вот обрезанный ответ рядом с законченным. Запрос один: «В одном коротком предложении: что такое токен?». Сначала с max_tokens, равным 16, потом — 200.

Пример для иллюстрации, не записанный ответ: ваши цифры и дополнительные поля будут другими.

json
{
  "choices": [
    {
      "message": { "role": "assistant", "content": "Токен — это небольшой фрагмент текста, который модель читает и пи" },
      "finish_reason": "length"
    }
  ],
  "usage": { "prompt_tokens": 21, "completion_tokens": 16, "total_tokens": 37 }
}
json
{
  "choices": [
    {
      "message": { "role": "assistant", "content": "Токен — это небольшой фрагмент текста, который модель читает и пишет: чаще всего слово или его часть." },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 21, "completion_tokens": 24, "total_tokens": 45 }
}

В первом ответе completion_tokens равно 16, то есть ровно потолку, и текст обрывается на «пи». Во втором модель остановилась на 24 токенах, сильно не дойдя до потолка в 200, потому что закончила мысль.

Чтобы понять, что произошло, пройдите по шагам:

  1. Посмотрите finish_reason. stop — ответ закончен: модель сама решила завершить или сработала заданная вами стоп-последовательность. length — ответ обрезал лимит; какой именно, покажет следующий шаг. Бывают и другие значения, например content_filter и tool_calls; к длине они отношения не имеют.
  2. Сравните completion_tokens с max_tokens, который вы отправили. Равны или почти равны — вы упёрлись в max_tokens.
  3. Если completion_tokens заметно меньше max_tokens, а prompt_tokens большое, скорее всего, заполнилось контекстное окно. В справочнике DeepSeek для обоих случаев используется length, так что одно это поле их не различает; различает сравнение из шага 2. В документации Anthropic и Z.ai второй случай назван отдельно — model_context_window_exceeded. Какое из названий придёт, видно по полю в ваших ответах.

Все три описания взяты из документации разработчиков, проверено 20 октября 2026 года: DeepSeek, Anthropic и Z.ai.

Что вы видите finish_reason Причина Что делать
Обрыв, completion_tokens равно max_tokens length Достигнут max_tokens Поднять max_tokens или просить ответ частями
Обрыв, completion_tokens гораздо меньше max_tokens, ввод длинный length (в некоторых API — model_context_window_exceeded) Контекстное окно заполнено Сократить ввод или историю либо взять модель с большим окном
Ответ законченный, но короче, чем хотелось stop Модель закончила сама или сработала стоп-последовательность Попросить подробнее; проверить параметр stop
Нет текста или отказ content_filter Ответ отфильтрован Переформулировать запрос
Нет текста, вместо него запрос инструмента tool_calls Модель хочет вызвать инструмент Выполнить вызов и вернуть результат модели

Исправление 1: поднять max_tokens#

Самая частая причина исправляется проще всего. Задавайте max_tokens сами, чтобы знать, какой потолок действует. На значение по умолчанию не рассчитывайте.

python
from openai import OpenAI

client = OpenAI(base_url="https://api.cheaptokens.dev/v1", api_key="YOUR_API_KEY")

resp = client.chat.completions.create(
    model="deepseek-ai/DeepSeek-V4-Flash-0731",
    messages=[{"role": "user", "content": "Write a detailed guide to setting up a home network."}],
    max_tokens=16000,  # example value: stay at or below the model's output limit
)

choice = resp.choices[0]
print(choice.finish_reason, resp.usage.completion_tokens)

Это форма вызова. Здесь ключ записан как YOUR_API_KEY; настоящий не оставляйте в коде, которым делитесь.

Увеличение числа помогает только до собственного лимита модели. Вот лимиты на CheapTokens, проверено 20 октября 2026 года по списку моделей CheapTokens:

Модель ID модели Максимум вывода за ответ Контекст
DeepSeek-V4-Flash (0731) deepseek-ai/DeepSeek-V4-Flash-0731 32 768 токенов 380K
GLM-5.3-Flash zai-org/GLM-5.3-Flash 8192 токена 390K
MiniMax-M2.7 MiniMaxAI/MiniMax-M2.7 8192 токена 200K

Разработчики публикуют свои лимиты для своих API. Z.ai, например, указывает до 128K на вывод для серии GLM-5. Это не лимиты GLM-5.3-Flash на CheapTokens: у нас 8192 токена за ответ. Для всего, что вы строите на CheapTokens, берите цифры из таблицы выше.

Исправление 2: когда заполнено контекстное окно#

В чате вся история уходит заново с каждым сообщением, поэтому ввод растёт с каждым ходом. В контекстное окно должны поместиться история и новый ответ. Если одна история занимает почти всё окно, на ответ места не остаётся.

Окна большие, и один короткий вопрос их не заполнит. Длинные чаты и вставленные документы заполнят. Что помогает:

  • Начинать новый чат для новой задачи, а не тянуть старый.
  • Попросить модель кратко пересказать разговор и переносить дальше только пересказ.
  • Убрать старые сообщения и вложения, которые больше не нужны.
  • Если огромен сам ввод, выбрать модель с самым большим окном. Из наших это GLM-5.3-Flash, 390K. Лимит вывода у неё 8192 токена, поэтому длинный результат просите частями.

Исправление 3: получить длинный ответ частями#

Если нужный вам ответ длиннее лимита вывода модели, никакая настройка не уместит его в одно сообщение. Просите по частям: когда finish_reason равен length, отправьте обратно неполный ответ и попросите продолжить.

python
messages = [{"role": "user", "content": "Write a detailed guide to setting up a home network."}]
parts = []

for _ in range(4):  # example limit: at most 4 rounds
    resp = client.chat.completions.create(
        model="zai-org/GLM-5.3-Flash",
        messages=messages,
        max_tokens=8000,  # example value: below this model's output limit
    )
    choice = resp.choices[0]
    parts.append(choice.message.content)
    if choice.finish_reason != "length":
        break
    messages.append({"role": "assistant", "content": choice.message.content})
    messages.append({"role": "user", "content": "Continue exactly where you stopped. Don't repeat anything."})

text = "".join(parts)

Оговорка та же: это пример схемы, а не записанный запуск. Перечитайте стыки между частями. Иногда модель повторяет предложение или начинает список заново.

Каждый круг заново отправляет всё накопленное как ввод, а каждый выходной токен оплачивается. Длинный ответ стоит дороже короткого. Вот ответ на восемь тысяч токенов при 2000 токенах ввода — он помещается в любую модель из таблицы:

Модель Стоимость OpenRouter
GLM-5.3-Flash $0.00036 $0.00069
DeepSeek-V4-Flash $0.00083 $0.0013
MiniMax-M2.7 $0.0013 $0.0102

2 000 входных и 8 000 выходных токенов всего. Цены за 1M токенов актуальны и меняются вместе с нашими тарифами; столбец OpenRouter показывает справочные цены для той же нагрузки.

Когда finish_reason равен stop#

stop значит, что модель сама закончила ответ. Если она закончила раньше, чем вам хотелось, это не лимит, и больший max_tokens ничего не изменит. Напишите, что нужно: длину, разделы, степень подробности. Ещё проверьте, не задан ли в запросе параметр stop: если стоп-последовательность встретится в ответе, ответ оборвётся на ней.

Выбор модели по длине ответа#

Отталкивайтесь от нужного ответа. Если он укладывается в 8192 токена, на CheapTokens с ним справится MiniMax-M2.7 (MiniMaxAI/MiniMax-M2.7). Её вывод дешевле референсной цены OpenRouter, а оплачивается он по цене $0.15 (за 1M выходных токенов). Цена одна в любое время суток, пиковых часов нет, API совместим с OpenAI и Anthropic.

Актуальные цены на все модели:

Модель Контекст Вход $/1M Выход $/1M OpenRouter вход OpenRouter выход
GLM-5.3-Flash reasoning 390K $0.02 $0.04 $0.0413 $0.0758
DeepSeek-V4-Flash 380K $0.015 $0.10 $0.0475 $0.1568
MiniMax-M2.7 180K $0.05 $0.15 $0.30 $1.20

Цены в USD за 1 млн токенов. Данные OpenRouter приведены для сравнения и могут меняться.

Если вы ещё не отправляли запрос, пошаговый разбор — в статье Ваш первый API-запрос в CheapTokens. О том, что такое токен и почему ввод и вывод считаются отдельно, — в статье Что такое токен в ИИ.

Адреса API, id моделей и лимиты — в документации CheapTokens.