Sep 9, 2026

Deep Dive into a Strands Agent Trace

When working with AI agents, one of the most useful ways to understand what is happening behind the scenes is through tracing.

A seemingly simple user request can result in multiple model invocations, tool executions, and event-loop cycles before the agent produces its final response.

In this post, I'll walk through a simple Strands Agent example:

greet rahul using tool


🧠 What Actually Happens?

The resulting trace looks roughly like this:

agent.run
|
+-- invoke_agent
    |
    +-- execute_event_loop_cycle #1
    |   |
    |   +-- chat #1
    |   |
    |   +-- execute_tool greet
    |
    +-- execute_event_loop_cycle #2
        |
        +-- chat #2

Although the user made only one request, the agent performed:

  • Two event-loop cycles

  • Two model calls

  • One tool execution

The obvious question is:

Why is a second model call needed?


⚙️ Event-Loop Cycle #1: Decide and Act

The first chat span represents a model invocation.

The model receives:

  • The user prompt

  • Conversation history

  • Available tools

It decides that the appropriate action is:

greet(name="rahul")

Strands then executes the tool.

chat #1
      |
      | decides to call
      v
execute_tool greet
      |
      v
"Hello, Rahul"

At this point the tool has completed.

But the agent has not.


🧩 Why Another Model Call?

Tools execute code.

They don't decide what should be shown to the user.

Once the tool returns its result, the model must reason over that result and determine:

  • Is another tool required?

  • Is the task complete?

  • What should the final response be?

That requires another model invocation.


⚙️ Event-Loop Cycle #2: Observe and Respond

The updated context now contains:

User:
greet rahul using tool

Assistant:
toolUse -> greet("rahul")

Tool:
toolResult -> "Hello, Rahul"

The agent enters another event-loop cycle:

execute_event_loop_cycle #2
        |
        +-- chat #2
               |
               v
         Final Response

The model observes the tool result, determines that no further actions are required, and generates the final response.

The complete execution becomes:

User Prompt
      |
      v
Cycle #1
      |
      +-- Model decides
      |
      +-- Tool executes
      |
      v
Tool Result
      |
      v
Cycle #2
      |
      +-- Model reasons over result
      |
      v
Final Response

Notice that the first model call decides what to do.

The second model call decides what to say.


🧠 Why This Looks Like ReAct

This execution naturally follows the ReAct pattern:

Reason
   |
   v
Act
   |
   v
Observe
   |
   v
Reason
   |
   v
Answer

For our example:

Reason  → Decide to call greet()
Act     → Execute greet()
Observe → Receive "Hello, Rahul"
Reason  → Determine no further actions are required
Answer  → Return final response

ReAct describes how an agent behaves.

OpenTelemetry describes how that behavior is observed.

For example:

Agent Execution              OpenTelemetry Representation

Model invocation       →     chat span
Tool execution         →     execute_tool span
Tool result            →     span output / attributes
Next model invocation  →     next chat span
Agent invocation       →     trace containing these spans

A ReAct iteration is therefore a logical agent concept—not an OpenTelemetry primitive.


📂 Where Does a Session Fit?

A session can contain multiple user interactions.

Each interaction creates a new trace.

Session
|
+-- Prompt #1
|     +-- Trace #1
|
+-- Prompt #2
|     +-- Trace #2
|
+-- Prompt #3
      +-- Trace #3

Within each trace, the agent may execute multiple event-loop cycles.

Session
     |
     | 1:N
     v
Trace
     |
     | 1:N
     v
Event-Loop Cycles
     |
     | captured as
     v
Spans

The exact relationship between sessions and traces depends on the application's instrumentation, but this is a useful mental model.


🧩 Two Views of the Same Execution

When debugging an agent, think about two different perspectives.

Execution

Event Loop
     |
     +-- Reason
     +-- Act
     +-- Observe
     +-- Repeat

This explains how the agent works.


Observability

Trace
   |
   +-- Span
   +-- Span
   +-- Span

This explains what happened while the agent was working.


🎯 Final Thought

For our simple example:

One User Request
      |
      v
One Agent Execution / Trace
      |
      +-- Event-Loop Cycle #1
      |      +-- chat
      |      +-- execute_tool
      |
      +-- Event-Loop Cycle #2
             +-- chat
      |
      v
Final Response

Understanding this distinction makes agent traces much easier to read.

The event loop explains how the agent reasons.

The trace records that reasoning as observable spans.

OpenTelemetry doesn't change how the agent works.

It simply makes that work visible—making it easier to debug behavior, optimize execution, analyze tool usage, and evaluate agent performance.