DEV Community

Arthur Doss
Arthur Doss

Posted on

Adding Tracing and Failure Analysis to a Multi-Step AI Agent

#ai

Multi-step AI agents introduce debugging challenges that traditional application monitoring cannot fully address. A single user request may trigger multiple LLM calls, retrieval operations, external API requests, tool executions, and agent handoffs. When an execution fails, it can be difficult to identify the responsible operation without visibility into the full workflow.

The solution is to combine distributed tracing, structured logging, and application metrics. By assigning traces to individual requests and spans to individual operations, engineering teams can reconstruct execution paths, identify bottlenecks, and investigate failures.

OpenTelemetry provides a vendor-neutral foundation for implementing this observability architecture across AI applications.

This guide explains how to instrument multi-step agents, capture failures, analyze execution traces, and prepare AI workflows for production environments.

Why Do Multi-Step AI Agents Need Distributed Tracing?

Applications generally follow predictable execution paths. A request enters the application, passes through several functions, and returns a response. Logs and application metrics often provide sufficient visibility into these operations.

AI agents introduce more dynamic execution patterns. Consider an enterprise research agent that receives a request to investigate a customer account. Its execution might involve:

An LLM interprets the user’s request.
A retrieval system searches internal documents.
A CRM tool retrieves customer information.
A secondary agent analyzes financial records.
The primary agent combines the results into a response.

The CRM API might time out, retrieval could return incomplete information, or the secondary agent might produce an invalid response. Even when individual operations succeed, their combined execution time might exceed the application’s latency budget. Without tracing, engineers might know that a request failed but have limited information about why.

Why are ordinary application logs insufficient?

Consider these log messages:

Agent execution started
Model response received
Retrieval completed
CRM request failed
Agent execution terminated

Although these events provide a basic timeline, they don’t establish the complete execution relationships. Engineers still need to determine which request failed, whether retries occurred, how long each operation took, and whether other operations completed successfully.

Distributed tracing solves this problem by connecting related operations through unique trace and span identifiers. For multi-step AI systems, this makes debugging more systematic and reduces dependence on manually reconstructing application behavior.

Understanding Traces, Spans, and Execution Context

Before implementing tracing, developers should understand these fundamental concepts.

What is a trace?

A trace represents one complete logical execution. For an AI agent, a trace typically corresponds to one user request and includes its associated model calls, retrieval operations, tool executions, and delegated tasks. Every trace receives a unique identifier that connects related operations across application components.

What is a span?

A span represents an individual operation within a trace. A span typically records:

Operation name
Start and end timestamps
Execution duration
Parent span identifier
Operation status
Relevant attributes
Exception information

The parent-child relationship helps engineers understand which operation initiated another operation.

Why does execution context matter?

Multi-step agents frequently use asynchronous functions, background workers, and distributed services. Execution context maintains tracing relationships as work moves between these components.

OpenTelemetry supports context propagation through mechanisms such as W3C Trace Context. Developers should ensure that trace context is preserved across supported execution boundaries and explicitly propagated when work crosses service or process boundaries.

Designing an Observability Architecture

A scalable tracing architecture should separate application instrumentation from telemetry collection and visualization. OpenTelemetry provides a vendor-neutral foundation for this design.

A typical architecture includes four components:

  • Agent instrumentation: The application creates spans around model calls, retrieval, tool execution, validation, retries, and orchestration.
  • Telemetry collection: An OpenTelemetry Collector receives, processes, and exports telemetry.
  • Observability backend: A tracing platform stores and visualizes execution traces.
  • Monitoring and alerting: Metrics and logs help identify recurring failures and operational problems.

The most important design principle is that every meaningful operation should remain connected to its originating request. This allows an engineer to investigate a failed user request without manually correlating unrelated application events.

Instrumenting an AI Agent With OpenTelemetry

The first implementation step is configuring a tracer provider and exporter. For Python applications, install the required packages:

pip install opentelemetry-api \
    opentelemetry-sdk \
    opentelemetry-exporter-otlp-proto-http
Initialize the tracer
The following example configures an application-level tracer and an OTLP exporter.

from opentelemetry import trace

from opentelemetry.sdk.resources import (
    Resource,
    SERVICE_NAME
)

from opentelemetry.sdk.trace import TracerProvider

from opentelemetry.sdk.trace.export import (
    BatchSpanProcessor
)

from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
    OTLPSpanExporter
)

resource = Resource.create({
    SERVICE_NAME: "multi-step-ai-agent"
})

provider = TracerProvider(resource=resource)

exporter = OTLPSpanExporter(
    endpoint="http://localhost:4318/v1/traces"
)

provider.add_span_processor(
    BatchSpanProcessor(exporter)
)

trace.set_tracer_provider(provider)

tracer = trace.get_tracer(__name__)
Enter fullscreen mode Exit fullscreen mode

This configuration creates a tracer provider, attaches a batch span processor, and exports completed spans to an OTLP-compatible endpoint.

The endpoint is illustrative. Production deployments should configure the actual Collector or observability backend, authentication, and encrypted transport.

Create a root span

Every logical agent request should have a root operation.

def execute_agent(user_request):

with tracer.start_as_current_span(
    "agent.workflow"
) as span:

    span.set_attribute(
        "agent.name",
        "customer-research-agent"
    )

    span.set_attribute(
        "agent.workflow",
        "customer_research"
    )

    return process_request(user_request)
Enter fullscreen mode Exit fullscreen mode

Child operations created within this context can automatically inherit the current tracing context. The root span provides a clear boundary for investigating individual agent executions.

Trace tool executions

External tools are common sources of unpredictable failures. Each tool should have an independent span.

from opentelemetry.trace import Status, StatusCode

def call_crm_tool(customer_id):

    with tracer.start_as_current_span(
        "agent.tool.crm_lookup"
    ) as span:

        span.set_attribute("tool.name", "crm_lookup")

        try:
            result = crm_client.get_customer(
                customer_id
            )

            span.set_attribute(
                "tool.result.status",
                "success"
            )

            return result

        except Exception as exc:

            span.set_status(
                Status(StatusCode.ERROR)
            )

            span.record_exception(exc)

            raise
Enter fullscreen mode Exit fullscreen mode

This example records the tool operation and captures exceptions without hiding the original failure. In production, engineers should review exception messages and stack traces before exporting them because they may contain sensitive information.

Trace model generation separately

LLM calls should also have dedicated spans. Useful attributes include:

  • Model provider and model identifier
  • Operation type
  • Request duration
  • Input and output token counts, when available
  • Provider error category
  • Completion status

OpenTelemetry’s GenAI semantic conventions guide standardizing AI-related telemetry. However, many GenAI conventions are still under development, so teams should verify their stability before relying on specific attribute names.

For applications using the OpenAI Agents SDK, built-in tracing can capture model generations, tool calls, guardrails, and custom spans. Developers should add custom instrumentation for application-specific operations rather than creating duplicate spans for work already traced by the framework.

Capturing Failures Across Agent Execution

Creating traces is only the beginning. The real value comes from recording failures in a way that makes them understandable. Multi-step agents encounter several categories of errors.

Model execution failures

Common model-related failures include:

  • API rate limits
  • Provider timeouts
  • Invalid request parameters
  • Context-window limitations
  • Unexpected response formats
  • Interrupted generations

A model span should capture the requested model, operation duration, response status, and provider error category. For structured-output workflows, response validation should be a separate operation. This helps distinguish a successful model request from an invalid application-level response.

Tool execution failures

Tool failures can originate from internal functions or external services. For example, an agent might successfully generate a CRM lookup request but fail when executing it because the CRM API is unavailable.

These are different operations and should be independently observable.

Retrieval failures

RAG-based agents introduce additional failure scenarios:

  • Vector database connectivity problems
  • Retrieval timeouts
  • Empty retrieval results
  • Invalid embedding requests
  • Permission-filtering errors
  • Incorrect document references

A successful HTTP response doesn’t necessarily mean retrieval was successful from a business perspective. Retrieval spans should therefore capture operational metadata such as result counts, collection identifiers, retrieval duration, and error categories.

Orchestration failures

Orchestration failures occur when the workflow cannot complete its expected execution path. Examples include invalid state transitions, failed subagent handoffs, exceeded execution budgets, and exhausted retries.

Recording state transitions as span events or structured logs helps engineers reconstruct what the agent was attempting when execution stopped.

Implementing Retry Tracing and Failure Analysis

Retries help applications recover from temporary failures, but they can also complicate debugging. Consider a tool that experiences two timeouts before succeeding on its third attempt.

If every attempt is hidden inside one span, engineers might see a successful operation with unusually high latency without understanding why.

A better approach is to represent each attempt as an individual child span. Example: Instrumenting retry attempts.

import asyncio

from opentelemetry.trace import Status, StatusCode


async def execute_with_retry(
    operation,
    max_attempts=3
):

    for attempt in range(1, max_attempts + 1):

        with tracer.start_as_current_span(
            "tool.execution.attempt"
        ) as span:

            span.set_attribute(
                "retry.attempt",
                attempt
            )

            span.set_attribute(
                "retry.max_attempts",
                max_attempts
            )

            try:
                result = await operation()

                span.set_attribute(
                    "tool.result.status",
                    "success"
                )

                return result

            except asyncio.TimeoutError as exc:

                span.set_status(
                    Status(StatusCode.ERROR)
                )

                span.record_exception(exc)

                if attempt == max_attempts:
                    raise

                await asyncio.sleep(
                    min(2 ** (attempt - 1), 8)
                )

Enter fullscreen mode Exit fullscreen mode

This example uses asynchronous execution and exponential backoff. Each attempt creates a separate span, allowing engineers to inspect its duration, outcome, and retry number. The implementation intentionally retries only timeouts. A production retry policy should classify errors explicitly rather than retrying every exception.

Which failures should be retried?

Potentially retryable failures include temporary network interruptions, service unavailability, rate limiting, and transient database connection failures.

Generally, non-retryable failures include invalid authentication, malformed parameters, permission violations, and deterministic business-rule failures.

Retries must also account for idempotency. If an agent creates an order or updates a customer record, repeating the operation can produce duplicate side effects. Use idempotency keys or application-level deduplication where supported.

For SRE teams, retry visibility helps explain why a seemingly small downstream issue can increase request latency and infrastructure load.

Connecting Traces With Logs and Metrics

Tracing should not replace application logging or metrics. A production-ready AI agent needs all three.

Structured logging

Structured logs provide detailed records of application events.

{
  "event": "tool_execution_failed",
  "service": "customer-agent",
  "tool": "crm_lookup",
  "attempt": 3,
  "error_type": "timeout",
  "trace_id": "example-trace-id",
  "span_id": "example-span-id"
}
Enter fullscreen mode Exit fullscreen mode

The trace and span identifiers allow engineers to move between individual log entries and the corresponding execution trace. These identifiers should be obtained from the active tracing context, not generated independently.

Application metrics

Metrics reveal patterns across many executions.

Important measurements include:

  • Agent workflow completion and failure rates.
  • End-to-end request latency.
  • Model request duration and token usage.
  • Tool invocation and timeout frequency.
  • Retrieval latency and empty-result frequency.
  • Retry counts and exhausted retry policies.

These measurements can support service-level objectives (SLOs).

For example, an organization might establish a target for successful agent workflow completion within an agreed latency budget.

Secure AI Agent Tracing

Tracing introduces additional security considerations because telemetry can contain information from prompts, model responses, retrieved documents, and external tools.

Recording every request and response can unintentionally create another repository of sensitive business information.

Avoid capturing sensitive payloads

Potentially sensitive telemetry includes:

  • Customer names and contact information
  • Authentication credentials and API keys
  • Financial records
  • Internal business documents
  • Complete model prompts and responses
  • Tool arguments and execution results

Instead of recording full payloads, capture operational metadata. For example, a retrieval span can record the collection identifier, result count, and execution duration without storing retrieved document contents.

Optimizing Tracing for Production

Tracing introduces resource requirements of its own. Every span consumes memory, contributes to telemetry volume, and requires processing and export.

Several practices help manage these costs.

Use batch exporting

OpenTelemetry’s BatchSpanProcessor collects completed spans and exports them in batches rather than requiring an individual export for every operation. This reduces synchronous telemetry overhead.

However, batching introduces a tradeoff: pending spans can be lost if a process terminates unexpectedly. Configure export timeouts, queue limits, and graceful shutdown flushing.

Apply sampling carefully

Recording every trace might be practical during development, but high-volume production applications can generate substantial telemetry.

Consider:

  • Sampling representative successful executions
  • Retaining failed and unusually slow executions
  • Increasing sampling during incident investigations
  • Monitoring telemetry ingestion and storage costs

Head sampling makes decisions when a trace starts, so it cannot guarantee retention of every eventual failure. Tail sampling can make decisions after observing more of the trace, but requires additional collection infrastructure.

Testing Failure Analysis Before Deployment

Tracing should be tested like any other production feature. A successful application startup doesn’t prove that telemetry is complete or that failures can be reconstructed accurately.

Engineering teams should implement deterministic failure scenarios.

  • Test tool timeouts: Simulate an external API timeout and verify that the correct span records the failure, exception, and retry attempts.
  • Test concurrent execution: Run multiple agent requests simultaneously and verify that their spans retain the correct trace relationships.
  • Test partial failures: Allow retrieval to succeed while forcing a downstream tool to fail. Confirm that completed operations remain visible.
  • Test exporter failures: Temporarily disconnect the telemetry endpoint and verify that application requests continue according to the defined failure policy.
  • Test sensitive data redaction: Use synthetic customer records and credentials to confirm that sensitive values don’t appear in exported telemetry.
  • Test shutdown behavior: Gracefully terminate workers and verify that pending spans are flushed within the configured shutdown window.

Moving Multi-Step Agents into Production

During experimentation, developers can inspect individual executions manually. That approach becomes less practical when agents serve multiple users, execute concurrently, and depend on enterprise services.

A production-ready architecture needs consistent observability across the complete execution lifecycle.

At CodingCops, the engineering focus is on building AI systems and automation workflows that help businesses scale smarter and faster. Enterprise AI implementation requires attention to the systems surrounding an agent, including integration reliability, secure execution, monitoring, and ongoing refinement.

The objective is not simply to collect more telemetry. It’s to make every meaningful execution observable enough that engineering teams can understand failures, improve reliability, and maintain control as AI workflows become more complex.

Conclusion

Reliable AI agents require more than successful model responses. They need observable execution paths, meaningful failure records, and measurable operational behavior. Combining distributed tracing, structured logging, and metrics gives engineering teams the visibility needed to diagnose problems, control retries, protect sensitive information, and confidently move multi-step AI workflows into production.

FAQs

1. What is distributed tracing in an AI agent?

Distributed tracing records an AI agent’s execution path, connecting model calls, tool executions, retrieval operations, and delegated tasks through trace and span identifiers.

2. How do you identify the root cause of an AI agent failure?

Inspect the failed span, its parent operation, execution duration, exception details, and retry history. Correlate these findings with application logs and metrics.

3. Can OpenTelemetry trace LLM calls and agent tools?

Yes. OpenTelemetry supports custom instrumentation for model calls, tool executions, retrieval operations, and orchestration. Framework integrations can also provide built-in tracing.

4. Should AI agent prompts and responses be stored in traces?

Not by default. Prompts and responses may contain confidential information. Prefer operational metadata, selective payload capture, and appropriate redaction.

5. How does tracing improve AI agent reliability?

Tracing helps engineering teams identify recurring failures, isolate slow operations, understand retry behavior, and investigate execution problems before they affect more production requests.

Top comments (0)