Skip to content

English · Español

00 — Motivación: por qué la observabilidad no es opcional para servir IA

🇪🇸 "Hacerlo funcionar" y "saber qué está haciendo" son dos problemas distintos. En servicios web normales puedes saltarte la observabilidad y sobrevivir; en servicios LLM la latencia, el coste y los errores se mueven en órdenes de magnitud entre peticiones — sin observabilidad no operas, intuyes.

Terminaste la Fase 33 con un servidor de inferencia con continuous-batching que bate al batching estático en rendimiento (throughput) a una latencia p95 fija. Enhorabuena: ahora posees una caja negra que acepta peticiones HTTP y emite tokens. Eso no es suficiente.

Esta página trata sobre el porqué la observabilidad (observability) es una fase distinta y no un rincón de la fase de servicio.

La posición ingenua

La posición ingenua dice: "los logs y un endpoint /health son observabilidad. Puedo hacer grep de errores y curl a /health para ver si está vivo. Listo."

Para un servicio CRUD sin estado que gestiona 10 peticiones por segundo, la posición ingenua es lo bastante correcta como para sobrevivir. Para un servicio LLM es errónea de tres formas simultáneamente, y cada una muerde a una escala distinta.

Por qué servir LLM rompe la posición ingenua

1. El coste por petición varía en órdenes de magnitud

Un servicio CRUD que sirve un GET /users/42 y un GET /users/9999 hace aproximadamente el mismo trabajo para ambos — lookup en índice, serializar, devolver. El tiempo de reloj por petición es uniforme dentro de un factor de 2 o 3.

Un servicio LLM que sirve "¿cuánto es 2+2?" y "explica el buffer overflow en este fichero C de 4 KB paso a paso" hace trabajos enormemente distintos:

  • El primero es un paso de decode sobre un KV cache diminuto. ~50 ms.
  • El segundo es un prefill de 4 KB seguido de un decode de varios miles de tokens. ~30 segundos.

La proporción es 600×. Los buckets de histograma por defecto de Prometheus cortan en 10 segundos. Por defecto, la segunda petición es invisible para tu histograma de latencia. Tu dashboard leerá "p99 < 10 s" y mentirá.

Servir LLM requiere buckets de histograma deliberadamente moldeados que cubran 4 décadas de latencia. Esa deliberación es lo que trata esta fase.

2. El coste ya no es una nota a pie de página

Un servicio web tiene un coste marginal por petición aproximadamente fijo — la caja está encendida, la petición añade un CPU-milisegundo.

Un servicio LLM tiene un coste por petición que escala linealmente con la longitud de salida y cuadráticamente con la longitud de entrada (porque el prefill de attention es O(N²)). Una sola petición de "escríbeme un ensayo de 5000 palabras" puede costar más que mil "¿cuánto es 2+2?" combinados.

No puedes razonar sobre si tu servicio es sostenible, o si un cliente/patrón de prueba concreto te está abusando, sin números de coste por petición. El coste tiene que ser una métrica de primera clase, no un ejercicio trimestral de hoja de cálculo financiera.

Esta fase convierte el coste en un histograma de Prometheus, exactamente con la misma forma que la latencia. Consultarás "p95 coste por 1k tokens de salida" con la misma fluidez con la que consultas "p95 latencia".

3. Los errores ya no son binarios

Un servicio web devuelve 2xx (bueno) o 5xx (malo). Contarlos es suficiente.

Un servicio LLM devuelve 200 OK con contenido erróneo, alucinado, rechazado, fuera de tema o truncado. Desde la perspectiva de la tasa de errores de Prometheus, todo esto son 200s — errores que parecen éxitos.

La Fase 34 no resuelve la medición de calidad (eso es Fase 20 / Fase 38). Pero pone los cimientos de traza y log a los que se enganchan las herramientas de medición de calidad: cada respuesta lleva un trace_id; cuando la Fase 38 ejecuta un LLM-como-juez sobre las respuestas, une los juicios de vuelta con las trazas y métricas vía ese id.

El coste-de-no-hacer-esto

Tres modos de fallo concretos que golpean a cualquier equipo que se salte esta fase.

Modo de fallo A — "la latencia está bien, ¿por qué se quejan los usuarios?" Los buckets de histograma por defecto cortan por debajo de tu cola larga real. p99 lee "9.8 s" para siempre, sin importar lo lento que vayan las peticiones reales. Los usuarios ven 45 s; tú ves 9.8 s. Discrepas con la realidad y pierdes.

Modo de fallo B — "estamos perdiendo dinero con este cliente." Sin coste por petición, descubres esto por la factura mensual de cloud, tres semanas después de que empezara la hemorragia. Con coste por petición en Prometheus, escribes una sola alerta PromQL: "alerta cuando el coste percentil 95 por 1k tokens supere €0.10 durante 10 minutos".

Modo de fallo C — "una petición murió en algún punto del pipeline; ¿dónde?" Sin tracing distribuido tienes una línea de log por etapa (tokenize, retrieve, prefill, decode), sin correlación entre ellas, y haces grep sobre 100k líneas de log para encontrar el hilo correcto. Con OpenTelemetry, haces clic en el trace_id de la petición fallida en Grafana y ves el árbol de spans completo, con timing por span.

Estos no son exóticos; son las primeras tres cosas que se rompen.

La estructura de la Fase 34

La fase tiene cuatro unidades, cada una aterrizando una pieza del cuadro operativo:

Unidad Qué Por qué
Métricas RED Rate, Errors, Duration Salud a nivel de servicio
Métricas USE Utilization, Saturation, Errors Salud a nivel de recurso
Tracing Spans de OpenTelemetry + logs Causalidad por petición
Coste Histograma de $_per_req Sostenibilidad

Estas cuatro no son intercambiables; responden a preguntas distintas. Un error que comete el practicante ingenuo es "tengo métricas de latencia, con eso vale" — la latencia es solo RED, y te dice que el servicio está lento sin decirte por qué. USE te dice por qué (cola llena, KV cache machacándose). El tracing te dice qué camino concreto de petición se torció. El coste te dice si la lentitud merece la pena arreglarla siquiera.

Cómo esto conecta con el currículo más amplio

  • Fase 33 construyó el servidor. La Fase 34 lo instrumenta.
  • Fase 35 introduce múltiples nodos; el contexto de tracing ahora se propaga entre procesos, y las métricas USE incluyen ahora la utilización de GPU. El cimiento de la Fase 34 debe ser propagable.
  • Fase 37 usa la observabilidad como defensa: trazas anómalas (una petición con 1000× la salida de tokens normal, un span cuyo retrieval RAG devolvió contenido sospechoso) se convierten en señales de ataque.
  • Fase 38 hace planificación de capacidad consciente del coste y autoscaling sobre tokens_per_second en lugar de %CPU. Eso necesita tanto el histograma de coste como el gauge de profundidad de cola de la Fase 34.
  • Fase 40 somete a test de carga al sistema completo; los dashboards de la Fase 34 son el artefacto de ese test de carga.

Así que el framework de métricas, trazas y coste que cableas en esta fase vive en cada fase posterior. No es scaffolding desechable.

Recapitulación en un párrafo

Los valores por defecto de observabilidad están calibrados para servicios web CRUD y mienten sobre cargas LLM en tres formas específicas: los buckets de histograma cortan por debajo de la cola larga, el coste es invisible a pesar de variar 100× por petición, y "200 OK con basura" se ve idéntico a "200 OK con salida correcta". La Fase 34 arregla las tres introduciendo métricas RED + USE con buckets moldeados para LLM, tracing OpenTelemetry a través de cada etapa del pipeline, logging estructurado unido a trazas por trace_id, y un CostTracker que emite coste por petición como histograma de Prometheus en microdólares. La fase es pequeña en volumen de código pero de alto apalancamiento: todo lo de aguas abajo depende de estos cimientos.


Siguiente: theory/01-red-use-metrics.md.