Doubao API предоставляется через Volcano Ark. По форме интерфейс близок к OpenAI, но семантика ошибок имеет свои особенности. Типичный пример — 404: сервис не упал, проблема обычно в ID эндпоинта инференса, имени модели, регионе или пути. 429 тоже часто понимают неверно: это может быть ограничение скорости, параллелизма, квоты, задолженность или исчерпание пакета ресурсов, и подход к каждому случаю разный.
Порядок диагностики лучше зафиксировать из пяти шагов: посмотреть HTTP-статус, прочитать code и message в теле, взять ID запроса, воспроизвести минимальным запросом и только затем менять параметры или модель. Ниже — 401, 404, 400, 429, тайм-ауты и 5xx, а также код обработки ошибок и чек-лист журналов. Модели и тарификация — на странице цены на модели.
Примечание: Doubao, Volcano Ark и Volcano Engine — товарные знаки ByteDance. Статья носит технический характер; мы не аффилированы с ByteDance, не выступаем её агентом и не состоим в партнёрских отношениях. Коды ошибок, правила лимитов и поведение интерфейсов могут меняться; ориентируйтесь на официальную документацию и фактический ответ.
1. Сначала различите два уровня ошибок
HTTP-статус описывает результат на уровне протокола, а code, type и message в теле — конкретную причину. Один и тот же 401 может означать отсутствующий ключ, опечатку, истечение срока или отсутствие прав у проекта; один и тот же 429 — слишком частые запросы, высокий параллелизм, исчерпанную квоту или задолженность. Если запоминать только статус, диагностика превращается в догадки.
| HTTP | Типичное значение | Сценарий Doubao | Повторять ли |
|---|---|---|---|
| 401 | Сбой аутентификации | Ключ отсутствует, неверный формат, истёк или не соответствует региону | Нет, сначала исправить учётные данные |
| 403 | Нет прав | У ключа нет прав на модель или эндпоинт | Нет, проверить разрешения |
| 404 | Ресурс не найден | Неверный endpoint ID, имя модели, путь или регион | Нет, сначала сверить |
| 400 | Ошибка параметра | Слишком длинный контекст, недопустимый max_tokens, неподдерживаемый формат изображения |
Нет, изменить запрос |
| 429 | Лимит или квота | Превышены RPM, TPM, параллелизм; задолженность или исчерпан пакет | Зависит от причины |
| 500/502/503 | Ошибка сервера | Сбой поставщика, нестабильность шлюза, кратковременная недоступность | Да, с задержкой |
| Тайм-аут | Соединение или чтение | Сеть, очередь, длинный вход, длинный выход | Ограниченное число раз |
Имена полей зависят от ответа: где-то значение лежит в error.code, где-то на верхнем уровне; код не должен предполагать единственную структуру.
2. 401: четыре причины сбоя аутентификации
401 не связан с возможностями модели или балансом; сначала проверьте цепочку учётных данных:
- Заголовок должен быть
Authorization: Bearer <key>, после двоеточия — пробел. - Ключ должен корректно загружаться из переменной окружения, без кавычек, пробелов или перевода строки по краям.
- Ключ не должен быть удалён, ротирован или просрочен.
- Проект, регион и Base URL, к которым относится ключ, должны совпадать.
Ключ, скопированный из окна чата, легко приносит невидимые символы. Сначала отправьте минимальный запрос с ответом в одно слово — это исключает большинство простых ошибок. Если в консоли тот же ключ работает, а код возвращает 401, проверьте переменные окружения и не отбрасывает ли обратный прокси заголовок аутентификации.
3. 404: endpoint ID и имя модели проще всего перепутать
В Volcano Ark распространены два способа указать модель: эндпоинт инференса, созданный в консоли (обычно начинается с ep-), и прямой вызов по ID модели, поддерживаемый частью моделей. Оба передаются в поле model, но права, лимиты и область применения могут различаться. Смешивание endpoint ID и имени модели, копирование эндпоинта из другого проекта дают 404 или похожее «ресурс не найден».
Порядок проверки:
- Убедитесь, что Base URL — региональный адрес вроде
https://ark.cn-beijing.volces.com/api/v3, без лишнего или пропущенного/api/v3. - В консоли проверьте, существует ли эндпоинт, относится ли он к текущему проекту и не отключён ли.
- Уточните, требует ли текущий способ вызова endpoint ID или ID модели; не заполняйте по памяти.
- Отправьте минимальный запрос через curl, чтобы исключить автодополнение пути SDK и перезапись прокси.
- Посмотрите тип содержимого ответа: если вернулась HTML-страница ошибки, запрос мог не дойти до Ark и быть перехвачен шлюзом или обратным прокси.
404 с HTML обычно означает проблему пути или прокси; 404 с JSON-телом ошибки больше похож на проблему модели или эндпоинта.
4. 400: длинный контекст и ошибки параметров
Диапазон 400 широк. Чаще всего это превышение контекста. Окно контекста обычно считается как входные токены плюс выходные; слишком большой max_tokens выводит за границу запрос, который иначе прошёл бы. Изображения, определения инструментов и история сообщений тоже занимают токены.
Решение — не увеличивать лимит, а оставить запас на входе:
- Сжать или разбить системный промпт, убрать повторяющиеся правила.
- Суммировать историю диалога, оставив последние несколько раундов и ключевые факты.
- Для длинных документов сначала выполнять поиск, а не вставлять текст целиком.
- Сжимать изображения и проверять, что формат и размер поддерживаются.
- Проверять, не выходят ли
temperatureиtop_pза диапазон, корректны ли роли сообщений.
Подсчёт токенов приблизительный; при приближении к пределу безопаснее оставлять запас 10–20%.
5. 429: лимиты, параллелизм и квоты нужно разбирать отдельно
У 429 четыре группы причин:
- Ограничение скорости: превышено число запросов или токенов в минуту относительно тарифа; после задержки обычно восстанавливается.
- Ограничение параллелизма: слишком много одновременных запросов; нужно снизить параллелизм или поставить в очередь, простой повтор лишь усиливает затор.
- Исчерпание квоты или пакета ресурсов: повторять бессмысленно, нужно пополнение или смена тарифа.
- Ненормальный статус аккаунта: задолженность, отсутствие верификации или изменение прав; действуйте по подсказке консоли.
Если в ответе есть Retry-After, ждите по нему; если нет — используйте экспоненциальную задержку со случайным разбросом. Для 429 из-за квоты или задолженности повторы не делайте: они только удлиняют простой.
Потоковый 429 может возникнуть при установке соединения или как событие ошибки внутри потока. Клиент должен обрабатывать и статус, и ошибку внутри потока, а не смотреть только на первый фрагмент.
6. Тайм-ауты и обрывы потока: три точки диагностики
Тайм-аут нужно разделять на три части:
- Тайм-аут соединения: DNS, TLS, выходной прокси или сеть недоступны; обычно сбой за несколько секунд.
- Тайм-аут первого токена: запрос дошёл до поставщика, но стоит в очереди или обрабатывает длинный вход; проявляется долгим отсутствием первого фрагмента.
- Тайм-аут чтения: слишком большой интервал между фрагментами — длинный выход, долгий вывод или разрыв соединения промежуточным устройством.
Для трёх частей нужны разные настройки. Слишком большой общий тайм-аут надолго занимает пул соединений сбойными запросами; слишком маленький убивает нормальный длинный вывод. Рекомендуется тайм-аут соединения около 5 секунд, тайм-аут чтения — по P95 бизнеса, а на уровне приложения — общий бюджет.
В потоковом режиме проверьте буферизацию обратного прокси. Из-за буфера фрагменты приходят с задержкой и выглядят как «зависание». После обрыва не сохраняйте половину ответа как полный результат.
7. ID запроса и журналы: доказательства для диагностики
Ответ Volcano Ark обычно содержит идентификатор запроса; распространённые поля — X-Request-Id, а часть интерфейсов возвращает журнальный ID вроде X-Tt-Logid. Имена полей зависят от фактического ответа; сохраняйте заголовки целиком, а не выбирайте одно поле.
Клиент также должен генерировать собственный trace_id, неизменный для всех повторов одного бизнес-запроса. Журнал должен содержать как минимум время, trace_id, Base URL, модель или эндпоинт, статус, code и message ошибки, длительность, число повторов, признак потока и расход токенов.
Ключ записывайте частично или в виде хеша; исходный текст пользователя и полный ответ не сохраняйте целиком. Тело ошибки достаточно сохранить в первых 500 символах.
8. Повторы и задержка: рабочий пример кода
Код ниже отключает автоматические повторы SDK, определяет необходимость повтора по статусу и содержимому ошибки, соблюдает Retry-After и генерирует trace_id для каждого логического запроса:
import os
import random
import time
import uuid
import httpx
from openai import OpenAI, APIConnectionError, APIStatusError, APITimeoutError
client = OpenAI(
api_key=os.environ["ARK_API_KEY"],
base_url=os.environ.get(
"ARK_BASE_URL", "https://ark.cn-beijing.volces.com/api/v3"
),
timeout=httpx.Timeout(connect=5.0, read=180.0, write=30.0, pool=10.0),
max_retries=0, # отключаем автоповторы SDK — управляем ими ниже
)
def parse_error(exc: APIStatusError) -> tuple[str, str]:
try:
body = exc.response.json()
except Exception:
return "", exc.response.text[:200]
err = body.get("error", body)
return str(err.get("code") or err.get("type") or ""), str(err.get("message") or "")
def is_retryable(exc: Exception) -> bool:
if isinstance(exc, (APITimeoutError, APIConnectionError)):
return True
if not isinstance(exc, APIStatusError):
return False
if exc.status_code >= 500:
return True
if exc.status_code != 429:
return False
code, message = parse_error(exc)
text = f"{code} {message}".lower()
# 429 из-за квоты, задолженности и прав повторять бессмысленно
return not any(k in text for k in ("quota", "arrears", "balance", "permission"))
def ask(prompt: str, max_attempts: int = 4) -> str:
trace_id = uuid.uuid4().hex[:12]
for attempt in range(1, max_attempts + 1):
try:
resp = client.chat.completions.create(
model=os.environ["ARK_MODEL"], # endpoint ID или ID модели
messages=[{"role": "user", "content": prompt}],
max_tokens=1024,
)
return resp.choices[0].message.content
except Exception as exc:
status = getattr(exc, "status_code", "")
code, message = parse_error(exc) if isinstance(exc, APIStatusError) else ("", "")
print(
f"trace={trace_id} attempt={attempt} status={status} "
f"code={code} message={message[:200]}"
)
if attempt == max_attempts or not is_retryable(exc):
raise
retry_after = getattr(
getattr(exc, "response", None), "headers", {}
).get("retry-after")
try:
wait = float(retry_after) if retry_after else min(2 ** (attempt - 1), 20)
except ValueError:
wait = min(2 ** (attempt - 1), 20)
time.sleep(wait + random.uniform(0, 1))
raise RuntimeError("Повторы исчерпаны")
Дополнительные правила: для запросов с побочными эффектами сначала проверьте состояние по ключу идемпотентности; бюджет повторов контролируйте глобально; следите за долей 429 и P95 задержки — при резком росте сначала снижайте параллелизм.
9. Чек-лист перед обращением в поддержку
- Время сбоя и часовой пояс, постоянный он или эпизодический.
- Base URL, полный путь, имя модели или endpoint ID.
- HTTP-статус, код ошибки, message и ID запроса.
- Минимальный воспроизводимый curl-запрос с обезличенным ключом.
- Потоковый ли запрос, длинный ли контекст, есть ли изображения или вызовы инструментов.
- Менялись ли недавно ключ, эндпоинт, квота или прокси.
- Масштаб: один ключ, один проект, один регион или все сервисы.
С этими данными поддержка сможет сразу сопоставить запрос с журналами поставщика. После каждого сбоя добавляйте мониторинг или оповещение.
10. Частые вопросы (FAQ)
1. 404 всегда означает, что модель снята?
Нет. Чаще неверен endpoint ID или имя модели, эндпоинт удалён, регион не совпадает или в пути пропущен /api/v3. Сначала посмотрите, JSON или HTML в ответе, затем проверяйте по пунктам.
2. Сколько раз повторять при 429?
Для ограничения скорости и кратковременного затора — 2–3 раза с экспоненциальной задержкой. Для 429 из-за исчерпания квоты, задолженности или нехватки прав повторы не делайте: сначала разберитесь с аккаунтом или тарифом. Соблюдайте Retry-After.
3. Как именно считается длина контекста?
Обычно как входные токены плюс выходные; max_tokens также входит в общий лимит. Изображения, определения инструментов и история сообщений учитываются во входе; при приближении к пределу оставляйте запас.
4. Как задавать тайм-аут потокового запроса?
Тайм-аут чтения обычно ограничивает интервал между двумя фрагментами, а не общую длительность. Тайм-аут соединения задаётся отдельно; на уровне приложения добавляются общий бюджет и тайм-аут простоя. Буферизация прокси задерживает отправку фрагментов.
5. После подключения шлюза ошибок стало больше — что делать?
Сначала определите, кто вернул ошибку: шлюз или поставщик. Смотрите формат тела, статус и ID запроса. Сохраните trace ID и сравните минимальные запросы напрямую и через шлюз. Чаще всего проблема в склейке пути, передаче заголовка аутентификации или тайм-ауте.
Что дальше
Создайте тестовый ключ в ZSQH AI Gateway, отработайте по одному разу 401, 404, 429 и тайм-аут, затем подключите производственный мониторинг. Доступные модели и тарификация — на странице цены на модели.
