Migrate from LangSmith to Rius
LangSmith traces LangChain and LangGraph apps through LangChain’s callback
system, and any other code through @traceable and its client wrappers.
Rius takes OpenTelemetry traces, and the Rius SDK hooks the same LangChain
callbacks, so for most apps the migration is a dependency and a few lines of
setup, not a rewrite. This guide maps the concepts, walks the migration
paths, and ends with a cutover checklist. Run both backends in parallel
during the evaluation; nothing here requires a hard switch.
TL;DR: For a LangChain or LangGraph app, install the Rius SDK with the
langchain extra and call rius.init() (Path A). For @traceable,
wrap_openai and wrap_anthropic, swap them for @rius.observe and the
Rius integrations (Path B). If you cannot change code yet, LangSmith’s own
OpenTelemetry export can send to Rius (Path C), with gaps listed below.
Why migrate from LangSmith to Rius
Rius is agent observability built on OpenTelemetry: traces arrive over plain OTLP, so the same instrumentation works with any backend. On top of the traces you get session and user grouping, server-side cost, alerts, and an MCP server so your coding agent can query production traces. With the Rius SDK you also see which agent processes are alive, and, with partial spans turned on, runs still in progress. LangSmith features with no Rius equivalent are listed in what does not carry over.
Concept mapping: LangSmith vs Rius
| LangSmith | Rius | Notes |
|---|---|---|
| Project | Agent (named by service.name) | Rius groups traces by agent, named by service.name (service_name in rius.init()). Give each environment (production, staging) its own workspace and API key. |
| Trace | Trace | Same tree of nested steps. |
| Run | Span | Each step of a trace is an OpenTelemetry span. |
Run type (llm, chain, tool, retriever, embedding) | Span kind (LLM, CHAIN, TOOL, RETRIEVER, EMBEDDING, AGENT) | Set with kind= on @rius.observe; integrations set it for you. |
| LLM run | Generation | A span with model, tokens, and cost. Rius computes cost server-side from model and tokens. |
Thread (thread_id or session_id metadata) | Session | with rius.session(thread_id): stamps session.id on every span in scope, child spans included. |
| Metadata | Span attributes | See Path B. |
| Tags | Span attributes | No separate tag concept; use an attribute. |
| Feedback | Not available | See what does not carry over. |
| Datasets, experiments, evaluators | Not available | See what does not carry over. |
| Prompt Hub and Playground | Not available | See what does not carry over. |
Choose your path
- Your app is built on LangChain or LangGraph and LangSmith traces it
through
LANGSMITH_TRACING=true: add the Rius SDK. Your chains, agents and graphs stay as they are. - You use
@traceable,wrap_openaiorwrap_anthropic: swap them for the Rius SDK. The mapping is one to one. - You cannot change code yet: point LangSmith’s OpenTelemetry export at Rius with environment variables, and accept the gaps listed there.
Path A: LangChain and LangGraph apps
The Rius SDK’s langchain integration hooks LangChain’s callback system,
the same hook LangSmith uses, so anything that runs through it is traced:
LCEL chains, agents built with create_agent, and LangGraph nodes.
pip install "glassflow-rius[langchain]"Then replace the LangSmith environment with one init() call at startup:
# Before: LangSmith
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY="lsv2_..."
export LANGSMITH_PROJECT="my-agent"
# After: Rius
export RIUS_API_KEY="ri_..."import rius
client = rius.init(service_name="my-agent")
# build and run your chains, agents and graphs exactly as before
from langchain.agents import create_agent
agent = create_agent("openai:gpt-4o-mini", tools=[get_weather])
agent.invoke({"messages": [{"role": "user", "content": "Weather in Lisbon?"}]})In a short-lived Python script, call client.flush() before it exits so
every call is counted once; see Count the call once.
The trace shows the graph as nested spans: the agent run, each model step
and tool step, with the model call as a generation carrying the model,
token counts, and cost. Unset LANGSMITH_TRACING once you no longer want
LangSmith’s callback tracer to run alongside.
For LangChain.js, the TypeScript SDK does the same; see the LangChain integration for the install line.
Without the Rius SDK
To use your own OpenTelemetry setup instead of the SDK, install
openinference-instrumentation-langchain from OpenInference, an open-source
set of OpenTelemetry instrumentations for LLM libraries. Wire an OTLP
exporter to Rius as shown on the
OpenInference page, swapping
OpenAIInstrumentor for LangChainInstrumentor:
from openinference.instrumentation.langchain import LangChainInstrumentor
LangChainInstrumentor().instrument(tracer_provider=provider)Raise the span attribute limit, for example with
OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT=4096, as that page
describes.
Without the SDK you get no view of which agent processes are alive or of
runs in progress (liveness).
Path B: swap @traceable and the client wrappers for the Rius SDK
For code instrumented with the LangSmith SDK, the Rius SDK has direct
equivalents. The client wrappers become nothing at all: rius.init()
instruments the OpenAI and Anthropic libraries process-wide, so every client
you create is traced.
pip install "glassflow-rius[openai,anthropic]"| LangSmith (Python) | Rius (Python) |
|---|---|
LANGSMITH_TRACING=true, LANGSMITH_API_KEY, LANGSMITH_PROJECT | RIUS_API_KEY plus rius.init(service_name="my-agent") |
wrap_openai(OpenAI()) | OpenAI(), traced by the OpenAI integration |
wrap_anthropic(Anthropic()) | Anthropic(), traced by the Anthropic integration |
@traceable | @rius.observe |
@traceable(name="Chat Pipeline") | @rius.observe(name="Chat Pipeline") |
@traceable(run_type="tool") | @rius.observe(kind=rius.SpanKind.TOOL) |
@traceable(run_type="retriever") | @rius.observe(kind=rius.SpanKind.RETRIEVER) |
@traceable(run_type="llm") around a call you trace by hand | rius.start_as_current_generation(model=..., provider=...) with set_usage(); see generations |
with trace("name", "chain", inputs=...) | with rius.start_as_current_span("name") as span: then span.set_input(...) |
metadata={"thread_id": thread_id} | with rius.session(thread_id): around the call |
metadata={...}, tags=[...] | span.set_attribute(key, value) inside rius.start_as_current_span(...), or opentelemetry.trace.get_current_span().set_attribute(key, value) inside an @rius.observe function |
A pipeline, before and after:
# LangSmith
from langsmith import traceable
from langsmith.wrappers import wrap_openai
from openai import OpenAI
client = wrap_openai(OpenAI())
@traceable(run_type="tool")
def retrieve(question: str) -> str:
return search(question)
@traceable(name="Chat Pipeline", metadata={"thread_id": thread_id})
def pipeline(question: str) -> str:
context = retrieve(question)
return client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "system", "content": f"Context: {context}"},
{"role": "user", "content": question}],
).choices[0].message.content
pipeline("What does Rius ingest?")# Rius
import rius
from openai import OpenAI
rius.init(service_name="my-agent")
client = OpenAI() # no wrapper: init() instruments the library
@rius.observe(kind=rius.SpanKind.TOOL)
def retrieve(question: str) -> str:
return search(question)
@rius.observe(name="Chat Pipeline")
def pipeline(question: str) -> str:
context = retrieve(question)
return client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "system", "content": f"Context: {context}"},
{"role": "user", "content": question}],
).choices[0].message.content
with rius.session(thread_id):
pipeline("What does Rius ingest?")Two differences worth knowing before you start:
- Threads are a scope, not metadata. LangSmith asks you to put
thread_idon every run, child runs included.rius.session()is a context manager that stamps every span started inside it, including spans from auto-instrumentation, so you set it once per request.observetakes no session argument for the same reason. - Process-wide instrumentation. Calling
rius.init()before you create clients is enough; there is no per-client wrapper to forget. If you trace some calls by hand today withrun_type="llm", check the integrations list first: you may be able to drop the manual code.
The TypeScript SDK has the same shape (observe as a wrapper function,
withSession); see the tracing guide.
Path C: point LangSmith’s OpenTelemetry export at Rius
The LangSmith SDK can export its runs as OpenTelemetry spans to any OTLP
endpoint, including Rius, through the standard OTEL_EXPORTER_OTLP_*
variables. It needs no code change, for LangChain apps and @traceable
code alike:
pip install "langsmith[otel]"
export LANGSMITH_TRACING=true
export LANGSMITH_OTEL_ENABLED=true
export LANGSMITH_OTEL_ONLY=true # send only to the OTLP endpoint below
export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.eu.console.rius-glassflow.com"
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer <your API key>"
export OTEL_SERVICE_NAME="my-agent" # LangSmith defaults it to "langsmith"This needs langsmith 0.4.25 or newer. No
LangSmith API key is needed. Recent langsmith releases also accept
LANGSMITH_TRACING_MODE=otel in place of the two LANGSMITH_OTEL_*
variables.
What arrives in Rius:
- The trace tree, with LangSmith’s run names: the graph, each model
and tool step, and your
@traceablefunctions. - Model calls as generations with model, token counts and cost.
- Tool runs as tool spans. Chain runs arrive without a span kind, and
langchainappears as a provider (with zero tokens) in provider breakdowns.
What does not:
- Inputs, outputs and messages: the trace view shows no content for these spans.
- Threads. A
thread_idorsession_idin run metadata arrives aslangsmith.metadata.thread_id, not assession.id, so traces are not grouped into sessions. Other metadata arrives the same way, aslangsmith.metadata.*span attributes. - Live views. Seeing which agent processes are alive and, with partial spans turned on, runs still in progress needs the Rius SDK. LangSmith’s exporter sends neither.
Treat Path C as a bridge for the evaluation period, then move to Path A or B for content and sessions.
Side by side during the evaluation
Pick whichever matches your path:
- Path A or B: run the Rius SDK in one service, or one environment,
while the rest keep reporting to LangSmith. Both can also run in the same
process: leaving
LANGSMITH_TRACING=trueset keeps LangSmith’s callback tracer running next to Rius for LangChain apps. - Path C: hybrid mode,
LANGSMITH_OTEL_ENABLED=truewithoutLANGSMITH_OTEL_ONLY, sends runs to LangSmith and spans to the OTLP endpoint at once. For more than one OTLP destination, use an OpenTelemetry Collector:
exporters:
otlphttp/langsmith:
traces_endpoint: https://api.smith.langchain.com/otel/v1/traces
headers:
x-api-key: ${env:LANGSMITH_API_KEY}
Langsmith-Project: my_project
otlphttp/rius:
endpoint: https://ingest.eu.console.rius-glassflow.com
encoding: proto
compression: gzip
headers:
authorization: Bearer ${env:RIUS_API_KEY}
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlphttp/langsmith, otlphttp/rius]The Collector page covers the Rius
exporter, including why it must be otlphttp and not otlp.
What does not carry over from LangSmith
LangSmith is a tracing, evaluation, prompt engineering and deployment platform. Rius is agent observability, and today it has no equivalent for:
- Evaluation: no datasets, experiments, offline or online evaluators, pairwise comparisons, or LLM-as-judge. Keep these in LangSmith or a dedicated eval tool.
- Feedback and annotation queues: no feedback scores on runs and no human review queues.
- Prompt Hub and Playground: no versioned prompts, prompt commits, or playground. Prompt content on spans is captured and inspectable, but there is no registry.
- LangSmith Deployment (formerly LangGraph Platform) and LangSmith Studio: Rius does not host or run agents. It observes them wherever they run, including on LangSmith Deployment, as long as they can export OTLP.
- Self-hosting: Rius is a hosted service only. LangSmith offers a self-hosted edition as an add-on to its Enterprise plan.
- Historical data: existing traces stay in LangSmith; Rius starts from the first span you send it.
What you keep: trace inspection with the same nested structure, sessions and users, token and server-side cost analytics, and alerts.
If evaluations, datasets or annotation queues are load-bearing in your workflow, run both backends and keep LangSmith for those pieces rather than cutting over completely.
LangSmith to Rius cutover checklist
- Create a Rius workspace and API key (quickstart). New organizations start with a free trial (30 days or 500,000 spans, whichever comes first), then a paid plan; see Plans and billing.
- Pick your path: LangChain and LangGraph,
@traceableand wrappers, or, to start without code changes, LangSmith’s OTel export. - Run both backends side by side for one service or environment (how).
- Verify one traced request end to end: the trace tree matches what you see in LangSmith, each model call is a generation with model and token counts, and cost appears.
- Map threads to sessions: wrap each conversation turn in
rius.session(thread_id)and check that the turns group in the sessions view. - Compare both backends on real traffic for a few days: trace counts, token totals, cost.
- Move anything that reads from LangSmith (dashboards, alerts, internal tools) to their Rius equivalents, or deliberately leave them behind.
- Unset
LANGSMITH_TRACING, remove@traceableand the wrappers, and revoke the LangSmith keys once nothing sends to them.
Frequently asked questions
Do I have to rewrite my LangChain or LangGraph app?
No. The Rius SDK hooks LangChain’s callbacks, the same mechanism LangSmith
uses, so your chains, agents and graphs stay as they are. You add
rius.init() and install the langchain extra.
Can I run LangSmith and Rius at the same time?
Yes. With the Rius SDK, leave LANGSMITH_TRACING=true set and both receive
traces from the same process. With LangSmith’s OTel export, its hybrid mode
or an OpenTelemetry Collector fans out to both. The migration is reversible
until you remove LangSmith from your code and revoke its keys.
Is Rius compatible with the LangSmith SDK?
Partly. Rius does not accept LangSmith’s native run API, but the LangSmith
SDK’s OpenTelemetry export can target Rius (Path C).
Model, tokens and cost come through that way, but content and threads do
not. Swap @traceable and the wrappers for the Rius SDK to get those; the
mapping is one to one.
Can I import my existing LangSmith traces?
No. Rius has no importer for LangSmith runs. Keep LangSmith available for looking up history until it ages out of your retention window.