Core concepts

Spans, traces, and how Respan organizes your LLM data.

What is tracing?

LLM applications are non-deterministic and usually multi-step: a single user request might embed a query, search a vector database, call a model, then call a tool. When something is slow, expensive, or wrong, you need to see every step of that one request, not just the final answer.

A trace is that record. It captures each step, how long it took, what it cost, what went in, and what came out. Tracing is the act of producing those records as your app runs.

Everything in Respan is built from one primitive, the span, plus a few ways of grouping spans together:

TermWhat it is
SpanOne recorded operation: an LLM call, a tool run, a retrieval step, an agent turn
TraceAll the spans for a single request, linked into a tree
ThreadSpans grouped into a conversation, ordered by time
InstrumentationThe code that watches your app and emits spans

All of these read from the same underlying span data. The difference is only how they organize it.

For evaluation concepts (scores, evaluators, experiments), see Evals concepts.


Spans

A span is a single recorded operation. Think of it as one line item on an itemized receipt for a request. When you send an LLM request through Respan, whether via the gateway, the API, or a tracing SDK, Respan creates a span.

Every span uses a universal input / output design. The system automatically serializes your data regardless of format, extracts type-specific fields (tool calls, thinking blocks, etc.), calculates metrics when possible, and associates the span with traces, threads, and customers based on the identifiers you provide.

What’s in a span

CategoryWhat it storesKey fields
ContentWhat was sent and receivedinput, output, model, log_type
MetricsPerformance and cost datalatency, cost, usage, time_to_first_token
IdentityWho and whatcustomer_identifier, metadata, thread_identifier, group_identifier
TracingWhere in the workflowtrace_unique_id, span_parent_id, span_name
ConfigLLM settingstemperature, max_tokens, tools
StatusSuccess or failurestatus_code, status, error_message

Every span has a log_type that determines its input/output format. The most common is chat (messages in, assistant message out), but Respan also supports embedding, speech, transcription, tool, agent, workflow, and more. See Span types & multimodal for the full list.

For the complete field reference, see Span attributes.


Traces

A trace is a group of spans that belong to the same request. Spans within a trace form a tree using parent-child relationships, so you can see exactly how the request flowed through your agents, tasks, and tools, much like a call stack.

Take a simple question-answering app. A user asks “What’s our refund policy?” and your app embeds the question, searches your docs, then asks a model to write the answer. That single request becomes one trace with four spans:

One trace named answer_question containing a workflow root span (answer_question) with three nested child spans: embedding (embed_query), tool (search_docs), and chat (generate_answer).

The root span is the whole request; the three child spans are the steps it took. If the answer was wrong, you can open the trace and see whether retrieval returned the right docs before blaming the model.

Key trace fields

  • trace_unique_id: groups all spans in the same request
  • span_unique_id: individual span identifier
  • span_parent_id: creates the parent-child hierarchy (omit it for the root span)
  • span_name: descriptive name for the operation (e.g. "search_docs")
  • span_workflow_name: the nearest workflow this span belongs to

Multi-trace grouping

Longer-running work (a multi-session agent, a job that resumes later) can span multiple traces. Use trace_group_identifier to tie them together:

A trace_group_identifier linking two traces. Trace A holds a workflow span (answer_question) with embedding and tool child spans; Trace B holds a workflow span (follow_up) with chat and tool child spans.

Spans can also be grouped into a thread (a time-ordered conversation view, ideal for chat apps) by giving them the same thread_identifier. A single span can belong to both a trace and a thread. See Metadata & tags to instrument the identifier, then follow a session with Threads in the platform.


How tracing works

You don’t write spans by hand. Instead, you add instrumentation: a small amount of setup that watches your app and emits spans automatically as it runs.

From your app to Respan

Respan is built on OpenTelemetry (OTEL), the open standard for tracing. A span travels from your code, through the OpenTelemetry layer, to the Respan dashboard:

The tracing pipeline: a span travels from your code (App/framework runs) through the OpenTelemetry layer (instrumentor captures the call, then exports over OTLP) to Respan (ingest and enrich with cost, tokens, and grouping, then the dashboard for traces, threads, and search).

Because the format is standard OTEL, anything that already speaks OTLP can send data to Respan with no custom integration.

Instrumentation approaches

How you set up instrumentation determines the shape of your traces: whether they come out as flat, individual spans or as a nested tree.

ApproachHow you start itWhat it capturesTrace shape
Auto-instrumentationRespan()Calls to supported LLM SDKs (OpenAI, Anthropic, …)Flat: each call is its own span
Framework instrumentationRespan(instrumentations=[…])Higher-level framework steps: agent runs, handoffs, tool callsNested tree, automatically
Decorators@workflow, @task, @agent, @toolYour own functionsNested tree, with boundaries you choose

The same operations produce different trace shapes depending on how you instrument. Auto-instrumentation (Respan()) records each LLM call as its own standalone span, so they land as separate flat traces. Explicit instrumentation (Respan(instrumentations=[…])) and decorators also capture the steps around those calls, nesting them under a shared root span:

Side-by-side comparison. Left, Auto-instrumentation with Respan(): three separate flat traces, each holding one span — embed_query, search_docs, and generate_answer. Right, Explicit instrumentation with Respan(instrumentations=[...]): a single trace with a workflow root span (answer_question) and three nested child spans — embed_query, search_docs, and generate_answer.

When you pass instrumentations=[…], auto-instrumentation is turned off by default to avoid duplicate spans. Pass is_auto_instrument=True (Python) to run both.

For the full SDK list, framework instrumentors, and setup code, see Set up the SDK. To add your own nesting with decorators, see Decorators.


Next steps