DEV Community

Cover image for ¿Los costos de los agentes IA crecen exponencial? Corrí mis logs y la respuesta me sorprendió
Juan Torchia
Juan Torchia

Posted on • Originally published at juanchi.dev

¿Los costos de los agentes IA crecen exponencial? Corrí mis logs y la respuesta me sorprendió

Un thread en Hacker News llegó a 208 puntos esta semana preguntando si los costos de los agentes IA crecen exponencialmente con la complejidad. La discusión es mayormente teórica — modelos matemáticos, análisis de complejidad algorítmica, extrapolaciones. Interesante. Pero yo tengo algo mejor: meses de logs reales de agentes que corrí en producción y en proyectos propios. Y la respuesta empírica es completamente diferente a lo que el thread concluye. No es exponencial. Pero tampoco es lineal ni predecible. Son saltos. Saltos discretos que vos generás sin darte cuenta.

Costos agentes IA 2025: qué dice la teoría vs. qué dicen mis logs

La hipótesis popular — la que el thread de HN da casi por sentada — es que si un agente maneja tareas de complejidad N, el costo en tokens crece como O(N²) o peor. La lógica es intuitiva: más contexto, más herramientas, más iteraciones, todo multiplicado entre sí.

Mi experiencia dice otra cosa.

Llevé tres meses de logs de agentes: el sistema de curación que describí en el post sobre Awesome desactualizadas, los experimentos con SPICE + Claude Code, las métricas que empecé a registrar después de armar CodeBurn, y algunos agentes de automatización interna que no publiqué. En total: 847 runs de agente, 23 tareas distintas, tres modelos diferentes.

Cuando grafiqué costo vs. complejidad de tarea, esperaba una curva. Lo que vi fueron escalones.

# Análisis de distribución de costos por run
# Datos reales anonimizados de mis logs

import pandas as pd
import numpy as np

# Cargo los logs exportados de CodeBurn
df = pd.read_csv('agent_runs_q1_q2_2025.csv')

# Clasifico por rango de costo
df['rango_costo'] = pd.cut(
    df['total_tokens'],
    bins=[0, 5000, 20000, 80000, 200000, np.inf],
    labels=['micro', 'pequeño', 'mediano', 'grande', 'monstruoso']
)

# Lo que esperaba: distribución gradual
# Lo que encontré: agrupamiento fuerte en rangos
print(df['rango_costo'].value_counts())

# Output real:
# pequeño      312  (36.8%)
# micro        298  (35.2%)
# mediano      187  (22.1%)
# grande        41  ( 4.8%)
# monstruoso     9  ( 1.1%)
Enter fullscreen mode Exit fullscreen mode

El 72% de mis runs vive en los dos rangos más baratos. Los runs "monstruosos" son 9. Nueve. En tres meses.

Pero esos 9 runs representaron el 31% de mi gasto total en API.

Dónde están los saltos: las decisiones que no parecen decisiones

Acá es donde se pone interesante. Cuando fui a investigar qué causaba los saltos — especialmente los runs grandes y monstruosos — encontré patrones muy específicos. No es complejidad de la tarea. Es cómo diseñé el agente.

Salto 1: el contexto acumulativo sin límite

El error más caro que cometí fue en el agente de curación. El diseño inicial acumulaba el historial completo de decisiones en el contexto del agente. La lógica era: "necesita saber qué decidió antes para ser consistente".

Correcto en teoría. Catastrófico en práctica.

// Versión original — la que me costó caro
async function procesarBatch(items: CuratedItem[], historial: Decision[]) {
  const contexto = {
    // ERROR: historial completo siempre incluido
    // Con 200 items procesados, esto se volvió enorme
    historialCompleto: historial,  // ← acá está el problema
    itemActual: items[0]
  }

  return await claude.complete(buildPrompt(contexto))
}

// Versión corregida — ventana deslizante
async function procesarBatchV2(items: CuratedItem[], historial: Decision[]) {
  const contexto = {
    // Solo las últimas N decisiones relevantes
    historialReciente: historial.slice(-10),  // ← ventana fija
    // Resumen comprimido del historial anterior
    resumenHistorial: historial.length > 10 
      ? await generarResumen(historial.slice(0, -10))
      : null,
    itemActual: items[0]
  }

  return await claude.complete(buildPrompt(contexto))
}
Enter fullscreen mode Exit fullscreen mode

Este cambio solo redujo el costo de ese agente un 67%. No cambié el modelo. No cambié la tarea. Cambié cómo manejo el contexto.

Salto 2: el modelo "por las dudas"

Después de la conversación sobre escasez en modelos frontier, revisé qué modelo estaba usando para cada subtarea de mis agentes. Encontré algo que me dio vergüenza: usaba Opus para tareas de clasificación simple porque "total, si falla el agente entero es un problema".

Eso es miedo disfrazado de arquitectura.

La realidad: para clasificar si una URL es relevante o no, Claude Haiku con un prompt bien escrito tiene 94% de accuracy en mi dataset. Opus tiene 97%. Pago 15x más por 3 puntos porcentuales en una tarea donde el error tiene costo cero (simplemente reclasifico el caso dudoso).

// Mapa de modelo por tipo de tarea — lo que implementé
const MODELO_POR_TAREA = {
  // Clasificación binaria simple → modelo barato
  clasificacion_relevancia: 'claude-haiku-4-5',

  // Extracción estructurada → modelo medio
  extraccion_metadata: 'claude-sonnet-4-5',

  // Razonamiento complejo, decisiones con consecuencias → modelo caro
  analisis_arquitectura: 'claude-opus-4-5',

  // Generación de código con contexto amplio → modelo medio
  generacion_codigo: 'claude-sonnet-4-5',
} as const

type TipoTarea = keyof typeof MODELO_POR_TAREA

async function ejecutarConModeloCorrecto(
  tarea: TipoTarea, 
  prompt: string
) {
  const modelo = MODELO_POR_TAREA[tarea]
  return await anthropic.messages.create({
    model: modelo,
    messages: [{ role: 'user', content: prompt }],
    max_tokens: 1024
  })
}
Enter fullscreen mode Exit fullscreen mode

Salto 3: el loop sin condición de salida

Este me costó la friolera de $23 en una noche. Un agente diseñado para iterar hasta "estar satisfecho" con el resultado. Sin definir qué significa estar satisfecho. Sin límite de iteraciones.

El agente corrió 47 veces sobre la misma tarea.

// El error clásico
async function agenteIterativo(tarea: string) {
  let resultado = ''
  let satisfecho = false

  // SIN LÍMITE — esto es una bomba de tiempo
  while (!satisfecho) {
    resultado = await ejecutarPaso(tarea, resultado)
    satisfecho = await evaluarCalidad(resultado)  // LLM evaluando LLM
  }

  return resultado
}

// Versión con circuit breaker
async function agenteIterativoSeguro(
  tarea: string,
  maxIteraciones: number = 5  // límite explícito siempre
) {
  let resultado = ''
  let iteracion = 0

  while (iteracion < maxIteraciones) {
    resultado = await ejecutarPaso(tarea, resultado)

    const evaluacion = await evaluarCalidad(resultado)
    if (evaluacion.score >= 0.85) break  // umbral numérico, no vibe check

    iteracion++

    // Log para detectar loops costosos
    if (iteracion >= 3) {
      console.warn(`⚠️ Agente en iteración ${iteracion} — revisar diseño`)
    }
  }

  return { resultado, iteraciones: iteracion }
}
Enter fullscreen mode Exit fullscreen mode

Esta combinación — loops sin límite + LLM evaluando LLM — es el patrón más caro que vi en mis logs. El agente de inferencia en edge con Cloudflare me enseñó que mover el punto de evaluación puede cambiar radicalmente el costo de un loop.

Los gotchas que no están en ningún tutorial

El costo de la "memoria" mal implementada. Todos los frameworks de agentes tienen algún tipo de memoria. Casi ninguno te explica que la memoria ingenua — guardar todo — es exponencial en costo. Cada mensaje nuevo paga por todos los mensajes anteriores. Necesitás compression activa o retrieval selectivo, no append.

El JSON innecesariamente grande. Mis agentes transmiten estado en JSON. Durante semanas no pensé en el tamaño de ese JSON. Tenía campos de debug, metadata redundante, timestamps en formato ISO completo. Comprimir el schema del JSON que circula en el contexto del agente me ahorró en promedio 800 tokens por llamada. Parece poco. Con 300 llamadas al día no es poco.

El system prompt que se duplica. En algunos frameworks, si no tenés cuidado, el system prompt se incluye en cada mensaje del historial además de como system. Lo descubrí mirando los logs de tokenización. Era un system prompt de 2000 tokens que aparecía 8 veces en un context window. 16.000 tokens de overhead puro.

La herramienta que siempre llama a la herramienta más cara. Si tu agente tiene herramientas con costos muy distintos (una llama a GPT-4o, otra hace un lookup en base de datos local) y el agente aprende a preferir la herramienta de LLM porque "es más flexible", vas a tener un problema de costos que parece aleatorio pero no lo es.

FAQ: Costos de agentes IA en 2025

¿Los costos de los agentes IA realmente crecen exponencialmente?
Empíricamente, en mis datos: no. Crecen en saltos discretos vinculados a decisiones de diseño específicas. El crecimiento exponencial que muestra la teoría asume contexto ilimitado y sin compresión — nadie debería diseñar un agente así. El problema real no es complejidad algorítmica sino arquitectura descuidada: contexto acumulativo sin límite, loops sin condición de salida, y selección de modelo "por las dudas".

¿Cuánto gasta en promedio un agente bien diseñado por tarea?
Depende muchísimo de la tarea, pero en mis logs el 72% de los runs quedan entre 1.000 y 20.000 tokens. Con precios actuales de Claude Sonnet, estamos hablando de $0.003 a $0.06 por run. Los runs "monstruosos" (más de 200k tokens) representan el 1% de los casos pero el 31% del gasto — ahí es donde hay que mirar.

¿Vale la pena usar modelos más baratos para subtareas?
Sí, rotundamente. El patrón de routing por complejidad de tarea — Haiku para clasificación, Sonnet para generación, Opus solo para razonamiento complejo — redujo mi gasto mensual un 40% sin degradación perceptible en calidad de output final. La clave es definir métricas de calidad por subtarea para saber qué modelo alcanza.

¿Cómo sé si mi agente tiene un problema de costos antes de que explote?
Tres señales de alerta temprana: (1) el costo por run tiene varianza muy alta — si hay runs que cuestan 10x el promedio, tenés un patrón mal diseñado, (2) el número de herramienta-calls crece más rápido que la complejidad de las tareas, (3) el tamaño promedio del contexto crece run a run en lugar de mantenerse estable. Herramientas como CodeBurn ayudan a detectar esto sistemáticamente.

¿Los circuit breakers en agentes son over-engineering?
No. Son lo mínimo viable. Un agente sin límite de iteraciones en producción es un incidente esperando pasar. El límite no tiene que ser rígido — puede ser "5 iteraciones, o cuando el score supere 0.85, lo que ocurra primero" — pero tiene que existir. El costo de un loop sin fin es potencialmente ilimitado y los LLMs no te van a decir "pará, esto no está funcionando".

¿Es mejor un agente con muchas herramientas especializadas o pocas herramientas generales?
En costos: muchas herramientas especializadas gana, siempre que el routing sea bueno. El problema de las herramientas generales es que el agente tiende a usarlas para todo, incluyendo casos donde una herramienta barata y específica hubiera bastado. El overhead de routing con más herramientas es real pero menor que el overhead de usar una herramienta cara cuando no hace falta.

La conclusión que no me esperaba

Empecé este análisis para responder el thread de HN. Terminé dándome cuenta de algo más incómodo: la mayoría de mis runs caros los generé yo. No por la complejidad de las tareas. Por decisiones de diseño que tomé en 30 segundos, sin pensar en el costo, porque "funcionaba".

El crecimiento exponencial de costos en agentes es un mito parcialmente verdadero. Es verdad si diseñás sin pensar. Es falso si tratás el contexto, los loops y la selección de modelos como decisiones de arquitectura con consecuencias económicas reales.

La buena noticia: una vez que encontrás los saltos en tus propios logs, son fáciles de eliminar. No requieren cambiar el modelo ni la tarea ni el framework. Requieren cambiar cómo pensás sobre el estado y el contexto de tu agente.

La mala noticia: nadie te va a avisar que los estás generando hasta que llegue la factura.

Si no estás midiendo tus runs, empezá hoy. No mañana. Hoy.

Top comments (0)