Image for post Lo que aprendí construyendo agentes IA en producción: la jerarquía real

Lo que aprendí construyendo agentes IA en producción: la jerarquía real


TL;DR: La mayoría de los agentes IA fallan antes de llegar a producción porque sus autores saltan directo a los frameworks sin establecer las capas previas. Este artículo describe la jerarquía de ingeniería que necesitas respetar en orden, basada en patrones que funcionan en entornos reales y en lo que no funcionó cuando los ignoré.

El problema real

Los wrappers no-code no son el problema en sí. El problema es que muchos desarrolladores ven un agente en un tutorial, lo replican en dos horas con LangChain o n8n, y cuando intentan escalarlo aparecen los fallos: el agente pierde el hilo del contexto, toma decisiones incorrectas en casos borde, o deja de responder cuando la cadena de herramientas falla en el paso tres.

El síntoma más común: un agente que funciona perfectamente en la demo y falla en producción a los cinco minutos de uso real. Según datos de LangChain, el 57,3% de las organizaciones ya tiene agentes corriendo en producción, pero Gartner predice que más del 40% de los proyectos de agentes serán cancelados antes de 2027 por costes descontrolados y comportamiento impredecible. La brecha entre "funciona en demo" y "funciona en producción" es real y documentada.

El problema no es el LLM. Es la ausencia de ingeniería en las capas que lo rodean.

El enfoque elegido

Antes de construir el primer agente con herramientas reales, vale la pena tratar el problema como lo haría con cualquier sistema de software: capas, dependencias, y orden de construcción. No construyes la capa de presentación antes de tener la base de datos. Con agentes ocurre lo mismo.

La jerarquía que me funciona en producción tiene cuatro niveles que deben respetarse en orden:

Nivel 1: dominio del modelo base

Antes de añadir herramientas o memoria, necesitas entender cómo se comporta el modelo bajo distintas condiciones. Eso significa conocer su ventana de contexto real, cómo degrada la calidad cuando el contexto se acerca al límite, y qué tipos de instrucciones producen outputs consistentes versus caóticos.

Un ejercicio práctico: toma una tarea representativa de tu caso de uso y ejecútala con el mismo prompt diez veces con temperatura 0. Si los outputs varían significativamente, el modelo no está listo para esa tarea sin más trabajo de prompt engineering.

import anthropic

def medir_consistencia(
    prompt: str,
    validar_formato: callable,
    iteraciones: int = 10
) -> dict:
    """
    Mide la consistencia del modelo para una tarea concreta.
    Devuelve tasa de formato correcto y varianza de longitud de respuesta.
    """
    client = anthropic.Anthropic()
    resultados = []

    for _ in range(iteraciones):
        mensaje = client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=1024,
            temperature=0,
            messages=[{"role": "user", "content": prompt}]
        )
        output = mensaje.content[0].text
        resultados.append({
            "valido": validar_formato(output),
            "longitud": len(output)
        })

    tasa_validos = sum(1 for r in resultados if r["valido"]) / iteraciones
    longitudes = [r["longitud"] for r in resultados]

    return {
        "tasa_consistencia": tasa_validos,
        "longitud_media": sum(longitudes) / len(longitudes),
        "varianza_longitud": max(longitudes) - min(longitudes)
    }

Nivel 2: tool use determinista

Añadir herramientas a un agente sin controlarlas es la forma más rápida de crear un sistema que falla de formas que no puedes depurar. Cada herramienta debe tener: schema de entrada tipado y validado (Pydantic funciona bien aquí), timeouts explícitos, manejo de errores que el agente pueda interpretar, y logging de cada llamada con input, output y duración.

El agente no puede recuperarse de un error que no entiende. Si tu herramienta lanza una excepción genérica, el LLM solo ve "error" y empieza a improvisar, que es exactamente lo que no quieres en producción.

from pydantic import BaseModel
from enum import Enum
from typing import Any

class EstadoHerramienta(str, Enum):
    OK = "ok"
    ERROR = "error"
    PARCIAL = "partial"  # resultado válido pero incompleto

class ResultadoHerramienta(BaseModel):
    estado: EstadoHerramienta
    datos: Any | None = None
    mensaje_error: str | None = None
    reintento_sugerido: bool = False

def buscar_documentos(consulta: str, max_resultados: int = 5) -> ResultadoHerramienta:
    """Herramienta de búsqueda con contrato de resultado explícito."""
    try:
        resultados = _ejecutar_busqueda(consulta, max_resultados)
        if not resultados:
            return ResultadoHerramienta(
                estado=EstadoHerramienta.PARCIAL,
                datos=[],
                mensaje_error="Sin resultados para la consulta proporcionada."
            )
        return ResultadoHerramienta(estado=EstadoHerramienta.OK, datos=resultados)
    except TimeoutError:
        return ResultadoHerramienta(
            estado=EstadoHerramienta.ERROR,
            mensaje_error="Timeout. Intenta con una consulta más específica.",
            reintento_sugerido=True
        )
    except Exception as e:
        return ResultadoHerramienta(
            estado=EstadoHerramienta.ERROR,
            mensaje_error=f"Error inesperado: {type(e).__name__}"
        )

Con este patrón, el LLM recibe información que puede usar para decidir si reintentar, continuar con datos parciales, o escalar el error al usuario. Los fallos silenciosos desaparecen porque el agente siempre sabe qué pasó.

Nivel 3: memoria y estado explícito

La mayoría de los fallos que he visto en producción ocurren en este nivel. Un agente reactivo, sin memoria persistente entre pasos, toma decisiones contradictorias cuando la tarea se alarga. No porque el LLM sea malo, sino porque no tiene acceso al contexto previo que generó.

La trampa más común es meter todo en el contexto. La solución correcta es diseñar qué información necesita el agente en cada paso y dónde la almacena entre pasos. Para tareas cortas puede ser un diccionario en memoria. Para tareas que requieren recuperar información semántica, una base vectorial.

En proyectos con RAG, el patrón que más me ha funcionado es separar la memoria episódica (qué ha hecho el agente en esta sesión) de la memoria semántica (qué sabe el sistema). Confundirlas produce agentes lentos y caros sin mejora proporcional en calidad.

Nivel 4: orquestación y control de flujo

Solo en este nivel tiene sentido hablar de multi-agente, jefes de orquestación, o ciclos de crítica. Sin los tres niveles anteriores estables, una arquitectura multi-agente solo multiplica los puntos de fallo. El patrón que describe el análisis de 13 agentes Claude con boss agent y ciclo de crítica ilustra bien cuándo la complejidad adicional se justifica y cuándo no.

Lo que funcionó

El cambio más efectivo fue introducir contratos explícitos entre el agente y sus herramientas, como el patrón ResultadoHerramienta del ejemplo anterior. La tasa de fallos silenciosos bajó de forma notable porque el agente siempre recibe información interpretable.

El segundo cambio que marcó diferencia fue adoptar especificaciones ejecutables antes de escribir el agente. Describir el comportamiento esperado como casos de prueba, no como instrucciones de prompt, obliga a pensar en los casos borde antes de que fallen en producción. Para ver este enfoque en más detalle, el artículo sobre Spec-Driven Multi-Agente con agtx, GSD y spec-kit es directamente aplicable.

El tercer factor fue el logging estructurado desde el primer día. Cada llamada al LLM, cada invocación de herramienta, y cada transición de estado del agente tiene un registro con campos consistentes. Según el State of Agent Engineering de LangChain, el 94% de las organizaciones con agentes en producción tienen alguna forma de observabilidad, y el 71,5% tienen tracing completo. No es casualidad: sin visibilidad, no puedes depurar ni mejorar.

Lo que falló

El error más caro fue asumir que un agente que funciona bien con herramientas simples escala directamente a herramientas con latencia variable. Cuando añadí acceso a una API externa con respuestas inconsistentes, el agente empezó a comportarse de formas no anticipadas: retries en bucle, interpretaciones erróneas de respuestas parciales, y en algún caso, acciones duplicadas porque no podía distinguir entre "la herramienta falló" y "la herramienta tardó demasiado".

El segundo fallo fue el contexto. Durante semanas mantuve el historial completo de conversación en el contexto de cada llamada al LLM. Funcionaba bien hasta que las sesiones se alargaban y el coste por sesión se triplicó sin mejora en calidad. La solución no fue comprimir el historial, sino diseñar desde cero qué información necesita el agente en cada paso. Si la gestión de contexto y tokens es algo que te preocupa, el artículo sobre CodeFire y RTK para el contexto de agentes IA cubre estrategias concretas para reducir tokens sin perder calidad de razonamiento.

El tercer fallo fue arquitectónico: usé un framework de orquestación antes de tener clara la lógica de negocio. El framework ocultó problemas que solo aparecieron cuando intenté depurar un comportamiento incorrecto en producción. No podía ver qué estaba pasando dentro. La lección: empieza sin framework hasta que entiendas exactamente qué necesitas de él.

Lo que haría diferente

Empezaría con el nivel más bajo posible que resuelva el problema. No un agente con diez herramientas y memoria persistente. Una función que llama al LLM con un prompt bien definido y devuelve un resultado validado. Añadiría complejidad solo cuando el nivel inferior esté probado y sus fallos documentados.

También invertiría más tiempo al principio en definir qué significa "correcto" para cada paso del agente. No a nivel de "el output tiene sentido", sino de "el output cumple estas condiciones verificables". Sin ese criterio, no puedes saber si el agente mejora o empeora cuando cambias algo.

Y sobre frameworks: me quedaría con las primitivas básicas del SDK del modelo antes de añadir capas de abstracción. Los frameworks son útiles cuando conoces el problema que resuelven. Si no lo conoces, añaden superficie de fallo que no controlas. Para pipelines que necesitan sobrevivir caídas de proveedores o picos de latencia, el patrón de LLM Fallback para pipelines que sobreviven caídas de API es algo que aplicaría desde el diseño inicial, no como parche posterior.

En Producción

Los costes son el factor que más cambia entre el prototipo y el sistema en producción. Un agente con cinco herramientas que hace diez llamadas al LLM por tarea puede costar menos de 0,01 € en pruebas locales y acumular 30-50 € al mes con carga real moderada. No es un problema insalvable, pero necesitas medirlo desde el principio.

Los tiempos de respuesta también cambian. Las latencias que son aceptables en desarrollo se convierten en problemas de experiencia de usuario cuando alguien está esperando. Si el agente necesita hacer llamadas en paralelo para cumplir los tiempos, ese requisito debe estar en el diseño inicial.

El 87% de los modelos de machine learning nunca llegan a producción, según datos del sector. La causa más frecuente no es técnica: es la falta de ingeniería en el ciclo completo, desde los tests automatizados hasta el monitoreo en producción. Un agente que nadie puede depurar cuando falla es un agente que tarde o temprano se desconecta.

Para infraestructura que necesita escalar o gestionar múltiples pipelines agenticos en paralelo, la arquitectura descrita en Dify para pipelines agenticos en producción cubre las consideraciones de escala que aparecen a partir de cierto volumen de uso.

Errores Comunes y Depuración

Error: El agente entra en bucle y repite la misma llamada de herramienta. Causa: La herramienta devuelve el mismo resultado o error y el agente no detecta que está atascado. Solución: Añade un contador de intentos por herramienta y una condición de salida explícita cuando se supera el límite. El campo reintento_sugerido del resultado ayuda a controlar este comportamiento.

Error: El agente produce outputs correctos en pruebas pero incorrectos con usuarios reales. Causa: Los casos de prueba no cubren la variabilidad real del input (idioma, formato, ambigüedad). Solución: Graba ejemplos de producción reales y úsalos como casos de prueba adicionales. La distribución real siempre difiere de la que imaginas al escribir los tests.

Error: Los costes de la API escalan más rápido que el número de usuarios. Causa: El contexto crece con cada paso del agente sin control. Una sesión de diez pasos puede usar diez veces más tokens que una de un paso. Solución: Implementa una estrategia de resumen de contexto o ventana deslizante. Comprime el historial antiguo antes de que el contexto alcance el 60% del límite del modelo.

¿Cuándo tiene sentido un framework de agentes en lugar de construir desde las primitivas del SDK?

Un framework tiene sentido cuando necesitas primitivas ya resueltas: ejecución paralela de herramientas, gestión de memoria multicapa, o integración con observabilidad. Si tu agente tiene menos de cuatro herramientas y una sola cadena de razonamiento, construirlo directamente con el SDK del modelo es más sencillo y más fácil de depurar.

¿Qué modelo elegir para empezar con agentes en producción?

Para prototipos, el modelo más económico que soporte tool use de forma fiable. Para producción, el que mejor combine coste por token con fiabilidad en los casos borde de tu dominio. Más de tres cuartos de las organizaciones usan múltiples modelos en producción, enrutando tareas según complejidad, coste y latencia. No hay respuesta universal: hay que medir con datos reales de tu caso de uso.

¿Cuándo pasar de agente único a arquitectura multi-agente?

Cuando un agente único no puede manejar la complejidad de la tarea sin degradar calidad, o cuando distintas partes de la tarea requieren modelos optimizados para distintos tipos de razonamiento. Antes de ese punto, la complejidad adicional raramente compensa el coste de mantenimiento.

Los agentes IA en producción no fallan por el LLM, sino por la falta de ingeniería en las capas que lo rodean. La jerarquía de nivel 1 a nivel 4 no es solo estructura: es la diferencia entre un sistema que puedes mantener y uno que depuras a ciegas. El camino más corto no es el que empieza con el framework más completo. Es el que empieza con el nivel que puedes controlar completamente.

¿En qué punto de la jerarquía te has atascado más al construir agentes? Cuéntamelo en los comentarios o en Twitter @sergiomarquezp_. El siguiente artículo cubrirá estrategias de context engineering específicas para agentes que trabajan en tareas de larga duración sin perder coherencia entre pasos.