← SCRAM AI Lab

Tutoriales

OpenTelemetry tracing para pipelines LLM

Domina el tracing de pipelines LLM con OpenTelemetry y GenAI semantic conventions. Optimiza latencias en producción y evita sobrecostos con tail sampling.

May 21, 2026

471 lecturas

OpenTelemetry tracing para pipelines LLM

Los logs te dicen qué pasó. Las traces te dicen por qué tardó 8 segundos.

Un chatbot LLM en producción es un sistema distribuido escondido: el usuario manda un mensaje, tu router decide el tier, llama a un provider (Anthropic, OpenAI, Google), parsea la respuesta, ejecuta side-effects (escribir al CRM, llamar a GLPI, sincronizar con Mautic), y devuelve. Si solo tienes logs, vas a poder reconstruir el camino — pero no vas a poder ver de un vistazo dónde se fueron los 6 segundos en un request lento. Para eso existe OpenTelemetry, y para LLMs las semantic conventions gen_ai son el estándar.

La jerarquía de spans en un request de chatbot

POST /v1/chat/sessions/:id/messages    [root span: 4.2s]
├── sanitize_message                   [12ms]
├── classify_intent                    [180ms]
├── ai_router.select_tier              [3ms]
├── llm_call (tier=2, anthropic)       [2.8s]
│   ├── prompt_assembly                [45ms]
│   ├── anthropic.messages.create      [2.7s]
│   └── response_parsing               [38ms]
├── side_effects                       [1.1s]
│   ├── crm.capture_lead               [320ms]
│   ├── glpi.create_ticket             [580ms]
│   └── mautic.sync_contact            [200ms]
└── persist_message                    [85ms]

Esa visualización en Grafana Tempo te dice en 3 segundos: "el side-effect de GLPI tardó 580ms y bloquea el response al usuario". Decisión: paralelizar side-effects no críticos, mover GLPI a background queue.

Setup mínimo en NestJS

// tracing-init.ts (debe ser el PRIMER import en main.ts)
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { Resource } from '@opentelemetry/resources';
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';

const sdk = new NodeSDK({
  resource: new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: 'chat-api',
    [SemanticResourceAttributes.SERVICE_VERSION]: process.env.VERSION,
  }),
  traceExporter: new OTLPTraceExporter({
    url: 'http://tempo:4318/v1/traces',
  }),
  instrumentations: [getNodeAutoInstrumentations({
    '@opentelemetry/instrumentation-fs': { enabled: false },
  })],
});

sdk.start();

Spans manuales con gen_ai semantic conventions

import { trace, SpanStatusCode } from '@opentelemetry/api';

const tracer = trace.getTracer('chat-api');

async function callLLM(provider: string, model: string, messages: Message[]) {
  return tracer.startActiveSpan('llm_call', {
    attributes: {
      'gen_ai.system': provider, // anthropic | openai | google
      'gen_ai.request.model': model, // claude-opus-4-7
      'gen_ai.request.max_tokens': 4096,
      'gen_ai.request.temperature': 0.7,
    },
  }, async (span) => {
    try {
      const response = await providers[provider].call(model, messages);
      span.setAttributes({
        'gen_ai.response.model': response.model,
        'gen_ai.response.id': response.id,
        'gen_ai.usage.input_tokens': response.usage.input_tokens,
        'gen_ai.usage.output_tokens': response.usage.output_tokens,
        'gen_ai.response.finish_reasons': response.stop_reason,
      });
      return response;
    } catch (err) {
      span.recordException(err);
      span.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
      throw err;
    } finally {
      span.end();
    } 
  });
}

Por qué structured logging no basta

Con logs estructurados puedes calcular latencia total de un request. No puedes ver:

  • El waterfall de operaciones nested (qué bloquea a qué)
  • Operaciones paralelas (¿se ejecutaron realmente en paralelo?)
  • Latencia de servicios externos a granularidad de span
  • El span específico donde cayó el error en un pipeline de 8 pasos

Logs y traces son complementarios. Loki para "qué pasó a lo largo del tiempo", Tempo para "qué pasó en este request específico". Linkéalos con trace_id en el JSON payload de tus logs.

Sampling para que no te quiebres

  • 100% de requests con error (siempre)
  • 100% de requests con latencia > p99 (tail sampling)
  • 10% sampling de requests exitosos rápidos

Tempo soporta tail-based sampling — recolectas todo y decides al final del trace si lo persistes. Costo de storage baja 70% sin perder los traces que importan.

La pregunta de la siguiente iteración: ¿cómo correlacionas un trace con el embedding del prompt para detectar que ciertos topics consistentemente disparan latencia alta? Estamos probando un sidecar que extrae features del prompt y los manda como atributos del span.

¿Por qué deberías usar OpenTelemetry en lugar de plataformas dedicadas como Langfuse o Arize Phoenix?

OpenTelemetry te protege del acoplamiento con proveedores propietarios al estandarizar la telemetría bajo las especificaciones de la Cloud Native Computing Foundation (CNCF). Permite unificar en una sola vista distribuida el rastreo de tus llamadas a modelos fundacionales con tus bases de datos relacionales, colas de mensajería y microservicios auxiliares sin duplicar agentes ni SDKs.

Las plataformas especializadas en evaluación de LLM son excelentes para calcular métricas de alucinación o gestionar datasets de fine-tuning. Sin embargo, cuando el problema operativo radica en que una consulta a Redis bloqueó el hilo antes de contactar a la API de inferencia, las herramientas puramente orientadas a IA fallan al no registrar el contexto de la infraestructura subyacente.

Comparativa técnica de enfoques de observabilidad

Para determinar qué stack implementar según el estado del proyecto, evaluamos las alternativas según criterios de adopción corporativa:

Criterio OpenTelemetry Nativo + Tempo Langfuse / Arize Phoenix APM Propietario (Datadog / New Relic)
Correlación con backend tradicional Nativa en un solo trace context Limitada; requiere puentes manuales Nativa mediante agentes propietarios
Vendor Lock-in Nulo (estándar abierto CNCF) Bajo (código abierto, esquema propio) Alto (formatos y agentes cerrados)
Métricas especializadas (evals, feedback) Requiere instrumentación manual Integradas out-of-the-box Módulos LLM dedicados con costo extra
Costo de almacenamiento y licencia Solo infraestructura de hosting (S3/GCS) Gratuito en auto-hospedaje o por consumo Tarificación por millón de eventos / spans
Soporte GenAI Semantic Conventions Oficial y directo en especificación Adaptadores OTLP parciales Mapeo interno a sus propios modelos

El impacto de la latencia transfronteriza en pipelines LLM para América Latina

Desplegar aplicaciones de IA generativa desde México, Colombia, Chile o Brasil añade un reto físico que ningún ajuste de código puede desaparecer: la distancia a los centros de datos de inferencia. Los principales proveedores (OpenAI, Anthropic y los clusters de Bedrock) concentran su cómputo en regiones como us-east-1 (Norte de Virginia) o us-west-2 (Oregón).

De acuerdo con mediciones de latencia reportadas por Cloudflare Radar y reportes de red de AWS, un paquete de red entre Ciudad de México y Virginia toma un Round Trip Time (RTT) base de entre 55ms y 75ms en condiciones óptimas. Si el tráfico se origina en São Paulo o Santiago, el RTT supera fácilmente los 130ms a 160ms por salto.

Si tu arquitectura comete el error de encadenar llamadas sincrónicas (por ejemplo, validar moderación, luego recuperar contexto de una base vectorial remota, luego invocar el modelo y finalmente parsear con una función externa), estás pagando ese castigo de RTT cuatro o cinco veces consecutivas antes de mandar el primer token al usuario. OpenTelemetry permite identificar con precisión milimétrica si los 3 segundos de espera provienen de la generación de tokens en el silicio (GPU/TPU) o del handshaking TLS acumulado en conexiones HTTP secuenciales desde infraestructura local.

Riesgos comunes: qué puede salir mal al instrumentar OpenTelemetry en LLMs

La adopción de tracing distribuido introduce puntos ciegos si no se toman medidas preventivas de diseño:

1. Fuga de datos personales (PII) en atributos de span

La convención semántica permite agregar prompts completos y completions dentro de los atributos del span. En México, la Ley Federal de Protección de Datos Personales en Posesión de los Particulares (LFPDPPP), así como normativas equivalentes en la región (LGPD en Brasil), prohíben el almacenamiento de datos sensibles sin consentimiento explícito y cifrado riguroso. Almacenar identificadores tributarios (RFC, RUT), números de tarjeta o expedientes médicos en texto plano dentro de Grafana Tempo o Jaeger constituye una brecha de seguridad. Regla: sanitiza o aplica hash a los payloads de texto antes de adjuntarlos al span, limitando los atributos en producción exclusivamente a tokens consumidos, IDs de modelos, latencias y códigos de parada.

2. Sobrecarga por granularidad excesiva en streaming

Cuando utilizas streaming mediante Server-Sent Events (SSE), emitir un span o un span event por cada token devuelto satura el bucle de eventos de NodeJS y desborda el recolector de OTLP. Para flujos continuos, instrumenta únicamente dos hitos: el span general de la llamada y un evento temporal interno correspondiente al Time to First Token (TTFT). El resto de la transmisión debe medirse como una métrica agregada al cierre del stream.

3. Explosión de costos por ingestión sin filtros en endpoints de alta frecuencia

Una API de chat con 200 requests concurrentes que registre spans anidados de cada sub-llamada (embeddings, re-ranking, base vectorial, llamadas a herramientas) generará gigabytes de telemetría por hora. Si envías todos los datos hacia un SaaS sin configurar un OpenTelemetry Collector intermedio con tail-based sampling, la factura de observabilidad superará con rapidez el costo de la propia API de inferencia. Despliega un Collector local en tu clúster de Kubernetes o instancia de cómputo para filtrar el 100% de traces correctos dentro del percentil 50 antes de salir hacia el backend final.

opentelemetry
tempo
observability
← Volver a SCRAM AI Lab