Auto-instrumentation
What you get
Install the integration’s extra (Python) or its peer package (TypeScript) and
call init(). Your model calls then show up in the console with model,
tokens, cost, and messages, the same as a
manual generation, and tool,
retrieval, and agent steps show up as their own kinds of span. Where a
wrapper such as LangChain, LiteLLM, LlamaIndex, or the Vercel AI SDK sits
over a traced model call, the call’s usage is counted once, not once per
layer.
Most integrations are built on an
OpenInference package, such as
openinference-instrumentation-openai in Python or
@arizeai/openinference-instrumentation-openai in TypeScript. This page
calls it the integration’s package.
The support matrix lists what is supported and Installing shows how to add each integration.
What the SDK normalizes
Each integration’s package writes its own attribute names, mostly
OpenInference’s llm.* keys. The SDK rewrites them onto the OpenTelemetry
GenAI keys a manual generation carries, inside your process and before the
privacy controls run. This always
runs; there is no option to turn it off. For you, it means:
- Query the canonical keys, such as
gen_ai.usage.input_tokensrather thanllm.token_count.prompt. A key with no canonical equivalent keeps its own name. - Token usage is complete: input and output tokens, cache reads and writes, and reasoning tokens.
- LiteLLM model names lose the routing prefix when it names the
provider, so
openai/gpt-4o-miniis stored asgpt-4o-mini. Update model filters that matched the prefixed form. - A failed call names its error class in
error.type, such asanthropic.NotFoundError, with the same spelling in both SDKs. - Embedding vectors are dropped rather than exported.
For attribute-level detail, for example when you build on raw attributes or send OTLP without the SDK, see the span attribute reference.
Known gaps
Still counted twice
In these cases two spans record the same model call and both keep its usage, so the call’s tokens and cost are counted twice:
- LangChain text-completion models, such as
langchain_openai.OpenAI, in both SDKs. Only chat models are covered. - A TypeScript LangChain call made from inside a LangChain callback.
- LlamaIndex together with the
openaiintegration beforeglassflow-rius1.1.1, or with aMultiModalLLMmodel on any version. The two spans of the same call land in separate traces. - Python package versions outside the supported ranges:
openinference-instrumentation-langchain0.1.67 to 0.1.79,openinference-instrumentation-llama-index4.4.3 to 4.6.0, and for streamed callsopeninference-instrumentation-litellm0.1.34 to 0.1.50. The extras set no upper bound, so a fresh install can pick up a newer release that is outside the range. - LiteLLM or Vercel AI SDK 7 (
@ai-sdk/otel) spans sent straight to Rius without the SDK. The usage dedup runs in the SDK, not on the platform.
Count the call once
- Pin the package to the supported range:
openinference-instrumentation-langchain<=0.1.79,openinference-instrumentation-llama-index<=4.6.0, andopeninference-instrumentation-litellm<=0.1.50for streamed LiteLLM calls. - Keep one layer. In Python, list the integrations you want with
rius.init(instruments=[...]), for exampleinstruments=["langchain"]orinstruments=["llama-index"]. TypeScript has no per-integration option, so leave the provider’s package uninstalled, such as@arizeai/openinference-instrumentation-openai. Either way the provider integration is off for the whole process: direct calls to that provider outside the framework are no longer traced, so trace those as manual generations. - Send the spans through the SDK. For LiteLLM or
@ai-sdk/otelspans exported without it, callrius.init()(init()in TypeScript) in that process so the SDK exports them.
No time to first token
Anthropic streams, TypeScript OpenAI streams, and LangChain and LiteLLM
streams carry no time to first token, because their integration packages
do not record it. In Python, a LangChain or LiteLLM stream over the openai
integration gets it on its nested OpenAI span. Where the metric matters,
trace the call as a manual generation and call record_first_token()
(recordFirstToken()); see
Streaming responses.
Auto-instrumentation or manual generations?
Auto-instrumentation is the right default: it needs no code. Reach for
manual generations
(start_as_current_generation / startAsCurrentGeneration, or
start_generation / startGeneration for streams and callbacks) when:
- There is no integration for your provider or framework, such as a provider’s own HTTP API.
- You need a field the integration does not record, such as time to first token.
- You compute usage yourself. Pass token counts to
set_usage()(setUsage()), cache and reasoning counts included; Rius prices them server-side. - A call is still counted twice and you want a single span for it.
When a manual generation replaces an auto-instrumented call, turn that call’s integration off, or the generation and the integration’s span both carry the usage and the call is counted twice.
Content capture
capture_content (captureContent) and mask apply to auto-instrumented
spans exactly as to your own: prompts, responses, tool arguments and results
captured by an integration are stripped or masked at export, inside your
process. See Privacy controls.