Guías de Frameworks12 min de lectura

Optimización del rendimiento de Agno: de 2 segundos a 200ms

Agno es rápido desde el inicio. Pero alcanzar tiempos de respuesta por debajo de 200ms requiere patrones específicos.

Carolina Fogliato

5 de febrero de 2026

Agno ya es rápido. El equipo afirma 70x más rápido que LangChain, y en nuestros benchmarks, no es marketing—es real.

Pero "rápido" es relativo.

Cuando desplegamos por primera vez nuestro sistema de resolución de disputas, las respuestas del agente promediaban 2,1 segundos. Para un chatbot, está bien. Para mediación en tiempo real donde los usuarios esperan respuestas casi instantáneas, no lo está.

Necesitábamos sub-200ms.

Llegar ahí requirió patrones específicos—algunos obvios, algunos contraintuitivos. Este post desglosa exactamente qué hicimos, con ejemplos de código que puedes aplicar a tus propios despliegues de Agno.

Por qué importan los 200ms

Primero, hablemos de por qué nos preocupaba específicamente 200ms.

La investigación es clara

  • • Menos de 100ms se siente instantáneo
  • 100-300ms se siente responsivo
  • 300-1000ms se siente notable
  • • Más de 1000ms se siente lento

Para nuestro sistema de resolución de disputas, los usuarios están en situaciones emocionales. Están frustrados. Quieren respuestas. Cada segundo de latencia amplifica esa frustración.

Pero no es solo UX. A escala, la latencia se acumula:

Antes: 2,1 segundos

2.1s × 15,000 casos × 8 llamadas

= 78 horas de espera

Después: 200ms

0.2s × 15,000 casos × 8 llamadas

= 6,7 horas de espera

Son 71 horas de tiempo de usuario ahorradas. Por año. Para un solo sistema.

El punto de partida: 2,1 segundos

Empecemos con lo que teníamos. Aquí es donde se iba el tiempo:

ComponenteTiempo
Serialización de contexto50ms
Llamada LLM (GPT-4)1,400ms
Ejecución de herramientas (secuencial)500ms
Parseo de respuesta50ms
Sobrecarga100ms
Total2,100ms

GPT-4 era la mayor parte, pero no podíamos simplemente "hacer GPT-4 más rápido". Necesitábamos optimizar todo lo que controlábamos.

Patrón #1: Ejecución paralela de herramientas

La primera mejora fue obvia una vez que la miramos. Nuestro agente llamaba cuatro herramientas secuencialmente:

Llamadas secuenciales a herramientas

  1. 1. Recuperar contrato (120ms)
  2. 2. Recuperar precedentes (180ms)
  3. 3. Recuperar historial de partes (100ms)
  4. 4. Verificar reglas de jurisdicción (100ms)

Total: 500ms

Pero estas herramientas no dependen entre sí. Pueden correr en paralelo.

Después: Ejecución paralela

agent = DisputeAnalysisAgent(
    tool_execution_mode="parallel"  # Enable parallel tools
)
# Total: 180ms (longest tool)

Resultado: 500ms → 180ms. 64% de reducción en tiempo de ejecución de herramientas.

Patrón #2: Enrutamiento de modelos

Aquí va el contraintuitivo: no toda tarea necesita GPT-4.

Nuestro análisis de disputas tenía múltiples subtareas:

  • • Clasificación de casos (simple)
  • • Extracción de entidades (media)
  • • Razonamiento legal (complejo)
  • • Cálculo de confianza (simple)

GPT-4 es excesivo para clasificación. Un modelo pequeño fine-tuned es más rápido Y más barato.

Implementación del Model Router

model = ModelRouter({
    "classification": "gpt-3.5-turbo",     # Fast, cheap
    "extraction": "claude-3-haiku",         # Good at structure
    "reasoning": "gpt-4",                   # Complex tasks only
    "scoring": "gpt-3.5-turbo",            # Fast, cheap
})
TareaAntes (GPT-4)Después (enrutado)
Clasificación400ms80ms
Extracción350ms120ms
Razonamiento500ms500ms
Puntuación150ms40ms
Tiempo total LLM1,400ms740ms

Resultado: 1,400ms → 740ms. 47% de reducción en tiempo LLM.

Para casos simples (60% del volumen), omitimos GPT-4 por completo: 1,400ms → 280ms

Patrón #3: Optimización de contexto

Estábamos pasando demasiado contexto. Para un caso complejo, podía ser 15,000+ tokens de contexto.

Problema: Más tokens = más latencia. El time-to-first-token de GPT-4 escala con el tamaño del input.

Construir contexto mínimo por tarea

def build_optimized_context(case: Case, task: str) -> str:
    # Always include core identifiers
    base = f"Case: {case.id} | Type: {case.dispute_type}"

    if task == "classification":
        return base + f"\nDescription: {case.description[:500]}"

    elif task == "reasoning":
        # Only for complex reasoning do we include more
        relevant_docs = retrieve_relevant_chunks(case, top_k=3)
        return base + f"\nRelevant Sections: {relevant_docs}"

    return base

# Before: 10,000+ tokens
# After: 200-800 tokens depending on task

Resultado: Reducción promedio de 100ms solo por optimización de contexto.

Patrón #4: Streaming de respuesta con salida temprana

Para muchas tareas, no necesitamos la respuesta completa. Podemos empezar a procesar en cuanto tenemos suficiente.

Stream y salida temprana

async def get_classification(case: Case) -> str:
    async for chunk in agent.stream(prompt):
        # Check if we have enough to classify
        if classification := try_parse_classification(chunk):
            return classification  # Exit early

    # Fallback: parse complete response
    return parse_classification(chunk)

Para tareas de clasificación, típicamente salimos después de que se genera el 30-40% de la respuesta.

Resultado: 80ms → 35ms para clasificación. 56% de reducción.

Patrón #5: Caché inteligente

Muchos inputs se repiten o son similares. El caché evita cómputo redundante.

Capa 1: Caché de coincidencia exacta

Usa caché LRU con hashing de prompts. Tasa de acierto: ~15%

Capa 2: Caché semántica

Para prompts similares (no idénticos), usa caché basada en embeddings con umbral de similitud de 0.95. Tasa de acierto: ~25%

Capa 3: Caché de resultados de herramientas

Los resultados de herramientas suelen no cambiar frecuentemente. Cachéa contratos por 1 hora, reglas por 5 minutos. Tasa de acierto: ~60%

Resultado: Reducción efectiva de 30-40% en latencia promedio gracias al caché.

Patrón #6: Connection pooling y keep-alive

Este es aburrido pero impactante. Una conexión nueva = 100-200ms de overhead.

Agrupación de conexiones

http_client = httpx.Client(
    http2=True,
    limits=httpx.Limits(
        max_connections=100,
        max_keepalive_connections=20,
        keepalive_expiry=30
    )
)

agno.configure(
    http_client=http_client,
    connection_pool_size=100
)

Resultado: Reducción de 100-200ms en la primera petición, latencia baja y consistente en peticiones subsiguientes.

Patrón #7: Async de punta a punta

Si estás haciendo algo síncrono en tu pipeline de agentes, estás dejando rendimiento sobre la mesa.

Pipeline asíncrono

async def process_case(case: Case) -> Result:
    # Independent steps run in parallel
    classification, entities = await asyncio.gather(
        classify(case),
        extract_entities(case)
    )

    # Dependent step runs after
    analysis = await analyze(case, classification, entities)

    return Result(classification, entities, analysis)

Antes: 80ms + 120ms + 500ms = 700ms

Después: max(80ms, 120ms) + 500ms = 620ms

El resultado combinado

OptimizaciónReducciónNuevo total
Punto de partida2,100ms
Herramientas en paralelo-320ms1,780ms
Enrutamiento de modelos-660ms1,120ms
Optimización de contexto-100ms1,020ms
Streaming + salida temprana-45ms975ms
Caché (30% de tasa de acierto)-290ms685ms
Agrupación de conexiones-150ms535ms
Pipeline asíncrono-80ms455ms

Espera—eso son 455ms, no 200ms. Correcto. Para el caso promedio.

Casos simples (60% del volumen)

175ms

Clasificación 35ms + Extracción 60ms + Análisis 80ms

Casos complejos (40% del volumen)

650ms

Incluye GPT-4 para razonamiento complejo

Promedio ponderado: 365ms

Con caché: 255ms

Llegamos a menos de 200ms para casos simples, menos de 300ms de promedio ponderado. 88% de reducción respecto al punto de partida.

La prioridad de optimización

Si estás optimizando el rendimiento de Agno, este es el orden de prioridad:

1. Enrutamiento de modelos — Mayor impacto. No uses GPT-4 para tareas simples.

2. Ejecución paralela de herramientas — Ganancia fácil. Actívala.

3. Caché — Retornos compuestos. Empieza con resultados de herramientas.

4. Optimización de contexto — Menos tokens, menos latencia.

5. Connection pooling — Configuración única, beneficio permanente.

6. Pipeline asíncrono — Si tienes pasos independientes.

7. Streaming + salida temprana — Para tareas de clasificación/extracción.

No necesitas todas estas. Implementa 1-3 y verás una mejora dramática.

Cuándo NO optimizar

Una palabra de precaución: la optimización prematura sigue siendo una cosa.

No optimices si:

  • • Tu latencia ya es aceptable para tu caso de uso
  • • Aún estás iterando en el comportamiento del agente
  • • Aún no tienes tráfico en producción
  • • El costo de complejidad supera el beneficio de latencia

Primero haz que funcione. Luego haz que sea correcto. Después hazlo rápido.

Reflexión final

Agno es rápido. Pero "rápido" es un punto de partida, no un destino.

Los patrones aquí—enrutamiento de modelos, ejecución en paralelo, caché, optimización de contexto—no son específicos de Agno. Son principios generales para construir sistemas de IA performantes.

De 2 segundos a 200ms no es magia. Es metodología.

¿Construyendo sistemas de IA críticos en rendimiento?

Hablemos

Hemos hecho este baile de optimización en múltiples despliegues en producción.

Newsletter

Patrones de rendimiento e insights de producción—cada martes.

Únete a 2,500+ ingenieros y líderes que reciben insights prácticos de implementación de IA.

Suscríbete a AI That Ships