Artificial IntelligenceAnthropicAI Agents

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

TT
TopicTrick
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:

  1. Context review: Claude reads the full history — goal, previous actions, and their results
  2. Goal assessment: Is the task complete? If yes, generate the final response. If no, continue.
  3. Plan update: Given what has happened so far, what is the best next action?
  4. Tool selection: Select the appropriate tool(s) and construct careful arguments
  5. 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:

python
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:

    python
    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.