Metricas de agentes

Las metricas muestran exito, llamadas de herramientas y pasos de ejecucion del agente.
En esta página
  1. Idea en 30 segundos
  2. Problema principal
  3. Como funciona
  4. Metricas tipicas de production para agentes
  5. Cuando usar
  6. Ejemplo de implementacion
  7. Errores tipicos
  8. Solo promedios, sin p95/p99
  9. Labels de alta cardinalidad
  10. Sin metricas de stop_reason
  11. Sin alertas para anomalias clave
  12. Autoevaluacion
  13. FAQ
  14. Paginas relacionadas

Idea en 30 segundos

Las metricas de agentes muestran el estado del sistema en muchos runs, no en un solo caso.

Responden: si el sistema es estable, si suben los costos, y donde empieza la degradacion.

Sin metricas, los problemas suelen verse tarde: despues de quejas de usuarios o sobrecostos de presupuesto.

Problema principal

Los logs y el tracing explican bien un incidente concreto.

Pero en production importa ver tendencias: que pasa con latency, token usage, error rate y tool calls entre releases. Sin metricas, el sistema puede degradarse de forma gradual y pasar desapercibido por mucho tiempo.

En production normalmente se ve asi:

  • el tiempo de respuesta promedio parece normal, pero p95 ya esta subiendo;
  • los costos de tokens suben en olas despues de una release;
  • crece la cantidad de tool calls por run;
  • el equipo detecta el problema solo despues del incidente.

Por eso las metricas son una senal separada de observability: ayudan a detectar anomalias a tiempo y reaccionar antes de fallos grandes.

Como funciona

Las metricas son senales numericas agregadas que muestran el comportamiento del sistema en el tiempo.

Normalmente hay tres niveles de metricas:

  • nivel run (run_count, success_rate, stop_reason);
  • pasos y herramientas (tool_calls_per_run, tool_error_rate, step_count);
  • costo y velocidad (token_usage, cost_per_run (se calcula desde token_usage en dashboards o consultas de metricas), latency_p50/p95).

Las metricas dan una senal temprana cuando el sistema empieza a degradarse. Los logs responden "que paso", y el tracing responde "como exactamente paso en un run concreto".

Metricas tipicas de production para agentes

MetricaQue muestraPara que sirve
run_countcantidad de runs por periodocontrol de carga y volumen de trafico
success_rateproporcion de runs exitososrevision rapida de estabilidad
latency_p50 / latency_p95latencia tipica y de coladeteccion de degradacion de rendimiento
token_usage_per_runcuantos tokens consume cada runcontrol de costo LLM
cost_per_runcosto estimado de un runcontrol de presupuesto y proyeccion de costos
tool_calls_per_runcuantas veces un run llama herramientasdeteccion de llamadas excesivas o ciclicas
tool_error_ratefrecuencia de errores de herramientasdeteccion temprana de dependencias inestables
stop_reason_distributiondistribucion de motivos de fin de runcontrol de limites y fallos tipicos

Para que las metricas sean utiles, normalmente se segmentan por release, model o tool.

Importante: no agregues campos de alta cardinalidad (run_id, request_id, user_id) en labels, o el almacenamiento de metricas se sobrecarga rapido.

Cuando usar

Un conjunto amplio de metricas no siempre es necesario.

Para un prototipo temprano, a veces bastan contadores basicos de runs y errores.

Pero las metricas se vuelven criticas cuando:

  • el sistema de agentes ya esta en production;
  • hay SLO de latency o calidad;
  • se deben controlar costos de tokens y tool calls;
  • hay releases frecuentes y se deben ver regresiones antes de incidentes.

Ejemplo de implementacion

Abajo tienes un ejemplo simplificado de instrumentacion de runtime al estilo Prometheus. En sistemas reales, los mismos principios funcionan para Datadog, Grafana Cloud, CloudWatch y otras plataformas.

PYTHON
import time
from prometheus_client import Counter, Histogram

RUN_TOTAL = Counter(
    "agent_run_total",
    "Total number of agent runs",
    ["status", "stop_reason", "release"],
)
# success_rate = RUN_TOTAL{status="ok"} / RUN_TOTAL

RUN_LATENCY_MS = Histogram(
    "agent_run_latency_ms",
    "Run latency in milliseconds",
    ["release"],
    buckets=(100, 250, 500, 1000, 2000, 5000, 10000),
)

STEP_COUNT = Histogram(
    "agent_steps_per_run",
    "Number of steps per run",
    ["release"],
    buckets=(1, 2, 4, 8, 12, 16, 24, 32),
)

TOOL_CALL_TOTAL = Counter(
    "agent_tool_call_total",
    "Total tool calls",
    ["tool", "status", "release"],
)

TOOL_ERROR_TOTAL = Counter(
    "agent_tool_error_total",
    "Total tool errors by class",
    ["tool", "error_class", "release"],
)

LLM_ERROR_TOTAL = Counter(
    "agent_llm_error_total",
    "Total LLM step errors by model and class",
    ["model", "error_class", "release"],
)

TOOL_LATENCY_MS = Histogram(
    "agent_tool_latency_ms",
    "Tool call latency in milliseconds",
    ["tool", "release"],
    buckets=(20, 50, 100, 250, 500, 1000, 2000, 5000),
)

TOKEN_USAGE_TOTAL = Counter(
    "agent_token_usage_total",
    "Total LLM tokens",
    ["model", "token_type", "release"],
)


def observe_llm_usage(model, token_usage, release):
    # la mayoria de proveedores LLM devuelve token usage en la respuesta
    if not token_usage:
        return
    TOKEN_USAGE_TOTAL.labels(model=model, token_type="prompt", release=release).inc(
        token_usage.get("prompt_tokens", 0)
    )
    TOKEN_USAGE_TOTAL.labels(model=model, token_type="completion", release=release).inc(
        token_usage.get("completion_tokens", 0)
    )


def run_agent(agent, task, release="2026-03-21"):
    started_at = time.time()
    steps = 0
    stop_reason = "max_steps"
    run_status = "ok"

    try:
        for step in agent.iter(task):
            steps += 1
            step_type = step.type
            result = None  # puede quedar en None para tipos de paso desconocidos (protegido por la verificacion de abajo)

            if step_type == "tool_call":
                tool_name = getattr(step, "tool_name", "unknown")
                tool_started_at = time.time()
                try:
                    result = step.execute()
                    TOOL_CALL_TOTAL.labels(tool=tool_name, status="ok", release=release).inc()
                    TOOL_LATENCY_MS.labels(tool=tool_name, release=release).observe(
                        (time.time() - tool_started_at) * 1000
                    )
                except Exception as error:
                    TOOL_CALL_TOTAL.labels(tool=tool_name, status="error", release=release).inc()
                    TOOL_ERROR_TOTAL.labels(
                        tool=tool_name,
                        error_class=type(error).__name__,
                        release=release,
                    ).inc()
                    TOOL_LATENCY_MS.labels(tool=tool_name, release=release).observe(
                        (time.time() - tool_started_at) * 1000
                    )
                    run_status = "error"
                    stop_reason = "tool_error"
                    raise
            else:
                try:
                    result = step.execute()
                    observe_llm_usage(
                        model=getattr(step, "model", "unknown"),
                        token_usage=getattr(result, "token_usage", None),
                        release=release,
                    )
                except Exception as error:
                    LLM_ERROR_TOTAL.labels(
                        model=getattr(step, "model", "unknown"),
                        error_class=type(error).__name__,
                        release=release,
                    ).inc()
                    run_status = "error"
                    stop_reason = "step_error"
                    raise

            if result and result.is_final:
                stop_reason = "completed"
                break

    finally:
        RUN_TOTAL.labels(status=run_status, stop_reason=stop_reason, release=release).inc()
        RUN_LATENCY_MS.labels(release=release).observe((time.time() - started_at) * 1000)
        STEP_COUNT.labels(release=release).observe(steps)

En production, estas metricas normalmente alimentan dashboards y alertas.

Asi se pueden ver estas metricas juntas en un dashboard real:

MetricaValor actualTendenciaEstado
latency_p952.4s+38% en 30 minwarning: por encima del SLO
tool_error_rate7.2%+4.1pp en 15 mincritical: alert
token_usage_per_run8.9k+22% despues de releasewarning: anomalia
success_rate91.4%-5.3pp en 1 horawarning: caida

Para error_class, es mejor usar un diccionario normalizado de valores para evitar cardinalidad innecesaria.

Por ejemplo, una linea de metrica puede verse asi:

TEXT
agent_tool_call_total{tool="search_docs",status="error",release="2026-03-21"} 47

Errores tipicos

Incluso cuando ya hay metricas, muchas veces no ayudan por errores tipicos como estos.

Solo promedios, sin p95/p99

El promedio oculta la cola larga de runs lentos. Para production, el minimo es p50 y p95.

Labels de alta cardinalidad

Labels como run_id o user_id aumentan fuertemente la carga del backend de metricas. Mejor segmentar por release, model, tool.

Sin metricas de stop_reason

Sin distribucion de stop_reason, es dificil entender por que los runs terminan por max_steps o tool_error. Esto suele ocultar fallo de herramienta y senales tempranas de explosion de presupuesto.

Sin alertas para anomalias clave

Metricas sin alertas se convierten en graficos pasivos. Sin alertas, es facil perder spam de herramientas o una caida brusca de success rate despues de una release.

Autoevaluacion

Abajo tienes un checklist corto de metricas base de agentes antes del release.

Progreso: 0/9

⚠ Falta observability base

Será difícil depurar el sistema en production. Empieza con run_id, structured logs y tracing de tool calls.

FAQ

P: En que se diferencian las metricas de logs y tracing?
R: Las metricas muestran tendencias y estado del sistema en el tiempo. Los logs explican eventos, y el tracing muestra el camino de un run concreto.

P: Cual es el minimo de metricas para una primera release de production?
R: Empieza con run_count, success_rate, latency_p95, tool_error_rate, token_usage_per_run y stop_reason_distribution.

P: Por que no alcanza con la latency promedio?
R: El promedio oculta runs largos y lentos. p95 muestra mucho antes la degradacion real para usuarios.

P: Que labels suelen romper el almacenamiento de metricas?
R: Todo lo de alta cardinalidad: run_id, request_id, user_id, prompts completos o raw args.

Paginas relacionadas

Siguiente sobre el tema:

⏱️ 7 min de lecturaActualizado 21 de marzo de 2026Dificultad: ★★★
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)
  • Permisos de herramientas (allowlist / blocklist)
  • Kill switch y parada por incidente
  • Idempotencia y dedupe
  • Audit logs y trazabilidad
Mención integrada: OnceOnly es una capa de control para sistemas de agentes en producción.

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.