hubris
Возможности
ВОЗМОЖНОСТИ

Model Fallbacks

Запасные модели на случай 429/5xx/таймаута. Передайте массив `models` — Hubris сам переключится при сбое, а шаги, не принимающие картинки или файлы, пропустит.

Если основная модель временно недоступна — упёрлась в rate limit провайдера, упала с 5xx, не начала отвечать вовремя или ответ зарезали модерацией — Hubris автоматически попробует следующие модели из массива models. Переключение происходит внутри одного HTTP-запроса: ретраи, паузы и вторая нода на вашей стороне не нужны. Биллинг по фактически ответившей модели (она возвращается в поле model ответа).

Поддерживается в POST /v1/chat/completions и POST /v1/messages (расширение Hubris: в Anthropic API поля models нет). На /v1/responses пока нет.

Как работает

Передайте массив models рядом с обычным model. model — основная, элементы models пробуются по порядку при сбое:

curl -s https://api.hubris.pw/v1/chat/completions \
  -H "Authorization: Bearer sk-gw-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-opus-4.7",
    "models": [
      "anthropic/claude-sonnet-4.6",
      "openai/gpt-4o-mini"
    ],
    "messages": [{"role": "user", "content": "Привет"}]
  }'

Если Opus 4.7 вернёт 429 от провайдера — сразу пойдёт Sonnet 4.6; если и тот недоступен — GPT-4o mini. Клиент получит обычный успешный ответ, как если бы fallback не было. Все модели из массива проверяются заранее: опечатка в любом имени — 404 model_not_found до вызова, а не «резерв молча не сработал» в момент аварии.

Когда срабатывает fallback

  • 429 — rate limit провайдера. Пока в цепочке есть резерв, Hubris не ждёт Retry-After и не повторяет запрос к той же модели — переключается сразу.
  • 5xx — апстрим упал (включая 529 «overloaded»).
  • Таймаут первого байта — модель приняла запрос, но не начала отвечать в отведённое время (для потока — не прислала первый чанк).
  • Модерация провайдера (403) — ответ заблокирован контент-фильтром; резерв другого вендора часто отвечает.
  • Сетевой сбой между Hubris и провайдером.

Не срабатывает на ошибках самого запроса: 400 invalid_request, 402 (баланс), 401/403 ключа Hubris. Это про ваш запрос или аккаунт, и другая модель тут не поможет.

Картинки и файлы

Модели различаются по тому, что принимают на вход. Если в запросе есть картинка (image_url / блок image) или документ (file / блок document), шаги цепочки, которые такой контент не принимают, пропускаются — запрос уходит в первый совместимый. Это касается и основной модели: цепочка "model": "текстовая", "models": ["vision-модель"] отправит запрос с картинкой сразу во вторую.

Контент никогда не урезается ради несовместимого шага — модель либо видит запрос целиком, либо не участвует. Если ни одна модель цепочки контент не принимает — 400 modality_not_supported без вызова апстрима. Возможности моделей берутся из каталога (фильтры «принимает картинки», «принимает файлы»).

Биллинг

Списывается стоимость только той модели, которая реально ответила, по её обычной цене — цепочка ничего не добавляет. Упавшие и пропущенные шаги не биллятся: 429 и 5xx от провайдера бесплатны, а таймаут первого байта по определению наступает до появления токенов. Поле model в JSON-ответе — это победитель (не первый из массива).

В /logs запрос залогирован под ответившей моделью. Запрошенная модель и причина переключения тоже сохраняются в учёте запроса.

Если в models модели разной цены и срабатывает fallback на самую дорогую — да, спишется по её тарифу. Поэтому имеет смысл располагать модели по возрастанию цены или ставить в конец «дешёвый, но всегда живой» вариант:

{
  "model": "anthropic/claude-opus-4.7",
  "models": [
    "anthropic/claude-sonnet-4.6",
    "anthropic/claude-haiku-4.5"
  ],
  "messages": [{"role": "user", "content": "..."}]
}

Стриминг

stream: true работает с fallback так же. Если основная модель отказала ДО первого SSE-чанка, Hubris молча переключится на следующую, и клиент получит чанки уже от неё. Поле model в каждом чанке — это уже итоговая модель. После первого чанка fallback больше не сработает: байты пошли клиенту, а начатый ответ не переигрывается — это относится и к обрыву генерации на середине.

/v1/messages

В Anthropic-формате массив models — расширение Hubris. Имена резолвятся так же, как model: принимаются и Anthropic-имена (claude-opus-4-1), и каноничные (anthropic/claude-sonnet-4.6). Поле model в ответе и в message_start — ответившая модель.

{
  "model": "claude-sonnet-4-5",
  "models": ["claude-opus-4-1"],
  "max_tokens": 1024,
  "messages": [{"role": "user", "content": "Привет"}]
}

Хранимые цепочки: route/…

Массив models удобен для разового вызова, но в проде цепочку хочется настроить один раз и не таскать по всем клиентам. Для этого в кабинете есть раздел Роутинг (пошагово — в документации кабинета): вы собираете цепочку (основная модель и до четырёх резервов), задаёте условия переключения и получаете виртуальную модель с именем route/<идентификатор>.

{
  "model": "route/prod-agent",
  "messages": [{"role": "user", "content": "Привет"}]
}
  • Имя работает везде, где принимается model: /v1/chat/completions, /v1/messages, SDK OpenAI и Anthropic, LangChain, n8n, cURL. При указанном route/… массив models из запроса игнорируется — цепочку определяет пресет.
  • Цепочка видна только в вашем аккаунте: в общий каталог она не попадает, а в ответе GET /v1/models по вашему ключу приходит вместе с обычными моделями (owned_by: "hubris") — так её видят выпадающие списки моделей в n8n и IDE. Чужой или выключенный идентификатор отвечает обычным 404 model_not_found.
  • Условия переключения настраиваются на странице цепочки: 429, 5xx (включая модерацию провайдера) и таймаут первого байта в секундах. Выключенное условие не переключает.
  • В /logs запрос через цепочку помечен значком: в подробностях видно, какая цепочка запрошена и почему пропущен шаг. На странице цепочки — запросы, переключения и расход за 30 дней.

Ограничения

  • Максимум 10 моделей в models (плюс основная).
  • /v1/responses — не поддерживается (используйте /v1/chat/completions).
  • /v1/embeddings — не поддерживается (embedding-модели обычно стабильны и не требуют fallback).
  • Структурные ошибки запроса (400 invalid_request) не триггерят fallback — это значит ваш запрос неверен, и пробовать другую модель бессмысленно.
  • В цепочку входят только текстовые chat-модели; генерация картинок, видео и аудио через models не каскадируется.

Что дальше

Обновлено: