Skip to Content

I trace CrewAI with LangSmith. How do I switch to Rius?

Rius traces CrewAI through its OpenAI integration: install glassflow-rius[openai], call rius.init(), and wrap your entrypoint and tools with observe. Model calls arrive as generations with model, tokens and cost, and your wrappers give the run and its tools their shape. You can keep LangSmith running while you compare, then remove its setup. Rius has no evals, datasets or prompt management, so keep those in LangSmith if you depend on them.

How it works

CrewAI 1.x drives the OpenAI client natively, so the Rius openai integration captures its model calls. If LiteLLM is installed, CrewAI uses it as a fallback, and you rely on the LiteLLM integration instead. The CrewAI integration page covers this in full.

The crew structure runs inside the framework, where auto-instrumentation cannot see it. You wrap the entrypoint and the tool bodies with observe, which replaces the LangSmith run types you used before:

  • Your entrypoint around crew.kickoff() becomes the root AGENT span.
  • Each model call becomes an LLM generation with model, tokens, cost and time to first token.
  • Each tool becomes a TOOL span from your observe wrapper on the function body.
  • A LangSmith thread becomes a session, set with rius.session().

Crews and tasks produce no spans of their own, and generation spans carry the generic name ChatCompletion. To see which task a call belongs to, wrap per-task entrypoints with observe.

The LangSmith migration guide maps @traceable to @rius.observe and run_type="tool" to kind=rius.SpanKind.TOOL. It also describes pointing LangSmith’s own OpenTelemetry export at Rius as a bridge, which leaves out content and thread grouping. For CrewAI, the integration route above is the one that gives you content and sessions.

Set it up

  1. Install the Rius SDK with the OpenAI extra next to CrewAI:

    pip install "glassflow-rius[openai]" crewai
  2. Add the Rius setup. Call rius.init() once at startup, and swap any @traceable decorators around your crew for observe. The LANGSMITH_* variables can stay until you cut over in step 5. Put @tool outermost on each tool and observe on the function body:

    import rius from crewai import Agent, Crew, Task from crewai.tools import tool from rius import SpanKind rius.init(api_key="ri_...", service_name="my-agent") @tool("account_status") @rius.observe(kind=SpanKind.TOOL) def account_status(email: str) -> str: """Fetch a customer's account standing by email.""" return lookup(email) support_agent = Agent( role="Support specialist", goal="Answer support tickets accurately and concisely.", backstory="You resolve product and account questions.", tools=[account_status], llm="gpt-5-mini", ) @rius.observe(name="handle-ticket", kind=SpanKind.AGENT) def handle_ticket(ticket: str) -> str: task = Task( description=f"Resolve this support ticket: {ticket}", expected_output="A short, direct answer.", agent=support_agent, ) return str(Crew(agents=[support_agent], tasks=[task]).kickoff())
  3. Map threads to sessions. Where you put a thread id in LangSmith metadata, scope each kickoff with with rius.session(thread_id): and reuse your own id.

  4. Keep CrewAI’s own tracing prompt quiet. CrewAI asks about its own tracing product on first run. Set CREWAI_TRACING_ENABLED=false where no terminal is attached, such as CI or containers.

  5. Run both backends for a while. Leave LangSmith in place while you compare trace counts, token totals and cost on real traffic. Once nothing needs it, unset LANGSMITH_TRACING, remove the LangSmith decorators and revoke its keys. The migration overview covers the general cutover.

  6. Verify one run that calls a tool. In the console you should see the root AGENT span, the LLM generations with model, tokens and cost, and your named TOOL spans:

    handle-ticket AGENT 8.4s ├─ ChatCompletion LLM 3.9s agent decides to call the tool ├─ execute_tool account_status TOOL 0ms └─ ChatCompletion LLM 4.3s agent answers

What you get

  • A trace per run with an AGENT root, LLM generations and TOOL spans, each generation carrying model, tokens, cost and time to first token.
  • Cost computed by Rius from the model and token counts. These are list-price estimates in US dollars, so you never send a cost value.
  • Sessions that group the turns of one conversation or job, from rius.session().
  • Streamed calls carry token counts only when usage is enabled on the underlying OpenAI client. See the OpenAI integration note on include_usage.
  • Everything else Rius does on top of traces, such as alerts, users and the Agents page.

When something else fits

  • If evaluation datasets, feedback scores, annotation queues or a prompt registry are central to your workflow, keep LangSmith for those pieces and run Rius beside it for tracing.
  • Rius starts from the first span you send. It does not import existing LangSmith traces, so keep LangSmith available for history.

Still stuck? Get help

Last updated on