RousselTMLEARNING

Observability

OpenInference: the OpenTelemetry conventions for tracing AI applications

Detailed guide to OpenInference: OpenTelemetry semantic conventions and instrumentations for LLMs, RAG and agents. Span kinds, llm.*, retrieval.*, tool.* attributes, automatic and manual instrumentation, sessions, privacy, interoperability with OpenTelemetry's GenAI conventions.

1. What is OpenInference? #

A common vocabulary for AI traces.

Definition #

OpenInference is an open source project (initiated by Arize) that defines two things:

  • semantic conventions: which attributes to put on a span to describe a model call, a document retrieval, a tool call or an agent step;
  • ready-to-use instrumentations that automatically produce these spans for the main AI SDKs and frameworks, in Python, JavaScript and Java.

Everything is built on OpenTelemetry: OpenInference spans are ordinary OpenTelemetry spans, exported over OTLP. Phoenix and Arize AX can display them richly (messages, documents, tokens), and any OTLP backend can store them.

The OpenInference layers on top of OpenTelemetry

Why conventions? #

Without conventions, each team names its attributes its own way (prompt, llm_input, messages...) and no tool can compute a token cost or display a conversation. With OpenInference, llm.token_count.prompt means the same thing whatever the framework, which enables generic dashboards, evaluations and comparisons.

2. Span kinds #

openinference.span.kind.

The values #

OpenInference span tree for an agent
KindRepresentsExample
LLMA call to a language modelchat.completions.create
EMBEDDINGComputing embeddingsVectorizing a question
RETRIEVERDocument retrievalQuery to a vector database
RERANKERDocument rerankingCross-encoder on the top 20 results
CHAINA sequence of steps or application logicFull RAG pipeline
TOOLA tool or function callget_weather(city)
AGENTAn agent reasoning stepTool-choice loop then answer
GUARDRAILA safety or compliance checkPersonal data detection
EVALUATORAn evaluationRelevance LLM judge
PROMPTRendering a prompt templateFilling in the variables
Good to know: The list of kinds evolves with the specification (for example DECISION for routing choices): see spec/semantic_conventions.md in the OpenInference repository.

3. Essential attributes #

What a span contains.

By family #

FamilyAttributesContent
Input and outputinput.value, input.mime_type, output.value, output.mime_typeWhat goes in and out of the step (text or JSON)
Modelllm.model_name, llm.provider, llm.invocation_parametersModel, provider, temperature, max_tokens (JSON)
Messagesllm.input_messages.<i>.message.role, .message.content, llm.output_messages.<i>...The conversation sent and received, message by message
Tokensllm.token_count.prompt, llm.token_count.completion, llm.token_count.totalThe basis for computing cost
Templatellm.prompt_template.template, .variables, .versionThe prompt before filling, to link an answer to a version
Documentsretrieval.documents.<i>.document.id, .content, .score, .metadataRetrieved passages and their score
Embeddingsembedding.model_name, embedding.embeddings.<i>.embedding.text, .vectorVectorized texts
Toolstool.name, tool.description, tool.parameters, tool_call.function.name, tool_call.function.argumentsTool called and arguments chosen by the model
Contextsession.id, user.id, metadata, tag.tagsGroup by conversation, user, version, feature

4. Instrumenting #

Automatic first, then manual.

Automatic instrumentation #

pip install arize-phoenix-otel openinference-instrumentation-openai openai
from 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"}])

Without Phoenix, the same instrumentation works with the standard OpenTelemetry SDK:

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)
EcosystemExample packages
Model providersopeninference-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, LangChain.js and LangChain4j instrumentations

Manual instrumentation #

For an in-house step (a search in your own index, a business tool), create the span yourself following the 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 docs

Context: sessions, users, metadata #

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 attributs
Good practice: Always set session.id for conversations and a version metadata: this is what makes it possible to display a complete conversation and compare two versions of the application.

5. Privacy and volume #

Prompts contain sensitive data.

Masking #

Prompts and answers may contain personal data. OpenInference instrumentations accept a masking configuration, in code (TraceConfig) or through environment variables:

VariableEffect
OPENINFERENCE_HIDE_INPUTSHides input.value and input messages
OPENINFERENCE_HIDE_OUTPUTSHides outputs
OPENINFERENCE_HIDE_INPUT_MESSAGES, ..._OUTPUT_MESSAGESHides only the messages
OPENINFERENCE_HIDE_EMBEDDING_VECTORSRemoves vectors, which are often large
OPENINFERENCE_BASE64_IMAGE_MAX_LENGTHLimits the size of encoded images
Common mistake: Hiding all inputs then makes it impossible to evaluate answers. Prefer masking sensitive fields (in code or in an OpenTelemetry Collector) and restricting access to traces.

6. OpenInference and OpenTelemetry's GenAI conventions #

Two close standards.

Comparison #

OpenTelemetry also defines conventions for generative AI (gen_ai.* attributes: gen_ai.request.model, gen_ai.usage.input_tokens...), still being stabilized. OpenInference came earlier, is richer for RAG and agents (documents, reranking, tools, span kinds), and is widely tooled.

OpenInferenceOpenTelemetry GenAI
Backed byOpenInference project (Arize)OpenTelemetry (CNCF)
Prefixllm.*, retrieval.*, tool.*gen_ai.*
Business span kindsYes (openinference.span.kind)By operation (gen_ai.operation.name)
InstrumentationsMany, Python, JS, JavaGrowing (contrib instrumentations)
Good practice: Choose the instrumentation based on your main backend; if you need to feed several tools, an OpenTelemetry Collector can rename attributes (transform processor) to switch from one convention to the other.

Related articles

Core OpenTelemetry concepts: signals, resources, context and maturity

The essential OpenTelemetry vocabulary: the four signals, API and SDK, resource and instrumentation scope, co…

OpenTelemetry Collector: connectors, extensions and observing the Collector

Go further with the Collector: connectors (spanmetrics, servicegraph, count, routing, failover), extensions (…

OpenTelemetry semantic conventions (semconv): naming telemetry

Understand and apply OpenTelemetry semantic conventions: resource, HTTP, database, messaging and GenAI attrib…

Keep learning

Support us

♥ SUPPORT US

Support RousselTM Learning

Courses, articles, labs and certificates stay free with no intrusive ads. A voluntary contribution, of any amount you choose, pays for hosting, lab environments and new content.

Contribute with PayPal Any amount · card or PayPal accountLearn more
QR code PayPal
Or scan this QR code with your phone

Thank you, every contribution counts!