Skip to Content

How do I switch from LangSmith to Rius for tracing the OpenAI API?

Rius traces the OpenAI client once you install the openai extra and call rius.init(), so you drop wrap_openai and the LangSmith environment variables. Every OpenAI call in your process is traced, and each chat completion arrives as a span with the model, token counts and a cost. Your @traceable functions become @rius.observe, and LangSmith thread metadata becomes a Rius session. The LangSmith migration guide covers the other paths.

How it works

LangSmith traces OpenAI calls through a client wrapper, wrap_openai(OpenAI()). Rius has no wrapper. The OpenAI integration patches the client library for the whole process when you call rius.init(), so every client you create, anywhere in your code, is traced.

The extra installs the instrumentation, not the openai package itself. If the library is missing, init() logs a DependencyConflict and the integration stays off.

The rest of the mapping is one to one:

  • @traceable becomes @rius.observe, and @traceable(name="Chat Pipeline") becomes @rius.observe(name="Chat Pipeline").
  • run_type="tool" becomes kind=rius.SpanKind.TOOL, and run_type="retriever" becomes kind=rius.SpanKind.RETRIEVER.
  • A thread set through metadata={"thread_id": thread_id} becomes with rius.session(thread_id):, which stamps the session on every span started inside it, child spans included.
  • Other metadata and tags become span attributes. Rius has no separate tag concept.

The integrations page lists every other library and framework that works the same way, in case you trace more than OpenAI.

Set it up

  1. Install the instrumentation for OpenAI next to the library you already use, and replace the LangSmith environment with a Rius key:
pip install "glassflow-rius[openai]" openai # Before: LangSmith export LANGSMITH_TRACING=true export LANGSMITH_API_KEY="lsv2_..." export LANGSMITH_PROJECT="my-agent" # After: Rius export RIUS_API_KEY="ri_..."
  1. Remove the wrapper and call rius.init() before you create the client. Here is the code you have today:
# Before: LangSmith from langsmith import traceable from langsmith.wrappers import wrap_openai from openai import OpenAI client = wrap_openai(OpenAI()) @traceable(name="Chat Pipeline", metadata={"thread_id": thread_id}) def pipeline(question: str) -> str: return client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": question}], ).choices[0].message.content pipeline("What does Rius ingest?")
  1. This is the same code on Rius. The client is a plain OpenAI():
# After: Rius import rius from openai import OpenAI rius.init(service_name="my-agent") client = OpenAI() # no wrapper: init() instruments the library @rius.observe(name="Chat Pipeline") def pipeline(question: str) -> str: return client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": question}], ).choices[0].message.content with rius.session(thread_id): pipeline("What does Rius ingest?")
  1. If your app is in TypeScript, install @arizeai/openinference-instrumentation-openai, call init() before you create the client, and await rius.ready to confirm openai is among the integrations that attached.
  2. If you stream, pass stream_options={"include_usage": True} to the call. Without it, streamed spans have no token counts, and no tokens means no cost.
  3. Run one call and open the trace in the console. When Rius shows what you need, unset LANGSMITH_TRACING, remove the wrapper and revoke the LangSmith keys. Until then, you can run both backends side by side. The migration overview describes the options.

What you get

  • A span for each model call. Each chat completion carries the model, token usage and the input and output messages. The span shows the resolved model, for example gpt-4o-mini-2024-07-18.
  • Cost per call. Rius computes it from the model and token counts. It is a list-price estimate in US dollars, and you never send a cost value.
  • Nesting. Inside an @rius.observe function, the model call appears under your pipeline’s span instead of as a standalone trace.
  • Time to first token on Python streams. The Python integration records it without manual code. TypeScript streamed completions carry token usage but no time to first token.
  • Errors that stand out. A rejected call, such as a 404 for an unknown model, a 429 or a timeout, is an ERROR span with error.type naming the error class, for example openai.NotFoundError.
  • Sessions. Turns wrapped in rius.session(thread_id) group together.
  • Content controls. capture_content=False and masking apply to instrumented calls exactly as they do to manual ones.

Existing LangSmith traces stay in LangSmith. Rius starts from the first span you send.

When something else fits

  • If you depend on datasets, experiments, evaluators, feedback queues or the Prompt Hub, keep LangSmith for those. Rius does not offer them, so run both backends instead of cutting over completely.
  • If you cannot change code yet, LangSmith’s own OpenTelemetry export can point at Rius with environment variables. Model, tokens and cost arrive that way, but message content and session grouping do not, so treat it as a bridge and see the LangSmith migration guide for the gaps.

Still stuck? Get help

Last updated on