Skip to Content

How do I trace a customer support agent built with AutoGen?

Rius traces an AutoGen support agent with AutoGen’s own OpenTelemetry spans and the openai integration, and you add a run root, a retrieval span, a step per stage, and a session and user. Install glassflow-rius[openai] and call rius.init(). Agent creation, agent runs, tool calls and model calls with tokens and cost then appear in one trace per ticket. This applies to the Python framework (AgentChat).

How it works

AutoGen combines two coverage paths, described on the AutoGen integration page:

  • Framework spans. AutoGen emits create_agent, invoke_agent and execute_tool spans through the global tracer provider that rius.init() installs. Agent and tool structure arrives with no wrappers.
  • Generations. Model calls go through the OpenAI client from autogen-ext[openai], so the openai integration records each call as a ChatCompletion generation with model, tokens and cost. Rius computes cost from the model and token counts. You never send it.

A support agent needs a few spans that AutoGen does not emit, which you add with the tracing helpers:

  • A run root. One observe wrapper on your entrypoint, with kind SpanKind.AGENT, groups agent creation and invocation into a single trace per ticket.
  • Retrieval. A span of kind SpanKind.RETRIEVER around your knowledge base search records the data source, how many documents you asked for, and the ids and scores of what came back. Unnamed, it is called retrieval support-kb.
  • A step per stage. A bare observe on a function such as ticket triage makes a span named after the function.

Do not wrap AutoGen tool functions with observe. The framework runs tools in a detached context, so the wrapper’s span cannot find the run and splits off as its own single-span trace. The execute_tool spans already cover your tools. For the same reason, run your own retrieval and triage in the entrypoint, before the agent runs, not inside a tool.

Set it up

  1. Install the SDK with the openai extra, plus AutoGen. The extra installs only the instrumentation, so your project must already have its own libraries. The integrations overview covers the shared setup.
pip install "glassflow-rius[openai]" "autogen-agentchat" "autogen-ext[openai]"
  1. Call rius.init() once at startup, wrap the entrypoint as the run root, and add the retrieval span and a triage step. lookup, triage and search stand for your own code.
import rius from autogen_agentchat.agents import AssistantAgent from autogen_ext.models.openai import OpenAIChatCompletionClient from rius import SpanKind rius.init(api_key="ri_...", service_name="support-agent") def account_status(email: str) -> str: """Fetch a customer's account standing by email.""" return lookup(email) @rius.observe def classify_ticket(ticket: str) -> str: return triage(ticket) @rius.observe(name="handle-ticket", kind=SpanKind.AGENT) async def handle_ticket(ticket: str) -> str: category = classify_ticket(ticket) with rius.start_as_current_span( kind=SpanKind.RETRIEVER, data_source_id="support-kb", top_k=5 ) as obs: obs.set_input(ticket) docs = search(ticket) obs.set_retrieved_documents([{"id": d.id, "score": d.score} for d in docs]) context = "\n\n".join(d.text for d in docs) agent = AssistantAgent( name="support_agent", model_client=OpenAIChatCompletionClient(model="gpt-5-mini"), tools=[account_status], system_message="Answer support questions; check accounts with the tool.", ) result = await agent.run(task=f"{category}\n\n{ticket}\n\n{context}") return str(result.messages[-1].content)
  1. Set the session and the user around each ticket. A session groups the turns of one conversation, so reuse your conversation id. The user ties together everything one customer did across conversations. Prefer an opaque customer id to an email.
async def answer(ticket: str, conversation_id: str, user_id: str) -> str: with rius.session(conversation_id), rius.user(user_id): return await handle_ticket(ticket)
  1. Run one ticket that calls the tool, then open the trace in the console. You should see the root span, your triage and retrieval spans, the framework’s invoke_agent and execute_tool spans, and the ChatCompletion generation with model, tokens and cost.

What you get

  • One trace per ticket, rooted at handle-ticket, with the agent’s construction, run, model calls and tool calls underneath.
  • A retrieval span that records which documents were returned and their scores. It holds ids and scores, not text. If you want the retrieved text captured as content, pass it to set_output().
  • Tokens and a list-price cost estimate in US dollars on every model call.
  • Every span of a ticket carries session.id and user.id, so you can follow a whole conversation and everything one customer did. Without a session, each trace is its own session. Without a user, spans are anonymous.
  • Three AutoGen quirks, checked against autogen-agentchat 0.7.5: framework span statuses arrive unset on success while the trace status still reads Ok, generation spans are all named ChatCompletion, and tool wrappers split traces.

When something else fits

  • AutoGen has an integration in Python only. For TypeScript, trace model calls with manual generations from the tracing guide.
  • If your agent runs on another framework or calls a provider client directly, start from the Integrations matrix to find the page for it.

Still stuck? Get help

Last updated on