NormaHub knowledge base

Первый запрос на Python

OpenAI SDK с base_url NormaHub: установка, синхронный и потоковый запросы, обработка ошибок и контроль бюджета.

1. Установка и ключ

Работайте в виртуальном окружении и храните ключ в переменных окружения процесса, а не в коде. Для локальной разработки добавьте файл .env в .gitignore и читайте его через python-dotenv — так ключ не попадёт в репозиторий.

python -m venv .venv
source .venv/bin/activate
python -m pip install openai python-dotenv
export NORMAHUB_API_KEY="ваш_api_ключ"

Создайте API-ключ в личном кабинете NormaHub. Скопируйте значение сразу: повторно оно не показывается. Для скриптов и агентов заводите отдельные ключи с лимитом расходов — тогда утечка одного ключа не опустошит общий баланс.

2. Первый запрос

Клиент OpenAI SDK совместим с NormaHub полностью: меняется только base_url и ключ. Модель указывайте точным ID из актуального каталога, а длину ответа ограничивайте max_tokens, чтобы контролировать стоимость каждого вызова.

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["NORMAHUB_API_KEY"],
    base_url="https://api.normahub.cc/v1",
)

response = client.chat.completions.create(
    model="gpt-5.6-sol",
    messages=[{"role": "user", "content": "Привет"}],
    max_tokens=512,
)
print(response.choices[0].message.content)

Проверьте ответ глазами и зафиксируйте фактическую модель и usage. Если SDK возвращает ошибку, не гадайте по тексту сообщения — смотрите HTTP-статус: разбор всех кодов собран в гайде по ошибкам API.

3. Streaming ответов

Для чатов и агентов показывайте ответ по мере генерации: пользователь видит первые слова через доли секунды, а не ждёт весь ответ. Поток гарантированно работает только через Responses API — для /v1/chat/completions и /v1/messages отправляйте stream: false.

stream = client.responses.stream(
    model="gpt-5.6-sol",
    input="Объясни коротко",
)
for event in stream:
    print(event, flush=True)

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

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

Делите ошибки на постоянные и временные. Постоянные — 400 (неверный запрос), 401 (ключ), 402 (баланс), 403 (модель недоступна ключу): их повтор не лечит, исправляйте причину. Временные — 429 и 5xx: их повторяйте с задержкой и верхним пределом попыток, сохраняя X-Request-Id для поддержки.

from openai import APIError, AuthenticationError, RateLimitError

try:
    response = client.chat.completions.create(
        model="gpt-5.6-sol",
        messages=[{"role": "user", "content": "Привет"}],
        timeout=30,
    )
except AuthenticationError:
    print("401: проверьте ключ NORMAHUB_API_KEY — он неверен или отозван")
except RateLimitError:
    print("429: превышен лимит ключа, подождите и повторите позже")
except APIError as e:
    print(f"HTTP {e.status_code}: смотрите разбор ошибок API")

Задавайте timeout каждому запросу (по умолчанию SDK может ждать долго) и не повторяйте неидемпотентные операции без проверки состояния. Полный разбор кодов, retry-политик и дедлайнов — в гайде по ошибкам.

5. Контроль стоимости

Каждый запрос стоит input + output по тарифу модели. Дороже всего обходятся длинные истории диалога (контекст пересылается целиком) и неограниченный max_tokens. Режьте контекст до необходимого, кэшируйте системные инструкции и считайте стоимость полной операции, а не одного вызова.

Формула и примеры расчёта — в гайде по стоимости токенов, финальная сумма каждого запроса — в истории личного кабинета. При возникновении ошибок проверяйте баланс и доступные модели в личном кабинете.

Частые вопросы

Где взять model ID для Python-запроса?

Точный идентификатор берите из каталога моделей или ответом GET /v1/models вашим ключом. ID из чужих примеров могут быть переименованы или недоступны вашему ключу.

Почему возвращается 401 invalid_api_key?

Ключ отсутствует в окружении, передан с опечаткой или отозван в личном кабинете. Проверьте переменную NORMAHUB_API_KEY и выпустите новый ключ, старый при этом отзовите.

Как получать ответ по частям?

Через Responses API: client.responses.stream с model и input, события читайте в цикле. Для /v1/chat/completions поток выключен — отправляйте stream: false. Детали потоковой выдачи и обработки обрывов — в гайде по streaming.

Нужен ли VPN для запросов из России?

Нет. Запросы идут на https://api.normahub.cc/v1 напрямую, без VPN и зарубежной карты. Оплата — с рублёвого баланса личного кабинета.