Producto de IA: KPIs, Impacto y Métricas de Éxito
De Modelo a Producto
Un modelo de IA brillante no es un producto de IA exitoso. El éxito se mide por el impacto en el negocio, no por la precisión del modelo. Esta lección conecta las métricas técnicas con las métricas de producto.
TÉCNICO PRODUCTO NEGOCIO
─────────────────────────────────────────────────────────────────────
Faithfulness 92% → Respuestas útiles 87% → Tickets -40%
Latencia p95 2.1s → UX fluida → NPS +12 pts
Costo $0.008/req → Margen saludable → ROI 340%
Framework de KPIs para IA
Nivel 1: Métricas de Uso (Adopción)
class AIProductMetrics:
"""KPIs de producto para features de IA."""
def adoption_metrics(self, data: dict) -> dict:
return {
# ── Adopción ─────────────────────────────
"daily_active_users": data["dau"],
"feature_adoption_rate": (
data["users_using_ai"] / data["total_active_users"] * 100
),
"queries_per_user_per_day": (
data["total_queries"] / max(data["dau"], 1)
),
"repeat_usage_rate": (
data["returning_ai_users"] / max(data["first_time_users"], 1)
* 100
),
# ── Engagement ───────────────────────────
"avg_session_queries": data["total_queries"] / max(data["sessions"], 1),
"follow_up_rate": (
data["follow_up_queries"] / max(data["initial_queries"], 1)
* 100
),
}
Nivel 2: Métricas de Calidad Percibida
def quality_metrics(self, data: dict) -> dict:
return {
# ── Satisfacción directa ─────────────────
"thumbs_up_rate": (
data["thumbs_up"] /
max(data["thumbs_up"] + data["thumbs_down"], 1) * 100
),
"csat_score": data["csat_avg"], # 1-5
# ── Señales implícitas ───────────────────
"copy_rate": (
data["response_copied"] / max(data["total_responses"], 1) * 100
),
"regeneration_rate": (
data["regenerations"] / max(data["total_responses"], 1) * 100
),
"abandonment_rate": (
data["abandoned_sessions"] / max(data["total_sessions"], 1)
* 100
),
# ── Escalación ───────────────────────────
"escalation_to_human": (
data["escalated"] / max(data["total_queries"], 1) * 100
),
}
Nivel 3: Métricas de Impacto en Negocio
def business_impact(self, data: dict) -> dict:
return {
# ── Eficiencia ───────────────────────────
"time_saved_hours": data["manual_time_hours"] - data["ai_time_hours"],
"cost_per_resolution": data["total_ai_cost"] / max(data["resolutions"], 1),
"human_cost_saved": (
data["deflected_tickets"] * data["avg_ticket_cost"]
),
# ── Revenue ──────────────────────────────
"ai_attributed_revenue": data["conversions_with_ai"] * data["avg_order"],
"upsell_from_ai": data["ai_recommendations_purchased"],
# ── ROI ──────────────────────────────────
"monthly_ai_cost": data["infra_cost"] + data["api_cost"],
"monthly_value_generated": (
data["human_cost_saved"] + data["ai_attributed_revenue"]
),
"roi_percentage": (
(data["monthly_value"] - data["monthly_cost"])
/ max(data["monthly_cost"], 1)
* 100
),
}
Diseñando un AI Scorecard
class AIScorecard:
"""Scorecard semanal para stakeholders."""
def generate_weekly(self, current: dict, previous: dict) -> dict:
def delta(key):
prev = previous.get(key, 0)
curr = current.get(key, 0)
if prev == 0:
return "N/A"
return f"{((curr - prev) / prev * 100):+.1f}%"
return {
"period": current["week"],
"adoption": {
"dau": {"value": current["dau"], "change": delta("dau")},
"queries_total": {
"value": current["total_queries"],
"change": delta("total_queries"),
},
"adoption_rate": {
"value": f"{current['adoption_rate']:.1f}%",
"target": "60%",
"status": "on-track"
if current["adoption_rate"] >= 55
else "at-risk",
},
},
"quality": {
"satisfaction": {
"value": f"{current['csat']:.1f}/5",
"change": delta("csat"),
"target": "4.0/5",
},
"useful_rate": {
"value": f"{current['thumbs_up_rate']:.0f}%",
"target": "85%",
},
},
"business": {
"tickets_deflected": {
"value": current["deflected"],
"cost_saved": f"${current['deflected'] * 25:,.0f}",
},
"roi": {
"value": f"{current['roi']:.0f}%",
"target": "200%",
},
},
"operational": {
"avg_latency": f"{current['avg_latency_ms']:.0f}ms",
"uptime": f"{current['uptime']:.2f}%",
"total_cost": f"${current['total_cost']:,.2f}",
},
}
A/B Testing para Features de IA
import hashlib
class AIFeatureExperiment:
"""Framework simple para A/B testing de IA."""
def __init__(self, experiment_name: str, variants: dict[str, float]):
"""
variants: {"control": 0.5, "new_prompt": 0.3, "new_model": 0.2}
"""
self.name = experiment_name
self.variants = variants
def get_variant(self, user_id: str) -> str:
"""Asignación determinística basada en hash."""
hash_input = f"{self.name}:{user_id}"
# SHA-256 produce un hash determinístico: el mismo user_id
# SIEMPRE obtiene el mismo hash → mismo variante en cada
# visita. Esto es mejor que random() porque garantiza
# consistencia: el usuario ve la misma variante entre sesiones.
# hexdigest() devuelve la representación hex del hash;
# int(..., 16) la convierte a entero para operar numéricamente.
hash_value = int(hashlib.sha256(hash_input.encode()).hexdigest(), 16)
# Mapea el entero al rango [0.0, 1.0) para bucketing por
# percentil. Ej: con 50/50 → bucket < 0.5 = control,
# bucket >= 0.5 = treatment.
bucket = (hash_value % 1000) / 1000
# Recorre los variantes acumulando pesos. Ej: con
# {"control": 0.5, "new_prompt": 0.3, "new_model": 0.2}
# bucket < 0.5 → control, < 0.8 → new_prompt, else → new_model
cumulative = 0
for variant, weight in self.variants.items():
cumulative += weight
if bucket < cumulative:
return variant
return list(self.variants.keys())[-1]
def analyze_results(self, data: list[dict]) -> dict:
"""Analizar resultados por variante."""
by_variant = {}
for entry in data:
v = entry["variant"]
if v not in by_variant:
by_variant[v] = {
"users": 0,
"satisfied": 0,
"queries": 0,
"total_cost": 0,
}
by_variant[v]["users"] += 1
by_variant[v]["queries"] += entry["queries"]
by_variant[v]["satisfied"] += 1 if entry["satisfied"] else 0
by_variant[v]["total_cost"] += entry["cost"]
results = {}
for variant, stats in by_variant.items():
results[variant] = {
"users": stats["users"],
"satisfaction_rate": stats["satisfied"] / max(stats["users"], 1),
"queries_per_user": stats["queries"] / max(stats["users"], 1),
"cost_per_user": stats["total_cost"] / max(stats["users"], 1),
}
return results
Calculadora de Unit Economics
class AIUnitEconomics:
"""Calcular unit economics de features de IA."""
def calculate(
self,
monthly_queries: int,
avg_cost_per_query: float,
infra_fixed_cost: float,
value_per_query: float,
team_cost: float,
) -> dict:
variable_cost = monthly_queries * avg_cost_per_query
total_cost = variable_cost + infra_fixed_cost + team_cost
total_value = monthly_queries * value_per_query
return {
"monthly_queries": monthly_queries,
"costs": {
"api_calls": round(variable_cost, 2),
"infrastructure": round(infra_fixed_cost, 2),
"team": round(team_cost, 2),
"total": round(total_cost, 2),
"per_query": round(total_cost / max(monthly_queries, 1), 4),
},
"value": {
"total": round(total_value, 2),
"per_query": round(value_per_query, 4),
},
"economics": {
"gross_margin": round(
(total_value - total_cost) / max(total_value, 1) * 100, 1
),
"roi": round(
(total_value - total_cost) / max(total_cost, 1) * 100, 1
),
"break_even_queries": round(
(infra_fixed_cost + team_cost) /
max(value_per_query - avg_cost_per_query, 0.001)
),
},
}
Resumen
Jerarquía de KPIs
┌─────────────────────────────────────────────────┐
│ NIVEL C-SUITE: ROI, Revenue Impact │
├─────────────────────────────────────────────────┤
│ NIVEL PRODUCTO: Adopción, Satisfacción, │
│ Retención │
├─────────────────────────────────────────────────┤
│ NIVEL TÉCNICO: Calidad, Latencia, Costos │
└─────────────────────────────────────────────────┘
Anti-patrones a Evitar
| Anti-patrón | Problema | Solución |
|---|---|---|
| Solo medir accuracy del modelo | No refleja valor de negocio | Medir impacto end-to-end |
| Optimizar solo costo | Sacrifica calidad y UX | Medir costo POR RESOLUCIÓN |
| Ignorar feedback implícito | Perder señales de insatisfacción | Rastrear copy, regeneration, abandonment |
| Reportar solo promedios | Oculta outliers problemáticos | Usar percentiles (p50, p95, p99) |
🧠 Preguntas de Repaso
1. ¿Por qué un modelo con 92% de faithfulness no garantiza un producto exitoso?
- A) Porque 92% es una métrica muy baja
- B) Porque el éxito se mide por impacto en negocio (adopción, satisfacción, ROI), no solo por métricas técnicas del modelo
- C) Porque la faithfulness no es una métrica real
- D) Porque los usuarios no entienden las métricas técnicas
Respuesta: B) — Un modelo brillante no es un producto exitoso. Se necesita conectar: Faithfulness 92% → Respuestas útiles 87% → Tickets -40% → Ahorro $15K/mes. Sin adopción, satisfacción y ROI positivo, la métrica técnica es irrelevante.
2. ¿Cómo funciona la asignación determinística de usuarios a variantes en un A/B test de IA?
- A) Se asigna al azar en cada sesión
- B) Se usa hash SHA-256 del "experiment_name:user_id" para generar un bucket consistente, garantizando que el mismo usuario siempre vea la misma variante
- C) Se asigna por orden de llegada
- D) El usuario elige su variante
Respuesta: B) — El hash SHA-256 de "experiment_name:user_id" genera un bucket determinístico (hash_value % 1000 / 1000). Esto garantiza que el mismo usuario siempre cae en la misma variante entre sesiones, a diferencia de random() que cambiaría cada vez.
3. ¿Cuáles son los 3 niveles de la jerarquía de KPIs para un producto de IA?
- A) Input, Process, Output
- B) C-Suite (ROI, Revenue Impact) → Producto (Adopción, Satisfacción, Retención) → Técnico (Calidad, Latencia, Costos)
- C) Desarrollo, Testing, Producción
- D) Corto plazo, Mediano plazo, Largo plazo
Respuesta: B) — La jerarquía fluye: el nivel Técnico (faithfulness, latencia) alimenta al nivel Producto (adopción, satisfacción, retención), que a su vez alimenta al nivel C-Suite (ROI, revenue impact). Cada audiencia necesita sus métricas correspondientes.
4. ¿Cuál es un anti-patrón común al reportar métricas de IA y cómo se soluciona?
- A) Medir demasiadas métricas → reducir a solo una
- B) Reportar solo promedios, que ocultan outliers problemáticos → usar percentiles (p50, p95, p99)
- C) Reportar en tiempo real → reportar semanalmente
- D) Usar gráficas → usar solo tablas
Respuesta: B) — Reportar solo promedios oculta outliers: un promedio de 2s de latencia puede esconder un p99 de 45s que afecta a usuarios reales. Los percentiles (p50, p95, p99) revelan la experiencia de todos los usuarios, no solo la típica.