Le Black Friday qui m'a fait comprendre l'importance du contexte distribué
Le 11 novembre 2024, à 02h47 du matin, mon téléphone vibre : alerte critique sur notre passerelle LLM d'e-commerce. Un pic de 14× le trafic normal — chatbot de service client dopé à GPT-4.1 qui sert simultanément 12 000 utilisateurs francophones. Les logs sont noyés, le rate-limit du fournisseur upstream se déclenche, et les 429 Too Many Requests se propagent en cascade vers le front, le worker de retry, et le système de tickets. Sans contexte de trace, impossible de savoir si l'erreur vient du quota par utilisateur, du token-per-minute, ou d'une panne régionale. Cette nuit-là, j'ai compris que OpenTelemetry n'était plus optionnel dans une architecture LLM.
Dans ce tutoriel, je vous montre comment instrumenter une passerelle d'API LLM compatible avec HolySheep AI pour que chaque erreur 429 — et chaque retry — conserve son trace_id de bout en bout, avec une latence P50 inférieure à 50 ms.
Pourquoi les erreurs 429 sont un cas particulier dans les chaînes LLM
Contrairement à un microservice REST classique, une requête LLM traverse plusieurs couches de rate-limiting invisibles :
- Limite par utilisateur (quota de tokens/minute sur votre passerelle)
- Limite par tenant (compte partagé entre plusieurs équipes)
- Limite du fournisseur (RPM, TPM côté OpenAI / Anthropic / DeepSeek)
- Limite du modèle (certains modèles flaggent les abus plus vite)
Sans propagation de contexte, le ticket d'incident ressemble à : « 429 sur le pod B à 03h12 ». Avec OpenTelemetry + W3C Trace Context + Baggage, il devient : « 429 déclenché par le quota upstream de l'utilisateur tier=free user_id=8421, retry_after=60s, propagation OK vers le worker d'embeddings ».
Architecture cible : passerelle Flask + collector OTLP + Tempo
Notre stack de référence :
- Passerelle : Flask 3.x + Python 3.12
- SDK OTel :
opentelemetry-sdk,opentelemetry-exporter-otlp-proto-grpc - Backend : OpenTelemetry Collector → Tempo → Grafana
- Provider LLM : HolySheep AI (base
https://api.holysheep.ai/v1, latence < 50 ms, paiement WeChat/Alipay, taux ¥1 = $1)
Code 1 — Passerelle LLM instrumentée avec span, baggage et capture des 429
# passerelle_llm.py
Passerelle API LLM avec traçage OpenTelemetry distribué.
from flask import Flask, request, jsonify
from opentelemetry import trace, context, baggage
from opentelemetry.sdk.trace import TracerProvider, Resource
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.propagate import inject, extract
from opentelemetry.semconv.resource import ResourceAttributes
from openai import OpenAI, RateLimitError
import time, logging
── 1. Configuration du tracer global ──────────────────────────────────
resource = Resource.create({
ResourceAttributes.SERVICE_NAME: "llm-api-gateway",
ResourceAttributes.SERVICE_VERSION: "1.4.2",
ResourceAttributes.DEPLOYMENT_ENVIRONMENT: "production",
})
provider = TracerProvider(resource=resource)
provider.add_span_processor(
BatchSpanProcessor(