Preparación para la Certificación Microsoft AI-200
OpenTelemetry y Azure Monitor para IA: trazas, spans, Application Insights y KQL
Instrumenta una canalización RAG distribuida, propaga el contexto W3C, exporta telemetría confiable, controla el muestreo y diagnostica latencia con Mapa de aplicación, detalles de transacción y KQL.
Tiempo de estudio sugerido: 125 minutos • Nivel intermedio • Reescritura original completa con versión resumida de cada tema, evaluación comentada y laboratorio Python guiado
Por João Ricardo Dutra••Contenido original completo
1. Escenario y objetivos de aprendizaje
Una solución RAG de soporte al cliente contiene una puerta de enlace de , un servicio de embeddings, un servicio de búsqueda vectorial y un orquestador de LLM. La mayoría de las respuestas tarda dos segundos, pero algunas superan diez. Cada servicio escribe un registro distinto, por lo que las marcas de tiempo no demuestran dónde se consumió el tiempo. El objetivo es mantener p95 por debajo de tres segundos y ver el estado de todos los servicios en un solo lugar.
Explicar la observabilidad y el papel de trazas, métricas y registros.
Instrumentar Python con la Distro de OpenTelemetry de .
Crear spans personalizados y correlacionados para operaciones de IA.
Exportar y comprobar telemetría en .
Usar diagnósticos visuales y KQL para localizar latencia, errores y patrones de IA.
Resumen rápido
El problema no es la falta de registros aislados, sino la ausencia de una historia correlacionada para la solicitud que atraviesa todo el RAG.
2. Observabilidad y sus tres pilares
La observabilidad permite inferir el estado interno de un sistema a partir de sus señales. En IA distribuida, la latencia, los errores o la degradación de calidad pueden originarse en el modelo, la recuperación, el acceso a datos o la orquestación.
Tres perspectivas complementarias
Señal
Pregunta que responde
Ejemplo de IA
Métricas
¿Cambia el comportamiento con el tiempo?
Volumen, tasa de error, procesados y duración p95.
Motivo de reintento, validación o error del modelo.
Las métricas detectan el cambio, las trazas ubican la etapa y los registros aportan detalle local. El foco es el trazado, pero el diagnóstico fiable combina las tres señales.
Resumen rápido
Las métricas detectan, las trazas localizan y los registros explican; ninguna señal sustituye a las otras.
3. OpenTelemetry como estándar neutral
OpenTelemetry es un marco abierto y neutral de observabilidad en el ecosistema de Cloud Native Computing Foundation. Las definen cómo se produce telemetría; los implementan procesamiento, lotes, muestreo y recursos; las bibliotecas instrumentan marcos comunes; y los exportadores serializan las señales para un .
Instrumenta la lógica una vez con estables.
Envía datos a , Jaeger, Prometheus, Grafana u otro destino compatible sin reescribir los spans de negocio.
Usa instrumentación automática para protocolos comunes y manual para la semántica de IA.
Mantén el modelo de telemetría independiente de un proveedor de análisis.
OpenTelemetry separa la producción de señales del destino; la distribución de reúne los componentes comunes para .
Resumen rápido
OpenTelemetry estandariza la producción y el transporte de telemetría sin atar el código al .
4. Trazas, spans, jerarquía y contexto
Una traza es el registro de extremo a extremo de una operación distribuida. Cada span es una unidad de trabajo con nombre y duración. Contiene el ID común, su span ID, el ID del padre si existe, nombre, tiempos, atributos y estado.
Las relaciones padre-hijo forman un árbol. La solicitud de la puerta de enlace es la raíz; embedding, búsqueda y modelo son descendientes. OpenTelemetry transporta esta relación mediante TraceContext. traceparent tiene versión--id-parent-span-id-, por ejemplo 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01. El 01 final indica muestreo.
Cada servicio conserva el ID, crea un span ID y registra al llamador como padre para reconstruir la cascada.
Resumen rápido
El ID correlaciona el recorrido, los ID de span preservan causalidad y traceparent lleva el contexto entre servicios.
5. Correspondencia con
Terminología y almacenamiento
OpenTelemetry
Python
Tracer
.get_tracer("nombre")
Fuente de instrumentación; no genera una fila por sí mismo.
Span SERVER o CONSUMER
SpanKind.SERVER o CONSUMER
Solicitud: en el esquema clásico o AppRequests en el área de trabajo.
Span , INTERNAL o PRODUCER
SpanKind correspondiente
Dependencia: dependencies o AppDependencies.
ID
span.get_span_context().trace_id
operation_Id / OperationId.
Span ID y padre
span_id y contexto padre
id y operation_ParentId.
Atributos
span.set_attribute()
customDimensions / Properties.
Registros, excepciones y métricas
, record_exception y Meter
/AppTraces, exceptions/AppExceptions y customMetrics/AppMetrics.
Las consultas abiertas desde un recurso de suelen usar los nombres clásicos de los ejemplos. Las transformaciones del área de trabajo usan tablas App*. operation_Id correlaciona las tablas clásicas.
Resumen rápido
El tipo de span decide solicitud o dependencia y operation_Id une todos los elementos de la transacción.
6. Instrumentación automática o basada en código
Enfoques
Enfoque
Cuándo usarlo
Compensación
Instrumentación automática del host
Cargas compatibles en , Functions o máquinas virtuales que necesitan una base sin cambiar código.
Esfuerzo bajo, pero menor control del contexto de negocio.
Distro dentro de la aplicación
Servicios de IA que deben mostrar embedding, recuperación, prompt, o modelo.
Requiere código y gobierno, pero permite spans, atributos y muestreo personalizados.
La Distro de OpenTelemetry de reúne el de Python, exportadores, detectores e instrumentaciones compatibles. Los spans manuales complementan —no duplican— la telemetría , de marcos, bases de datos, y .
Resumen rápido
Usa automatización como base y la Distro incorporada cuando la traza deba expresar operaciones propias de IA.
7. Instala y conecta la Distro de Python
Instala -monitor-opentelemetry y llama configure_azure_monitor() una vez al iniciar. Configura proveedores globales de trazas, métricas y registros. En producción, guarda la cadena en APPLICATIONINSIGHTS_CONNECTION_STRING y no en el repositorio.
pip install azure-monitor-opentelemetry
from azure.monitor.opentelemetry import configure_azure_monitor
from opentelemetry import trace
# Read APPLICATIONINSIGHTS_CONNECTION_STRING from the environment.
configure_azure_monitor()
tracer = trace.get_tracer("rag-api")
La cadena identifica el punto de ingesta y el recurso. Un argumento connection_string explícito prevalece sobre la variable equivalente; las variables de muestreo son una excepción documentada y prevalecen sobre sus argumentos. No registres la cadena.
Resumen rápido
Una llamada inicial establece la canalización; la cadena pertenece a la configuración de implementación.
8. Comprende la recopilación automática
Cobertura común de Python
Origen
Telemetría recopilada
Flask, Django y FastAPI
Rutas entrantes como solicitudes, duración, estado y, en integraciones compatibles, excepciones no controladas.
, urllib y urllib3
Dependencias salientes.
psycopg2
Operaciones y tiempo de PostgreSQL.
Bibliotecas cliente del de
Llamadas a servicios compatibles de .
de Python
Registros conectados a OpenTelemetry.
La automatización elimina código repetitivo, pero no sabe que una función crea un prompt o que result_count mide recuperación. Agrega spans manuales con valor operativo y evita duplicar o base de datos.
Resumen rápido
La colección automática aporta estructura; los spans personalizados aportan significado de IA.
9. Identifica servicios con atributos de recurso
Cuando varios servicios informan al mismo , service.name proporciona un nombre de rol en la nube. service. agrupa la solución y service.instance.id distingue réplicas. Sin nombres estables, componentes distintos se mezclan en un nodo.
from azure.monitor.opentelemetry import configure_azure_monitor
from opentelemetry.sdk.resources import Resource
resource = Resource.create({
"service.name": "embedding-service",
"service.namespace": "support-rag",
"service.instance.id": "embedding-01",
})
configure_azure_monitor(resource=resource)
El nombre de rol combina service. y service.name si existen ambos; de lo contrario usa service.name. OTEL_SERVICE_NAME y OTEL_RESOURCE_ATTRIBUTES son alternativas. Puerta de enlace, embedding, búsqueda y orquestador necesitan nombres únicos y un común.
Resumen rápido
Los atributos de recurso describen al emisor y hacen fiable la topología del Mapa de aplicación.
10. Crea spans, atributos, estado y excepciones
.get_tracer() obtiene una fuente. start_as_current_span() inicia, activa y cierra el span al salir de with. Usa atributos con : embedding.model, embedding.token_count, search.top_k, search.result_count, llm.prompt_tokens y llm.response_tokens. Evita prompts sensibles, datos personales y nombres genéricos.
from opentelemetry import trace
from opentelemetry.trace import SpanKind, Status, StatusCode
tracer = trace.get_tracer("rag-pipeline")
with tracer.start_as_current_span("SearchVectorIndex") as span:
span.set_attribute("search.index_name", "support-docs")
span.set_attribute("search.top_k", 5)
try:
results = search_index(embedding, top_k=5)
span.set_attribute("search.result_count", len(results))
except Exception as error:
span.record_exception(error)
span.set_status(Status(StatusCode.ERROR, "Vector search failed"))
raise
with tracer.start_as_current_span("CallLlmApi", kind=SpanKind.CLIENT) as span:
span.set_attribute("gen_ai.request.model", model_name)
response = call_model(prompt)
Una excepción no controlada que sale del contexto se registra y marca error. Si el código la captura, record_exception() y set_status() conservan la evidencia. SERVER y CONSUMER son entrada; y PRODUCER son salida; INTERNAL es trabajo local y el valor predeterminado.
Resumen rápido
Los spans nombran el trabajo, los atributos lo contextualizan, kind clasifica la dirección y el estado conserva el error.
11. Modela una solicitud RAG con spans anidados
Iniciar un span mientras otro está activo crea automáticamente la relación padre-hijo mediante variables de contexto de Python. No hace falta pasar el padre para trabajo síncrono anidado.
with tracer.start_as_current_span("ProcessQuery", kind=SpanKind.SERVER):
with tracer.start_as_current_span("GenerateEmbedding") as embedding_span:
embedding_span.set_attribute("embedding.token_count", token_count)
embedding = create_embedding(query)
with tracer.start_as_current_span("SearchVectorIndex") as search_span:
documents = search(embedding, top_k=5)
search_span.set_attribute("search.result_count", len(documents))
with tracer.start_as_current_span("CallLlm", kind=SpanKind.CLIENT) as llm_span:
llm_span.set_attribute("llm.prompt_tokens", prompt_tokens)
answer = generate_answer(query, documents)
llm_span.set_attribute("llm.response_tokens", answer_tokens)
La cascada muestra ProcessQuery como raíz y embedding, búsqueda y LLM como hijos. Ocho segundos en CallLlm dentro de diez totales hacen visible el cuello de botella. En , clientes instrumentados inyectan traceparent y servidores instrumentados lo extraen.
Resumen rápido
Los contextos anidados expresan causalidad local y la propagación extiende la misma traza a otros procesos.
12. Exporta directamente o mediante Collector
Con exportación directa, la instrumentación alimenta el , el exportador serializa lotes y el proceso envía al punto de ingesta. Es la opción más simple y predeterminada. OpenTelemetry Collector añade transformación central, múltiples o políticas comunes, pero es otro servicio que operar.
La exportación directa reduce infraestructura; usa Collector cuando el procesamiento central o varios destinos lo justifiquen.
Resumen rápido
Prefiere exportación directa y adopta Collector solo por una necesidad concreta.
13. Controla volumen y coste con muestreo
El porcentaje fijo conserva una fracción representativa; el límite de velocidad restringe trazas nuevas por segundo. La Distro actual usa muestreo limitado por velocidad si no se configura una estrategia. OTEL_TRACES_SAMPLER y OTEL_TRACES_SAMPLER_ARG cambian la política sin reconstruir.
# Fixed percentage: about 10% of traces.
configure_azure_monitor(sampling_ratio=0.10)
# Or rate limited: at most about 1.5 traces per second.
configure_azure_monitor(traces_per_second=1.5)
# Equivalent environment configuration:
export OTEL_TRACES_SAMPLER="microsoft.fixed_percentage"
export OTEL_TRACES_SAMPLER_ARG="0.10"
El muestreo afecta trazas, no métricas. Los registros pueden seguir la decisión. Tasas bajas reducen precisión; usa métricas no muestreadas para alertas. Una fila puede llevar itemCount, que representa varios eventos; usa sum(itemCount), no el número bruto de filas.
Resumen rápido
Controla el coste sin ocultar errores raros y no confundas filas muestreadas con tráfico total.
14. Tolera fallos de exportación y verifica la ingesta
El exportador almacena localmente transmisiones fallidas y reintenta tras interrupciones. La ruta debe ser escribible, privada, supervisada y suficientemente persistente. disable_offline_storage elimina la protección y solo procede si una política prohíbe persistencia o existe otra garantía.
configure_azure_monitor(
storage_directory="/var/telemetry/support-rag",
# Keep False in production unless local persistence is prohibited.
disable_offline_storage=False,
)
Genera tráfico correcto y erróneo.
Comprueba la información general tras el retraso normal.
Abre Métricas en directo para solicitudes, dependencias y excepciones casi en tiempo real; viene habilitado.
Consulta solicitudes recientes y roles en la nube.
Abre una traza y confirma operation_Id, padres y atributos.
Prueba una interrupción breve en un entorno controlado y supervisa el almacenamiento.
Resumen rápido
Verificar significa demostrar llegada, identidad, correlación, atributos y recuperación.
15. Usa Mapa de aplicación y diagnóstico de transacciones
Mapa de aplicación reconstruye la topología a partir de roles y dependencias. Los nodos son componentes y los conectores son llamadas. Duración, volumen y errores permiten acotar la investigación.
Los detalles de transacción de extremo a extremo muestran una línea temporal estilo Gantt: raíz arriba, hijos sangrados, trabajo secuencial seguido y trabajo paralelo solapado. Selecciona un evento para ver duración, código, propiedades y excepción. Se accede desde Rendimiento, Errores, búsqueda de transacciones o el mapa.
Resumen rápido
El mapa encuentra el servicio sospechoso; la transacción explica una solicitud correlacionada en el tiempo.
16. Analiza trazas distribuidas con KQL
KQL responde preguntas sobre muchas transacciones. contiene entradas, dependencies contiene trabajo descendente e interno, contiene registros y exceptions contiene fallos. operation_Id conecta las tablas clásicas.
// Slow server operations by service.
requests
| where timestamp > ago(1h) and duration > 3s
| summarize slowRequests=count(), averageDuration=avg(duration)
by cloud_RoleName
| order by averageDuration desc
// Dependencies belonging to slow requests.
requests
| where timestamp > ago(1h) and duration > 5s
| project operation_Id, requestName=name, requestDuration=duration
| join kind=inner (
dependencies
| project operation_Id, dependencyName=name,
dependencyDuration=duration, dependencyTarget=target,
dependencyResult=resultCode
) on operation_Id
| order by requestDuration desc
// Embedding latency segmented by custom span attributes.
dependencies
| where name == "GenerateEmbedding"
| extend model=tostring(customDimensions["embedding.model"]),
tokenCount=toint(customDimensions["embedding.token_count"])
| summarize averageDuration=avg(duration), p95=percentile(duration, 95),
averageTokens=avg(tokenCount) by model
Las dimensiones personalizadas aportan contexto de IA: segmenta embedding por modelo y , búsqueda por cantidad y umbral y LLM por modelo y . No guardes prompts, texto privado recuperado ni credenciales para facilitar consultas.
Resumen rápido
Une por operation_Id, agrega duraciones y usa dimensiones seguras para probar una hipótesis.
17. Diagnostica patrones de IA y completa el laboratorio
Patrones
Señal
Investigación
Tiempo de espera de embedding
Dependencia larga o fallida; compara embedding.model.
Arranque en frío de búsqueda
Primeros spans tras inactividad lentos y después normales; compara result_count.
Limitación del LLM
Dependencias con 429 o reintentos largos; correlaciona .
Desbordamiento de contexto
Fallo cerca del límite de ; no almacenes el prompt.
Crea alertas, Libros para estado de la canalización y métricas para tendencias. El laboratorio usa Flask con Python 3.12+, una suscripción de , y la CLI de más reciente. Crea , instrumenta un proceso documental y diagnostica latencia simulada.
Crea el recurso y configura la cadena en el entorno.
Instala la Distro y define atributos.
Agrega spans padre e hijo con seguros.
Genera tráfico normal, lento y fallido.
Ubica el retraso en mapa y transacción.
Confirma con KQL y guarda una vista útil.
Elimina el recurso y la cadena local.
export APPLICATIONINSIGHTS_CONNECTION_STRING="<application-insights-connection-string>"
az login
python -m flask --app app run
# Generate normal, slow, and failing requests, then inspect:
# Application Map -> Performance/Failures -> End-to-end transaction details -> Logs.
Resumen rápido
El laboratorio termina cuando topología, una traza y una consulta agregada sostienen el mismo diagnóstico.
18. Evaluación comentada, lista final y referencias
Decisiones
Pregunta
Mejor respuesta
Razón
¿Cómo se propaga contexto ?
TraceContext mediante traceparent.
Transporta ID, padre, versión y .
¿Dónde configurar la cadena?
APPLICATIONINSIGHTS_CONNECTION_STRING.
Mantiene la implementación fuera del código.
¿Qué ocurre con una excepción no controlada?
El la registra y marca error.
El contexto captura el fallo antes de cerrar.
¿Dónde aparece ?
dependencies / AppDependencies.
Es una llamada saliente.
¿Qué campo correlaciona?
operation_Id / OperationId.
Corresponde al ID.
Lista final
Define service.name estable y común.
Verifica traceparent en cada frontera.
Combina automatización con pocos spans semánticos.
Usa atributos con baja cardinalidad y sin datos sensibles.
Clasifica SpanKind correctamente.
Documenta muestreo, almacenamiento y retención.
Valida mapa, transacciones, Métricas en directo, KQL, alertas y Libros.
Supervisa lagunas, errores de exportación, almacenamiento, coste y p95.
Una solución de producción une instrumentación semántica, correlación , exportación controlada, muestreo consciente del coste, entrega resistente, diagnóstico visual, KQL y supervisión proactiva.