How do I switch from Arize Phoenix to Rius for tracing the OpenAI API?
To switch from Arize Phoenix to Rius for OpenAI calls, replace register() from phoenix.otel with rius.init() and install the OpenAI extra of the Rius SDK. The SDK instruments the OpenAI client for you, so your call sites stay as they are. Each chat completion then arrives in Rius as a span with the model, token counts, messages and a cost computed by Rius.
How it works
Phoenix and Rius both read OpenInference spans, so this is a routing change more than a rewrite. The Rius SDK ships the same OpenInference OpenAI instrumentation behind the openai extra, and rius.init() turns on every supported library it finds installed. That means your own OpenAIInstrumentor().instrument() call and the auto_instrument=True flag go away together with register().
The Phoenix settings map across like this:
register(project_name=...)becomesrius.init(service_name=...). Rius groups traces into an agent byservice.name, so the project name no longer drives grouping.using_sessionbecomesrius.session, andusing_userbecomesrius.user. They stamp every span in scope, the root span included.@tracer.chain,@tracer.agentand@tracer.toolbecome@rius.observe, withkind=rius.SpanKind.AGENTorkind=rius.SpanKind.TOOLfor the last two.- The SDK raises the span attribute limit to 4096, so long agent loops keep their model, usage and output.
The endpoint defaults to EU ingest, so RIUS_API_KEY is usually the only setting. If you would rather keep your OpenInference instrumentors and your own exporter, re-point the exporter at Rius instead. The Phoenix migration guide covers that path.
Set it up
- Create a Rius workspace and API key, then replace the Phoenix package with the OpenAI extra. The extra installs the instrumentation, not
openaiitself, so a fresh environment namesopenaitoo. Removearize-phoenix-otelfrom your environment if nothing else uses it.
pip install "glassflow-rius[openai]" openai
export RIUS_API_KEY="<your API key>"- Swap
register()forrius.init()and move session scoping torius.session. Hereconversation_idandrun_agentare your own names.
# Before
from phoenix.otel import register
from openinference.instrumentation import using_session
register(project_name="my-agent", auto_instrument=True)
with using_session(conversation_id):
run_agent(message)# After
import rius
rius.init(service_name="my-agent")
with rius.session(conversation_id):
run_agent(message)-
Switch
using_sessionandusing_userin the same change. The OpenInference context managers do not stamp spans you start with@rius.observe, which are usually the root, so the trace would lose its session and user. -
For streamed calls, set
include_usageto true instream_options. Without it a streamed span has no token counts, and no tokens means no cost. -
Run one traced request and open it in the console. The span shows the resolved model, input and output token counts and a cost. Wrap the call in
observeto see it nested inside your agent’s run instead of as a standalone trace.
Using the TypeScript SDK? Install @arizeai/openinference-instrumentation-openai, call init() before you create the OpenAI client, and await rius.ready to confirm openai attached. The OpenAI integration page has both languages, and the integrations list shows what else is covered.
What you get
- One span per chat completion. It is an LLM-kind span carrying the model, token usage and input and output messages, read in Rius as a generation.
- Cost per call. Rius computes it on the server from the model and token counts. Costs are list-price estimates in US dollars, and a model Rius does not know gets an empty cost, not zero. You never send a cost value.
- Time to first token on streamed calls in Python, with no manual code. TypeScript streamed completions carry token usage but no time to first token.
- Errors as ERROR spans. A rejected call, such as a 404 for an unknown model, a 429 or a timeout, is recorded with
error.typenaming the error class. - Sessions and users from
rius.sessionandrius.user, plus heartbeats that show which agent processes are alive. - Content controls.
capture_content=Falseand masking apply to instrumented calls exactly like manual ones.
Some Phoenix features do not carry over. Rius has no evals, datasets, experiments, annotations, prompt management or playground, no custom model prices, and no import of historical Phoenix traces. It is a managed service only, so there is nothing to self-host. Rius starts from the first span you send.
When something else fits
- If you only want the smallest diff, or want to run both backends during an evaluation, keep your OpenInference instrumentors and add Rius as a second exporter, as the Phoenix migration guide shows. The general options are on Migrate to Rius.
- If evals, datasets or annotations are central to your workflow, keep Phoenix for those pieces and send traces to both backends rather than cutting over completely.