Qwen API tiene dos formas habituales de llamada: la interfaz nativa DashScope de Alibaba Cloud Bailian y la interfaz compatible con OpenAI. Las estructuras de error no son idénticas, pero el orden de diagnóstico es el mismo: primero mira el código de estado HTTP, luego lee code y message en el cuerpo de la respuesta, después busca request_id, reproduce con una solicitud mínima y solo al final cambia parámetros o de modelo.
Este artículo desglosa 401, 404, 429, 400, 5xx y timeouts, y ofrece una tabla de códigos de error, los campos de log, código de reintento y una lista de comprobación antes de contactar al soporte. Modelos, cuotas y facturación se rigen por la documentación oficial y los precios de modelos del sitio.
Nota: Qwen, Tongyi Qianwen, Alibaba Cloud, Bailian y DashScope son marcas del Grupo Alibaba y de sus respectivos titulares. Este artículo solo discute diagnóstico técnico y no implica afiliación, agencia ni relación de cooperación con esas empresas. Los códigos de error, los criterios de límite y el comportamiento de la interfaz pueden cambiar según la versión; prevalecen la documentación oficial y la respuesta real.
1. Distingue primero el modo de interfaz y la estructura de error
La interfaz nativa DashScope suele devolver code, message y request_id en el nivel superior de la respuesta; la interfaz compatible con OpenAI sigue el estilo de OpenAI, con un cuerpo de error como {"error": {"message": "...", "type": "...", "code": "..."}}. En el modo compatible, request_id puede aparecer en las cabeceras o en el cuerpo; el nombre del campo depende de la respuesta real.
En ingeniería, no analices una sola estructura. Registra primero el cuerpo completo de la respuesta tal cual en el log y luego toma el valor en el orden error.code, code de nivel superior. Así, al cambiar de modo de interfaz, el código de manejo de errores no hay que reescribirlo.
2. 401: fallo de autenticación, revisa primero la región
Un 401 indica que la identidad no pasó la verificación y normalmente no tiene relación con la capacidad del modelo ni con el saldo. Los tres errores más comunes en Bailian son:
InvalidApiKeyoinvalid_api_key: la clave es incorrecta, se copió incompleta o la URL base no coincide con la región a la que pertenece la clave.invalid access token or token expired: el token expiró, o se usa una dirección exclusiva de un plan con una clave normal.- Un error de permisos denegados: el WorkspaceId no es válido o la cuenta no pertenece a ese espacio de trabajo.
Las claves de API de Qwen están vinculadas a la región; las claves de Pekín y Singapur no se pueden mezclar. Este es el punto que más se pasa por alto: el código no cambió, solo se cambió la URL base, y el 401 se reproduce de forma constante.
Diagnostica en este orden:
- Confirma que la cabecera es
Authorization: Bearer <key>, con un espacio después de los dos puntos. - Imprime el prefijo de la variable de entorno y confirma que no esté vacía, desactualizada ni con un salto de línea.
- Verifica que la URL base y la región de la clave coincidan.
- Confirma que el tipo de clave corresponda a la interfaz: las direcciones de pago por uso, plan Coding y plan de tokens son distintas.
- Prueba con una clave nueva y una solicitud mínima para separar un problema de clave de uno de proxy o gateway.
3. 404 y 400: nombre del modelo, estado de activación y contexto
Un 404 casi nunca es una falla del servicio, sino un problema con el nombre o la disponibilidad del modelo. Ante ModelNotFound o model_not_found, revisa tres cosas: si el nombre del modelo está mal escrito, si el modelo ya está activado y si está disponible en la región actual. model_not_supported indica que el modelo no admite el modo compatible con OpenAI y hay que cambiar de interfaz o de modelo.
Las causas de un 400 son más variadas. InvalidParameter es un parámetro fuera de rango, por ejemplo temperature o top_p fuera del intervalo; InvalidParameter.NotSupportEnableThinking indica que el modelo no admite el parámetro de modo de razonamiento. Cuando se excede el contexto suele devolverse Range of input length should be [1, xxx], con el código interno InternalError.Algo.InvalidParameter, o puede que la longitud total de los mensajes supere el límite del modelo. La solución es recortar el historial, resumir por bloques o cambiar a un modelo de contexto largo, no reintentar una y otra vez.
4. 429: distingue primero cuatro tipos de límite y dos clases de cuota
El 429 es el error que más se maneja mal. El 429 de Bailian incluye al menos las siguientes categorías; la tabla también muestra errores de saldo pendiente y de servicio no activado que se confunden fácilmente con límites:
| HTTP | Código de error | Significado | ¿Conviene reintentar? |
|---|---|---|---|
| 429 | Throttling.RateQuota, LimitRequests |
Se superó el número de solicitudes por minuto (RPM) | Sí, con retroceso |
| 429 | Throttling.AllocationQuota, insufficient_quota |
Se superó el número de tokens por minuto (TPM) | Sí, retroceso y reducir la entrada |
| 429 | Throttling.BurstRate |
Protección por un pico breve de tráfico | Sí, suavizar el ritmo de envío |
| 429 | Throttling.Concurrency |
Demasiadas solicitudes concurrentes | Sí, reducir la concurrencia |
| 429 | AllocationQuota.FreeTierOnly |
Cuota gratuita agotada y opción de usar solo la cuota gratuita activada | No, recargar o desactivar la opción |
| 429 | BudgetLimitExceeded |
Presupuesto de la cuenta agotado | No, ajustar el presupuesto |
| 400 | Arrearage |
Cuenta con saldo pendiente o estado anómalo | No, primero regularizar la cuenta |
| 403 | AccessDenied.Unpurchased |
Servicio no activado | No, activarlo primero |
Los límites se contabilizan por la cuenta principal de Alibaba Cloud; las llamadas de subcuentas RAM, espacios de trabajo y varias claves se suman. Por eso «una clave por servicio» no evita la cuota total, solo evita que se desplacen entre sí. Los límites suelen recuperarse en cuestión de minutos; durante la espera no reintentes a alta frecuencia.
5. Timeouts y 5xx: localiza en tres tramos
El timeout debe mirarse en tres tramos: el timeout de conexión suele ser DNS, salida o proxy inaccesible; la lentitud del primer token suele ser cola en el upstream o una entrada demasiado larga; el timeout de lectura puede deberse a una salida demasiado extensa o a un razonamiento prolongado. Los tres se tratan de forma distinta; no basta con aumentar el tiempo de espera.
RequestTimeOut de Bailian indica que la solicitud agotó el tiempo; la documentación oficial señala un límite de 300 segundos por solicitud. GatewayTimeout.InputDownload está relacionado con la descarga del archivo de entrada. La interfaz compatible con OpenAI también puede devolver 503, que indica sobrecarga del motor. Si una solicitud en streaming se interrumpe, puede no haber código de error: registra primero el contenido recibido, el último fragmento y el motivo de finalización, y luego determina si fue una fluctuación de red, un corte del proxy o un timeout del upstream.
6. request_id y logs: la evidencia del diagnóstico
La documentación oficial indica que request_id se devuelve con la respuesta, posiblemente en las cabeceras o en el cuerpo. En ingeniería conviene registrar por dos vías: un trace_id generado por el cliente que atraviese todos los reintentos y, al mismo tiempo, guardar tal cual el identificador de la cabecera y el request_id del cuerpo. Si no se registró, se puede buscar en los logs de monitoreo de modelos de la consola, siempre que el registro de inferencia esté activado.
El log debe incluir al menos: hora, trace_id, URL base, región, nombre del modelo, código de estado HTTP, código de error, mensaje de error, request_id, duración, número de reintentos y si fue streaming. De la clave solo se registran los primeros caracteres o un hash; no se debe volcar el texto original del usuario ni la respuesta completa. Al contactar al soporte, un registro con estos campos es mucho más útil que decir «a veces da error».
7. Reintentos y retroceso: código de ejemplo
El siguiente código desactiva los reintentos automáticos del SDK, reintenta solo los 429 y 5xx recuperables y muestra juntos el código de estado, el código de error y el request_id. El saldo pendiente, la cuota gratuita agotada y el presupuesto excedido no entran en el reintento.
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, # Desactiva los reintentos automáticos del SDK; la lógica siguiente los controla
)
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("Se agotaron los reintentos")
Tres reglas adicionales: si el servidor devuelve Retry-After, respétalo con prioridad; el presupuesto de reintentos debe controlarse globalmente para que varios servicios no amplifiquen el tráfico a la vez; y en solicitudes con efectos secundarios, confirma primero si ya se ejecutaron antes de decidir si reenviarlas.
8. Gobernanza de la concurrencia: más eficaz que aumentar los reintentos
Los problemas de límite normalmente no se resuelven con reintentos, sino gobernando la entrada:
- Separa las claves por negocio y fija límites de concurrencia distintos para que una tarea por lotes no derribe el servicio en línea.
- Divide las tareas por lotes en fragmentos y escalona su ejecución para evitar picos a la hora en punto.
- Usa colas para suavizar los picos; las tareas fallidas van a una cola con retraso en lugar de girar en el mismo punto.
- Monitoriza la proporción de 429 y la latencia p95; ante un aumento repentino, baja primero la concurrencia.
- Para tareas sin conexión, prioriza la interfaz Batch y evita los límites en tiempo real.
- Prepara un modelo o una entrada de respaldo y confirma la compatibilidad de parámetros antes de cambiar.
Los umbrales de límite se configuran por modelo y por cuenta; recargar no aumenta automáticamente el RPM ni el TPM. Si necesitas más cuota, solicítala por el canal comercial y no copies cifras de otros.
9. Lista antes de contactar al soporte
- Hora y zona horaria del incidente, y si las fallas se concentran en un momento.
- URL base, región, ruta de la interfaz, nombre del modelo y método de la solicitud.
- Código de estado HTTP, código de error y mensaje completo.
request_id; si no existe, eltrace_idgenerado por ti.- Una solicitud curl mínima reproducible, con la clave enmascarada.
- Si fue streaming, si usaba contexto largo y si se acaba de cambiar la configuración.
- Alcance: una sola clave, un solo espacio de trabajo o todos los servicios.
10. Preguntas frecuentes (FAQ)
1. ¿Un 429 siempre es límite de tasa?
No. Un 429 también puede deberse a cuota gratuita agotada o presupuesto excedido; el saldo pendiente puede devolver un 400 Arrearage, y un servicio no activado puede devolver 403. Lee primero el código de error y luego decide si aplicar retroceso, recargar o cambiar la configuración.
2. Cambié el 401 por una clave nueva y sigue fallando, ¿qué hago?
Revisa sobre todo la región y el tipo de clave. Las claves de Qwen están vinculadas a la región; una clave de Pekín con una dirección de Singapur devuelve 401, y una dirección exclusiva de plan con una clave normal también falla. Comprueba además la cabecera, las variables de entorno y si el proxy inverso descarta la información de autenticación.
3. ¿Cómo se resuelve un contexto excedido?
Primero recorta los mensajes del historial y elimina adjuntos irrelevantes y párrafos repetidos; después resume por bloques o aplica recuperación sobre los documentos largos; si aún no alcanza, cambia a un modelo de contexto largo. No intentes resolver un exceso de entrada aumentando max_tokens.
4. ¿Conviene reintentar los timeouts?
Solo reintenta un número limitado de veces los fallos de conexión y los timeouts de lectura, con retroceso exponencial y un límite. En operaciones con efectos secundarios, confirma primero si ya se ejecutaron para evitar pedidos duplicados o escrituras repetidas.
5. ¿Dónde se encuentra el request_id?
Revisa primero las cabeceras y el cuerpo de la respuesta; el nombre del campo depende de la interfaz real. Si no se registró, búscalo en los logs de monitoreo de modelos de la consola, siempre que el registro de inferencia esté activado. Al contactar al soporte, entrega el trace_id y una solicitud mínima de reproducción.
Siguiente paso
Crea una clave de prueba en el ZSQH AI Gateway, ensaya una vez cada caso de 401, 404, 429, contexto excedido y timeout, y después conecta el monitoreo de producción. Consulta modelos disponibles y formas de facturación en los precios de modelos.
