Alors que les grands modèles de langage (LLM) deviennent centraux dans les applications modernes, garantir leur fiabilité, leur rentabilité et leurs performances est crucial. Les outils de surveillance traditionnels montrent souvent leurs limites pour tracer les flux de travail génératifs complexes et non déterministes. C'est là qu'OpenTelemetry (OTel) brille, en fournissant une norme unifiée et agnostique aux fournisseurs pour les données de télémétrie.
Le défi de l'instrumentation des LLM
L'instrumentation des LLM diffère considérablement de la surveillance standard des API. Vous devez capturer non seulement la latence et les codes d'état, mais aussi les modèles de prompt, le nombre de jetons, les versions des modèles et les métadonnées de réponse. Sans une approche standardisée, vous risquez de vous verrouiller dans le SDK d'un fournisseur spécifique, ce qui rend difficile le changement de fournisseur ou l'agrégation des données entre plusieurs services d'IA.
Premiers pas avec les bibliothèques LLM d'OpenTelemetry
Les bibliothèques d'instrumentation LLM d'OpenTelemetry (spécifiquement pour Python et Node.js) abstraient la complexité de la création de traces pour différents fournisseurs de modèles. Elles créent automatiquement des spans pour les prompts, les complétions et les embeddings, assurant la cohérence que vous utilisiez OpenAI, Anthropic ou une instance locale d'Ollama.
Mise en œuvre pratique en Python
Regardons un exemple pratique utilisant le SDK Python. Tout d'abord, vous devez installer les packages nécessaires :
pip install opentelemetry-api opentelemetry-sdk \
opentelemetry-exporter-otlp \
opentelemetry-instrumentation-llm
Ensuite, configurez le traceur et instrumentez votre client LLM. Le code suivant montre comment configurer l'exportateur et appliquer l'instrumentation :
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.llm import OpenTelemetryLLMInstrumentor
# Configurer le fournisseur de traceurs
trace.set_tracer_provider(TracerProvider())
# Configurer l'exportateur OTLP pour envoyer des données à votre backend
exporter = OTLPSpanExporter(endpoint="localhost:4317")
trace.get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tracer_provider().add_span_processor(
trace.get_tracer_provider().get_tracer(__name__).get_tr