Как отлаживать запросы к API нейросети: от curl до кодов ошибок
Чаще всего проблема не в модели, а в запросе: адрес, ключ, лимит, размер тела. Пошаговый порядок отладки и таблица кодов ошибок Zukko с решениями.
5 мин · · разработка · ошибки · API-ключи
Отладка запросов к API нейросети обычно сводится к одному вопросу: что именно ответил сервер. SDK часто прячет это за общим исключением, а логи приложения показывают только «что-то пошло не так». Ниже — порядок действий, который быстро находит причину: воспроизвести запрос в curl, прочитать JSON-ошибку, сверить код с таблицей и правильно настроить повторы и логирование.
Шаг 1. Воспроизведите запрос через curl
curl убирает из уравнения SDK, фреймворк и ваш код. Если в curl ошибка та же — дело в запросе или аккаунте; если в curl всё работает — ищите разницу в коде.
curl -i https://api.zukko.pro/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-5.6-sol","messages":[{"role":"user","content":"привет"}]}'Флаг -i выводит статус и заголовки ответа вместе с телом. Флаг -v показывает ещё и исходящие заголовки и детали соединения — полезно, когда подозреваете прокси, DNS или TLS. Помните, что -v печатает и заголовок Authorization с ключом: не вставляйте такой вывод в чаты и тикеты без маскировки.
На что смотреть:
- Строка статуса:
HTTP/2 200или код ошибки. - Content-Type: для обычного ответа
application/json, для стриминга —text/event-stream. HTML вместо JSON обычно означает, что запрос ушёл не на тот адрес. - Служебные заголовки Zukko в успешных ответах:
X-Zukko-Cost-MicrosиX-Fetch-Balance-Cents— стоимость запроса и остаток баланса. Для учёта расходов надёжнее раздел «Использование» в кабинете.
Проверьте и сам JSON: echo '<тело>' | python3 -m json.tool. Лишняя запятая или неэкранированная кавычка в shell-строке — частая причина ошибки 400.
Шаг 2. Прочитайте JSON-ошибку
Ошибки Zukko приходят в теле в такой форме:
{
"error": {
"message": "Модель 'glm-5.3' временно недоступна. Актуальный список: GET /v1/models",
"type": "service_unavailable",
"code": "model_disabled"
}
}- message — описание для человека. В конец сообщения может добавляться строка со ссылкой на поддержку, поэтому не сравнивайте
messageв коде целиком. - type — категория:
authentication_error,permission_error,rate_limit_error,invalid_request_error,service_unavailable. - code — машинный код. Ветвите логику по нему и по HTTP-статусу. У некоторых ответов (например, 401) поля
codeможет не быть — тогда ориентируйтесь на статус иtype.
Если в ответе ошибка от провайдера модели, а не от шлюза, её форма может отличаться, но статус и текст помогут понять причину. В обращении в поддержку прикладывайте JSON целиком, а не пересказ.
Коды ошибок Zukko и что с ними делать
| HTTP | code | Причина | Решение |
|---|---|---|---|
| 401 | — (type: authentication_error) | Ключ неверный, отозван или не передан | Проверьте заголовок Authorization: Bearer fetch_... и переменные окружения |
| 402 | insufficient_balance | На балансе меньше $0.01 | Пополните баланс в кабинете |
| 403 | email_unverified | Почта аккаунта не подтверждена | Подтвердите email |
| 403 | model_not_allowed_for_key | Модель не входит в список разрешённых для ключа | Добавьте модель в настройках ключа или смените ключ |
| 413 | payload_too_large | Тело запроса больше 32 МБ | Уменьшите тело: чаще всего виноваты картинки в base64 или огромные вложения |
| 429 | key_daily_limit_reached | Исчерпан дневной лимит ключа в долларах | Ждите сброса в 00:00 UTC или поднимите лимит в кабинете |
| 429 | key_monthly_limit_reached | Исчерпан месячный лимит ключа | Поднимите лимит в кабинете |
| 400 | model_retired | Модель снята с обслуживания | В сообщении указана замена; обновите имя модели |
| 503 | model_disabled | Модель временно выключена | Переключитесь на модель из GET /v1/models |
Важно про 429: ограничения частоты запросов на стороне Zukko нет. Собственные 429 шлюза — это только исчерпанные лимиты ключа, и повторять такой запрос через секунду бесполезно. Прочие 5xx, пришедшие от провайдера, обычно временные — их имеет смысл повторить с паузой.
Шаг 3. Настройте повторы в коде
Официальный OpenAI SDK по умолчанию сам повторяет запрос дважды при ошибках соединения, 408, 409, 429 и 5xx. Для 429 от лимита ключа и 503 model_disabled это лишние запросы и задержка. Отключите встроенные повторы и решайте сами:
import os
import time
import openai
from openai import OpenAI
client = OpenAI(
base_url="https://api.zukko.pro/v1",
api_key=os.environ["OPENAI_API_KEY"],
max_retries=0,
)
def error_code(exc: Exception) -> str | None:Функция error_code работает и с исключениями Anthropic SDK: у них тоже есть атрибуты status_code и body. В Anthropic SDK base URL указывается без /v1 — https://api.zukko.pro. Подробнее о клиентах — в руководстве по Python SDK.
Шаг 4. Логируйте безопасно
Правила простые:
- ключ не пишется в лог никогда — ни целиком, ни частично; храните его в переменной окружения;
- тело запроса логируйте выборочно: модель, число сообщений, длину текста, а не содержимое с личными данными;
- заголовки ответа и usage логируйте полностью — в них нет секретов.
Чтобы получить заголовки ответа в OpenAI SDK, используйте with_raw_response:
raw = client.chat.completions.with_raw_response.create(
model="gpt-5.6-sol",
messages=[{"role": "user", "content": "test"}],
)
completion = raw.parse()
print("status:", raw.status_code)
print("cost header:", raw.headers.get("X-Zukko-Cost-Micros"))
print("usage:", completion.usage)Шаг 5. Проверьте base URL и имя модели
404 на /chat/completions почти всегда означает неверный адрес:
- OpenAI SDK и OpenAI-совместимые клиенты:
https://api.zukko.pro/v1; SDK добавит/chat/completionsсам. - Anthropic SDK и Claude Code:
https://api.zukko.proбез/v1, путь/v1/messagesклиент добавляет сам.
Список включённых моделей отдаёт публичный эндпоинт, ключ для него не нужен:
curl https://api.zukko.pro/v1/models{
"object": "list",
"data": [
{"id": "claude-sonnet-5", "object": "model", "created": 1700000000, "owned_by": "zukko"},
{"id": "gpt-5.6-sol", "object": "model", "created": 1700000000, "owned_by": "zukko"}
]
}В списке только модели, которые включены прямо сейчас. Если нужной модели там нет, запрос к ней получит model_disabled или model_retired. Актуальный список также есть на странице «Модели» в кабинете; описание эндпоинта — в справке по моделям, про ключи и авторизацию — в разделе об аутентификации.
Частые вопросы
Как отлаживать стриминг?
Посмотрите сырые события через curl с флагом -N (без буферизации) и "stream": true в теле. Каждое событие — строка data: {...}; в Zukko последний чанк приходит с usage и пустым choices. Поэтому в коде перед chunk.choices[0] нужна проверка:
stream = client.chat.completions.create(
model="gpt-5.6-sol",
messages=[{"role": "user", "content": "test"}],
stream=True,
)
for chunk in stream:
if chunk.choices:
print(chunk.choices[0].delta.content or "", end="", flush=True)Ошибка до первого события придёт обычным JSON с HTTP-статусом; обрыв посреди потока — это сетевая ошибка, её стоит повторить целиком.
Как узнать число токенов до отправки?
Для моделей Claude есть эндпоинт POST https://api.zukko.pro/v1/messages/count_tokens в Anthropic-формате (с заголовком anthropic-version: 2023-06-01). Он возвращает input_tokens — число входных токенов; выходные зависят от ответа и заранее не считаются. Подробнее — в документации count_tokens.
Получаю 429, хотя запросов мало. Почему?
Потому что 429 в Zukko — это не частота, а деньги: у ключа исчерпан дневной (key_daily_limit_reached) или месячный (key_monthly_limit_reached) лимит. Проверьте настройки ключа на странице ключей.
Нужно ли логировать текст сообщений?
Только если без этого не обойтись, и с учётом личных данных. Обычно хватает модели, размера запроса, usage, HTTP-статуса и error.code. Если текст нужен, храните его отдельно с ограниченным доступом и сроком хранения.
zukko
Платите в 25×
меньше
за Claude Code & ChatGPT
Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.
Похожие статьи
- Ключи OpenAI API в открытом доступе: почему ими нельзя пользоватьсяОткуда берутся «бесплатные» ключи на GitHub, почему пользоваться ими опасно и для вас, и для владельца, и как защитить собственный ключ от такой же утечки.
- Ошибки GLM API: почему не работает запрос и как это исправитьНеверный id модели, переполненный контекст 128K, ключ, баланс, лимиты: типичные причины ошибок GLM API и быстрый способ найти свою.
- This organization has been disabled в Claude API: что это и как продолжитьКлюч Anthropic внезапно отвечает «organization has been disabled». Объясняем, что это за ошибка, что проверить и как перенести SDK и Claude Code на другой провайдер.
- Свой прокси к нейросети на Node.js: не показывать API-ключ во фронтендеНебольшой сервер на Express между вашим фронтендом и API нейросети: ключ остаётся на сервере, а модели, длина запроса и частота ограничены.