Skip to Content
RiusSDKAuto-instrumentation

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_tokens rather than llm.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-mini is stored as gpt-4o-mini. Update model filters that matched the prefixed form.
  • A failed call names its error class in error.type, such as anthropic.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 openai integration before glassflow-rius 1.1.1, or with a MultiModalLLM model on any version. The two spans of the same call land in separate traces.
  • Python package versions outside the supported ranges: openinference-instrumentation-langchain 0.1.67 to 0.1.79, openinference-instrumentation-llama-index 4.4.3 to 4.6.0, and for streamed calls openinference-instrumentation-litellm 0.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, and openinference-instrumentation-litellm<=0.1.50 for streamed LiteLLM calls.
  • Keep one layer. In Python, list the integrations you want with rius.init(instruments=[...]), for example instruments=["langchain"] or instruments=["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/otel spans exported without it, call rius.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.

Last updated on