Debugging the Agent Transcript
Explore how to instrument and debug agent loops in Claude AI architecture by implementing structured logging at key iteration points. Learn to read detailed turn-level logs and message arrays to identify and fix issues in tool calls and stop reasons, improving your system's reliability and transparency.
The loop from the previous lessons works, but when it breaks, there is nothing to inspect. The messages array changes on every iteration, tool calls come and go, and errors surface only as wrong output or silent None returns. Without visibility into what happened between the first API call and the final answer, debugging is guesswork.
In this lesson, we instrument the loop with structured logging that prints state at each decision point. We then use that output to trace a failing run and identify the exact turn where it went wrong.
By the end of this lesson, we will have:
A logging helper that formats message-array turns in human-readable form
Turn-level log output for every API call, stop reason, tool call, and tool result
A failing transcript annotated to show where and why it breaks
A methodology for reading agent transcripts that applies to any loop
What to log and why
A loop produces four types of events worth capturing, each at a different moment in the iteration:
Event | When It Fires | What to Capture |
API call | Before | Turn count, message count, input token estimate |
Stop reason | After the response arrives |
|
Tool dispatch | Before each tool function runs | Tool name, input arguments |
Tool result | After each tool function returns | Tool name, result string (truncated if long) |
These four points cover the full life cycle of one iteration. Any failure in the loop, wrong stop reason handling, missing tool result, ID mismatch, or truncation will be visible in at least one of these log lines.
The logging helper
Rather than scattering print() calls throughout the loop, we write one helper that formats any event as a consistent, scannable line:
import jsondef log(event: str, **kwargs) -> None:parts = [f"[{event}]"]for key, value in kwargs.items():if isinstance(value, (dict, list)):parts.append(f"{key}={json.dumps(value, default=str)[:120]}")else:parts.append(f"{key}={value}")print(" ".join(parts))
Line 1: ...