1. Qu'est-ce qu'OpenInference ? #
Un vocabulaire commun pour les traces d'IA.
Définition #
OpenInference est un projet open source (initié par Arize) qui définit deux choses :
- des conventions sémantiques : quels attributs mettre sur un span pour décrire un appel de modèle, une recherche de documents, un appel d'outil ou une étape d'agent ;
- des instrumentations prêtes à l'emploi qui produisent automatiquement ces spans pour les principaux SDK et frameworks d'IA, en Python, JavaScript et Java.
Tout repose sur OpenTelemetry : les spans OpenInference sont des spans OpenTelemetry ordinaires, exportés en OTLP. Phoenix et Arize AX savent les afficher de façon riche (messages, documents, jetons), et n'importe quel backend OTLP peut les stocker.
Pourquoi des conventions ? #
Sans convention, chaque équipe nomme ses attributs à sa façon (prompt, llm_input, messages...) et aucun outil ne peut calculer un coût en jetons ou afficher une conversation. Avec OpenInference, llm.token_count.prompt signifie la même chose quel que soit le framework, ce qui permet des tableaux de bord, des évaluations et des comparaisons génériques.
2. Les types de spans #
openinference.span.kind.
Les valeurs #
| Type | Représente | Exemple |
|---|---|---|
LLM | Un appel à un modèle de langage | chat.completions.create |
EMBEDDING | Le calcul d'embeddings | Vectorisation d'une question |
RETRIEVER | La recherche de documents | Requête vers une base vectorielle |
RERANKER | Le reclassement de documents | Cross-encoder sur les 20 premiers résultats |
CHAIN | Un enchaînement d'étapes ou la logique applicative | Pipeline RAG complet |
TOOL | Un appel d'outil ou de fonction | get_weather(city) |
AGENT | Une étape de raisonnement d'agent | Boucle choix d'outil puis réponse |
GUARDRAIL | Un contrôle de sécurité ou de conformité | Détection de données personnelles |
EVALUATOR | Une évaluation | LLM juge de pertinence |
PROMPT | Le rendu d'un gabarit de prompt | Remplissage des variables |
À savoir : La liste des types évolue avec la spécification (par exempleDECISIONpour les choix de routage) : consultezspec/semantic_conventions.mddu dépôt OpenInference.
3. Les attributs essentiels #
Ce que contient un span.
Par famille #
| Famille | Attributs | Contenu |
|---|---|---|
| Entrée et sortie | input.value, input.mime_type, output.value, output.mime_type | Ce qui entre et sort de l'étape (texte ou JSON) |
| Modèle | llm.model_name, llm.provider, llm.invocation_parameters | Modèle, fournisseur, température, max_tokens (JSON) |
| Messages | llm.input_messages.<i>.message.role, .message.content, llm.output_messages.<i>... | La conversation envoyée et reçue, message par message |
| Jetons | llm.token_count.prompt, llm.token_count.completion, llm.token_count.total | La base du calcul de coût |
| Gabarit | llm.prompt_template.template, .variables, .version | Le prompt avant remplissage, pour relier une réponse à une version |
| Documents | retrieval.documents.<i>.document.id, .content, .score, .metadata | Les passages récupérés et leur score |
| Embeddings | embedding.model_name, embedding.embeddings.<i>.embedding.text, .vector | Textes vectorisés |
| Outils | tool.name, tool.description, tool.parameters, tool_call.function.name, tool_call.function.arguments | Outil appelé et arguments choisis par le modèle |
| Contexte | session.id, user.id, metadata, tag.tags | Regrouper par conversation, utilisateur, version, fonctionnalité |
4. Instrumenter #
Automatique d'abord, manuel ensuite.
Instrumentation automatique #
pip install arize-phoenix-otel openinference-instrumentation-openai openaifrom phoenix.otel import register
# configure OpenTelemetry et active toutes les instrumentations OpenInference installées
tracer_provider = register(
project_name="support-bot",
endpoint="http://localhost:6006/v1/traces", # Phoenix, en OTLP/HTTP
auto_instrument=True,
)
from openai import OpenAI
client = OpenAI()
client.chat.completions.create(model="gpt-4o-mini",
messages=[{"role": "user", "content": "Bonjour"}])Sans Phoenix, la même instrumentation fonctionne avec le SDK OpenTelemetry standard :
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from openinference.instrumentation.openai import OpenAIInstrumentor
provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(endpoint="http://collector:4318/v1/traces")))
OpenAIInstrumentor().instrument(tracer_provider=provider)| Écosystème | Exemples de paquets |
|---|---|
| Fournisseurs de modèles | openinference-instrumentation-openai, -anthropic, -bedrock, -vertexai, -mistralai, -litellm |
| Frameworks | -langchain, -llama-index, -dspy, -haystack |
| Agents | -openai-agents, -crewai, -smolagents, -autogen |
| JavaScript, Java | @arizeai/openinference-instrumentation-openai, instrumentations LangChain.js, LangChain4j |
Instrumentation manuelle #
Pour une étape maison (une recherche dans votre propre index, un outil métier), créez le span vous-même avec les conventions :
from opentelemetry import trace
from openinference.semconv.trace import SpanAttributes, OpenInferenceSpanKindValues
tracer = trace.get_tracer("rag")
def retrieve(question: str):
with tracer.start_as_current_span("retrieve") as span:
span.set_attribute(SpanAttributes.OPENINFERENCE_SPAN_KIND, OpenInferenceSpanKindValues.RETRIEVER.value)
span.set_attribute(SpanAttributes.INPUT_VALUE, question)
docs = index.search(question, k=3)
for i, d in enumerate(docs):
span.set_attribute(f"retrieval.documents.{i}.document.id", d.id)
span.set_attribute(f"retrieval.documents.{i}.document.content", d.text)
span.set_attribute(f"retrieval.documents.{i}.document.score", d.score)
return docsContexte : sessions, utilisateurs, métadonnées #
from openinference.instrumentation import using_attributes
with using_attributes(session_id=conversation_id, user_id=user.id,
metadata={"app_version": "2.3.0", "feature": "faq"}, tags=["beta"]):
answer = agent.run(question) # tous les spans créés ici portent ces attributsBonne Pratique : Renseignez toujours session.id pour les conversations et une métadonnée de version : c'est ce qui permet d'afficher une conversation complète et de comparer deux versions de l'application.5. Confidentialité et volume #
Les prompts contiennent des données sensibles.
Masquer #
Les prompts et les réponses peuvent contenir des données personnelles. Les instrumentations OpenInference acceptent une configuration de masquage, en code (TraceConfig) ou par variables d'environnement :
| Variable | Effet |
|---|---|
OPENINFERENCE_HIDE_INPUTS | Masque input.value et les messages d'entrée |
OPENINFERENCE_HIDE_OUTPUTS | Masque les sorties |
OPENINFERENCE_HIDE_INPUT_MESSAGES, ..._OUTPUT_MESSAGES | Masque seulement les messages |
OPENINFERENCE_HIDE_EMBEDDING_VECTORS | Supprime les vecteurs, souvent volumineux |
OPENINFERENCE_BASE64_IMAGE_MAX_LENGTH | Limite la taille des images encodées |
Erreur Courante : Masquer toutes les entrées empêche ensuite d'évaluer les réponses. Préférez masquer les champs sensibles (dans le code ou dans un OpenTelemetry Collector) et limiter l'accès aux traces.
6. OpenInference et les conventions GenAI d'OpenTelemetry #
Deux standards proches.
Comparaison #
OpenTelemetry définit aussi des conventions pour l'IA générative (attributs gen_ai.* : gen_ai.request.model, gen_ai.usage.input_tokens...), encore en cours de stabilisation. OpenInference est antérieur, plus riche sur les RAG et les agents (documents, reranking, outils, types de spans), et largement outillé.
| OpenInference | OpenTelemetry GenAI | |
|---|---|---|
| Porté par | Projet OpenInference (Arize) | OpenTelemetry (CNCF) |
| Préfixe | llm.*, retrieval.*, tool.* | gen_ai.* |
| Types de spans métier | Oui (openinference.span.kind) | Par opération (gen_ai.operation.name) |
| Instrumentations | Nombreuses, Python, JS, Java | En croissance (instrumentations contrib) |
Bonne Pratique : Choisissez l'instrumentation selon votre backend principal ; si vous devez alimenter plusieurs outils, un OpenTelemetry Collector peut renommer des attributs (processeur transform) pour passer d'une convention à l'autre.
