The Agentic Loop: How Claude Reasons, Acts, and Self-Corrects

The previous post introduced the core agent pattern: a loop where Claude calls tools, receives results, and continues until the task is done. But that description understates the sophistication of what is actually happening inside that loop. Claude is not simply executing a predetermined script. It is continuously reasoning about the situation, evaluating whether its approach is working, and revising its plan based on what it observes.
Understanding this deeper layer of the agentic loop is what separates agents that work in demos from agents that are reliable in production. This post covers the mechanics of Claude's reasoning cycle, how error recovery works, when and how to use sub-agents, and the critical orchestration patterns that make agents dependable under real-world conditions.
What Happens Inside Each Iteration
On each iteration of the agent loop, Claude receives the full conversation history — every message, every tool call, and every tool result from the beginning of the session. Claude processes all of this context together to decide what to do next.
This full context access enables something important: Claude can notice when something is not going right. If a tool returned an error, Claude can try a different approach. If its first search returned irrelevant results, it can refine the query. If it discovers the task is more complex than expected, it can add more steps.
This is what makes Claude an agent rather than a simple automation script — it adapts.
The Five Phases of an Agentic Iteration
Each loop iteration follows this internal structure:
- Context review: Claude reads the full history — goal, previous actions, and their results
- Goal assessment: Is the task complete? If yes, generate the final response. If no, continue.
- Plan update: Given what has happened so far, what is the best next action?
- Tool selection: Select the appropriate tool(s) and construct careful arguments
- Execution: Return the tool_use block(s) to your code for execution
The key insight is step 3 — Claude is not following a fixed plan. It is reassessing its plan on every iteration based on accumulated evidence.
How Claude Self-Corrects
Self-correction in agents happens naturally through the context window. Because Claude sees everything that has happened, it can detect and respond to problems:
1# Example: If a tool returns an error, Claude sees it and adapts
2
3# Iteration 1: Claude searches for "Anthropic Claude API pricing 2026"
4# Tool result: {"error": "Search API rate limit exceeded"}
5
6# Iteration 2: Claude sees the error and waits, then tries a narrower query
7# Tool call: search_web(query="Claude API token pricing")
8
9# Iteration 3: Results are too general, Claude refines again
10# Tool call: search_web(query="Anthropic API pricing page input output tokens")
11
12# Iteration 4: Good results found. Claude extracts facts and moves on.You do not write error recovery logic for Claude to follow — Claude observes the error and decides how to respond. Your job is to return errors clearly in tool results rather than silently swallowing them.
Return Errors as Tool Results, Not Exceptions
When a tool call fails — network error, invalid API response, timeout — do not raise an exception that crashes the loop. Instead, return a clear error description as the tool_result content. Claude will see the error, understand it, and decide whether to retry, try a different approach, or inform the user it cannot complete the task. Crashing the loop loses all context from previous successful steps.
Handling Long-Running Agents
For complex tasks that may take many steps, your agent loop needs robust state management:
1import anthropic
2import json
3from typing import Callable
4
5client = anthropic.Anthropic()
6
7def run_agent(
8 goal: str,
9 tools: list,
10 tool_executor: Callable,
11 system_prompt: str,
12 max_iterations: int = 20,
13 on_tool_call: Callable = None # Callback for logging/monitoring
14) -> str:
15 """
16 Generic agent runner with robust error handling and state tracking.
17 """
18 messages = [{"role": "user", "content": goal}]
19 iteration_count = 0
20 tool_call_history = []
21
22 while iteration_count < max_iterations:
23 iteration_count += 1
24
25 try:
26 response = client.messages.create(
27 model="claude-opus-4-6",
28 max_tokens=8096,
29 system=system_prompt,
30 tools=tools,
31 messages=messages
32 )
33 except anthropic.APIError as e:
34 return f"Agent failed due to API error: {str(e)}"
35
36 # Agent is done
37 if response.stop_reason == "end_turn":
38 for block in response.content:
39 if block.type == "text":
40 return block.text
41 return "Task completed."
42
43 # Process tool calls
44 tool_results = []
45
46 for block in response.content:
47 if block.type != "tool_use":
48 continue
49
50 tool_call_history.append({"tool": block.name, "input": block.input})
51
52 # Optional monitoring callback
53 if on_tool_call:
54 on_tool_call(block.name, block.input, iteration_count)
55
56 try:
57 result = tool_executor(block.name, block.input)
58 result_content = json.dumps(result)
59 except Exception as e:
60 result_content = f"Tool execution error: {str(e)}"
61
62 tool_results.append({
63 "type": "tool_result",
64 "tool_use_id": block.id,
65 "content": result_content
66 })
67
68 messages.append({"role": "assistant", "content": response.content})
69 messages.append({"role": "user", "content": tool_results})
70
71 # Max iterations reached
72 return f"Agent reached maximum of {max_iterations} iterations. Last tools used: {[t['tool'] for t in tool_call_history[-3:]]}"Orchestrator and Sub-Agent Patterns
For complex tasks, a single agent with many tools becomes hard to manage and can lose focus. A better pattern is an orchestrator agent that delegates specific sub-tasks to specialised sub-agents.
The orchestrator breaks the goal into sub-tasks. Each sub-agent has a narrow set of tools and a clear scope. Results flow back to the orchestrator which synthesises them.
User Goal: "Analyse this company's online presence and produce a competitive report"
Orchestrator
├── Sub-agent 1: Web Research Agent (tools: web_search, extract_facts)
│ └── Task: Research the company's recent news and announcements
├── Sub-agent 2: Social Media Agent (tools: twitter_search, linkedin_search)
│ └── Task: Analyse their social media presence and engagement
├── Sub-agent 3: Technical Analysis Agent (tools: website_scanner, tech_stack_detector)
│ └── Task: Analyse their website technology and performance
└── Orchestrator synthesises all findings into the final report
Keep Sub-Agent Scope Narrow and Well-Defined
The most common mistake with multi-agent systems is giving sub-agents too broad a scope. A sub-agent works best when it has 2-4 tools, a single clear objective, and a defined output format. Narrow scope makes sub-agents more reliable, easier to test in isolation, and simpler to debug when something goes wrong.
Prompt Patterns for Reliable Agents
The quality of your system prompt directly determines how reliable your agent is. These patterns consistently improve agent behaviour:
Goal-Process-Output Structure
GOAL: [What the agent is trying to achieve]
PROCESS:
1. [Step 1 description]
2. [Step 2 description]
3. [Step 3 or adapt based on findings]
OUTPUT: [Exactly what the final response should contain and format]
CONSTRAINTS:
- [Hard limit 1]
- [Hard limit 2]
Explicit Stopping Conditions
Always tell the agent explicitly when to stop:
Stop when:
- You have found information that answers all three required questions
- You have made more than 5 search attempts without finding relevant results
- You encounter a permission error on a tool — stop and report the error
Do NOT continue searching once you have sufficient information to produce the required output.
Managing Context Window in Long Agents
For long-running agents with many tool calls, the context window can fill up. Watch for this and implement compression when needed:
- Summarise tool results: If a search result returns a 5000-word article, extract and store only the relevant 200-word snippet before adding it to the conversation
- Compress intermediate history: For very long agents, periodically summarise the tool call history into a condensed context block
- Use structured state: Maintain a state dictionary outside the conversation and pass only the current state to each iteration, rather than the full raw tool call history
Monitor Context Window Usage
Claude models have context window limits — 200,000 tokens for Opus and Sonnet 4.6. Long agents that make many tool calls with verbose results can approach this limit. Monitor the total token count of your messages array across iterations. When it approaches 80% of the limit, implement compression or start a summary-based handoff to a clean conversation context.
Summary
The agentic loop is more than a while loop with tool calls. It is Claude continuously reasoning about its situation, updating its plan, and adapting to unexpected results. Building reliable agents requires:
- Returning errors as tool results — never silently swallowing failures
- Setting maximum iteration limits with meaningful fallback behaviour
- Using orchestrator/sub-agent patterns for complex tasks with distinct phases
- Writing clear system prompts with explicit goals, process steps, and stopping conditions
- Monitoring and managing context window consumption for long-running tasks
Next: how to connect Claude agents to any tool ecosystem through an open standard — Model Context Protocol (MCP): Connect Claude to Any Tool.
This post is part of the Anthropic AI Tutorial Series. Previous post: What is an AI Agent? Building Your First Agent with Claude.
