Módulo 4: Dashboards y Visualización
5. Panels de Cost y Tokens
Descripción de la cápsula
En software tradicional, el costo de operación es fijo: pagas por servidores al mes y ese costo no cambia con el tráfico (hasta cierto punto). En AI, el costo es variable por request. Cada llamada al LLM consume tokens, y cada token tiene un precio. Un cambio de prompt que agrega 200 tokens de contexto extra puede incrementar el costo 30% sin que ninguna otra métrica cambie. Un endpoint que accidentalmente envía el histórico completo de la conversación puede generar un cost spike de 10x en una hora.
Los paneles de costo son tu sistema de alerta temprana financiera. No sustituyen las alertas del módulo 5 — complementan los paneles de latencia que construiste en la cápsula anterior. Si la latencia te dice "algo cambió en el comportamiento", el costo te dice "algo cambió en el consumo".
Esta cápsula te enseña a construir paneles de costo con trends diarios y semanales, breakdown por modelo y endpoint, proyección de gasto mensual, y budget line overlays que hacen obvio cuando estás excediendo el presupuesto. También construyes paneles de token usage que son el driver subyacente del costo.
Anatomía del Costo en AI
La cadena: tokens → USD
Request del usuario
│
├── Prompt tokens (input)
│ ├── System prompt (~200 tokens, fijo)
│ ├── User message (~50 tokens, variable)
│ └── Context/RAG (~500 tokens, muy variable)
│ Total prompt: ~750 tokens
│
└── Completion tokens (output)
└── LLM response (~200 tokens, variable)
Total completion: ~200 tokens
Costo = (prompt_tokens × prompt_price) + (completion_tokens × completion_price)
gpt-4o-mini: (750 × $0.00015/1K) + (200 × $0.0006/1K) = $0.000233
gpt-4o: (750 × $0.0025/1K) + (200 × $0.01/1K) = $0.003875
Diferencia: gpt-4o cuesta 16.6x más que gpt-4o-mini por el mismo request
Esa diferencia de 16x es por qué necesitas breakdown por modelo. Un solo endpoint que usa gpt-4o en vez de gpt-4o-mini puede dominar tu factura.
Métricas Prometheus para costo
from prometheus_client import Counter, Gauge
AI_COST = Counter(
"ai_cost_usd_total",
"Total cost in USD",
["model", "endpoint"],
)
AI_TOKENS = Counter(
"ai_tokens_total",
"Total tokens used",
["model", "endpoint", "type"],
)
AI_COST_PER_REQUEST = Gauge(
"ai_cost_per_request_usd",
"Cost of the last request in USD",
["model", "endpoint"],
)
AI_TOKEN_BUDGET_REMAINING = Gauge(
"ai_token_budget_remaining",
"Remaining token budget for current period",
["model"],
)
Panel 1: Cost Trend — Hourly Rate
El panel más importante de cost. Muestra cuánto estás gastando por hora como time series.
PromQL
# Costo total por hora
sum(rate(ai_cost_usd_total[1h])) * 3600
# Costo por hora, desglosado por modelo
sum(rate(ai_cost_usd_total[1h])) by (model) * 3600
# Costo por hora, desglosado por endpoint
sum(rate(ai_cost_usd_total[1h])) by (endpoint) * 3600
Panel JSON
import json
cost_trend_panel = {
"title": "Cost per Hour",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 0},
"fieldConfig": {
"defaults": {
"unit": "currencyUSD",
"custom": {
"lineWidth": 2,
"fillOpacity": 20,
"gradientMode": "scheme",
"showPoints": "never",
"axisSoftMin": 0,
},
"thresholds": {
"mode": "absolute",
"steps": [
{"value": None, "color": "green"},
{"value": 0.50, "color": "yellow"},
{"value": 1.00, "color": "red"},
],
},
},
},
"targets": [
{
"refId": "A",
"expr": "sum(rate(ai_cost_usd_total[1h])) * 3600",
"legendFormat": "Total cost/hour",
},
],
"options": {
"tooltip": {"mode": "single"},
"legend": {"displayMode": "table", "placement": "bottom", "calcs": ["mean", "max", "lastNotNull"]},
},
}
print(json.dumps(cost_trend_panel, indent=2))
Los thresholds de costo dependen de tu presupuesto. Si tu budget mensual es $300, eso es ~$0.42/hora. El threshold amarillo en $0.50 te avisa cuando estás por encima del rate sostenible.
Panel 2: Cost by Model — Stacked Area
Muestra qué modelo consume más presupuesto. Fundamental para decisiones de cost optimization.
PromQL
# Costo acumulado hoy, por modelo
sum(increase(ai_cost_usd_total[1d])) by (model)
# Costo por hora, por modelo (para time series)
sum(rate(ai_cost_usd_total[1h])) by (model) * 3600
Panel JSON
cost_by_model_panel = {
"title": "Cost by Model (Stacked)",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 0},
"fieldConfig": {
"defaults": {
"unit": "currencyUSD",
"custom": {
"fillOpacity": 40,
"stacking": {"mode": "normal", "group": "A"},
"lineWidth": 1,
"axisSoftMin": 0,
},
},
},
"targets": [
{
"refId": "A",
"expr": "sum(rate(ai_cost_usd_total[1h])) by (model) * 3600",
"legendFormat": "{{model}}",
},
],
"options": {
"tooltip": {"mode": "multi", "sort": "desc"},
"legend": {"displayMode": "table", "placement": "bottom", "calcs": ["mean", "lastNotNull"]},
},
}
print(json.dumps(cost_by_model_panel, indent=2))
Si el área de gpt-4o domina el gráfico, sabes exactamente dónde optimizar: migrar endpoints de gpt-4o a gpt-4o-mini donde la calidad lo permita.
Panel 3: Cost Today — Stat Panel
Stat panel que muestra el gasto acumulado del día con color-coding respecto al budget diario.
PromQL
# Costo acumulado hoy
sum(increase(ai_cost_usd_total[1d]))
Panel JSON
cost_today_stat = {
"title": "Cost Today",
"type": "stat",
"gridPos": {"h": 4, "w": 4, "x": 0, "y": 0},
"fieldConfig": {
"defaults": {
"unit": "currencyUSD",
"thresholds": {
"mode": "absolute",
"steps": [
{"value": None, "color": "green"},
{"value": 10, "color": "yellow"},
{"value": 25, "color": "red"},
],
},
"color": {"mode": "thresholds"},
"decimals": 2,
},
},
"targets": [
{
"refId": "A",
"expr": "sum(increase(ai_cost_usd_total[1d]))",
},
],
"options": {
"graphMode": "area",
"reduceOptions": {"calcs": ["lastNotNull"]},
},
}
print(json.dumps(cost_today_stat, indent=2))
Panel 4: Cost Projection — Monthly Estimate
Proyecta cuánto gastarás al mes si el rate actual se mantiene. Un stat panel que hace la multiplicación simple.
PromQL
# Proyección mensual basada en el rate de las últimas 24h
sum(increase(ai_cost_usd_total[1d])) * 30
# Proyección más estable basada en los últimos 7 días
sum(increase(ai_cost_usd_total[7d])) / 7 * 30
Panel JSON
cost_projection_panel = {
"title": "Projected Monthly Cost",
"type": "stat",
"gridPos": {"h": 4, "w": 4, "x": 4, "y": 0},
"fieldConfig": {
"defaults": {
"unit": "currencyUSD",
"thresholds": {
"mode": "absolute",
"steps": [
{"value": None, "color": "green"},
{"value": 200, "color": "yellow"},
{"value": 500, "color": "red"},
],
},
"color": {"mode": "thresholds"},
"decimals": 0,
},
},
"targets": [
{
"refId": "A",
"expr": "sum(increase(ai_cost_usd_total[7d])) / 7 * 30",
},
],
"options": {
"graphMode": "none",
"reduceOptions": {"calcs": ["lastNotNull"]},
},
}
print(json.dumps(cost_projection_panel, indent=2))
La proyección basada en 7 días es más estable que la de 24 horas (menos ruido por días atípicos). Los thresholds de yellow en $200 y red en $500 dependen de tu presupuesto — ajústalos según tu caso.
Panel 5: Token Usage — Stacked by Type
Tokens son el driver del costo. Este panel muestra prompt vs completion tokens por modelo.
PromQL
# Tokens por minuto, por modelo y tipo
sum(rate(ai_tokens_total[5m])) by (model, type) * 60
# Token ratio (prompt/completion)
sum(rate(ai_tokens_total{type="prompt"}[5m]))
/
sum(rate(ai_tokens_total{type="completion"}[5m]))
# Total tokens hoy
sum(increase(ai_tokens_total[1d]))
Panel JSON
token_usage_panel = {
"title": "Token Usage by Model & Type",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 8},
"fieldConfig": {
"defaults": {
"unit": "tokens/min",
"custom": {
"fillOpacity": 30,
"stacking": {"mode": "normal", "group": "A"},
"lineWidth": 1,
},
},
},
"targets": [
{
"refId": "A",
"expr": 'sum(rate(ai_tokens_total{type="prompt"}[5m])) by (model) * 60',
"legendFormat": "{{model}} prompt",
},
{
"refId": "B",
"expr": 'sum(rate(ai_tokens_total{type="completion"}[5m])) by (model) * 60',
"legendFormat": "{{model}} completion",
},
],
"options": {
"tooltip": {"mode": "multi", "sort": "desc"},
"legend": {"displayMode": "table", "placement": "bottom", "calcs": ["mean", "max"]},
},
}
print(json.dumps(token_usage_panel, indent=2))
El stacked area muestra la composición del consumo de tokens. Si los prompt tokens crecen pero los completion tokens se mantienen, algo está enviando más contexto — quizás un cambio en el prompt template o el RAG retrieval trae más documentos.
Panel 6: Cost per Request — Trend
El costo promedio por request es una métrica derivada que revela cambios sutiles.
PromQL
# Costo promedio por request (últimas 24h)
sum(increase(ai_cost_usd_total[1h]))
/
sum(increase(ai_requests_total[1h]))
# Costo promedio por request, por modelo
sum(increase(ai_cost_usd_total[1h])) by (model)
/
sum(increase(ai_requests_total[1h])) by (model)
Panel JSON
cost_per_request_panel = {
"title": "Cost per Request (1h window)",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 8},
"fieldConfig": {
"defaults": {
"unit": "currencyUSD",
"decimals": 6,
"custom": {
"lineWidth": 2,
"fillOpacity": 10,
"showPoints": "never",
},
},
},
"targets": [
{
"refId": "A",
"expr": "sum(increase(ai_cost_usd_total[1h])) / sum(increase(ai_requests_total[1h]))",
"legendFormat": "Avg cost/request",
},
{
"refId": "B",
"expr": "sum(increase(ai_cost_usd_total[1h])) by (model) / sum(increase(ai_requests_total[1h])) by (model)",
"legendFormat": "{{model}}",
},
],
"options": {
"tooltip": {"mode": "multi", "sort": "desc"},
"legend": {"displayMode": "table", "placement": "bottom", "calcs": ["mean", "lastNotNull"]},
},
}
print(json.dumps(cost_per_request_panel, indent=2))
Si el cost per request sube sin que el tráfico cambie, algo cambió en cómo construyes prompts o qué modelo usas. Este panel es el detector de cambios silenciosos.
Panel 7: Budget Overlay — Cost vs Budget
Una línea horizontal que representa tu presupuesto. Cuando la línea de costo cruza la línea de budget, es inmediatamente visible.
Implementación con PromQL constants
# Budget diario como constante (ejemplo: $10/día = $0.42/hora)
vector(0.42)
# Costo real por hora
sum(rate(ai_cost_usd_total[1h])) * 3600
Panel combinado
budget_overlay_panel = {
"title": "Cost vs Budget (Hourly Rate)",
"type": "timeseries",
"gridPos": {"h": 8, "w": 24, "x": 0, "y": 16},
"fieldConfig": {
"defaults": {
"unit": "currencyUSD",
"custom": {
"showPoints": "never",
"axisSoftMin": 0,
},
},
"overrides": [
{
"matcher": {"id": "byName", "options": "Budget limit"},
"properties": [
{"id": "color", "value": {"fixedColor": "red", "mode": "fixed"}},
{"id": "custom.lineWidth", "value": 2},
{"id": "custom.lineStyle", "value": {"fill": "dash", "dash": [10, 10]}},
{"id": "custom.fillOpacity", "value": 0},
],
},
{
"matcher": {"id": "byName", "options": "Actual cost/hour"},
"properties": [
{"id": "color", "value": {"fixedColor": "blue", "mode": "fixed"}},
{"id": "custom.lineWidth", "value": 2},
{"id": "custom.fillOpacity", "value": 15},
],
},
],
},
"targets": [
{
"refId": "A",
"expr": "sum(rate(ai_cost_usd_total[1h])) * 3600",
"legendFormat": "Actual cost/hour",
},
{
"refId": "B",
"expr": "vector(0.42)",
"legendFormat": "Budget limit",
},
],
"options": {
"tooltip": {"mode": "multi"},
"legend": {"displayMode": "list", "placement": "bottom"},
},
}
print(json.dumps(budget_overlay_panel, indent=2))
La línea roja punteada (budget) contra la línea azul sólida (costo real) es la visualización más intuitiva de si estás dentro de presupuesto. Cuando el área azul cruza la línea roja, es imposible no notarlo.
Assembling the Cost Row
import httpx
import json
GRAFANA_URL = "http://localhost:3000"
GRAFANA_AUTH = ("admin", "admin")
def create_cost_dashboard():
panels = [
{
"id": 1,
"title": "Cost Today",
"type": "stat",
"gridPos": {"h": 4, "w": 6, "x": 0, "y": 0},
"targets": [{
"refId": "A",
"expr": "sum(increase(ai_cost_usd_total[1d]))",
"datasource": {"type": "prometheus", "uid": "prometheus"},
}],
"fieldConfig": {
"defaults": {
"unit": "currencyUSD",
"decimals": 2,
"thresholds": {
"mode": "absolute",
"steps": [
{"value": None, "color": "green"},
{"value": 10, "color": "yellow"},
{"value": 25, "color": "red"},
],
},
"color": {"mode": "thresholds"},
},
"overrides": [],
},
"options": {"graphMode": "area", "reduceOptions": {"calcs": ["lastNotNull"]}},
},
{
"id": 2,
"title": "Projected Monthly",
"type": "stat",
"gridPos": {"h": 4, "w": 6, "x": 6, "y": 0},
"targets": [{
"refId": "A",
"expr": "sum(increase(ai_cost_usd_total[7d])) / 7 * 30",
"datasource": {"type": "prometheus", "uid": "prometheus"},
}],
"fieldConfig": {
"defaults": {
"unit": "currencyUSD",
"decimals": 0,
"thresholds": {
"mode": "absolute",
"steps": [
{"value": None, "color": "green"},
{"value": 200, "color": "yellow"},
{"value": 500, "color": "red"},
],
},
"color": {"mode": "thresholds"},
},
"overrides": [],
},
"options": {"graphMode": "none", "reduceOptions": {"calcs": ["lastNotNull"]}},
},
{
"id": 3,
"title": "Cost per Request",
"type": "stat",
"gridPos": {"h": 4, "w": 6, "x": 12, "y": 0},
"targets": [{
"refId": "A",
"expr": "sum(increase(ai_cost_usd_total[1h])) / sum(increase(ai_requests_total[1h]))",
"datasource": {"type": "prometheus", "uid": "prometheus"},
}],
"fieldConfig": {"defaults": {"unit": "currencyUSD", "decimals": 6}, "overrides": []},
"options": {"graphMode": "area", "reduceOptions": {"calcs": ["lastNotNull"]}},
},
{
"id": 4,
"title": "Cost per Hour",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 4},
"targets": [
{
"refId": "A",
"expr": "sum(rate(ai_cost_usd_total[1h])) * 3600",
"legendFormat": "Actual",
"datasource": {"type": "prometheus", "uid": "prometheus"},
},
{
"refId": "B",
"expr": "vector(0.42)",
"legendFormat": "Budget ($10/day)",
"datasource": {"type": "prometheus", "uid": "prometheus"},
},
],
"fieldConfig": {"defaults": {"unit": "currencyUSD"}, "overrides": []},
},
{
"id": 5,
"title": "Cost by Model (Stacked)",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 4},
"targets": [{
"refId": "A",
"expr": "sum(rate(ai_cost_usd_total[1h])) by (model) * 3600",
"legendFormat": "{{model}}",
"datasource": {"type": "prometheus", "uid": "prometheus"},
}],
"fieldConfig": {
"defaults": {
"unit": "currencyUSD",
"custom": {"fillOpacity": 40, "stacking": {"mode": "normal"}},
},
"overrides": [],
},
},
{
"id": 6,
"title": "Token Usage (Stacked)",
"type": "timeseries",
"gridPos": {"h": 8, "w": 24, "x": 0, "y": 12},
"targets": [
{
"refId": "A",
"expr": 'sum(rate(ai_tokens_total{type="prompt"}[5m])) by (model) * 60',
"legendFormat": "{{model}} prompt",
"datasource": {"type": "prometheus", "uid": "prometheus"},
},
{
"refId": "B",
"expr": 'sum(rate(ai_tokens_total{type="completion"}[5m])) by (model) * 60',
"legendFormat": "{{model}} completion",
"datasource": {"type": "prometheus", "uid": "prometheus"},
},
],
"fieldConfig": {
"defaults": {
"unit": "short",
"custom": {"fillOpacity": 30, "stacking": {"mode": "normal"}},
},
"overrides": [],
},
},
]
payload = {
"dashboard": {
"title": "AI Cost & Tokens Dashboard",
"panels": panels,
"refresh": "30s",
"time": {"from": "now-24h", "to": "now"},
},
"overwrite": True,
}
r = httpx.post(
f"{GRAFANA_URL}/api/dashboards/db",
json=payload,
auth=GRAFANA_AUTH,
timeout=10.0,
)
if r.status_code == 200:
result = r.json()
print(f"Cost Dashboard created: {GRAFANA_URL}{result.get('url', '')}")
else:
print(f"Error: {r.status_code} — {r.text}")
create_cost_dashboard()
Ejercicios
Ejercicio 1: Calcular Cost Savings de Model Switching (Fácil)
Escribe un script que, dado el tráfico actual por modelo, calcule cuánto ahorrarías si migras un porcentaje de requests de gpt-4o a gpt-4o-mini. Muestra el ahorro diario, semanal y mensual.
current_traffic = {
"gpt-4o": {"requests_per_day": 200, "avg_prompt_tokens": 600, "avg_completion_tokens": 300},
"gpt-4o-mini": {"requests_per_day": 800, "avg_prompt_tokens": 500, "avg_completion_tokens": 200},
}
Ver solución
MODEL_PRICING = {
"gpt-4o": {"prompt": 0.0025, "completion": 0.01},
"gpt-4o-mini": {"prompt": 0.00015, "completion": 0.0006},
}
current_traffic = {
"gpt-4o": {"requests_per_day": 200, "avg_prompt_tokens": 600, "avg_completion_tokens": 300},
"gpt-4o-mini": {"requests_per_day": 800, "avg_prompt_tokens": 500, "avg_completion_tokens": 200},
}
def calculate_cost(model: str, requests: int, prompt_tokens: int, completion_tokens: int) -> float:
pricing = MODEL_PRICING[model]
cost_per_request = (
prompt_tokens / 1000 * pricing["prompt"]
+ completion_tokens / 1000 * pricing["completion"]
)
return cost_per_request * requests
def simulate_migration(traffic: dict, migration_percent: float) -> dict:
current_cost = 0
for model, info in traffic.items():
current_cost += calculate_cost(
model, info["requests_per_day"],
info["avg_prompt_tokens"], info["avg_completion_tokens"],
)
gpt4o_info = traffic["gpt-4o"]
requests_to_migrate = int(gpt4o_info["requests_per_day"] * migration_percent / 100)
remaining_gpt4o = gpt4o_info["requests_per_day"] - requests_to_migrate
new_cost = (
calculate_cost(
"gpt-4o", remaining_gpt4o,
gpt4o_info["avg_prompt_tokens"], gpt4o_info["avg_completion_tokens"],
)
+ calculate_cost(
"gpt-4o-mini",
traffic["gpt-4o-mini"]["requests_per_day"] + requests_to_migrate,
gpt4o_info["avg_prompt_tokens"], gpt4o_info["avg_completion_tokens"],
)
)
daily_savings = current_cost - new_cost
return {
"migration_percent": migration_percent,
"requests_migrated": requests_to_migrate,
"current_daily": round(current_cost, 4),
"new_daily": round(new_cost, 4),
"daily_savings": round(daily_savings, 4),
"weekly_savings": round(daily_savings * 7, 2),
"monthly_savings": round(daily_savings * 30, 2),
"savings_percent": round(daily_savings / current_cost * 100, 1),
}
print(f"{'Migration':>10s} {'Current':>10s} {'New':>10s} {'Save/day':>10s} {'Save/mo':>10s} {'%':>6s}")
print("-" * 58)
for pct in [25, 50, 75, 100]:
result = simulate_migration(current_traffic, pct)
print(
f"{pct:9d}% "
f"${result['current_daily']:8.4f} "
f"${result['new_daily']:8.4f} "
f"${result['daily_savings']:8.4f} "
f"${result['monthly_savings']:8.2f} "
f"{result['savings_percent']:5.1f}%"
)
Explicación: La migración de gpt-4o a gpt-4o-mini puede ahorrar significativamente — la diferencia de precio es ~16x. Migrar 50% de requests de gpt-4o puede ahorrar 30-40% del costo total. Este tipo de análisis se hace con datos del dashboard: ves que gpt-4o domina el costo, calculas el ahorro potencial, y decides qué endpoints pueden funcionar con un modelo más barato.
Ejercicio 2: Detectar Cost Anomalies (Medio)
Escribe una función que analice una serie temporal de costo por hora y detecte anomalías: (1) spikes repentinos (>3x del promedio), (2) cambios de baseline (el costo "normal" cambió). Simula un escenario donde un cambio de prompt incrementa el costo un 50% gradualmente.
import random
Ver solución
import random
import statistics
def generate_cost_series(hours: int = 168) -> list[float]:
series = []
for h in range(hours):
if h < 72:
base = 0.35
elif h < 80:
base = 0.35 + (h - 72) * 0.02
elif h < 140:
base = 0.51
elif h == 100:
base = 1.50
else:
base = 0.51
noise = random.gauss(0, base * 0.15)
spike = random.random() < 0.02
if spike:
value = base * random.uniform(3, 5)
else:
value = base + noise
series.append(max(0.01, value))
return series
def detect_cost_anomalies(series: list[float], window: int = 12) -> list[dict]:
anomalies = []
for i in range(window, len(series)):
current = series[i]
recent_window = series[max(0, i - window):i]
recent_avg = statistics.mean(recent_window)
recent_std = statistics.stdev(recent_window) if len(recent_window) > 1 else 0
if current > recent_avg + 3 * max(recent_std, recent_avg * 0.1):
anomalies.append({
"hour": i,
"type": "spike",
"value": round(current, 4),
"baseline": round(recent_avg, 4),
"ratio": round(current / recent_avg, 1),
})
for i in range(window * 2, len(series) - window):
old_window = series[i - window * 2:i - window]
new_window = series[i - window:i]
old_avg = statistics.mean(old_window)
new_avg = statistics.mean(new_window)
change_pct = (new_avg - old_avg) / old_avg * 100
if abs(change_pct) > 25:
already_detected = any(
a["type"] == "baseline_shift" and abs(a["hour"] - i) < window
for a in anomalies
)
if not already_detected:
anomalies.append({
"hour": i,
"type": "baseline_shift",
"old_baseline": round(old_avg, 4),
"new_baseline": round(new_avg, 4),
"change_percent": round(change_pct, 1),
})
anomalies.sort(key=lambda a: a["hour"])
return anomalies
series = generate_cost_series()
anomalies = detect_cost_anomalies(series)
print(f"Series: {len(series)} hours (7 days)")
print(f"Avg cost first 72h: ${statistics.mean(series[:72]):.4f}/hour")
print(f"Avg cost last 72h: ${statistics.mean(series[-72:]):.4f}/hour")
print(f"\nAnomalies detected: {len(anomalies)}")
for a in anomalies:
if a["type"] == "spike":
print(f" Hour {a['hour']:3d}: SPIKE — ${a['value']}/hr ({a['ratio']}x of baseline ${a['baseline']}/hr)")
elif a["type"] == "baseline_shift":
print(f" Hour {a['hour']:3d}: BASELINE SHIFT — ${a['old_baseline']}/hr → ${a['new_baseline']}/hr ({a['change_percent']:+.1f}%)")
Explicación: La función detecta dos tipos de anomalías en costo. Spikes: valores que superan 3 desviaciones estándar del promedio reciente, típicos de un request anómalo o un error que consume tokens excesivos. Baseline shifts: cambios sostenidos en el promedio, típicos de un cambio de prompt, un nuevo endpoint, o una migración de modelo. En producción, el spike requiere investigación inmediata; el baseline shift requiere entender qué cambió.
Ejercicio 3: Budget Tracking con Alertas (Medio)
Implementa un tracker de presupuesto que calcule: (1) burn rate (a qué velocidad estás gastando), (2) projected exhaustion date (cuándo se te acaba el presupuesto), (3) safe daily limit (cuánto puedes gastar por día para llegar a fin de mes).
from datetime import datetime, timedelta
Ver solución
from datetime import datetime, timedelta
def budget_tracker(
monthly_budget: float,
spent_so_far: float,
daily_costs_last_7d: list[float],
) -> dict:
today = datetime.now()
days_in_month = 30
day_of_month = today.day
days_remaining = days_in_month - day_of_month
budget_remaining = monthly_budget - spent_so_far
budget_used_pct = spent_so_far / monthly_budget * 100
time_elapsed_pct = day_of_month / days_in_month * 100
avg_daily_cost = sum(daily_costs_last_7d) / len(daily_costs_last_7d)
burn_rate_per_hour = avg_daily_cost / 24
if avg_daily_cost > 0:
days_until_exhaustion = budget_remaining / avg_daily_cost
projected_exhaustion = today + timedelta(days=days_until_exhaustion)
else:
days_until_exhaustion = float("inf")
projected_exhaustion = None
projected_monthly_spend = spent_so_far + (avg_daily_cost * days_remaining)
projected_over_budget = projected_monthly_spend - monthly_budget
safe_daily_limit = budget_remaining / max(days_remaining, 1)
if budget_used_pct > time_elapsed_pct + 15:
status = "OVER_PACE"
elif budget_used_pct > time_elapsed_pct + 5:
status = "SLIGHTLY_OVER"
elif budget_used_pct < time_elapsed_pct - 10:
status = "UNDER_BUDGET"
else:
status = "ON_TRACK"
return {
"status": status,
"monthly_budget": monthly_budget,
"spent_so_far": round(spent_so_far, 2),
"budget_remaining": round(budget_remaining, 2),
"budget_used_pct": round(budget_used_pct, 1),
"time_elapsed_pct": round(time_elapsed_pct, 1),
"avg_daily_cost": round(avg_daily_cost, 2),
"burn_rate_per_hour": round(burn_rate_per_hour, 4),
"days_until_exhaustion": round(days_until_exhaustion, 1),
"projected_exhaustion": projected_exhaustion.strftime("%Y-%m-%d") if projected_exhaustion else "Never",
"projected_monthly_spend": round(projected_monthly_spend, 2),
"projected_over_budget": round(projected_over_budget, 2),
"safe_daily_limit": round(safe_daily_limit, 2),
}
daily_costs = [8.50, 9.20, 7.80, 12.30, 11.00, 9.50, 10.20]
result = budget_tracker(
monthly_budget=300.0,
spent_so_far=145.0,
daily_costs_last_7d=daily_costs,
)
print("=" * 50)
print(f"BUDGET TRACKER — {result['status']}")
print("=" * 50)
print(f" Monthly Budget: ${result['monthly_budget']}")
print(f" Spent So Far: ${result['spent_so_far']}")
print(f" Budget Remaining: ${result['budget_remaining']}")
print(f" Budget Used: {result['budget_used_pct']}%")
print(f" Time Elapsed: {result['time_elapsed_pct']}%")
print(f" Avg Daily Cost: ${result['avg_daily_cost']}")
print(f" Burn Rate: ${result['burn_rate_per_hour']}/hour")
print(f" Days Until Exhausted: {result['days_until_exhaustion']}")
print(f" Projected Exhaustion: {result['projected_exhaustion']}")
print(f" Projected Monthly: ${result['projected_monthly_spend']}")
print(f" Over Budget By: ${result['projected_over_budget']}")
print(f" Safe Daily Limit: ${result['safe_daily_limit']}")
Explicación: El tracker compara el porcentaje de presupuesto gastado contra el porcentaje de tiempo transcurrido. Si has gastado 50% del budget pero solo ha pasado 30% del mes, estás OVER_PACE. La "safe daily limit" te dice cuánto puedes gastar por día para llegar a fin de mes sin exceder el budget. En Grafana, estos valores pueden ser stat panels que se actualizan automáticamente.
Ejercicio 4: Token Efficiency Score (Avanzado)
Define y calcula una métrica de "token efficiency" que mida cuánto valor produce cada token gastado. Considera: tokens totales, calidad del output, y costo. Un sistema que gasta muchos tokens pero produce outputs de baja calidad es ineficiente.
import random
Ver solución
import random
import statistics
def generate_request_data(n: int = 100) -> list[dict]:
requests = []
for _ in range(n):
model = random.choices(["gpt-4o-mini", "gpt-4o"], weights=[0.8, 0.2])[0]
prompt_tokens = random.randint(200, 1000)
completion_tokens = random.randint(50, 500)
total_tokens = prompt_tokens + completion_tokens
if model == "gpt-4o":
quality = random.gauss(0.90, 0.05)
cost_per_1k_prompt = 0.0025
cost_per_1k_completion = 0.01
else:
quality = random.gauss(0.82, 0.08)
cost_per_1k_prompt = 0.00015
cost_per_1k_completion = 0.0006
quality = max(0.0, min(1.0, quality))
cost = (prompt_tokens / 1000 * cost_per_1k_prompt +
completion_tokens / 1000 * cost_per_1k_completion)
requests.append({
"model": model,
"prompt_tokens": prompt_tokens,
"completion_tokens": completion_tokens,
"total_tokens": total_tokens,
"quality_score": round(quality, 3),
"cost_usd": round(cost, 6),
})
return requests
def calculate_efficiency(requests: list[dict]) -> dict:
by_model = {}
for req in requests:
model = req["model"]
if model not in by_model:
by_model[model] = []
by_model[model].append(req)
results = {}
for model, reqs in by_model.items():
total_tokens = sum(r["total_tokens"] for r in reqs)
total_cost = sum(r["cost_usd"] for r in reqs)
avg_quality = statistics.mean(r["quality_score"] for r in reqs)
total_requests = len(reqs)
quality_per_token = avg_quality / (total_tokens / total_requests) * 1000
quality_per_dollar = avg_quality / (total_cost / total_requests)
tokens_per_quality_point = (total_tokens / total_requests) / avg_quality
efficiency_score = (avg_quality * 100) / (total_cost / total_requests * 1000)
results[model] = {
"requests": total_requests,
"avg_tokens": round(total_tokens / total_requests),
"avg_cost": round(total_cost / total_requests, 6),
"avg_quality": round(avg_quality, 3),
"quality_per_1k_tokens": round(quality_per_token, 4),
"quality_per_dollar": round(quality_per_dollar, 1),
"tokens_per_quality_point": round(tokens_per_quality_point),
"efficiency_score": round(efficiency_score, 2),
}
return results
data = generate_request_data(500)
efficiency = calculate_efficiency(data)
print(f"{'Metric':35s}", end="")
for model in efficiency:
print(f" {model:>15s}", end="")
print()
print("-" * 70)
metrics = [
("Requests", "requests"),
("Avg Tokens/Request", "avg_tokens"),
("Avg Cost/Request", "avg_cost"),
("Avg Quality Score", "avg_quality"),
("Quality per 1K Tokens", "quality_per_1k_tokens"),
("Quality per Dollar", "quality_per_dollar"),
("Tokens per Quality Point", "tokens_per_quality_point"),
("Efficiency Score", "efficiency_score"),
]
for label, key in metrics:
print(f"{label:35s}", end="")
for model in efficiency:
val = efficiency[model][key]
if isinstance(val, float):
print(f" {val:>15.4f}", end="")
else:
print(f" {val:>15}", end="")
print()
print("\nKey Insight:")
print(" gpt-4o-mini has MUCH higher quality_per_dollar despite lower raw quality")
print(" gpt-4o produces slightly better outputs but at 10-16x the cost")
print(" For most use cases, gpt-4o-mini is the efficient choice")
Explicación: La métrica de eficiencia (quality_per_dollar) revela que gpt-4o-mini produce mucho más valor por dólar que gpt-4o, a pesar de tener un quality score ligeramente menor. Esto es la información que un finance stakeholder necesita: no "¿cuál modelo es mejor?" sino "¿cuál modelo da más valor por dólar?". En Grafana, puedes crear un stat panel con quality_per_dollar como métrica derivada.
Resumen
- El costo en AI es variable por request. No es un gasto fijo mensual — depende del modelo, los tokens del prompt, y los tokens de completion. Cada request tiene un costo diferente.
- Cost per hour es el panel más accionable. Muestra la velocidad de gasto actual. Combinado con una budget line, es inmediatamente visible cuando excedes el rate sostenible.
- Breakdown por modelo revela dónde optimizar. Si gpt-4o consume 80% del presupuesto pero solo maneja 20% de requests, la optimización es clara: migrar endpoints donde gpt-4o-mini sea suficiente.
- Token usage es el driver. Si el costo sube, los tokens te dicen por qué: más requests, prompts más largos, o modelo más caro. Sin breakdown de tokens, investigar cost spikes es adivinar.
- Cost per request detecta cambios silenciosos. Un cambio de prompt que agrega 200 tokens no dispara alertas de cost total, pero sí mueve el cost per request. Este panel es tu detector de drift.
- Proyección mensual convierte datos actuales en una predicción accionable. "Estamos gastando $10/día" no genera urgencia. "Projected monthly: $450 (budget: $300)" sí.
- Budget overlay hace imposible ignorar cuando el gasto excede el presupuesto. Una línea roja punteada cruzada por la línea de costo real es la señal visual más clara.
Recursos Adicionales
- OpenAI Pricing — Precios actualizados por modelo
- Anthropic Pricing — Referencia de precios de Claude
- tiktoken — Estimar tokens antes de enviar requests
- Prometheus — Recording Rules — Pre-calcular métricas de costo
- Grafana — Transformations — Transformar datos en Grafana para métricas derivadas
- FinOps Foundation — AI Cost Management — Prácticas de gestión de costos en AI/Cloud