smartaipack
Документация SmartAIPack
Responses API

Обработка ошибок

Как различать ошибки Responses API по HTTP-статусу и слою, повторять временные сбои и диагностировать обрыв потока.

Ошибки Responses API нужно разбирать в два этапа: сначала проверить HTTP-статус и Content-Type, затем осторожно читать тело в том формате, который действительно пришёл. Не рассчитывайте на одну схему ошибки для шлюза и всех поставщиков. Для временных 429, 502 и 503 допустимы ограниченные повторы, а 400, 401, 402, 403, 404 и 405 сначала требуют исправления причины.

Адрес Responses API — POST https://route.smartaipack.ru/v1/responses. Модель и точное значение request_model_id выбирайте в каталоге моделей, у варианта с опубликованным путём /v1/responses. Общий контракт маршрута описан в обзоре Responses API, а минимальный запрос — в руководстве по базовому использованию.

Каждый запрос обрабатывается отдельно

Каждый вызов /v1/responses обрабатывается отдельно. AI Gateway не заявляет собственного серверного хранения истории диалога для последующих запросов. Если приложению нужен контекст, храните его на своей стороне и формируйте следующий input из той истории, которую действительно хотите передать модели.

Поля store: true и previous_response_id не следует считать гарантированным контрактом AI Gateway. Шлюз может передать их выбранному поставщику, но поддержка, смысл и срок хранения будут зависеть от этого поставщика. AI Gateway также не гарантирует, что такие поля обязательно будут отклонены локально. Для переносимого сценария храните историю у себя и начинайте интеграцию с проверенной формой model + input.

Это особенно важно для повторов. Новый HTTP-запрос — новая попытка выполнения. Даже если предыдущий ответ не дошёл до клиента, поставщик мог уже принять запрос и начать вычисление.

Формат ответа с ошибкой

Часть локальных проверок AI Gateway возвращает JSON с объектом error. Например, некорректное JSON-тело может получить ответ такого вида:

{
  "error": {
    "code": "INVALID_JSON",
    "message": "Request body must be valid JSON"
  }
}

Но это пример одного слоя, а не единая схема всех ошибок. Внутренняя проверка допуска и внешний маршрутизатор используют собственные ответы, а поставщик может вернуть свой JSON, обычный текст или тело другого формата. Регистр кодов тоже различается: локально встречаются и INVALID_JSON, и model_not_published.

Поэтому клиенту нужен безопасный порядок:

  1. Получить HTTP-статус и заголовки.
  2. Проверить Content-Type.
  3. Разбирать JSON только при подходящем типе содержимого и с обработкой ошибки разбора.
  4. Искать code, type и message только как доступные диагностические поля, а не как обязательные.
  5. Сохранить ограниченный фрагмент непонятного тела без секретов, если это разрешено правилами вашего приложения.

Пример для fetch:

async function readResult(response) {
  const contentType = response.headers.get("content-type") ?? "";
  let body;

  if (contentType.includes("application/json")) {
    try {
      body = await response.json();
    } catch {
      body = { parse_error: true };
    }
  } else {
    body = { text: await response.text() };
  }

  if (!response.ok) {
    const error = new Error("Responses API request failed");
    error.status = response.status;
    error.contentType = contentType;
    error.body = body;
    throw error;
  }

  return body;
}

Не выводите в пользовательский интерфейс тело поставщика целиком: оно может содержать технические детали или отражённые части входных данных.

Коды ошибок

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

HTTPКодЧто означает и что делать
400INVALID_JSONТело нельзя разобрать как JSON. Исправьте синтаксис и Content-Type.
400MODEL_REQUIREDНет непустого строкового поля model. Скопируйте request_model_id из каталога.
400model_not_publishedДля указанной модели и пути нет опубликованного маршрута. Проверьте модель и /v1/responses в каталоге.
400PROVIDER_ENDPOINT_NOT_SUPPORTEDЯвно выбранный вариант поставщика не поддерживает запрошенный протокол. Этот локальный код подтверждён на проверке совместимости пути, но не является обязательной формой каждого отказа /v1/responses; здесь чаще возможен model_not_published.
401unauthorizedBearer-ключ отсутствует или не распознан. Проверьте заголовок и используемый секрет.
401api_key_expiredСрок ключа истёк. Выпустите или выберите действующий ключ.
402insufficient_balanceКлюч приостановлен из-за недостаточного баланса. Проверьте биллинг и не повторяйте запрос до пополнения.
403model_not_allowedВыбранная модель не входит в разрешения ключа. Измените модель или ограничения ключа.
403api_key_scope_not_allowedУ ключа нет требуемой области доступа. Используйте ключ с подходящими правами.
404ENDPOINT_NOT_SUPPORTEDПуть /v1/* не опубликован. Проверьте адрес; Responses API находится на /v1/responses.
405METHOD_NOT_ALLOWEDДля опубликованного вызываемого пути нужен POST.
429код может зависеть от ограничителя, в том числе TOO_MANY_REJECTED_REQUESTSСлишком много запросов или повторных отклонений. Снизьте параллелизм и примените ограниченные повторы.
502UPSTREAM_UNAVAILABLEЛокальный промежуточный слой не смог получить ответ от следующего узла до начала ответа клиенту. Код подтверждён для одного из маршрутизирующих слоёв и не гарантируется каждым поставщиком Responses API.
503ADMISSION_UNAVAILABLEСервис предварительного допуска временно недоступен, а пригодного сохранённого решения нет.
503ADMISSION_INVALID_DECISIONПредварительный допуск вернул ответ, из которого нельзя получить корректный маршрут.
503SERVER_BUSYЛокальный промежуточный слой достиг предела одновременной работы. Код зависит от задействованного слоя.
503route_blockedОпубликованный маршрут временно заблокирован защитой AI Gateway; внутренний отказ 409 преобразуется публичным маршрутизатором в 503.

Эта таблица не заменяет чтение фактического ответа. Поставщик может вернуть другой статус, другой регистр кода, собственное поле или вообще не JSON. Более общий разбор отказов шлюза есть в статье «Ошибки API», а ограничения частоты и баланса — в руководстве по лимитам API.

Поле типа ошибки

AI Gateway не гарантирует единое верхнеуровневое поле error_type. В одном ответе тип может находиться в error.type, в другом будет только error.code, а в ответе поставщика структура может быть иной. Не стройте ветвление приложения вокруг обязательного error_type и не ожидайте фиксированный словарь его значений.

Практичная классификация начинается с HTTP-статуса. Доступные code, type и message используйте для уточнения причины и диагностики. Если поля нет, клиент должен продолжать корректно работать по статусу и типу содержимого.

Также не полагайтесь на обязательный metadata: null, единый идентификатор запроса или наличие Retry-After. Идентификатор записывайте только тогда, когда он реально присутствует в заголовках или теле. Retry-After учитывайте только при фактическом наличии и корректном значении.

Ошибки до начала потока

При stream: true ошибка до начала успешной передачи приходит обычным HTTP-ответом. Клиент ещё может увидеть статус 400, 401, 402, 403, 404, 405, 429, 502 или 503, проверить Content-Type и разобрать тело по правилам выше.

Не начинайте разбор SSE, пока не проверили успешный статус и тип text/event-stream. Даже ответ со статусом 200 нельзя автоматически считать SSE, если Content-Type указывает на другой формат.

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

Ошибка после начала потока

После отправки успешного HTTP-статуса сервер уже не может заменить его новым статусом. Ошибка может прийти отдельным событием SSE по схеме поставщика, проявиться исключением клиента или простым обрывом соединения. Единой структуры такого события AI Gateway не гарантирует.

Считайте ответ завершённым только после штатного признака окончания, предусмотренного выбранным поставщиком. Если поток оборвался раньше:

  • пометьте накопленный результат как неполный;
  • не склеивайте его автоматически с ответом новой попытки;
  • запишите, что поток уже начался;
  • сохраните последнее корректно разобранное событие и доступную ошибку без чувствительных данных;
  • перед повтором проверьте, допустим ли второй результат для этой операции.

Обрыв соединения не доказывает, что поставщик не принял запрос. Вычисление и расход могли уже начаться. AI Gateway не обещает идемпотентность повторного вызова /v1/responses, поэтому после неопределённого завершения проверьте событие в журнале использования и стоимость в аналитике. Подробная работа с SSE описана в статье «Потоковые ответы AI Gateway».

Какие запросы повторять

Не повторяйте без исправления запросы со статусами 400, 401, 402, 403, 404 и 405. Задержка не исправит JSON, ключ, баланс, разрешения, путь или HTTP-метод.

Для 429, 502 и 503 разрешайте небольшое конечное число попыток с растущей задержкой и случайным разбросом. Если ответ содержит корректный Retry-After, не отправляйте повтор раньше указанного времени. При отсутствии заголовка используйте собственную политику.

Пример решения без привязки к схеме тела:

const retryableStatuses = new Set([429, 502, 503]);
const maxAttempts = 4;

for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
  const response = await sendRequest();

  if (!retryableStatuses.has(response.status)) {
    return readResult(response);
  }

  if (attempt === maxAttempts) {
    return readResult(response);
  }

  const retryAfter = parseRetryAfter(response.headers.get("retry-after"));
  const fallbackMs = 500 * 2 ** (attempt - 1);
  const jitterMs = Math.floor(Math.random() * 250);
  await wait(Math.max(retryAfter ?? 0, fallbackMs + jitterMs));
}

sendRequest(), parseRetryAfter() и wait() здесь условные функции вашего приложения. Повторы должны иметь общий предел времени и попыток. Сначала уменьшите параллелизм, иначе несколько процессов могут одновременно повторять один и тот же всплеск.

Для потока автоматический повтор безопаснее разрешать только до получения первого события. После начала потока повтор может создать второй ответ и дополнительный расход. Для операций с внешним эффектом — например, когда результат модели запускает отправку сообщения или изменение записи — сначала введите собственный идентификатор операции и защиту от повторного выполнения в приложении. Это защита бизнес-действия на вашей стороне, а не обещание идемпотентности Responses API.

Что записать и передать поддержке

Для каждой неуспешной попытки записывайте:

  • точное время с часовым поясом;
  • путь, например /v1/responses;
  • значение model, отправленное в запросе;
  • HTTP-статус;
  • фактический Content-Type;
  • доступные code, type и безопасную часть message;
  • номер попытки;
  • был ли уже начат поток;
  • идентификатор запроса, только если он реально пришёл в заголовках или теле.

Никогда не записывайте и не передавайте полный API-ключ, заголовок Authorization, полное чувствительное тело запроса, персональные данные или секреты инструментов. Если текст ошибки может повторять входные данные, очистите его перед сохранением.

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

На этой странице