Выбор модели программно
Как фильтровать каталог через 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 и модель уехала из каталога:
- Поймайте
404сerror.code: "model_not_found". - Либо используйте model fallbacks: передайте
models: ["primary-id", "backup-id"]— Hubris сам переключится. - Либо подберите замену через
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— это бесплатные модели. У них свои лимиты на стороне провайдера, не публикуемые.
Что дальше
- GET /v1/models — полная схема ответа.
- Model fallbacks —
models: [...]для авто-замены. - Каталог моделей — то же самое в UI.
- Ошибки — обработка
404 model_not_found.
Обновлено: