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

Выбор модели программно

Как фильтровать каталог через GET /v1/models, подбирать модель под задачу и обрабатывать переименования.

В Hubris доступны десятки моделей с разными возможностями и ценами. Чтобы не хардкодить ID, а подбирать модель программно — есть GET /v1/models. Этот гайд про то, как фильтровать каталог под конкретные задачи и обрабатывать случаи, когда «нужной» модели не оказалось.

Что возвращает /v1/models

curl -s https://api.hubris.pw/v1/models \
  -H "Authorization: Bearer sk-gw-..."

Ответ — OpenAI-совместимый список:

{
  "object": "list",
  "data": [
    {
      "id": "anthropic/claude-haiku-4.5",
      "object": "model",
      "created": 1714000000,
      "owned_by": "anthropic",
      "display_name": "Claude Haiku 4.5",
      "description": "Быстрая и недорогая модель Anthropic...",
      "context_window": 200000,
      "modalities": ["text"],
      "input_modalities": ["text", "image"],
      "output_modalities": ["text"],
      "pricing": {
        "input_rub_per_million": 88,
        "output_rub_per_million": 440,
        "currency": "RUB"
      }
    }
    // ...
  ]
}

Поля каждой модели:

ПолеЧто
idидентификатор для использования в model запроса
owned_byпровайдер модели — anthropic, openai, google, deepseek, и т.д.
display_nameчеловекочитаемое имя (для UI каталога)
descriptionкороткое описание возможностей
context_windowразмер контекста в токенах
input_modalitiesчто принимает на вход: text, image
output_modalitiesчто выдаёт: text, image
pricing.input_rub_per_millionцена в рублях за 1М prompt-токенов
pricing.output_rub_per_millionцена в рублях за 1М completion-токенов

В ответ попадают только активные модели — снятые с публикации не приходят.

Сценарии фильтрации

«Хочу самую дешёвую модель с поддержкой изображений на вход»

import httpx

resp = httpx.get(
    "https://api.hubris.pw/v1/models",
    headers={"Authorization": "Bearer sk-gw-..."},
).json()

vision_models = [
    m for m in resp["data"]
    if "image" in m["input_modalities"]
]

cheapest = min(
    vision_models,
    key=lambda m: m["pricing"]["input_rub_per_million"],
)
print(cheapest["id"], cheapest["pricing"])

«Нужен большой контекст — от 500k токенов»

big_context = [m for m in resp["data"] if m["context_window"] >= 500_000]

«Только модели определённого провайдера»

anthropic_only = [m for m in resp["data"] if m["owned_by"] == "anthropic"]

«Сортирую по цене prompt-токенов»

by_input_price = sorted(
    resp["data"],
    key=lambda m: m["pricing"]["input_rub_per_million"],
)

TypeScript

type Model = {
  id: string;
  owned_by: string;
  context_window: number;
  input_modalities: string[];
  output_modalities: string[];
  pricing: {
    input_rub_per_million: number;
    output_rub_per_million: number;
    currency: 'RUB';
  };
};

const resp = await fetch('https://api.hubris.pw/v1/models', {
  headers: { Authorization: 'Bearer sk-gw-...' },
}).then((r) => r.json() as Promise<{ data: Model[] }>);

const visionModels = resp.data.filter((m) =>
  m.input_modalities.includes('image'),
);

Стабильность ID

ID модели — стабильный идентификатор. Мы не меняем его молча. При больших изменениях:

  • Новая мажорная версия — публикуется как новый ID. Например, anthropic/claude-haiku-4.5 отдельная сущность от anthropic/claude-haiku-5.0. Старая модель может ещё работать или быть архивирована (см. ниже).
  • Архивация — модель снимается с активного каталога. Запросы с её ID возвращают 404 model_not_found. Архивированные модели не возвращаются в GET /v1/models.
  • Мелкие обновления провайдера (контекст ↑, скорость ↑, цена ↓) — id остаётся прежним, поля карточки обновляются.

Что делать с 404 model_not_found

Если в коде захардкожен ID и модель уехала из каталога:

  1. Поймайте 404 с error.code: "model_not_found".
  2. Либо используйте model fallbacks: передайте models: ["primary-id", "backup-id"] — Hubris сам переключится.
  3. Либо подберите замену через GET /v1/models и обновите ID у себя.
configured_model_id = "anthropic/claude-haiku-4.5"  # ID, который вы используете

try:
    resp = client.chat.completions.create(model=configured_model_id, messages=[...])
except openai.NotFoundError:
    # модель архивирована — fallback на актуальный каталог
    models = httpx.get("https://api.hubris.pw/v1/models", headers={...}).json()
    new_model = pick_similar(models["data"], owned_by="anthropic")
    resp = client.chat.completions.create(model=new_model["id"], messages=[...])

Самое надёжное решение в продакшене — models: [...] параметр запроса. Тогда выбор fallback'а делается атомарно внутри запроса, без отдельного round-trip к каталогу.

Версионированные slug'и

Некоторые провайдеры в ответе возвращают модель с дат-версионированным slug'ом — например, запрос ушёл на anthropic/claude-haiku-4.5, а в response.model приходит anthropic/claude-haiku-4.5-20251101. Это нормально: мы биллим по канонической модели (anthropic/claude-haiku-4.5), а слаг просто говорит, какая именно дата-версия ответила.

В Hubris ответ на запрос всегда содержит реально использованный ID в поле model — удобно для логов и аналитики, чтобы видеть, какая именно версия модели работала на ваших запросах.

Что важно знать

  • Не кешируйте каталог дольше нескольких часов. Цены пересчитываются при обновлении курса ЦБ. Раз в час — нормальная частота обновления.
  • Caps по провайдеру меняются. Иногда у Anthropic / OpenAI заканчиваются мощности — модель временно отвечает 502/503. На уровне каталога модель остаётся, но провайдер недоступен. Model fallbacks спасают.
  • Цены 0 — это бесплатные модели. У них свои лимиты на стороне провайдера, не публикуемые.

Что дальше

Обновлено:

Выбор модели программно · Hubris