Skip to content

OpenAI context_length_exceeded ("maximum context length"): причины и способы решения ​

Ваш запрос завершается ошибкой HTTP 400 с сообщением вроде "This model's maximum context length is N tokens", либо потоковый вызов Responses обрывается событием response.failed с кодом context_length_exceeded. Ниже разобрано, как именно рассчитывается этот лимит, как измерить размер запроса до его отправки и какими четырьмя способами можно удерживать длинные диалоги в рамках допустимого окна.

Краткий ответ

Ошибка context_length_exceeded означает, что запросу требуется больше токенов, чем вмещает контекстное окно модели — причем это окно включает входные данные, зарезервированный вами объем выходных данных и токены рассуждений. Генерация не выполняется; повторная отправка того же запроса снова приведет к ошибке. Чтобы исправить проблему, измеряйте входные данные (POST /v1/responses/input_tokens), обрезайте или суммаризируйте старые реплики, сокращайте вывод инструментов, а в Responses API либо укажите truncation: "auto", либо включите compaction (сжатие). Иногда достаточно просто уменьшить завышенный лимит на выходные токены.

Симптомы и смысл ошибки ​

Классическое тело ответа в Chat Completions:

json
{
  "error": {
    "message": "This model's maximum context length is 128000 tokens. However, you requested 1000024 tokens (24 in the messages, 1000000 in the completion). Please reduce the length of the messages or completion.",
    "type": "invalid_request_error",
    "param": "messages",
    "code": "context_length_exceeded"
  }
}

Более старая формулировка, которая все еще часто встречается в логах, учитывает только сообщения:

text
This model's maximum context length is 4097 tokens. However, your messages resulted in 4123 tokens. Please reduce the length of the messages.

При потоковом запросе к Responses API сбой приходит в виде события, а не тела ошибки HTTP:

json
{
  "type": "response.failed",
  "response": {
    "id": "resp_5c66...",
    "object": "response",
    "status": "failed",
    "error": {
      "code": "context_length_exceeded",
      "message": "Your input exceeds the context window of this model. Please adjust your input and try again."
    }
  }
}

Какие выводы из этого следуют:

  • Ориентируйтесь на поле code, а не на текст сообщения. Формулировки различаются в зависимости от эндпоинта и меняются со временем; надежным маркером служит именно код context_length_exceeded. Собственный клиент Codex от OpenAI определяет эту ошибку по коду внутри события response.failed.
  • Первое сообщение разделяет подсчет. Фраза "24 in the messages, 1000000 in the completion" наглядно показывает, что запрашиваемый вами бюджет на генерацию ответа участвует в проверке лимита.
  • Потоковому коду нужен собственный обработчик. Потоковый запрос может вернуть статус HTTP 200, а затем завершиться ошибкой уже внутри потока, поэтому проверяйте наличие событий response.failed, а не только HTTP-код ответа.

Эта ситуация отличается от случая, когда генерация ответа останавливается раньше времени из-за достижения лимита на вывод — тогда возвращается status: "incomplete" с причиной incomplete_details.reason: "max_output_tokens", что подробно разобрано в статье Unsupported parameter: max_tokens.

Почему это происходит ​

Руководство OpenAI по управлению состоянием диалога определяет контекстное окно как максимальное количество токенов, которое можно использовать в одном запросе, включая входные данные, выходные данные и (для некоторых моделей) токены рассуждений. Обычно запросы выходят за рамки окна по одной из следующих причин:

  1. История растет без ограничений. С каждым шагом диалога пересылаются все предыдущие реплики; через некоторое время одна только история переписки превышает размер окна.
  2. Накапливается вывод инструментов. В агентских циклах основную массу токенов обычно составляет не сам диалог, а содержимое файлов, результаты поиска и вывод консольных команд.
  3. Слишком большой бюджет на вывод. Установка max_completion_tokens или max_output_tokens на максимум модели оставляет меньше места для входных данных.
  4. Скрытые входные данные. Определения инструментов, JSON-схемы, изображения и файлы тоже расходуют токены, и о них легко забыть при предварительной оценке.
  5. Лимит на входные данные меньше самого контекстного окна. На страницах моделей OpenAI для gpt-6.1-sol, gpt-6-astra, gpt-6-sol, gpt-6-luna и gpt-5.6-sol указано контекстное окно в 1,050,000 токенов, при этом максимальный размер входных данных составляет 922,000 токенов, а выходных — до 128,000 токенов. Входные данные объемом свыше 922,000 токенов вызовут ошибку, даже если вы запросите совсем короткий ответ.
  6. Связывание запросов ничего не сжимает. При использовании previous_response_id все предыдущие реплики по-прежнему включаются во входные данные модели (и тарифицируются как входные токены), поэтому длинная цепочка упрется в тот же самый потолок. О варианте работы без сохранения состояния читайте в статье previous_response_not_found.

Решение 1: Измеряйте объем перед отправкой ​

Прикидка по формуле «количество символов ÷ 4» ненадежна для кода, текстов не на английском языке, изображений и инструментов. OpenAI предоставляет специальный эндпоинт для подсчета входных токенов, который принимает ту же структуру данных, что и запрос к Responses API:

python
from openai import OpenAI

client = OpenAI()  # официальный эндпоинт OpenAI

count = client.responses.input_tokens.count(
    model="gpt-6-sol",
    input=history,          # точные входные данные, которые вы собираетесь отправить
    tools=tools,            # определения инструментов тоже учитываются
)
print(count.input_tokens)
bash
curl https://api.openai.com/v1/responses/input_tokens \
  -H "Authorization: Bearer sk-YOUR_OPENAI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "gpt-6-sol", "input": "How many tokens is this?"}'

Не каждый OpenAI-совместимый провайдер поддерживает этот эндпоинт. Там, где он недоступен, используйте значение usage.input_tokens (в Responses) или usage.prompt_tokens (в Chat Completions) из предыдущего вызова в качестве текущего ориентира — это точное количество токенов, отправленных вами в прошлый раз. В руководстве OpenAI по подсчету токенов отмечается, что локальные токенизаторы вроде tiktoken обрабатывают только обычный текст и не учитывают разметку ролей, инструменты и изображения.

Решение 2: Обрезайте историю под бюджет токенов ​

Самое универсальное решение — самостоятельно контролировать окно: сохраняйте системный промпт и самые свежие реплики, а все остальное отбрасывайте (или суммаризируйте) при достижении заданного бюджета.

python
from openai import OpenAI

client = OpenAI(api_key="sk-YOUR_TOKEN", base_url="https://byesu.com/v1")

INPUT_BUDGET = 200_000        # с большим запасом ниже максимального лимита входа модели
OUTPUT_CAP = 32_000           # оставляет место для рассуждений и ответа

def estimate(msg) -> int:
    # Грубая оценка для подстраховки; ниже корректируйте ее по реальным цифрам из usage
    return len(str(msg["content"])) // 3 + 8

def fit(system, turns, budget=INPUT_BUDGET):
    kept, used = [], estimate(system)
    for msg in reversed(turns):            # начиная с самых новых
        cost = estimate(msg)
        if used + cost > budget:
            break
        kept.append(msg)
        used += cost
    return [system] + list(reversed(kept))

system = {"role": "system", "content": "You are a concise code reviewer."}
turns = []  # накопленные сообщения user/assistant

turns.append({"role": "user", "content": "Review the diff below ..."})
resp = client.chat.completions.create(
    model="gpt-6-luna",
    messages=fit(system, turns),
    max_completion_tokens=OUTPUT_CAP,
)
turns.append({"role": "assistant", "content": resp.choices[0].message.content})
print("real input tokens:", resp.usage.prompt_tokens)

Два практических правила, которые делают этот подход эффективным в продакшене:

  • Усекайте вывод инструментов на этапе получения. Ограничивайте чтение файлов и вывод команд (оставляйте начало и конец либо краткую сводку) еще до того, как они попадут в историю. Обычно это экономит гораздо больше токенов, чем обрезка реплик чата.
  • Суммаризируйте вместо удаления, если старые реплики все еще важны: заменяйте самый старый блок сообщений краткой сводкой, сгенерированной моделью.

Решение 3: Позвольте Responses API обрезать контекст (truncation: "auto") ​

В Responses API предусмотрен параметр truncation. Его значение по умолчанию — "disabled", при котором слишком большой запрос завершается ошибкой 400. Если установить значение "auto", API будет отбрасывать элементы из начала диалога до тех пор, пока входные данные не поместятся в окно:

python
resp = client.responses.create(
    model="gpt-6-sol",
    input=history,
    truncation="auto",
    max_output_tokens=32_000,
)

Это избавляет от ошибки, но требует компромисса: самые старые элементы удаляются без уведомления. Если в первых сообщениях содержатся критически важные правила или постановка задачи, они исчезнут первыми — поэтому либо дублируйте эту информацию в недавних репликах, либо используйте Решение 2 или Решение 4, где вы сами контролируете, что именно остается в контексте.

Решение 4: Используйте Compaction для долгих сессий ​

Для агентов и продолжительных чатов в Responses API от OpenAI предусмотрен механизм compaction (сжатие): сервер сворачивает предыдущие реплики в зашифрованный элемент сжатия, который сохраняет состояние и ход рассуждений, занимая при этом меньше токенов.

Сжатие на стороне сервера в рамках запроса, срабатывающее при превышении заданного порога отрендеренных токенов:

python
resp = client.responses.create(
    model="gpt-6.1-sol",
    input=history,
    store=False,
    context_management=[{"type": "compaction", "compact_threshold": 400_000}],
)
history += resp.output   # включает элемент compaction, когда он был создан

Согласно руководству OpenAI по сжатию, как только в ответе появляется элемент compaction, в следующем запросе вы можете отбросить все предшествующие ему элементы истории. Если же вы связываете запросы через previous_response_id, вручную удалять старые элементы не нужно. Также существует отдельный эндпоинт /responses/compact: вы отправляете полное окно контекста, а он возвращает сжатое окно, которое можно передать в следующий вызов /responses как есть (при этом отправляемое вами окно само должно помещаться в контекст модели). Оба режима работают при store=false.

Compaction — это функция Responses API от OpenAI; при работе с другими провайдерами заранее убедитесь, что она поддерживается, и держите Решение 2 в качестве резервного варианта.

Осознанно выбирайте бюджет на вывод ​

Поскольку лимит на выходные токены учитывается при проверке контекстного окна, привычка выставлять его на максимум модели «на всякий случай» часто становится причиной этой ошибки на длинных входных данных. В руководстве OpenAI по рассуждающим моделям рекомендуется на старте экспериментов резервировать не менее 25,000 токенов под рассуждения и ответ, а затем корректировать это значение исходя из реальной длины получаемых ответов, не завышая его до предела.

Если вы вызываете GPT через byesu ​

byesu — это шлюз AI API с OpenAI-совместимым эндпоинтом по адресу https://byesu.com/v1, поддерживающий как Chat Completions, так и Responses, с оплатой по мере использования (pay-as-you-go) без подписок.

  • Лимиты контекста определяются самой моделью. Доступное вам окно соответствует собственному лимиту модели, поэтому все описанные выше методы контроля бюджета и обрезки истории применяются без изменений; при тарификации pay-as-you-go обрезка истории также напрямую снижает количество входных токенов, за которые вы платите на каждом шаге диалога.
  • Используйте usage как счетчик. Считывайте usage.input_tokens (в Responses) или usage.prompt_tokens (в Chat Completions) из каждого ответа и передавайте эти данные в вашу логику обрезки истории — этот механизм работает одинаково на любом эндпоинте.

Чтобы начать работу, следуйте инструкции в разделе Быстрый старт.

FAQ ​

Что означает context_length_exceeded? ​

Запрос требует больше токенов, чем допускает контекстное окно модели. Это окно включает входные данные, выходные данные, а для рассуждающих моделей — еще и токены рассуждений. В Chat Completions ошибка возвращается как 400 invalid_request_error; в потоковом запросе к Responses API она приходит в виде события response.failed с кодом ошибки context_length_exceeded.

Учитываются ли max_completion_tokens или max_output_tokens в лимите контекста? ​

Могут учитываться. В одном из документированных вариантов ошибки количество токенов в сообщениях и количество токенов, запрошенных для ответа, указываются отдельно — поэтому слишком большой лимит на генерацию может привести к превышению общего окна. Кроме того, на страницах актуальных моделей GPT-6 указан максимальный размер входных данных, который меньше полного контекстного окна.

Как посчитать токены перед отправкой запроса? ​

OpenAI предоставляет эндпоинт POST /v1/responses/input_tokens (в Python SDK вызывается как client.responses.input_tokens.count), который возвращает точное количество входных токенов для запроса к Responses API с учетом инструментов и изображений. Локальные токенизаторы вроде tiktoken дают лишь приблизительную оценку для обычного текста.

Что делает truncation auto в Responses API? ​

По умолчанию для truncation установлено значение disabled, и запрос, входные данные которого превышают контекстное окно, завершается ошибкой 400. Если задать для truncation значение auto, API будет отбрасывать элементы с начала диалога до тех пор, пока входные данные не поместятся в лимит. Это предотвращает ошибку, но незаметно удаляет самый старый контекст.

Что такое compaction в Responses API? ​

Compaction (сжатие) сворачивает длинный диалог в зашифрованный элемент сжатия, который переносит предыдущее состояние в меньшем количестве токенов. Вы можете включить его для отдельного запроса с помощью context_management и порога compact_threshold или вызвать отдельный эндпоинт /responses/compact. Оба варианта работают при store, установленном в false.

Возникла проблема? Напишите в поддержку или в наш чат.