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í:
- el contexto y la history crecen turn tras turn, así que cada llamada al modelo cuesta más;
- un paso del agente puede disparar fan-out de herramientas, y el costo se multiplica;
- los retries viven en varias capas y convierten un fallo corto en una ola larga de gasto;
- no existe un budget gate único para pasos, tokens, llamadas a tools, tiempo y USD;
- 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étrica | Señal de explosión de presupuesto | Qué hacer |
|---|---|---|
cost_per_run | crecimiento brusco del costo de un run | activar max_usd y budget gate antes de cada paso |
tool_cost_share | la parte de costo en tools es desproporcionada | limitar fan-out y añadir caps por herramienta |
retry_attempts_per_run | muchas repeticiones de las mismas llamadas | centralizar retries en tool gateway y añadir retry budget |
prompt_tokens_per_run | subida estable de tokens sin mejora de calidad | caps en fuentes de contexto + summarization |
queue_backlog | la cola crece junto con runs largos y caros | limitar 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_successse 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:
- definir execution budgets:
max_steps,max_seconds,max_prompt_tokens,max_tool_calls,max_usd; - revisar budget gate en cada paso, no solo al final del run;
- centralizar retries en un único tool gateway y cortar errores non-retryable;
- si se supera el límite, devolver stop reason, partial/fallback y alerta.
Guard mínimo para control de presupuesto:
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:
- Por qué fallan los agentes de IA - mapa general de fallos en producción.
- Token overuse - cómo el crecimiento de contexto se convierte en crecimiento de costos.
- Tool spam - cómo las llamadas repetidas a tools inflan el presupuesto.
- Tool failure - cómo la ola de errores y retries sube el costo de los runs.
- Agent Runtime - dónde colocar execution budgets y stop reasons.
- Tool Execution Layer - dónde mantener retries, fan-out y cost gates.