Por qué muchos sistemas agenticos fallan en producción y cómo diseñar agentes fiables con máquinas de estados, contratos claros de herramientas, reintentos e observabilidad profunda.

Los sistemas agenticos son aplicaciones en las que un LLM no solo responde a un prompt, sino que decide qué hacer después: qué herramientas invocar, qué datos recuperar, qué pasos ejecutar y cuándo ha terminado. Combinan un modelo, un conjunto de herramientas (APIs, bases de datos, servicios), un bucle de planificación/ejecución y la infraestructura que lo conecta todo.
En una demo, esto parece mágico: un agente diseña un plan, invoca unas cuantas herramientas y devuelve un resultado perfecto. La ruta feliz es corta, la latencia baja y nada falla al mismo tiempo.
Bajo cargas reales, el mismo agente se ve forzado de maneras que la demo nunca vio:
El resultado: comportamiento intermitente difícil de reproducir, corrupción silenciosa de datos y flujos de usuario que ocasionalmente se quedan colgados o girando indefinidamente.
Los agentes intermitentes no solo afectan la “satisfacción”. Ellos:
Este artículo trata sobre patrones de ingeniería, no sobre “mejores prompts”. Veremos máquinas de estados, contratos explícitos de herramientas, estrategias de reintento y manejo de fallos, control de memoria y concurrencia, y patrones de observabilidad que hacen a los sistemas agenticos predecibles bajo carga, no solo impresionantes en el escenario.
La mayoría de los sistemas de agentes parecen bien en una demo de ruta feliz. Fallan cuando llegan tráfico, herramientas y casos límite al mismo tiempo.
La orquestación ingenua asume que el modelo “hará lo correcto” en una o dos llamadas. Bajo uso real, aparecen patrones recurrentes:
Sin estados explícitos y condiciones de finalización, estos comportamientos son inevitables.
El muestreo del LLM, la variabilidad de latencia y el timing de las herramientas crean no determinismo oculto. La misma entrada puede recorrer ramas distintas, invocar herramientas diferentes o interpretar resultados de herramientas de distinto modo.
A escala, los problemas de las herramientas dominan:
Cada uno de estos se convierte en bucles espurios, reintentos o respuestas finales incorrectas.
Lo que raramente falla a 10 RPS fallará constantemente a 1.000 RPS. La concurrencia revela:
Los equipos de producto a menudo esperan flujos deterministas, SLAs claros y auditabilidad. Los agentes, dejados sin restricciones, ofrecen comportamiento probabilístico y de mejor esfuerzo con garantías débiles.
Cuando las arquitecturas ignoran este desajuste —tratando a los agentes como servicios tradicionales en vez de planificadores estocásticos— los sistemas se comportan de forma impredecible justo cuando la fiabilidad importa más.
Los agentes listos para producción tienen menos que ver con “prompts inteligentes” y más con diseño de sistemas disciplinado. Una forma útil de pensar en ellos es como pequeñas máquinas predecibles que ocasionalmente llaman a un LLM, no como masas misteriosas de LLM que de vez en cuando tocan tus sistemas.
Cuatro propiedades importan más:
No obtienes estas propiedades solo con prompts. Se obtienen mediante estructura.
El patrón por defecto con el que muchos equipos empiezan es: "mientras no esté hecho, llama al modelo, que el modelo piense, quizá llama a una herramienta, repetir". Esto es fácil de prototipar y difícil de operar.
Un patrón más seguro es representar el agente como un flujo explícito:
COLLECTING_INPUT, PLANNING, EXECUTING_STEP, WAITING_ON_HUMAN, DONE).Esto convierte al agente en una máquina de estados donde cada paso es inspeccionable, testeable y reproducible. Los bucles libres parecen flexibles, pero los flujos explícitos son los que hacen que los incidentes sean depurables y el comportamiento auditable.
Los agentes monolíticos que “lo hacen todo” son atractivos, pero crean acoplamientos fuertes entre responsabilidades no relacionadas: planificación, recuperación, lógica de negocio, orquestación de UI y más.
En su lugar, compón agentes pequeños y bien acotados o skills:
Cada skill puede tener su propia máquina de estados, herramientas y reglas de seguridad. La lógica de composición se convierte entonces en un flujo de alto nivel, no en un prompt cada vez más grande dentro de un único agente.
Esta modularidad mantiene cada agente lo bastante simple como para razonar sobre él y te permite evolucionar una capacidad sin desestabilizar el resto.
Un modelo mental útil es dividir un agente en tres capas:
Política de decisión (prompts + modelo)
Encapsula cómo el agente elige las siguientes acciones, interpretado bajo restricciones estrictas. Debes poder cambiar el modelo, ajustar la temperatura o refinar prompts sin tocar el cableado del sistema.
Máquina de estados / motor de workflow
Posee dónde estás en el proceso, qué transiciones son posibles y cómo persistir el progreso. La política sugiere un movimiento; la máquina de estados lo valida y lo aplica.
Capa de herramientas
Implementa qué puede ocurrir en el mundo: APIs, bases de datos, colas, servicios externos. Las herramientas exponen contratos estrechos y tipados y hacen cumplir autorización, límites de tasa y validación de entrada.
Al forzar esta separación, evitas la trampa de esconder lógica de negocio en prompts o descripciones de herramientas. El LLM se convierte en un componente de decisión dentro de una carcasa determinista clara, no en la carcasa misma.
Los sistemas agenticos más fiables no son las demos más impresionantes: son aquellos cuyo comportamiento puedes explicar en una pizarra.
Concretamente:
Esta preferencia por agentes pequeños, componibles y bien estructurados es lo que permite que los sistemas crezcan en alcance sin colapsar bajo su propia complejidad.
La mayoría de las implementaciones de agentes empiezan como un bucle de "pensar, actuar, observar" alrededor de una llamada al LLM. Eso está bien para demos, pero rápidamente se vuelve opaco y frágil. Un enfoque mejor es tratar al agente como una máquina de estados explícita: un conjunto finito de estados, con transiciones bien definidas disparadas por eventos.
En lugar de permitir que el modelo decida implícitamente qué hacer a continuación, define un pequeño diagrama de estados:
Las transiciones entre estos estados son disparadas por eventos tipados como UserRequestReceived, ToolCallSucceeded, ToolValidationFailed, TimeoutExceeded o HumanOverride. Cada evento, junto con el estado actual, determina el siguiente estado y acciones.
Esto hace que los reintentos y timeouts sean directos: adjuntas políticas a estados individuales (por ejemplo, CALL_TOOL puede reintentar 3 veces con backoff exponencial, PLAN podría no reintentar) en vez de esparcir la lógica de reintentos por todo el código.
Persiste el estado actual y el contexto mínimo en un almacén externo (base de datos, cola o motor de workflows). El agente se convierte entonces en una función pura:
next_state, actions = transition(current_state, event, context)
Esto permite:
Con una máquina de estados, cada paso del comportamiento del agente es explícito: en qué estado estaba, qué evento ocurrió, qué transición se disparó y qué efectos secundarios se produjeron. Esa claridad acelera la depuración, simplifica las investigaciones de incidentes y crea una traza natural para auditorías de cumplimiento. Puedes probar, a partir de logs e historial de estado, que ciertas acciones arriesgadas solo se toman desde estados específicos y bajo condiciones definidas.
Los agentes se comportan de forma mucho más predecible cuando las herramientas se parecen menos a “APIs escondidas en prosa” y más a interfaces bien diseñadas con garantías explícitas.
Cada herramienta debería tener un contrato que cubra:
InvalidInput, NotFound, RateLimited, TransientFailure) con semánticas claras.Expón este contrato al modelo como documentación estructurada, no como un muro de texto. El planificador del agente debe saber qué errores son reintentables, cuáles requieren intervención humana y cuáles deben detener el flujo.
Trata la E/S de las herramientas como cualquier otra API de producción:
Esto te permite simplificar los prompts: en lugar de instrucciones verbosas, confía en orientación dirigida por esquemas. Las restricciones claras reducen argumentos alucinados y secuencias de herramientas sin sentido.
Las herramientas evolucionan; los agentes no deberían romperse cada vez que lo hacen.
v1, v1.1, v2) y fija los agentes a una versión.La lógica de planificación puede entonces mezclar agentes y herramientas en distintos niveles de madurez con seguridad.
Diseña contratos con fallos parciales en mente:
El agente puede entonces adaptarse: continuar el flujo con funcionalidad reducida, pedir confirmación al usuario o cambiar a una herramienta de respaldo.
Los contratos de herramientas son un lugar natural para codificar límites de seguridad:
confirm: true).Combina esto con verificaciones server-side; nunca confíes únicamente en que el modelo “se comporte”.
Cuando las herramientas tienen contratos claros, validados y versionados, los prompts pueden ser más cortos, la orquestación más sencilla y la depuración mucho más fácil. Mueves complejidad de instrucciones en lenguaje natural frágiles a esquemas y políticas deterministas, reduciendo llamadas a herramientas alucinadas y efectos secundarios inesperados.
Los sistemas agenticos fiables asumen que todo fallará eventualmente: modelos, herramientas, redes e incluso tu propia capa de coordinación. La meta no es evitar el fallo, sino hacerlo barato y seguro.
Idempotencia significa: repetir la misma solicitud tiene el mismo efecto visible externamente que hacerla una vez. Esto es crítico para agentes LLM, que frecuentemente reemiten llamadas a herramientas tras fallos parciales o respuestas ambiguas.
Haz que las herramientas sean idempotentes por diseño:
request_id estable. La herramienta almacena esto y devuelve el mismo resultado si ve el ID otra vez.Usa reintentos estructurados para fallos transitorios (timeouts, límites de tasa, 5xx): backoff exponencial, jitter para evitar manadas y un máximo de intentos estricto. Registra cada intento con IDs de correlación para poder trazar el comportamiento del agente.
Para fallos permanentes (4xx, errores de validación, violaciones de reglas de negocio), no reintentes. Muestra un error estructurado a la política del agente para que pueda revisar el plan, pedir al usuario o elegir otra herramienta.
Implementa circuit breakers tanto en la capa del agente como en la de la herramienta: tras fallos repetidos, bloquea temporalmente llamadas a esa herramienta y falla rápido. Acompaña esto con alternativas bien definidas: modos degradados, datos en caché o herramientas alternativas.
Evita reintentos ciegos desde el bucle del agente. Sin herramientas idempotentes y clases de fallo claras, solo multiplicarás efectos secundarios, latencia y coste.
Los agentes fiables empiezan por pensar claramente en qué es estado y dónde vive.
Trata a un agente como tratarías a un servicio que maneja una petición:
Mezclarlos lleva a confusión y errores. Por ejemplo, poner resultados efímeros de herramientas en “memoria” hace que los agentes reutilicen contexto obsoleto en conversaciones futuras.
Tienes tres opciones principales:
Una buena regla: el LLM es una función sin estado sobre un objeto de estado explícito. Persiste ese objeto fuera del modelo y regenera prompts a partir de él.
Un patrón de fallo común es usar logs de conversación, trazas o prompts crudos como memoria de facto.
Problemas:
En su lugar, define esquemas de memoria estructurados: user_profile, project, task_history, etc. Deriva logs del estado, no al revés.
Cuando múltiples herramientas o agentes actualizan las mismas entidades (por ejemplo, un registro CRM o el estado de una tarea), necesitas controles básicos de consistencia:
Para operaciones de alto valor, registra un log de decisiones separado del log conversacional: qué cambió, por qué y basado en qué entradas.
Para sobrevivir crashes, despliegues y límites de tasa, los workflows deben ser reanudables:
Esto también habilita la depuración por viaje en el tiempo: puedes inspeccionar y reproducir el estado exacto que llevó a una decisión errónea.
La memoria es una responsabilidad tanto como un activo. Para agentes en producción:
Trata la memoria como una superficie de producto: diseñada, versionada y gobernada —no como un volcado de texto que crece sin control.
Los agentes se ven secuenciales en un diagrama, pero se comportan como sistemas distribuidos bajo carga real. En cuanto tienes muchos usuarios concurrentes, herramientas y jobs en background, te encuentras con condiciones de carrera, trabajo duplicado y problemas de orden.
Modos comunes de falla:
Mitígalos con contratos idempotentes de herramientas, estado de workflow explícito y bloqueo optimista/pesimista en la capa de datos.
Los flujos síncronos request–response son simples pero frágiles: cada dependencia debe estar arriba, dentro de límites de tasa y ser rápida. Cuando los agentes disparan muchas herramientas o subtareas en paralelo, mueve pasos de larga ejecución o con efectos secundarios detrás de una cola.
La orquestación basada en colas te permite:
Los agentes suelen chocar con tres clases de límites:
Necesitas una capa de limitación de tasa explícita con throttles por usuario, por tenant y globales. Usa token buckets o leaky buckets para aplicar políticas, y expón tipos de error claros (por ejemplo, RATE_LIMIT_SOFT, RATE_LIMIT_HARD) para que los agentes retrocedan con gracia.
El backpressure es cómo el sistema se protege bajo estrés. Estrategias incluyen:
Monitoriza señales de saturación: profundidad de colas, utilización de workers, tasas de error y percentiles de latencia. Colas que crecen junto con latencias o errores 429/503 son la señal temprana de que los agentes están sobrepasando su entorno.
No puedes hacer fiable a un agente si no puedes responder dos preguntas rápido: ¿qué hizo? y ¿por qué lo hizo? La observabilidad para sistemas agenticos consiste en hacer esas respuestas baratas y precisas.
Diseña la observabilidad para que una sola tarea tenga una traza que atraviese:
Dentro de esa traza, adjunta logs estructurados para decisiones clave (elección de enrutamiento, revisión de planes, disparos de guardrails) y métricas de volumen y salud.
Una traza útil suele incluir:
Loggea prompts, entradas y salidas de herramientas en forma estructurada, pero pásalos primero por una capa de redacción:
Mantén contenido crudo detrás de feature flags en entornos inferiores; producción debe por defecto mostrar vistas redactadas.
Como mínimo, controla:
Cuando ocurren incidentes, buenas trazas y métricas te permiten pasar de “el agente está inestable” a afirmar con precisión: “P95 de tareas fallando en ToolSelection tras 2 reintentos debido a un nuevo esquema en billing_service”, reduciendo el diagnóstico de horas a minutos y dándote palancas concretas para ajustar el comportamiento.
Probar agentes significa probar tanto las herramientas que llaman como los flujos que lo cosen todo. Trátalo como pruebas de sistemas distribuidos, no solo como ajuste de prompts.
Empieza con tests unitarios en el borde de la herramienta:
Estos tests nunca dependen del LLM. Llama a la herramienta directamente con entradas sintéticas y afirma la salida o el contrato de error exacto.
Los tests de integración ejercitan el workflow del agente end-to-end: LLM + herramientas + orquestación.
Modela esto como tests basados en escenarios:
Estos tests verifican transiciones de estado y llamadas a herramientas, no cada token del LLM. Comprueba: qué herramientas fueron llamadas, con qué argumentos, en qué orden y qué estado/resultado final alcanzó el agente.
Para mantener tests repetibles, fija tanto respuestas del LLM como salidas de herramientas:
Un patrón típico:
with mocked_llm(fixtures_dir="fixtures/llm"), mocked_tools():
result = run_agent_scenario(input_case)
assert result.state == "COMPLETED"
Cada cambio de prompt o esquema debe activar una ejecución de regresión no negociable:
La evolución de esquemas (añadir campos, endurecer tipos) tiene sus propios casos de regresión para detectar agentes o herramientas que aún asumen el contrato antiguo.
Nunca lances un nuevo modelo, política o estrategia de enrutamiento directo a tráfico de producción.
En su lugar:
Solo tras pasar las puertas offline debería una nueva variante alcanzar producción, idealmente tras un rollout gradual y controlado por feature flags.
Los logs de agentes suelen contener datos sensibles. Las pruebas deben respetar eso.
Codifica estas reglas como parte de tu pipeline CI para que ningún artefacto de prueba pueda generarse o almacenarse sin checks de anonimización.
Operar agentes en producción se parece más a ejecutar un sistema distribuido que a desplegar un modelo estático. Necesitas controles de despliegue, objetivos de fiabilidad claros y gestión disciplinada del cambio.
Introduce nuevos agentes o comportamientos gradualmente:
Apóyalo todo con feature flags y políticas configurables: reglas de enrutamiento, herramientas habilitadas, temperatura, ajustes de seguridad. Los cambios deben ser desplegables por configuración, no por código, y reversible al instante.
Define SLOs que reflejen tanto la salud del sistema como el valor para el usuario:
Conecta esto a alertas y opera incidentes como cualquier servicio de producción: propiedad clara, runbooks para triage y pasos de mitigación estándar (revertir flag, drenar tráfico, modo seguro).
Usa logs, trazas y transcripciones para refinar prompts, herramientas y políticas. Trata cada cambio como un artefacto versionado con revisión, aprobación y capacidad de rollback.
Evita cambios silenciosos en prompts o herramientas. Sin control de cambios no podrás correlacionar regresiones con ediciones específicas, y la respuesta a incidentes se convierte en conjeturas en vez de ingeniería reproducible.
Un sistema agentico listo para producción se beneficia de una separación clara de responsabilidades. El objetivo es mantener al agente inteligente en decisiones, pero tonto en infraestructura.
1. Gateway / edge API
Punto único de entrada para clientes (apps, servicios, UIs). Maneja:
2. Orquestador
El orquestador es el “tronco”, no el cerebro. Coordina:
Los LLMs viven detrás del orquestador, usados por el planner y por herramientas específicas que necesitan comprensión de lenguaje.
3. Capa de herramientas y almacenamiento
La lógica de negocio permanece en microservicios, colas y sistemas de datos existentes. Las herramientas son wrappers delgados alrededor de:
El orquestador invoca herramientas vía contratos estrictos, mientras los sistemas de almacenamiento siguen siendo la fuente de verdad.
Aplica auth y cuotas en el gateway; aplica seguridad, acceso a datos y políticas en el orquestador. Todas las llamadas (LLM y herramientas) emiten telemetría estructurada a un pipeline que alimenta:
Una arquitectura más simple (gateway → orquestador único → herramientas) es más fácil de operar; añadir planners separados, engines de política y gateways de modelos incrementa flexibilidad a costa de más coordinación, latencia y complejidad operacional.
Ahora tienes los ingredientes básicos para agentes que se comporten de forma predecible bajo carga real: máquinas de estados explícitas, contratos de herramientas claros, reintentos disciplinados y observabilidad profunda. El paso final es convertir esas ideas en una práctica repetible para tu equipo.
Piensa en cada agente como un workflow con estado:
Cuando estas piezas se alinean, obtienes sistemas que se degradan con gracia en lugar de colapsar ante casos límite.
Antes de enviar un agente prototipo a usuarios reales, confirma:
Si falta alguno, aún estás en modo prototipo.
Una estructura sostenible suele separar:
Esto permite a los equipos de producto moverse rápido mientras los equipos de plataforma garantizan fiabilidad, seguridad y control de costes.
Una vez que tengas cimientos estables, puedes explorar:
El progreso aquí debe ser incremental: introduce nuevos componentes de aprendizaje tras feature flags, con evaluación offline y salvaguardas fuertes.
El tema a lo largo de todo esto es el mismo: diseña para el fallo, prefiere claridad sobre la ingeniosidad e itera donde puedas observar y revertir con seguridad. Con esas restricciones en su lugar, los sistemas agenticos dejan de ser prototipos temibles y se convierten en infraestructura de la que tu organización puede depender.
Un sistema agentico es una aplicación donde un LLM no se limita a responder un único prompt, sino que decide qué hacer a continuación: qué herramientas invocar, qué datos recuperar, qué paso de un flujo ejecutar y cuándo debe detenerse.
A diferencia de una simple finalización de chat, un sistema agentico combina:
En producción, el LLM se convierte en un componente de decisión dentro de una envoltura determinista más amplia, no en todo el sistema.
Los demos suelen ejecutarse en una ruta feliz: un usuario, comportamiento ideal de las herramientas, sin timeouts, sin deriva de esquemas y conversaciones cortas. En producción, los agentes se enfrentan a:
Sin flujos explícitos, contratos y manejo de fallos, estos factores generan bucles, bloqueos, trabajo parcial y errores silenciosos que no aparecen en entornos de demo.
Haz que el LLM opere dentro de una estructura clara en lugar de un bucle libre:
Modela el agente como un flujo de trabajo con estados nombrados y eventos tipados en lugar de while not done: call LLM.
Los estados típicos pueden incluir:
Diseña las herramientas como APIs de producción, no como descripciones en prosa. Cada herramienta debería tener:
Asume que cualquier llamada externa fallará alguna vez y diseña en torno a eso.
Patrones clave:
Separa el estado de corto plazo de la memoria de largo plazo y mantén el LLM sin estado.
Piensa en tu sistema de agentes como un sistema distribuido bajo carga, incluso si cada flujo parece secuencial.
Para mantener la fiabilidad:
Necesitas poder responder “¿qué hizo el agente?” y “¿por qué lo hizo?” para cualquier tarea.
Requisitos prácticos:
Trata a los agentes como servicios en evolución y gánalos con el mismo rigor que otros sistemas de producción.
Prácticas recomendadas:
Esto te permite explicar, probar y depurar el comportamiento paso a paso en lugar de perseguir bucles opacos de “pensamiento del agente”.
PLAN – interpretar la solicitud y producir un plan paso a pasoCALL_TOOL – invocar una herramienta específica o lotes de herramientasVERIFY – comprobar salidas contra reglas simples o verificaciones secundarias con modelosRECOVER – manejar errores mediante reintentos, alternativas o escaladoDONE / FAILED – resultados terminalesLos eventos (por ejemplo, ToolCallSucceeded, TimeoutExceeded) junto con el estado actual determinan el siguiente estado. Esto hace que los reintentos, timeouts y el manejo de errores sean explícitos en vez de estar escondidos en prompts o código “pegamento”.
InvalidInput, NotFound, RateLimited, TransientFailureValida las entradas antes de llamar a la herramienta y las salidas después. Versiona los contratos de las herramientas y fija a los agentes a una versión para que los cambios de esquema no rompan los flujos silenciosamente.
request_id estable o una clave de negocio y devolver el mismo resultado si se llaman de nuevo.Esto mantiene la fiabilidad alta sin crear bucles descontrolados, efectos secundarios duplicados o costos desmesurados.
Evita usar registros crudos o todo el historial de conversación como “memoria”; en lugar de eso, deriva registros compactos y estructurados con reglas claras de retención y privacidad.
Monitorea la profundidad de colas, percentiles de latencia y tasas de 429/503 para detectar sobrecarga antes de que se convierta en un incidente.
Con esto, la investigación de incidentes pasa de “el agente parece inestable” a localizar el estado, la herramienta y el cambio exacto que causó la regresión.
Esto permite mejorar agentes continuamente mientras mantienes los fallos contenidos, diagnosticables y reversibles.