Skip to main content

Mejores prácticas para gestionar la limitación de tasa

Las API de Model Studio limitan el volumen de solicitudes, el uso de tokens y la tasa de crecimiento. Aplique estas estrategias para maximizar el rendimiento y mantener la disponibilidad.

Las API de Model Studio limitan las solicitudes, el uso de tokens y la tasa de crecimiento a lo largo del tiempo; esto es la limitación de tasa. Los modelos de lenguaje grandes tienen alta latencia y están restringidos en dos dimensiones (cantidad de solicitudes y volumen de tokens). Las estrategias simples de "reintentar en caso de error" fallan aquí; se necesita un control de tráfico diseñado específicamente. Tres tipos de soluciones, ordenadas de menor a mayor costo de implementación: Si está solucionando un error 429 ahora, vaya a Diagnóstico de errores y recomendaciones de estrategia para identificar la causa. Para errores por ráfagas de tráfico, pruebe primero la cola del lado del servidor, ya que solo requiere un encabezado de solicitud.

Mecanismo de limitación de tasa de la plataforma

La plataforma aplica límites de tasa a cada modelo de forma independiente a nivel de cuenta raíz. Tras activarse, el servicio suele reanudarse en un minuto. Para conocer las condiciones de limitación de tasa y el uso actual por modelo, consulte Limitación de tasa y Monitoreo de modelos. Se aplican tres tipos de reglas de limitación de tasa:
  • Límites de cuota a nivel de minuto (RPM / TPM): El número máximo de solicitudes por minuto (RPM) y el uso máximo de tokens por minuto (TPM).
  • Límites de frecuencia instantánea (RPS / TPS): Máximo de solicitudes por segundo (RPS) y máximo de uso de tokens por segundo (TPS). Llamadas densas a la API o consumo de tokens en un solo segundo pueden activar la limitación de tasa.
  • Límites de tasa de crecimiento (Ráfaga de tráfico): Un aumento repentino en el volumen de solicitudes o uso de tokens activa la limitación de tasa. El umbral se ajusta dinámicamente. Aumente las solicitudes gradualmente para evitar activar este límite.
Las siguientes secciones cubren soluciones en tres niveles: configuración de la plataforma, control de tráfico del lado del cliente y respaldo arquitectónico.

Diagnóstico de errores y recomendaciones de estrategia

El mismo código de error puede activarse por diferentes dimensiones de limitación de tasa. Una concurrencia elevada también puede saturar el servidor y provocar tiempos de espera agotados. La estrategia de control de congestión adaptativa puede ayudar a mitigar este problema.

Código de error (DashScope / OpenAI)

Dimensión de activación

Diagnóstico de características

Estrategia recomendada

Throttling.RateQuota / limit_requests

Tasa de solicitudes excedida
(RPM excedido)

Errores intermitentes. La tasa de éxito disminuye con el tiempo.

Cubeta de tokens: Controla la cuota de solicitudes por unidad de tiempo.

Tasa de solicitudes excedida
(RPS excedido)

Errores concentrados al inicio o durante picos de concurrencia.

Semáforo de concurrencia o limitador de tasa de suavizado: Aumenta el intervalo entre solicitudes.

Throttling.AllocationQuota / insufficient_quota

Uso de tokens excedido
(TPM excedido)

Errores intermitentes al procesar textos largos.

Cubeta de tokens dual: Limita simultáneamente las cuotas de RPM y TPM.

Uso de tokens excedido
(TPS excedido)

El consumo instantáneo de tokens es demasiado alto durante el procesamiento concurrente de textos largos.

Semáforo de concurrencia o limitador de tasa de suavizado.

Throttling.BurstRate / limit_burst_rate

Tasa de crecimiento de tráfico excedida
(Ráfaga de tráfico)

Gran volumen repentino de solicitudes después del inicio o tras recuperarse de un estado inactivo.

Recomendamos probar primero la cola del lado del servidor. Alternativamente, utilice un cubo de tokens con un valor inicial bajo, como initial_tokens=0, para implementar un inicio lento, o use un limitador de tasa de suavizado para el desplazamiento de carga pico.

Soluciones de configuración de plataforma

Estas soluciones dependen de las capacidades de la plataforma y requieren cambios mínimos o nulos en el código del lado del cliente.

Cola del lado del servidor (recomendado)

Para la limitación de tasa por ráfagas de tráfico, Model Studio acepta un límite superior del tiempo de espera en el encabezado de la solicitud. Tras recibir la solicitud, el servidor la reintenta cuando hay oportunidad dentro de ese intervalo hasta que comienza a procesarla o terminan los reintentos del intervalo. El valor es solo un límite superior; el servidor no espera a alcanzarlo antes de reintentar. Esto mejora significativamente las tasas de éxito durante ráfagas de tráfico en comparación con una respuesta 429 inmediata.
Esta función solo se aplica a la limitación de tasa de crecimiento / ráfaga de tráfico (Throttling.BurstRate). No se aplica a la limitación de tasa por cuota absoluta (RPM/TPM).
Configuración Agregue el campo X-DashScope-Wait-Timeout al encabezado de la solicitud:

Campo de encabezado

Ejemplo

Descripción

X-DashScope-Wait-Timeout

90

Límite superior del intervalo de espera en cola para solicitudes en ráfaga, en segundos. El servidor reintenta la solicitud dentro de este intervalo en lugar de esperar a alcanzar el valor.

  • Valor 0: Sin cola. Se devuelve inmediatamente un error 429.

  • Este valor solo es un límite superior y el tiempo de espera real puede ser menor. Por ejemplo, con un valor de 90 segundos, una llamada puede empezar a reintentarse a los 30 segundos aproximadamente; si el reintento sigue fallando, se devuelve un error 429.

  • Rango recomendado: de 3 a 120 segundos. En caso de ráfagas de tráfico, use un valor mayor para disponer de más reintentos y mejorar la tasa de éxito.

Configuración de tiempo de espera Después de habilitar las colas, ajuste el tiempo de espera del cliente para tener en cuenta el tiempo de espera adicional:
  • Solicitudes sin streaming (stream: false): Tiempo de espera = tiempo de espera base original + valor Wait-Timeout.
  • Solicitudes con streaming (stream: true): Timeout > valor de Wait-Timeout. Las solicitudes con streaming comienzan a contar el tiempo tras el primer fragmento, por lo que el tiempo de espera de respuesta inicial solo necesita superar el tiempo de espera en cola.
Ejemplo: Si el tiempo de espera base original es de 120 segundos y Wait-Timeout se establece en 90 segundos, el tiempo de espera para solicitudes sin streaming debe configurarse en 210 segundos.
OpenAI Python SDK
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    timeout=210.0,  # Original timeout 120s + queuing wait upper bound 90s
)

response = client.chat.completions.create(
    model="qwen-plus",
    messages=[{"role": "user", "content": "Hello"}],
    extra_headers={
        "X-DashScope-Wait-Timeout": "90"  # Queuing wait upper bound: 90 seconds
    }
)
print(response.choices[0].message.content)

Unidad de rendimiento aprovisionado (PTU)

El servicio PTU proporciona potencia de cómputo dedicada y reservada. Evita la contienda en el pool de recursos públicos y es la solución preferida para requisitos de alto throughput en tiempo real. Utilice PTU cuando su negocio tenga requisitos deterministas de throughput (como compromisos de SLA) o cuando want un throughput alto y estable sin control de tráfico del lado del cliente. Las PTU son recursos reservados que se facturan continuamente, incluso cuando no se utilizan por completo. Evalúe las especificaciones requeridas basándose en la carga pico real para evitar desperdicios.

Procesamiento por lotes asíncrono (Batch API)

Para tareas sin requisitos estrictos de tiempo real (limpieza de datos, análisis por lotes), utilice la Batch API para enviarlas a procesamiento por lotes. Las tareas se ejecutan durante horas de baja demanda, devuelven resultados de forma asíncrona y no están sujetas a límites de tasa en línea. Adecuado para tareas offline que toleran tiempos de retorno de horas a días: anotación de datos, análisis de registros, resúmenes por lotes. Los costos de la Batch API suelen ser inferiores a los de las llamadas a la API en tiempo real. El tiempo de retorno no está garantizado. No es adecuado para servicios que requieren respuestas inmediatas. Recupere los resultados mediante sondeo o callback después de la envío.

Estrategias de control de tráfico del lado del cliente

Cuando las soluciones de plataforma (como la cola del lado del servidor) no son suficientes, añada control de tráfico en el lado del cliente. El principio fundamental es: distribuir las solicitudes uniformemente dentro de una ventana de tiempo para evitar ráfagas. Después del inicio del sistema o de un periodo prolongado de inactividad, aumente la concurrencia gradualmente. Cuatro estrategias en orden creciente de complejidad. Cada una incluye la anterior y se suma a ella:
  • El reintento básico solo proporciona defensa pasiva.
  • La limitación de tasa de solicitudes añade colas activas.
  • El modelado de tráfico introduce además control a nivel de token y envío suave.
  • El control de congestión adaptativa ajusta dinámicamente la tasa de envío basándose en retroalimentación en tiempo real.
Elija la estrategia de menor costo que satisfaga sus necesidades.

Comparación del rendimiento de throughput de cada estrategia

imagen
Comparación de rendimiento bajo diferentes cargas:
  • Estrategia básica de reintentos: Eficaz bajo baja carga. Propensa al colapso por congestión bajo alta concurrencia, causando una caída abrupta en el throughput.
  • Estrategia de limitación de tasa de solicitudes: Fuerte protección contra colapsos. Sin embargo, bajo cargas de trabajo mixtas con textos largos, el throughput muestra fluctuaciones en forma de diente de sierra debido a la falta de control de tokens.
  • Estrategia de modelado de tráfico: Alta estabilidad. Logra una salida suave sacrificando parte del rendimiento pico.
  • Estrategia adaptativa de control de congestión: Puede converger dinámicamente a un punto estable de alto throughput bajo carga elevada, pero tiene overhead de sondeo durante el arranque en frío.

Estrategia de reintento básico

Adecuado para pruebas personales, scripts locales y tareas en segundo plano de baja frecuencia. Sin límite de tasa en solicitudes salientes. Solo activa reintentos con retroceso exponencial y jitter aleatorio ante errores 429 o 5xx. Sin control proactivo de tráfico. Bajo concurrencia multihilo, esto activa fácilmente la limitación de tasa y causa acumulación de solicitudes.
import openai
from openai import OpenAI
from tenacity import (
    retry,
    stop_after_attempt,
    wait_random_exponential,
    retry_if_exception_type
)

RETRYABLE_ERRORS = (
    openai.RateLimitError,
    openai.InternalServerError,
    openai.APIConnectionError,
)

@retry(
    wait=wait_random_exponential(min=1, max=60),
    stop=stop_after_attempt(6),
    retry=retry_if_exception_type(RETRYABLE_ERRORS)
)
def chat_with_retry(client, model, messages, max_tokens):
    return client.chat.completions.create(
        model=model,
        max_tokens=max_tokens,
        messages=messages
    )

client = OpenAI(
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    api_key="YOUR_DASHSCOPE_API_KEY"
)

try:
    response = chat_with_retry(
        client=client,
        model="qwen-plus",
        messages=[{"role": "user", "content": "What is exponential backoff retry?"}],
        max_tokens=1024
    )
    print(response.choices[0].message.content)
except Exception as e:
    print(f"Request failed: {e}")
El código utiliza retroceso exponencial, no reintentos de intervalo fijo. Los reintentos de intervalo fijo provocan que todas las solicitudes fallidas se reenvíen simultáneamente, lo que activa nuevamente la limitación de tasa. El retroceso exponencial con fluctuación aleatoria distribuye los reintentos:
  • El tiempo de espera se duplica progresivamente: Por ejemplo, 1s, 2s, 4s.... Esto evita solicitudes repetidas en un periodo corto.
  • Añadir jitter aleatorio: Un valor aleatorio (como 2s +/- 0.5s) distribuye el tráfico de reintentos, evitando una inundación secundaria (efecto de manada).
El sistema se recupera gradualmente en lugar de quedar atascado en un ciclo de "fallo — reintento sincronizado — fallo nuevamente".

Estrategia de limitación de tasa de solicitudes

Los reintentos pasivos por sí solos no pueden manejar el tráfico real. Los reintentos frecuentes aumentan la latencia. Esta estrategia introduce control activo de tráfico: verifica y regula las solicitudes antes de enviarlas, organizando el tráfico desordenado en una cola que respeta el límite de RPM. El suavizado activo añade un pequeño retraso de cola predecible, muy inferior al costo de un ciclo de "error — espera — reintento". Un costo pequeño conocido supera a uno grande desconocido. Adecuado para chatbots y otros servicios ligeros de solicitud-respuesta sensibles al tiempo hasta el primer token. La cola activa del lado del cliente utiliza dos niveles de control:
  • Cubeta de tokens RPM: Limita el total de solicitudes por minuto. La capacidad de la cubeta equivale a la cuota de RPM; los tokens se rellenan a una tasa constante. Admite préstamos: si los tokens son insuficientes, una solicitud toma prestado de la cuota futura, estrictamente en orden FIFO.
  • Semáforo de concurrencia: Limita las solicitudes concurrentes para evitar que una alta concurrencia instantánea active los límites de RPS.
Ejecute estos dos niveles en orden estricto: adquirir primero el token de RPM, luego adquirir el semáforo. Los espacios de concurrencia son escasos; asígnelos solo a solicitudes listas para ejecutarse. Invertir el orden provoca bloqueo de cabeza de línea bajo alta carga: las solicitudes retienen espacios pero no tienen tokens, todos los espacios se llenan y nada se envía. Principio: no retenga un recurso escaso mientras espera. El siguiente código inicializa el cubo de tokens lleno (initial_tokens=rpm_limit), adecuado para servicios en línea que necesitan procesar solicitudes inmediatamente al iniciarse. Si un cubo lleno activa la limitación de tasa, reduzca el valor inicial (por ejemplo, initial_tokens=0 para un "inicio con cubo vacío") para aumentar la tasa de manera más gradual. Esta estrategia no rastrea el uso de tokens. Las tareas de texto largo aún pueden agotar la cuota de TPM.
import time

class TokenBucket:
    """
    Token bucket implementation to control requests per minute (RPM).
    Supports a debt mechanism to ensure first-in, first-out (FIFO) order under high concurrency.
    """
    def __init__(self, quota_per_minute: float, initial_tokens: float = 0.0):
        self.capacity = quota_per_minute
        self.tokens = initial_tokens
        self.refill_rate = quota_per_minute / 60.0
        self.last_refill = time.monotonic()

    def reserve(self, cost: float = 1.0) -> float:
        """
        Acquires a token.
        If tokens are insufficient, returns the number of seconds to wait (supports debt).
        """
        self._refill()

        # 1. Sufficient tokens: Deduct directly
        if self.tokens >= cost:
            self.tokens -= cost
            return 0.0

        # 2. Insufficient tokens: Calculate wait time and incur debt
        # "Reserves" future tokens for the current request to ensure FIFO order
        deficit = cost - self.tokens
        wait_seconds = deficit / self.refill_rate
        self.tokens -= cost
        return wait_seconds

    def _refill(self):
        """Refills tokens based on elapsed time."""
        now = time.monotonic()
        elapsed = now - self.last_refill
        if elapsed > 0:
            self.tokens = min(self.capacity, self.tokens + elapsed * self.refill_rate)
            self.last_refill = now

Estrategia de modelado de tráfico

En escenarios por lotes que requieren un rendimiento alto y estable (ingesta RAG en tiempo real, análisis masivo de documentos largos), la limitación de tasa de solicitudes tiene un punto ciego de TPM. El modelado de tráfico añade conciencia dual de recursos (RPM y TPM) y un mecanismo de modelado que convierte el tráfico irregular en un flujo uniforme. Mejoras sobre la limitación de tasa de solicitudes:
  • Control dual de recursos (RPM y TPM): Mantiene cubetas de tokens tanto para RPM como para TPM. Todas las solicitudes deben pasar las verificaciones de cuota para ambas dimensiones antes de ser enviadas.
  • Prededucción para entrada, liquidación posterior para salida: La longitud de la salida es desconocida antes de la solicitud. El cubo de TPM prededuce los tokens de entrada al enviar y liquida los tokens de salida reales tras la finalización. Incluso si los tokens pasan a negativo, las solicitudes posteriores esperan a que el recuento sea positivo, suavizando naturalmente el flujo.
  • Calentamiento continuo: Durante un arranque en frío, la tasa de emisión de tokens aumenta linealmente con el tiempo, eliminando el riesgo de ráfagas iniciales.
  • Limitador de tasa de suavizado (Pacing): Suaviza la tasa de envío imponiendo un intervalo mínimo entre solicitudes (pacing), reduciendo el riesgo de activar límites de tasa.
Alternativa: Si es aceptable un ligero retraso de cola al inicio, reutilice el cubo de tokens estándar (configure initial_tokens=0) para un comienzo seguro con menor complejidad. El cubo de tokens de Python aquí es solo demostrativo. En producción, utilice bibliotecas maduras de limitación de tasa como SmoothRateLimiter de Guava en Java. En el ejemplo de código, la espera de suavizado se coloca dentro del bloqueo de concurrencia. Varias solicitudes podrían competir por el semáforo simultáneamente después de que finalice su espera, reagrupando el tráfico a la salida. El suavizado dentro del bloqueo reduce ligeramente la eficiencia de la concurrencia, pero garantiza intervalos de envío precisos. El pipeline completo de modelado de tráfico es: Estimate input tokens → Dual admission (RPM & TPM) → Concurrency lock → Traffic shaping → Send → Settle output tokens.
imagen
El suavizado conservador sacrifica cierta concurrencia pico. No es adecuado para servicios que requieren latencia extremadamente baja.
import time

class TokenBucket:
    """Advanced token bucket that supports a continuous warm-up mechanism."""
    def __init__(self, quota_per_minute: float, warmup_seconds: float = 0.0):
        self.capacity = quota_per_minute
        self.tokens = 0.0
        self.target_refill_rate = quota_per_minute / 60.0
        self.warmup_seconds = warmup_seconds
        self.start_time = time.monotonic()
        self.last_update_time = self.start_time
        self.cumulative_generated = 0.0

    def _get_cumulative_tokens(self, t: float) -> float:
        if t <= 0:
            return 0.0
        R = self.target_refill_rate
        T = self.warmup_seconds
        if T <= 0:
            return R * t
        if t <= T:
            return (R / (2 * T)) * (t ** 2)
        else:
            warmup_total = (R * T) / 2.0
            return warmup_total + R * (t - T)

    def _get_time_for_cumulative_tokens(self, target_cumulative: float) -> float:
        if target_cumulative <= 0:
            return 0.0
        R = self.target_refill_rate
        T = self.warmup_seconds
        if T <= 0:
            return target_cumulative / R
        warmup_total = (R * T) / 2.0
        if target_cumulative <= warmup_total:
            return ((2 * T * target_cumulative) / R) ** 0.5
        else:
            return (target_cumulative - warmup_total) / R + T

    def reserve(self, cost: float = 1.0) -> float:
        now = time.monotonic()
        relative_now = now - self.start_time
        current_cumulative = self._get_cumulative_tokens(relative_now)
        new_tokens = current_cumulative - self.cumulative_generated
        self.tokens = min(self.capacity, self.tokens + new_tokens)
        self.cumulative_generated = current_cumulative
        self.last_update_time = now
        if self.tokens >= cost:
            self.tokens -= cost
            return 0.0
        deficit = cost - self.tokens
        self.tokens -= cost
        target_cumulative = self.cumulative_generated + deficit
        target_time = self._get_time_for_cumulative_tokens(target_cumulative)
        wait_seconds = target_time - relative_now
        return max(0.0, wait_seconds)

    def adjust(self, amount: float):
        self.tokens = min(self.capacity, self.tokens + amount)

Estrategia de control de congestión adaptativa

Adecuada para cargas de trabajo dinámicas y a gran escala: puertas de enlace API, proxies complejos, sistemas multiinquilino.
Consejo de selección: Esta estrategia no es una solución universalEsta estrategia maneja entornos altamente inciertos y volátiles. No es una opción universal:
  • Paradoja del rendimiento: Si la carga es predecible (como en el procesamiento por lotes), los parámetros estáticos óptimos superan al sondeo dinámico que requiere "prueba y convergencia".
  • Overhead de sondeo: Los algoritmos dinámicos implican inevitablemente un aumento gradual durante el arranque en frío y fluctuaciones exploratorias, lo cual representa un overhead innecesario en escenarios conocidos.
  • Costo de mantenimiento: La retroalimentación de ciclo cerrado aumenta la complejidad del sistema y la dificultad de resolución de problemas.
A menos que su negocio tenga una escala muy grande, carga compleja y volatilidad significativa, elija una de las tres primeras estrategias más simples.
La limitación de tasa de solicitudes y el modelado de tráfico son estrategias de cuota estática; funcionan bien bajo cargas estables y predecibles. Pero a nivel de puerta de enlace, las cargas descendentes cambian constantemente (solicitudes cortas mezcladas con inferencias profundas) y los umbrales de la plataforma fluctúan dinámicamente. Las estrategias estáticas tienen dificultades para equilibrar eficiencia y estabilidad. Inspirada en BBR, esta estrategia construye un sistema de control de bucle cerrado basado en EBP (Sondeo de Ancho de Banda Elástico). Utiliza las cuotas de RPM/TPM como límite superior orientativo y calcula dinámicamente la tasa de envío óptima a partir de retroalimentación en tiempo real (cambios de latencia, señales de limitación de tasa).
  • EBP: Almacena el nivel máximo histórico exitoso. Calcula la ganancia de sondeo simulando la tensión de un resorte según la distancia entre la concurrencia actual y dicho nivel (más lejos = más rápido, más cerca = más lento). Añade un pequeño impulso lineal para seguir explorando incluso bajo alta saturación.
  • Detección de congestión TPT: El tiempo de generación del LLM escala con la longitud de la salida; una latencia alta en textos largos no indica congestión. El TPT (Tiempo por Token) filtra el ruido derivado de la longitud del contenido. La congestión solo se declara cuando el TPT se degrada significativamente.
  • Regulador de tasa anti-ráfaga: Independientemente del objetivo EBP, el regulador limita la aceleración del crecimiento de concurrencia para asegurar un aumento gradual y evitar cambios escalonados que activen límites de tasa de crecimiento.
imagen
Modificaciones clave respecto al BBR nativo para modelos grandes:
  • Sondeo guiado: Introduce cuotas conocidas de RPM/TPM como un "límite superior guía" para evitar colisiones frecuentes causadas por sondeos a ciegas.
  • Fuente de señal (RTT → TPT): BBR nativo usa RTT. En escenarios de LLM, la latencia por longitud de contenido eclipsa el jitter de red. TPT elimina esa interferencia.
  • Mejora del mecanismo de respuesta (ProbeRTT → Hold): Ante fluctuaciones de latencia, opta por mantener el nivel actual de concurrencia en lugar de retroceder proactivamente y reducir el throughput.
  • Respuesta estricta al límite de tasa (Pérdida de paquetes → Drenaje 429): Una vez que se activa un error 429, entra en un estado agresivo de Drenaje y realiza una recuperación rápida tras un periodo de enfriamiento.
Limitaciones:
  • Ruido en TPT: TPT se estima como "latencia total / tokens totales". La latencia total incluye ida y vuelta de red, espera en cola y tiempo hasta el primer token, siendo susceptible a jitter o entradas largas, lo cual puede activar falsamente el estado Hold.
  • Inanición de solicitudes grandes: Utiliza una activación FIFO no estricta para el rendimiento de la programación. Cuando las cuotas son escasas, las solicitudes de pocos tokens pueden acaparar recursos, provocando que las solicitudes de muchos tokens esperen demasiado.
  • Arranque en frío: Requiere un periodo de calentamiento para construir un modelo estadístico. En tareas de baja carga o de corta duración, el throughput puede ser menor que en las tres primeras estrategias.
class ElasticCongestionController:
    async def acquire(self):
        """[Admission phase] Check before initiating a request"""
        # 1. SSR slow-start restart: If idle for too long, proactively decay the limit
        #    to prevent burst traffic caused by an outdated watermark.
        if self.is_idle_too_long():
            self.perform_slow_start_restart()

        # 2. Circuit breaker check: If in DRAIN (cooldown) state, force wait.
        if self.state == CongestionState.DRAIN:
            await self.wait_for_cooldown()

        # 3. Dual budget check: Check both concurrency slots and token budget.
        await self.wait_for_budget(request_tokens)

    async def release(self, latency, actual_tokens, error):
        """[Feedback phase] Decision after the request finishes"""
        if error:
            # [Fault response] On rate limit error (429/503): Immediately drain + multiplicative backoff
            self.state = CongestionState.DRAIN
            self.concurrency_limit *= self.backoff_factor  # e.g. 0.7
            return

        # [Normal response] Calculate TPT (Time-Per-Token)
        current_tpt = latency / actual_tokens

        # [Congestion awareness] TPT spike (generation slows down): Enter HOLD to observe
        # Maintain concurrency level, neither backing off nor increasing
        if current_tpt > self.metrics.ema_tpt * 2.0:
            self.state = CongestionState.HOLD
        else:
            # [Steady-state probing] Network is healthy: Perform EBP elastic probing
            self.state = CongestionState.PROBING
            self.update_limit_via_ebp()

Soluciones de respaldo arquitectónico

Cuando la configuración de la plataforma y el control de tráfico del lado del cliente aún no pueden cumplir con los requisitos de disponibilidad o throughput pico, añada mecanismos de respaldo a nivel de arquitectura.

Respaldo de modelo

Cuando el modelo principal no puede responder debido a limitaciones de tasa o problemas de servicio, recurra automáticamente a un modelo alternativo con una cuota más generosa. Principios de diseño de ruta de respaldo
  • Elegir modelos de diferentes series: La limitación de tasa es por modelo. Utilice un modelo diferente como respaldo; por ejemplo, cambie de qwen3.6-plus a qwen3.6-flash.
  • Activar el respaldo solo en errores de límite de tasa: Realice el respaldo ante errores 429, no ante todas las excepciones. Cambiar de modelo no solucionará tiempos de espera de red ni errores de parámetros.
  • Valide el modelo de respaldo con antelación: Asegúrese de que admita las funciones requeridas (Function Calling, salida estructurada, etc.) para evitar problemas funcionales tras el respaldo.
El siguiente ejemplo demuestra la lógica de respaldo de modelo basada en el código de error 429. Cuando una solicitud al modelo principal activa un límite de tasa, cambia automáticamente al modelo de respaldo para un reintento.
import os
import asyncio
from openai import AsyncOpenAI, APIStatusError

# Primary and fallback models (different series, independent quotas)
PRIMARY_MODEL = "qwen3.6-plus"
FALLBACK_MODEL = "qwen3.6-flash"

client = AsyncOpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

async def chat_with_fallback(messages: list) -> str:
    """Request with fallback: Automatically switches to the fallback model when the primary model is rate-limited."""
    for model in [PRIMARY_MODEL, FALLBACK_MODEL]:
        try:
            response = await client.chat.completions.create(
                model=model,
                messages=messages
            )
            return response.choices[0].message.content
        except APIStatusError as e:
            if e.status_code == 429 and model == PRIMARY_MODEL:
                print(f"[Rate Limit Triggered] {model}, falling back to {FALLBACK_MODEL}")
                continue
            raise
    raise RuntimeError("All models are unavailable")

async def main():
    result = await chat_with_fallback(
        messages=[{"role": "user", "content": "Hello"}]
    )
    print(result)

if __name__ == "__main__":
    asyncio.run(main())
El modelo de respaldo puede combinarse con estrategias de control de tráfico del lado del cliente. Por ejemplo, puede integrar la lógica de respaldo en el mecanismo de reintento de la estrategia de limitación de tasa de solicitudes. Cuando se agotan los reintentos y se sigue activando la limitación de tasa, cambie al modelo de respaldo.

Desplazamiento de carga pico mediante colas de mensajes (MQ)

Para servicios backend que no requieren respuestas inmediatas, introduzca un middleware de mensajería (RabbitMQ, Kafka) para el desplazamiento de carga pico. El tráfico repentino ingresa primero al MQ; los consumidores extraen y procesan a una tasa constante acorde con la cuota de limitación de tasa. Esto desacopla los picos del frontend de las llamadas al backend. Adecuado para negocios donde los usuarios aceptan resultados asíncronos: procesamiento de tickets, moderación de contenido, anotación de datos por lotes. Puntos clave de diseño:
  • Control de tasa del consumidor: El lado del consumidor debe usar la estrategia de limitación de tasa de solicitudes o de modelado de tráfico para consumir mensajes a una tasa constante basada en la cuota de RPM/TPM, en lugar de extraer mensajes sin límites.
  • Manejo de mensajes muertos: Mueva los mensajes que fallan tras múltiples reintentos a una cola de mensajes muertos y active una alerta. Evite que los reintentos infinitos bloqueen el consumo.
  • Propagación de contrapresión: Cuando la acumulación en MQ supera un umbral, propague la presión hacia arriba (por ejemplo, devuelva un estado de espera) para evitar un crecimiento ilimitado de la cola.

Consideraciones para entorno de producción

Los ejemplos de código utilizan un bucle de un solo hilo con asyncio de Python para demostrar algoritmos centrales. Antes de su uso en producción a gran escala, considere lo siguiente.
  • Adaptación a modelos no textuales Las estrategias anteriores utilizan modelos de texto como ejemplos, pero los principios fundamentales se aplican a servicios multimodales (generación de imágenes, síntesis de voz). Las unidades difieren, pero la esencia es la misma: limitar la tasa de envío y la capacidad de procesamiento.
    • Modelos como el reconocimiento de voz suelen estar restringidos tanto por el número de solicitudes por unidad de tiempo (como RPM) como por el uso (como duración de audio). Las estrategias son básicamente las mismas que para los modelos de texto.
    • Los modelos para imágenes y videos suelen estar restringidos por la tasa de envío de tareas y el número de tareas concurrentes. Puede utilizar el mismo enfoque que la estrategia de limitación de tasa de solicitudes: limite la tasa de envío de tareas y utilice un semáforo para controlar la concurrencia.
    Independientemente de cómo cambien las métricas, el principio de limitación del lado del cliente sigue siendo el mismo. Reemplace el contador o la métrica de sondeo con la correspondiente a su modalidad. Para reglas específicas, consulte Limitación de tasa.
  • Atomicidad en modelos concurrentes Ejemplo: asyncio utiliza programación cooperativa de un solo hilo, por lo que las modificaciones de estado son inherentemente atómicas dentro de un solo proceso. Producción: En entornos multihilo o multiproceso, garantice la seguridad de concurrencia de la cubeta de tokens y la ventana de estadísticas. Las condiciones de carrera romperán el control de tráfico.
  • Limitación de tasa distribuida Ejemplo: Todos los componentes de control de tráfico están en memoria. Producción: En despliegues de múltiples instancias, cada instancia limita la tasa independientemente. El uso total puede exceder el límite. Utilice un contador centralizado (como Redis) para gestionar el uso en todos los nodos.
  • Colas prioritarias y prevención de inanición Ejemplo: Sin diferenciación de prioridad. La estrategia adaptativa de control de congestión utiliza activación FIFO no estricta para el rendimiento de la programación. Producción: Para solicitudes de alta/baja prioridad, implemente una cola de prioridad ponderada para garantizar ancho de banda al tráfico de alta prioridad. Reserve una cuota mínima para las colas de baja prioridad para evitar la inanición.