У Qwen API есть два распространённых способа вызова: нативный интерфейс DashScope в Alibaba Cloud Model Studio и интерфейс, совместимый с OpenAI. Структуры ошибок у них различаются, но порядок диагностики один: сначала HTTP-статус, затем поля code и message в теле ответа, затем request_id, воспроизведение минимальным запросом и только после этого изменение параметров или смена модели.
Ниже разобраны 401, 404, 429, 400, 5xx и тайм-ауты: таблица кодов, поля журналов, код повторов и чек-лист перед обращением в поддержку. Модели, квоты и тарификация — по официальной документации и странице цены на модели.
Примечание: Qwen, Tongyi Qianwen, Alibaba Cloud, Bailian и DashScope — товарные знаки Alibaba Group и соответствующих правообладателей. Статья носит технический характер; мы не аффилированы с указанными компаниями, не выступаем их агентом и не состоим в партнёрских отношениях. Коды ошибок, правила лимитов и поведение интерфейсов могут меняться; ориентируйтесь на официальную документацию и фактический ответ.
1. Сначала различите режим интерфейса и структуру ошибки
Нативный интерфейс DashScope обычно возвращает code, message и request_id на верхнем уровне ответа. Совместимый с OpenAI интерфейс следует стилю OpenAI: тело ошибки выглядит как {"error": {"message": "...", "type": "...", "code": "..."}}. В режиме совместимости request_id может находиться в заголовках или в теле ответа; имя поля зависит от фактического ответа.
В коде не стоит разбирать только одну структуру. Сначала сохраните полное тело ответа в журнал как есть, затем извлекайте значение сначала из error.code, потом из code верхнего уровня. Тогда при смене режима интерфейса обработчик ошибок не придётся переписывать.
2. 401: сбой аутентификации, сначала проверьте регион
401 означает, что идентификация не прошла, и обычно не связан с возможностями модели или балансом. В Bailian чаще встречаются три ошибки:
InvalidApiKeyилиinvalid_api_key: неверный ключ, неполное копирование или несовпадение Base URL и региона, к которому относится ключ.invalid access token or token expired: токен истёк или используется специальный адрес тарифного плана с обычным ключом.- Сообщение об отказе в доступе: неверный WorkspaceId или аккаунт не входит в это рабочее пространство.
Ключ Qwen привязан к региону: ключи Пекина и Сингапура нельзя смешивать. Это самый частый пропуск: код не менялся, но после замены Base URL стабильно воспроизводится 401.
Проверяйте по порядку:
- Убедитесь, что заголовок —
Authorization: Bearer <key>и после двоеточия есть пробел. - Выведите префикс переменной окружения и проверьте, что там не пустое значение, не старое и нет перевода строки.
- Сверьте Base URL и регион, к которому относится ключ.
- Проверьте соответствие типа ключа интерфейсу: адреса для оплаты по факту, пакета Coding и пакета Token различаются.
- Возьмите новый ключ и выполните минимальный запрос, чтобы отделить проблему ключа от проблемы прокси или шлюза.
3. 404 и 400: имя модели, активация и контекст
404 чаще означает не сбой сервиса, а проблему с именем модели или её доступностью. При ModelNotFound или model_not_found проверьте три вещи: нет ли опечатки в имени, активирована ли модель и доступна ли она в текущем регионе. model_not_supported означает, что модель не поддерживает режим совместимости с OpenAI; нужно сменить интерфейс или модель.
Причины 400 разнообразнее. InvalidParameter — выход параметра за границы, например temperature или top_p вне диапазона; InvalidParameter.NotSupportEnableThinking — модель не поддерживает параметр режима рассуждений. Превышение контекста обычно возвращает Range of input length should be [1, xxx] с внутренним кодом InternalError.Algo.InvalidParameter; возможен и вариант, когда суммарная длина сообщений превышает предел модели. Решение — сократить историю, суммировать по частям или перейти на модель с длинным контекстом, а не повторять запрос.
4. 429: различите четыре вида лимитов и две квоты
429 — ошибка, которую чаще всего обрабатывают неправильно. В Bailian 429 включает как минимум несколько категорий; в таблице также приведены ошибки задолженности и неактивированного сервиса, которые легко спутать с лимитом:
| HTTP | Код ошибки | Значение | Стоит ли повторять |
|---|---|---|---|
| 429 | Throttling.RateQuota, LimitRequests |
Превышено число запросов в минуту (RPM) | Да, с задержкой |
| 429 | Throttling.AllocationQuota, insufficient_quota |
Превышено число токенов в минуту (TPM) | Да, с задержкой и сокращением входа |
| 429 | Throttling.BurstRate |
Кратковременный всплеск трафика вызвал защиту | Да, сгладить темп |
| 429 | Throttling.Concurrency |
Слишком много параллельных запросов | Да, снизить параллелизм |
| 429 | AllocationQuota.FreeTierOnly |
Бесплатная квота исчерпана, включён режим «только бесплатно» | Нет, пополнить или отключить режим |
| 429 | BudgetLimitExceeded |
Бюджет аккаунта исчерпан | Нет, скорректировать бюджет |
| 400 | Arrearage |
Задолженность или ненормальный статус аккаунта | Нет, сначала восстановить аккаунт |
| 403 | AccessDenied.Unpurchased |
Сервис не активирован | Нет, сначала активировать |
Лимиты считаются по основному аккаунту Alibaba Cloud: вызовы RAM-субаккаунтов, рабочих пространств и нескольких ключей суммируются. Поэтому «свой ключ на каждый сервис» не обходит общую квоту, а лишь избегает взаимного вытеснения. Лимит обычно восстанавливается в течение минуты; не повторяйте запросы с высокой частотой в период ожидания.
5. Тайм-ауты и 5xx: три точки диагностики
Тайм-аут нужно разделять на три части: тайм-аут соединения обычно означает недоступность DNS, выхода или прокси; медленный первый токен — очередь у поставщика или слишком длинный вход; тайм-аут чтения — слишком длинный выход или долгий вывод. Обработка у всех разная, поэтому простое увеличение общего тайм-аута не помогает.
RequestTimeOut в Bailian означает тайм-аут запроса; официально указанный предел — 300 секунд. GatewayTimeout.InputDownload связан со скачиванием входного файла. Совместимый с OpenAI интерфейс может вернуть 503 при перегрузке движка. Если потоковый запрос прерывается без кода ошибки, сначала запишите уже полученное содержимое, последний фрагмент и причину завершения, а затем решайте, это сетевая нестабильность, разрыв прокси или тайм-аут поставщика.
6. request_id и журналы: доказательства для диагностики
Официальная документация указывает, что request_id возвращается с ответом — в заголовках или в теле. Рекомендуется вести двойную запись: клиент генерирует trace_id, который сохраняется для всех повторов, а идентификатор запроса из заголовков и request_id из тела сохраняются как есть. Если записи нет, можно найти её в журнале мониторинга моделей в консоли — при условии, что журнал вывода включён.
Журнал должен содержать как минимум: время, trace_id, Base URL, регион, имя модели, HTTP-статус, код ошибки, сообщение, request_id, длительность, число повторов и признак потокового запроса. Ключ записывайте только частично или в виде хеша; исходный текст пользователя и полный ответ не сохраняйте целиком. При обращении в поддержку одна запись с этими полями полезнее, чем «иногда возникают ошибки».
7. Повторы и задержка: пример кода
Код ниже отключает автоматические повторы SDK, повторяет только восстановимые 429 и 5xx и печатает статус, код ошибки и request_id. Задолженность, исчерпание бесплатной квоты и превышение бюджета в повторы не входят.
import os
import random
import time
import uuid
import httpx
from openai import OpenAI, APIConnectionError, APIStatusError, APITimeoutError
client = OpenAI(
api_key=os.environ["DASHSCOPE_API_KEY"],
base_url=os.environ.get(
"DASHSCOPE_BASE_URL",
"https://dashscope.aliyuncs.com/compatible-mode/v1",
),
timeout=httpx.Timeout(connect=5.0, read=180.0, write=30.0, pool=10.0),
max_retries=0, # отключаем автоповторы SDK — управляем ими ниже
)
RETRYABLE_429 = {
"Throttling",
"Throttling.RateQuota",
"Throttling.AllocationQuota",
"Throttling.BurstRate",
"Throttling.Concurrency",
"LimitRequests",
"limit_requests",
"ResourceExhausted",
}
def unpack_error(exc: APIStatusError):
body = {}
try:
body = exc.response.json()
except Exception:
pass
err = body.get("error", body) if isinstance(body, dict) else {}
code = err.get("code") if isinstance(err, dict) else None
request_id = None
if isinstance(body, dict):
request_id = body.get("request_id")
request_id = (
request_id
or exc.response.headers.get("x-request-id")
or exc.response.headers.get("x-dashscope-request-id")
)
return code, request_id, exc.response.text[:500]
def ask(prompt: str, model: 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=model,
messages=[{"role": "user", "content": prompt}],
)
return resp.choices[0].message.content
except APIStatusError as exc:
code, request_id, body = unpack_error(exc)
print(
f"trace={trace_id} attempt={attempt} "
f"http={exc.status_code} code={code} "
f"request_id={request_id} body={body}"
)
retryable = exc.status_code >= 500 or (
exc.status_code == 429 and code in RETRYABLE_429
)
if not retryable or attempt == max_attempts:
raise
except (APITimeoutError, APIConnectionError) as exc:
print(f"trace={trace_id} attempt={attempt} err={type(exc).__name__}")
if attempt == max_attempts:
raise
wait = min(2 ** (attempt - 1), 30) + random.uniform(0, 1)
time.sleep(wait)
raise RuntimeError("Повторы исчерпаны")
Дополнительные правила: если сервер вернул Retry-After, соблюдайте его в первую очередь; бюджет повторов должен контролироваться глобально, чтобы несколько сервисов не усиливали трафик одновременно; для запросов с побочными эффектами сначала выясните, был ли он уже выполнен, и только потом решайте, отправлять ли снова.
8. Управление параллелизмом эффективнее увеличения числа повторов
Проблему лимитов обычно решают не повторами, а управлением на входе:
- Разделите ключи по бизнесу и задайте отдельные пределы параллелизма, чтобы одна пакетная задача не роняла онлайн-сервис.
- Дробите пакетные задачи и разносите их по времени, избегая импульса трафика в начале часа.
- Используйте очередь для сглаживания пиков, а неудачные задачи отправляйте в отложенную очередь, а не крутите на месте.
- Следите за долей 429 и p95 задержки; при резком росте сначала снижайте параллелизм.
- Для офлайн-задач по возможности используйте Batch, чтобы обойти лимиты реального времени.
- Подготовьте резервную модель или резервный вход и до переключения проверьте совместимость параметров.
Пороги лимитов настраиваются по модели и аккаунту; пополнение не повышает RPM или TPM автоматически. Если нужен более высокий лимит, подавайте коммерческую заявку, а не копируйте чужие цифры.
9. Чек-лист перед обращением в поддержку
- Время и часовой пояс, а также характер сбоя: постоянный или эпизодический.
- Base URL, регион, путь интерфейса, имя модели и способ запроса.
- HTTP-статус, код ошибки и полное сообщение.
request_id; если его нет — собственныйtrace_id.- Минимальный воспроизводимый curl-запрос с обезличенным ключом.
- Потоковый ли запрос, длинный ли контекст, не менялась ли недавно конфигурация.
- Масштаб: один ключ, одно рабочее пространство или все сервисы.
10. Частые вопросы (FAQ)
1. 429 всегда означает лимит запросов?
Нет. 429 также может означать исчерпание бесплатной квоты или бюджета; задолженность может вернуть 400 Arrearage, а неактивированный сервис — 403. Сначала прочитайте код ошибки, затем решайте, ждать, пополнять или менять конфигурацию.
2. 401 сохраняется после смены ключа — что делать?
Проверяйте регион и тип ключа. Ключ Qwen привязан к региону: ключ Пекина с адресом Сингапура вернёт 401; специальный адрес тарифа с обычным ключом тоже не сработает. Затем проверьте заголовок, переменные окружения и не отбрасывает ли обратный прокси данные аутентификации.
3. Как обрабатывать превышение контекста?
Сначала сократите историю, уберите нерелевантные вложения и повторяющиеся фрагменты; затем суммируйте длинный документ по частям или используйте поиск; если этого мало — перейдите на модель с длинным контекстом. Не пытайтесь решить переполнение входа увеличением max_tokens.
4. Стоит ли повторять запрос при тайм-ауте?
Только для сбоя соединения и тайм-аута чтения, с ограниченным числом попыток, экспоненциальной задержкой и верхним пределом. Для операций с побочными эффектами сначала проверьте, не выполнена ли операция, чтобы не создать повторный заказ или повторную запись.
5. Где искать request_id?
Сначала в заголовках и теле ответа; имя поля зависит от интерфейса. Если нигде не записано, ищите в журнале мониторинга моделей в консоли при включённом журнале вывода. В поддержку передавайте одновременно trace_id и минимальный запрос для воспроизведения.
Что дальше
Создайте тестовый ключ в ZSQH AI Gateway, отработайте по одному разу 401, 404, 429, превышение контекста и тайм-аут, затем подключите производственный мониторинг. Доступные модели и тарификация — на странице цены на модели.
