welclaiAI·TREND·DIGEST
Tutoriales

Gestionar errores y timeouts con elegancia

Las llamadas a modelos fallan, se cuelgan y topan con límites de tasa. Guía práctica de reintentos, timeouts, fallbacks y comportamiento a prueba de fallos.

tutorials2026-04-21 12:49 KST·Editor jefe·7 min

Una demo asume que todo funciona. Un producto asume que las cosas fallarán y se mantiene útil de todos modos. Cuando llamas a un modelo de lenguaje por la red, has heredado todos los modos de fallo de un servicio remoto —timeouts, límites de tasa, errores transitorios, respuestas lentas—, más algunos específicos de los modelos, como salidas que no encajan con la forma que necesitabas. La diferencia entre una funcionalidad frágil y una fiable está casi por completo en cómo maneja los caminos infelices. Esta guía recorre los fallos que deberías prever y cómo manejar cada uno con elegancia.

Conoce los fallos para los que estás planificando

Las llamadas a modelos fallan de unas pocas formas reconocibles, y manejarlas bien empieza por distinguirlas. Los errores transitorios son contratiempos temporales —un breve parpadeo de red o un error del lado del servidor que tiene éxito si simplemente lo vuelves a intentar—. Los límites de tasa son el proveedor diciéndote que vayas más despacio porque estás enviando peticiones demasiado rápido. Los timeouts ocurren cuando una respuesta tarda más de lo que estás dispuesto a esperar, lo cual con los modelos es común porque el tiempo de generación varía con la longitud de la salida. Los errores de entrada inválida significan que la propia petición estaba mal formada y reintentarla sin cambios fallará idénticamente. Y hay fallos a nivel de contenido: la llamada tiene éxito, pero la salida es incorrecta, está vacía o no tiene el formato que requeriste.

Estas categorías importan porque la respuesta correcta difiere para cada una. Reintentar un error transitorio es correcto; reintentar una petición mal formada es inútil. Replegarse ante un límite de tasa ayuda; insistir con más fuerza lo empeora. Antes de escribir código de manejo, clasifica el error que tienes delante, porque la clasificación determina la cura.

Reintenta lo transitorio, repliega con cortesía

Para errores transitorios y límites de tasa, reintentar es la respuesta, pero cómo reintentas importa. Reintentar de inmediato y repetidamente puede empeorar las cosas, sobre todo con límites de tasa, donde una avalancha de reintentos instantáneos te mantiene estrangulado. El enfoque estándar y bien educado es el retroceso exponencial con jitter: espera un tiempo corto antes del primer reintento, duplica aproximadamente la espera en cada intento posterior y añade un pequeño desfase aleatorio para que muchos clientes no reintenten todos al unísono.

delay = base
for attempt in range(max_attempts):
    try:
        return call_model(request)
    except Transient or RateLimited:
        wait(delay + random_jitter())
        delay = delay * 2
raise GiveUp

Limita el número de intentos y el retraso máximo para que una llamada fallida no reintente para siempre. Y reintenta solo los errores que el reintento puede arreglar: envuelve los reintentos en torno a fallos transitorios y de límite de tasa, pero deja que los errores de petición mal formada fallen rápido, porque reintentarlos desperdicia tiempo y dinero en una petición que no puede tener éxito.

Pon siempre un timeout

Una llamada a un modelo sin timeout es una trampa. El tiempo de generación es variable, y de vez en cuando una petición se cuelga mucho más de lo habitual. Sin timeout, una sola llamada lenta puede acaparar un manejador de peticiones, agotar un pool de conexiones y desencadenar una caída que parece un fallo total aunque solo unas pocas llamadas se hayan comportado mal. Pon siempre un timeout explícito en cada llamada a un modelo, elegido para encajar con cuánto puede esperar realmente el contexto que la rodea.

Elige el timeout con deliberación. Una funcionalidad interactiva en la que una persona espera necesita un límite más ajustado que un trabajo por lotes en segundo plano que puede permitirse paciencia. Cuando una llamada supera el timeout, trátala como un fallo transitorio: cancélala, y reintenta o repliégate. El punto es que decides cuánto esperar, en lugar de dejar que una llamada sin límite lo decida por ti. El streaming también ayuda aquí: si transmites la respuesta, el tiempo hasta el primer token te da una señal temprana de que una llamada está viva, y puedes aplicar un timeout separado y más ajustado a ese primer fragmento.

Ten un fallback para cuando se agoten los reintentos

Los reintentos te compran resiliencia frente a problemas temporales, pero a veces el problema no es temporal: un proveedor tiene una caída prolongada, o cada intento agota el tiempo. Para estos casos, decide de antemano qué hace tu funcionalidad cuando el modelo está simplemente no disponible. La respuesta equivocada es una excepción no manejada que burbujea hasta una pantalla rota.

Los fallbacks vienen en varios sabores según la tarea. Puedes replegarte a un modelo más pequeño o alternativo que sea más probable que esté disponible. Puedes servir una respuesta en caché o por defecto si alguna encaja. Puedes degradar con elegancia hacia un camino sin IA: una regla simple, una opción manual, un mensaje de "inténtalo más tarde" que preserva la entrada del usuario para que nada se pierda. El fallback correcto depende de la funcionalidad, pero toda funcionalidad de IA debería tener uno. La pregunta a responder antes de lanzar es: cuando el modelo no puede responder en absoluto, ¿qué ve el usuario? "Una página de error" no es una respuesta aceptable para nada importante.

Valida la salida, no solo la llamada

Una llamada exitosa no es un resultado exitoso. El modelo puede devolver texto vacío, fuera de tema o —lo más dolorosamente común— sin la estructura que tu código espera. Si pediste JSON y analizas la respuesta asumiendo que es válida, una salida mal formada hace caer tu código tan seguramente como un error de red. Trata la salida del modelo como entrada no confiable y valídala antes de depender de ella.

Tras una llamada, comprueba que la salida cumple tus requisitos: que se analiza, que tiene los campos requeridos, que está dentro de los límites esperados. Cuando la validación falla, tienes opciones. Puedes reintentar la llamada, a veces con una instrucción aclaratoria que señale qué estuvo mal. Puedes intentar una reparación tolerante para problemas menores. O puedes replegarte. Lo que no deberías hacer es pasar salida del modelo sin validar directamente a código que asume que está bien formada. El modelo es un componente probabilístico; la validación defensiva es cómo haces que un componente probabilístico sea seguro como base.

Haz los fallos visibles y observables

No puedes arreglar fallos que nunca ves. Registra los errores con suficiente contexto para entenderlos: el tipo de fallo, la entrada que lo provocó, cuántos reintentos hicieron falta, si se disparó el fallback. Vigilar las tasas de timeouts, límites de tasa y fallos de validación te dice cuándo algo se está degradando antes de que los usuarios se quejen. Un pico repentino de timeouts podría significar un problema del proveedor; un goteo constante de fallos de validación podría significar que tu prompt se desvió o que las entradas cambiaron.

Muestra los errores a los usuarios con honestidad pero con suavidad. Un mensaje claro y sereno de que algo salió mal y su entrada está a salvo supera a un volcado de pila críptico o a una respuesta vacía silenciosa. Internamente, asegúrate de que los fallos sean ruidosos en tu monitorización aunque sean silenciosos para el usuario. La combinación —elegante para el usuario, visible para ti— es lo que te permite mantener una funcionalidad fiable a lo largo del tiempo en lugar de descubrir sus puntos débiles a través de las quejas.

En resumen

La fiabilidad se construye sobre los caminos infelices. Clasifica el fallo que enfrentas —transitorio, de límite de tasa, timeout, mal formado o mala salida— porque cada uno necesita una respuesta distinta. Reintenta lo reintentable con retroceso exponencial y jitter, falla rápido con el resto, y pon un timeout explícito en cada llamada para que una petición lenta no atasque tu sistema. Decide de antemano qué pasa cuando el modelo no está disponible, y dale a cada funcionalidad un fallback real. Valida la salida como entrada no confiable antes de depender de ella, y mantén los fallos visibles en tu monitorización. Maneja bien esto y tu funcionalidad se mantiene útil incluso en los días en que el modelo no coopera.

#reliability#errors#timeouts#resilience