Explosión de presupuesto: cuando los costos del agente se disparan

La explosión de presupuesto ocurre cuando la ejecución sin control hace crecer rápidamente los costos del agente. Cómo evitarlo con límites y budgets.
En esta página
  1. El problema
  2. Por qué pasa
  3. Fallos más frecuentes
  4. Crecimiento acumulativo del contexto (Context cost creep)
  5. Fan-out inflado de herramientas (Tool fan-out spike)
  6. Amplificación de retries entre capas
  7. Bola de nieve en la cola (Queue cost snowball)
  8. Cómo detectar estos problemas
  9. Cómo distinguir explosión de presupuesto de una tarea realmente cara
  10. Cómo parar este tipo de fallos
  11. Dónde vive esto en la arquitectura
  12. Autoevaluación
  13. FAQ
  14. Páginas relacionadas

El problema

La solicitud parece simple: verificar el pago de varios pedidos y devolver un resumen corto.

En las trazas se ve otra cosa: en 14 minutos, un run hizo 63 pasos, 41 llamadas a herramientas y quemó cerca de $11.80. Para esta clase de tarea, lo normal suele ser ~$0.20-0.30.

No hay un fallo evidente: parte de las llamadas devuelve 200, el agente formalmente "funciona", pero la cola de runs crece y cost_per_run sale del presupuesto ya en los primeros minutos.

El sistema no se cae de golpe.

Simplemente infla poco a poco la factura y la cola de runs, hasta que el gasto sale de los límites.

Analogía: imagina un taxi con el taxímetro que nunca se reinicia entre viajes. El coche se mueve, cambian los pasajeros, pero el importe solo se acumula. La explosión de presupuesto en agentes se ve igual: el trabajo parece avanzar, pero los costos crecen más rápido que el valor.

Por qué pasa

La explosión de presupuesto casi nunca aparece por una única llamada cara, sino por falta de control estricto del costo acumulado en runtime.

En producción, normalmente se combina así:

  1. el contexto y la history crecen turn tras turn, así que cada llamada al modelo cuesta más;
  2. un paso del agente puede disparar fan-out de herramientas, y el costo se multiplica;
  3. los retries viven en varias capas y convierten un fallo corto en una ola larga de gasto;
  4. no existe un budget gate único para pasos, tokens, llamadas a tools, tiempo y USD;
  5. sin stop reasons y métricas de costo, el incidente se ve solo cuando llega la factura.

En traza se ve como crecimiento simultáneo de prompt_tokens, tool_calls y retry_attempts, donde cada paso siguiente cuesta más que el anterior.

Sin budget gate al nivel de runtime, cada nuevo paso solo empeora el incidente.

Fallos más frecuentes

En producción se repiten sobre todo cuatro patrones de explosión de presupuesto.

Crecimiento acumulativo del contexto (Context cost creep)

El prompt crece sin prioridades: history, retrieval y salida de tools se agregan casi sin límites.

Causa típica: no hay max_prompt_tokens, caps de fuentes ni nivel de summarization.

Fan-out inflado de herramientas (Tool fan-out spike)

Un solo paso lanza demasiadas llamadas externas, muchas veces en paralelo. Incluso sin errores, eso sube de golpe el costo del run.

Causa típica: no hay caps por herramienta ni bounded fan-out.

Amplificación de retries entre capas

Runtime, tool gateway y SDK hacen retries al mismo tiempo. Una degradación corta de una dependencia se vuelve una ola larga de gasto repetido.

Causa típica: la policy de retry no está centralizada en un solo punto.

Bola de nieve en la cola (Queue cost snowball)

Runs largos y caros ocupan workers, el backlog crece, y los nuevos runs también salen más caros por espera y timeout.

Causa típica: no hay max_seconds, max_steps estrictos ni stop reason para overflow de budget.

Cómo detectar estos problemas

La explosión de presupuesto se ve bien por la combinación de métricas de costo, runtime y cola.

MétricaSeñal de explosión de presupuestoQué hacer
cost_per_runcrecimiento brusco del costo de un runactivar max_usd y budget gate antes de cada paso
tool_cost_sharela parte de costo en tools es desproporcionadalimitar fan-out y añadir caps por herramienta
retry_attempts_per_runmuchas repeticiones de las mismas llamadascentralizar retries en tool gateway y añadir retry budget
prompt_tokens_per_runsubida estable de tokens sin mejora de calidadcaps en fuentes de contexto + summarization
queue_backlogla cola crece junto con runs largos y caroslimitar max_seconds, terminar runs runaway de forma controlada

Cómo distinguir explosión de presupuesto de una tarea realmente cara

No toda tarea cara implica un incidente. La pregunta clave: si el costo extra aporta una mejora de calidad predecible.

Es normal si:

  • el costo crece junto con precisión o cobertura en una tarea compleja;
  • existe un perfil de gasto controlado para esa clase de solicitudes;
  • cost_per_success se mantiene dentro de la unit economics objetivo.

Es peligroso si:

  • el costo crece más rápido que la tasa de éxito;
  • se repiten los mismos retries y firmas de tools sin señal nueva;
  • el presupuesto "explota" sin cambios en la complejidad de la tarea ni en SLA.

Cómo parar este tipo de fallos

En la práctica, el patrón es este:

  1. definir execution budgets: max_steps, max_seconds, max_prompt_tokens, max_tool_calls, max_usd;
  2. revisar budget gate en cada paso, no solo al final del run;
  3. centralizar retries en un único tool gateway y cortar errores non-retryable;
  4. si se supera el límite, devolver stop reason, partial/fallback y alerta.

Guard mínimo para control de presupuesto:

PYTHON
from dataclasses import dataclass
import time


@dataclass(frozen=True)
class BudgetLimits:
    max_steps: int = 30
    max_seconds: int = 120
    max_prompt_tokens: int = 12000
    max_tool_calls: int = 20
    max_retries: int = 6
    max_usd: float = 2.0


@dataclass
class BudgetUsage:
    steps: int = 0
    prompt_tokens: int = 0
    completion_tokens: int = 0
    tool_calls: int = 0
    retries: int = 0
    model_usd: float = 0.0
    tool_usd: float = 0.0


def estimate_model_usd(prompt_tokens: int, completion_tokens: int) -> float:
    # Placeholder pricing: replace with your real model pricing.
    return (prompt_tokens / 1000) * 0.003 + (completion_tokens / 1000) * 0.015


class BudgetGuard:
    def __init__(self, limits: BudgetLimits = BudgetLimits()):
        self.limits = limits
        self.usage = BudgetUsage()
        self.started_at = time.time()

    def total_usd(self) -> float:
        return self.usage.model_usd + self.usage.tool_usd

    def on_step(self) -> None:
        self.usage.steps += 1

    def on_model_call(self, prompt_tokens: int, completion_tokens: int) -> None:
        self.usage.prompt_tokens += prompt_tokens
        self.usage.completion_tokens += completion_tokens
        self.usage.model_usd = estimate_model_usd(
            self.usage.prompt_tokens,
            self.usage.completion_tokens,
        )

    def on_tool_call(self, tool_cost_usd: float = 0.0) -> None:
        self.usage.tool_calls += 1
        self.usage.tool_usd += tool_cost_usd

    def on_retry(self) -> None:
        self.usage.retries += 1

    def check(self) -> str | None:
        elapsed_s = time.time() - self.started_at

        if self.usage.steps > self.limits.max_steps:
            return "budget:max_steps"
        if elapsed_s > self.limits.max_seconds:
            return "budget:timeout"
        if self.usage.prompt_tokens > self.limits.max_prompt_tokens:
            return "budget:prompt_tokens"
        if self.usage.tool_calls > self.limits.max_tool_calls:
            return "budget:tool_calls"
        if self.usage.retries > self.limits.max_retries:
            return "budget:retries"
        if self.total_usd() > self.limits.max_usd:
            return "budget:usd"
        return None

Este es un guard básico. En producción suele ampliarse con límites por herramienta, backoff + jitter y budgets separados para la parte de modelo y de tool. check() se llama después de cada paso antes de planear la siguiente acción. on_model_call(...) y on_tool_call(...) actualizan usage justo tras la llamada real, para que la stop reason refleje el costo real del run.

Dónde vive esto en la arquitectura

En producción, el control de explosión de presupuesto casi siempre se reparte entre tres capas del sistema.

Agent Runtime mantiene execution budgets, stop reasons y cierre controlado de runs. Aquí el budget se vuelve una regla, no un deseo.

Tool Execution Layer controla fan-out, retries, timeouts y costo de llamadas externas. Si los retries se reparten entre varias capas, el gasto casi siempre se multiplica.

Memory Layer controla qué entra al prompt y qué queda en memoria de largo plazo. Sin esta capa, el costo en tokens crece de forma estable incluso sin tareas más complejas.

Autoevaluación

Verificación rápida antes del release. Marca los puntos y mira el estado abajo.
Este es un sanity-check corto, no una auditoría formal.

Progreso: 0/7

⚠ Hay señales de riesgo

Faltan controles básicos. Cierra los puntos clave del checklist antes del release.

FAQ

Q: ¿Necesito cálculo exacto de costo para usar budget guard?
A: No. Al inicio basta con una estimación conservadora. El objetivo no es contabilidad financiera, sino parar pronto runs runaway.

Q: ¿Con qué límite conviene empezar?
A: Empieza con max_usd y max_seconds conservadores, y súbelos solo donde haya mejora de calidad demostrada.

Q: ¿Qué hacer si el budget se agota en una solicitud importante?
A: Devuelve una stop reason explícita, muestra resultado partial y ofrece escalado controlado (tier superior o revisión manual).

Q: ¿Dónde deben vivir los retries para no inflar costos?
A: En un solo choke point, normalmente en el tool gateway. Cuando hay retries en varias capas, la explosión de presupuesto casi es inevitable.


La explosión de presupuesto casi nunca parece un accidente ruidoso. Es una degradación financiera lenta que normalmente solo se ve en métricas y en comparación con baseline. Por eso, los agentes de producción necesitan no solo mejores modelos, sino control estricto de execution budget.

Páginas relacionadas

Si este problema aparece en producción, también conviene revisar:

⏱️ 8 min de lecturaActualizado 12 de marzo de 2026Dificultad: ★★☆
Implementar en OnceOnly
Guardrails for loops, retries, and spend escalation.
Usar en OnceOnly
# onceonly guardrails (concept)
version: 1
budgets:
  max_steps: 25
  max_tool_calls: 12
  max_seconds: 60
  max_usd: 1.00
policy:
  tool_allowlist:
    - search.read
    - http.get
controls:
  loop_detection:
    enabled: true
    dedupe_by: [tool, args_hash]
  retries:
    max: 2
    backoff_ms: [200, 800]
stop_reasons:
  enabled: true
logging:
  tool_calls: { enabled: true, store_args: false, store_args_hash: true }
Integrado: control en producciónOnceOnly
Guardrails para agentes con tool-calling
Lleva este patrón a producción con gobernanza:
  • Presupuestos (pasos / topes de gasto)
  • Kill switch y parada por incidente
  • Audit logs y trazabilidad
  • Idempotencia y dedupe
  • Permisos de herramientas (allowlist / blocklist)
Mención integrada: OnceOnly es una capa de control para sistemas de agentes en producción.
Ejemplo de policy (concepto)
# Example (Python — conceptual)
policy = {
  "budgets": {"steps": 20, "seconds": 60, "usd": 1.0},
  "controls": {"kill_switch": True, "audit": True},
}

Autor

Nick — ingeniero que construye infraestructura para agentes de IA en producción.

Enfoque: patrones de agentes, modos de fallo, control del runtime y fiabilidad del sistema.

🔗 GitHub: https://github.com/mykolademyanov


Nota editorial

Esta documentación está asistida por IA, con responsabilidad editorial humana sobre la exactitud, la claridad y la relevancia en producción.

El contenido se basa en fallos reales, post-mortems e incidentes operativos en sistemas de agentes de IA desplegados.