Track 4 - Agent Architectures
Module 12 of 30

The ReAct Pattern

Reason, Act, Observe: the loop that turns Claude into an autonomous problem-solver.

20 min read 7 concepts 39 cards
Prerequisites
M05 Function Calling · M06 Multi-Tool Orchestration
What you'll learn
  • Why agents differ fundamentally from chatbots
  • The four phases: Reason, Act, Observe, Repeat
  • How to implement the agentic loop correctly
  • Why thought traces improve accuracy by 10-40%
  • The correct stop condition and two anti-patterns
  • Manual loop vs. Agent SDK - what each handles
Swipe right to start
Concept Map

What You'll Learn

Tap any concept to jump directly to it.

1
Chatbot vs. Agent
When one response is not enough
2
What Is ReAct?
Reasoning + Acting interleaved
3
The ReAct Loop
Reason, Act, Observe, Repeat
4
Implementing ReAct
The agentic loop pattern
5
Thought Traces
Working memory and audit trail
6
Stop Conditions
When should the agent stop?
7
Manual vs. Agent SDK
What the SDK hides (and what it doesn't)
Concept 1 of 7
Big Idea

Chatbot vs. Agent

A chatbot responds to one message and stops. An agent receives a goal and works through multiple steps - reasoning, calling tools, observing results, and looping - until the goal is achieved.

The difference is not the model. The difference is the loop. A chatbot is a single API call. An agent is a while loop that keeps calling the API until the task is done.

CHATBOT
User message
-->
One response
-->
Done
AGENT (ReAct)
Goal
-->
Reason
-->
Act
-->
Observe
-->
Loop / Done
Concept 1 of 7
Analogy

Help Desk vs. Project Manager

Everyday Analogy

Before: a help desk where every operator reads from a single script. You call to ask if your order was shipped - they look up one field, read it back, and the call ends.

The pain: if your order needs rerouting and the new tracking number needs emailing, the operator says "I can't help - call three separate departments." Each one has a one-answer script.

The mapping: a chatbot is that operator - one message in, one response out. An agent is a project manager: it gets your request, decides what steps to take, calls the right departments in sequence, and comes back with the complete solution. That ability to loop across multiple steps is what ReAct gives Claude.

Concept 1 of 7
How It Works

When to Use Each

DimensionChatbotAgent
API calls1 per turnMany per task
ToolsNoneSearch, code, APIs
MemoryCurrent turn onlyHistory grows each turn
Stops whenAfter one responsestop_reason = "end_turn"
Best forQ&A, summaries, generationResearch, multi-step tasks
Concept 1 of 7
Decision Framework

Chatbot or Agent?

-- Decision: chatbot or agent? -- IF task requires only one response: USE chatbot -- simpler and cheaper IF task needs info from multiple tools: USE agent IF each step depends on previous results: USE agent IF task needs real-time or external data: USE agent IF training knowledge answers it completely: USE chatbot -- Rule of thumb: if you would need multiple -- browser tabs to answer it yourself, use agent.
Concept 1 of 7
Misconceptions + Takeaway

Common Wrong Beliefs

Agents are always better than chatbots
Agents cost more and add complexity. A chatbot is right for simple Q&A and single-response tasks. Use the simplest tool that solves the problem.
Agents need a smarter model
The difference is the loop, not the model. The same claude-haiku model is a chatbot in a single call and an agent inside a while loop. The loop creates the autonomous behavior.
An agent is a chatbot plus a loop. The loop calls the model repeatedly, executes tool results, and updates shared conversation history until the task is done. That loop is the only structural difference.
Concept 2 of 7
Big Idea

What Is ReAct?

ReAct (Reasoning + Acting) is a pattern where the model alternates between writing explicit reasoning ("Thought: ...") and calling tools ("Act: ..."). The thought step is not decoration - it's the mechanism that makes multi-step reasoning accurate.

Before ReAct, two approaches existed: pure chain-of-thought (all reasoning, no tools - hallucinated facts) and silent tool use (calls tools without reasoning - picked the wrong ones). ReAct fuses both: reason about which action fills the gap, then act, then observe the result.

Origin From the 2022 paper "ReAct: Synergizing Reasoning and Acting in Language Models" (Yao et al.). Showed 10-40% improvement on knowledge-intensive benchmarks vs. silent tool use. Now the default agent pattern in every major framework.
Concept 2 of 7
Analogy

The Detective's Case Notes

Everyday Analogy

Before: a detective who interviews witnesses and reads documents but takes no notes. By the third witness, they've forgotten what the first one said.

The pain: the final report is either a copy of the last interview or disconnected fragments. The detective can't connect clue A to clue B because A was never recorded.

The mapping: ReAct's "Thought:" is the detective's case notes. Every reasoning step is written out, stays in the case file, and informs the next step. The agent's thought traces are why it can synthesize a coherent answer after five tool calls - it's been leaving notes for itself the whole time.

Concept 2 of 7
How It Works

Why Explicit Reasoning Helps

Concept 2 of 7
Pseudocode

ReAct Pattern Structure

-- ReAct: thought before every action -- SYSTEM_PROMPT: "Before EVERY tool call, write: Thought: [what I know, what I need, why THIS tool] After EVERY result, write: Thought: [what I learned, do I need more?]" TURN 1: Claude writes "Thought: need benchmark scores..." Claude calls web_search("LLM benchmarks 2025") [your code runs search, appends result] TURN 2: Claude writes "Thought: got benchmarks, missing pricing data..." Claude calls web_search("LLM pricing 2025") [your code runs search, appends result] TURN 3: Claude writes final answer synthesizing both
Concept 2 of 7
Misconceptions + Takeaway

Common Wrong Beliefs

Thought traces are only for debugging - strip them in production to save tokens
Thought traces are functional working memory. Stripping them degrades multi-step reasoning because the model loses the notes it's been leaving itself. Keep them in context.
ReAct is a library or framework I need to install
ReAct is a pattern - a prompt instruction plus a loop structure you implement with the standard Messages API. No library required, though SDKs can handle the bookkeeping.
ReAct's power: reason before you act. The explicit thought makes the model choose the right tool, stay anchored to the original goal, and produce answers that synthesize across multiple steps.
Concept 3 of 7
Big Idea

The ReAct Loop

The loop has four named phases: Reason (Claude writes a Thought), Act (Claude calls a tool), Observe (your code appends the tool result), and Repeat or stop. One full cycle is one "turn."

Critical clarification: Claude does not run the tools. Claude requests a tool call and pauses. Your code reads that request, executes the tool, and sends the result back. Claude reads the result in the next turn - that's the "Observe" phase. The loop is a collaboration between the model and your code.

Reason
-->
Act
-->
Observe
-->
Loop / Done
Claude writes -- Claude calls -- Your code runs -- Repeat or stop
Concept 3 of 7
Analogy

The Research Loop

Everyday Analogy

Before: researching a complex topic with a strict rule - you can only read one source at a time, and between each source you must write a note on what you learned and what you still need.

The pain: without the notes, you'd read one paper, give a partial answer, and miss all the context from subsequent sources.

The mapping: the ReAct loop is that process. Each iteration: write a note (Reason), read a source (Act), update your understanding (Observe), decide if you need more (Repeat or Done). The conversation history is the stack of notes that makes the final answer coherent.

Concept 3 of 7
How It Works

The Four Phases

Key distinction: Claude requests tool calls. Your code executes them. If your code doesn't run the tool and return the result, the loop stalls.
Concept 3 of 7
Pseudocode

The Loop

-- ReAct loop (simplified) -- messages = [user_question] LOOP: response = ASK_CLAUDE(messages, tools) APPEND response TO messages IF response.stop_reason == "end_turn": RETURN final answer -- done! FOR EACH tool_call IN response: result = RUN_TOOL(tool_call.name, tool_call.inputs) APPEND tool_result TO messages CONTINUE -- observe, then reason again -- messages grows each iteration: -- [user] [thought+call] [result] -- [thought+call] [result] [answer]
Concept 3 of 7
Misconceptions + Takeaway

Common Wrong Beliefs

Claude automatically runs the tools it calls
Claude only requests tool calls. Your code must execute them and append results. Claude has no direct access to the internet, files, or APIs - it only sees what you pass through the messages array.
The loop requires a complex framework to implement
The loop is a simple while loop: call the API, check stop_reason, execute tools if needed, append results, repeat. No framework required.
The ReAct loop is a conversation that grows. Each turn adds Claude's reasoning, Claude's tool request, your tool result. The accumulating history is what gives the agent coherence across steps.
Concept 4 of 7
Big Idea

Implementing ReAct

ReAct implementation has three pieces: tool definitions (what Claude can call), the agent loop (the while loop that runs until stop_reason = "end_turn"), and tool execution (your code that runs each tool and returns results).

The conversation history array is the agent's stateful memory. Because the Messages API is stateless, you maintain the history yourself - every tool request and result gets appended before the next API call. Claude "remembers" because everything it's said is passed back to it each turn.

Concept 4 of 7
Analogy

The Amnesiac Consultant

Everyday Analogy

Before: imagine calling a brilliant consultant who has total amnesia between phone calls. Each call starts fresh - they remember nothing from the previous conversation.

The pain: they give great answers within a single call, but any follow-up starts from zero. "As I mentioned last time..." gets a blank stare every time.

The mapping: Claude is that consultant - each API call starts fresh. Your messages array is the transcript you read back at the start of every call: "Here's what we discussed so far..." You maintain the state; Claude provides the intelligence.

Concept 4 of 7
How It Works

Three Building Blocks

Concept 4 of 7
Pseudocode

Tool Definitions + Loop

-- 1. Define available tools -- TOOLS = [ {name: "web_search", description: "Search web for current info. Use for: recent events, prices, stats. NOT for: stable facts you know already.", inputs: {query: string (required)}}, {name: "read_url", description: "Fetch full text of a web page.", inputs: {url: string (required)}} ] -- 2. Run the agent loop -- FUNCTION run_agent(question): messages = [USER: question] LOOP (cap: 20 turns for safety): resp = CALL_API(messages, tools=TOOLS) APPEND resp TO messages IF resp.stop_reason == "end_turn": RETURN resp.text FOR EACH call IN resp: result = EXECUTE_TOOL(call.name, call.inputs) APPEND tool_result(id=call.id, result) TO messages
Concept 4 of 7
Misconceptions + Takeaway

Common Wrong Beliefs

Tool descriptions don't matter much - Claude will figure it out
Tool descriptions are the primary signal Claude uses for tool selection. Vague descriptions cause wrong calls and wasted turns. Include: what it does, when to use it, when NOT to use it.
I should raise an exception when a tool fails so Claude knows about the error
Always catch exceptions and return structured error results: {error: "...", isError: true}. Claude reads the error and decides whether to retry, try an alternative, or escalate. Uncaught exceptions crash the loop.
The messages array is everything. Every API call passes the full history, and every response plus tool result gets appended before the next call. This is how a stateless API becomes a stateful agent.
Concept 5 of 7
Big Idea

Thought Traces

Thought traces are the "Thought: ..." paragraphs Claude writes before each tool call. They serve two purposes: working memory (each thought accumulates in context so Claude stays oriented across many turns) and audit trail (every tool call has a recorded "why" immediately before it).

You enable thought traces by instructing Claude in the system prompt: "Before every tool call, write a Thought: explaining what you know, what's missing, and why this specific tool call fills that gap." No special API flag is needed - just the system prompt instruction.

Concept 5 of 7
Analogy

The Researcher's Notebook

Everyday Analogy

Before: a researcher opens Paper 1, reads a paragraph, closes it, opens Paper 2, reads, closes - with no notes. By Paper 3 they've forgotten what Paper 1 said.

The pain: the final report either copies the last thing read or strings together disconnected fragments. No synthesis is possible without connections between the papers.

The mapping: thought traces are the notebook. "After Paper 1: my understanding is X, I still need Y." That note travels into every subsequent step. The agent can synthesize a coherent answer because it's been annotating the whole time - and every annotation is in the conversation context.

Concept 5 of 7
How It Works

What Thought Traces Do

Concept 5 of 7
Pseudocode

System Prompt for Thought Traces

-- System prompt enabling thought traces -- SYSTEM_PROMPT = """ Before EVERY tool call, write: Thought: [what I currently know] [what specific info I still need] [why THIS tool call fills that gap] After EVERY tool result, write: Thought: [what I just learned] [do I have enough to answer?] [if no: what do I still need?] When you have enough info, produce a structured answer that cites the searches you ran. """ -- Thought traces appear as text blocks in -- the assistant message before tool_use blocks. -- They accumulate in messages[] automatically. -- No special handling required in your code.
Concept 5 of 7
Misconceptions + Takeaway

Common Wrong Beliefs

Remove thought traces in production to save tokens
Thought traces are working memory. Stripping them degrades multi-step reasoning quality because Claude loses the notes it's been leaving itself. Keep them; log them separately for debugging.
I need to parse and store thought traces separately
Thought traces are just text in the assistant response. They automatically accumulate in the messages array and are passed to Claude in every subsequent turn. No special handling needed.
Thought traces turn blind tool calls into coherent reasoning. They're not optional - they're the mechanism that makes multi-step agents reliable and debuggable in production.
Concept 6 of 7
Big Idea

Stop Conditions

The correct way to stop a ReAct loop is to check stop_reason in the API response. When Claude is done, it sets stop_reason = "end_turn" and produces a text response. When it wants more tool calls, it sets stop_reason = "tool_use".

An iteration cap (max_turns) should exist as a safety net only - not as the primary stopping mechanism. If you're hitting the cap regularly, your agent has a design problem. Let Claude decide when it's done.

Cert Tip - Domain 1.1 Checking stop_reason is the exam-correct stopping pattern. "end_turn" = done. "tool_use" = continue. Anti-pattern: parsing Claude's text for phrases like "I'm done."
Concept 6 of 7
Analogy

Navigation vs. Fuel Gauge

Everyday Analogy

Before: driving to a destination with a rule: stop after exactly 10 turns, regardless of whether you've arrived. Sometimes you're there by turn 3 and drive circles for 7 more. Sometimes you need 15 turns and get stranded 5 short.

The pain: an arbitrary turn count produces both wasted effort (stopping too late) and incomplete results (stopping too early) - and you never know which failure mode you hit.

The mapping: stop_reason = "end_turn" is the GPS saying "you have arrived." The turn cap is the fuel gauge - a safety measure against driving forever, not the thing that determines when you're done. Stop when you arrive, not when the gauge hits a number.

Concept 6 of 7
How It Works

Two Anti-Patterns, One Correct Pattern

Anti-pattern 1: Parse the text

Check if Claude's response contains "I'm done" or "task complete." Fails because Claude phrases completion differently every run, and the phrase may appear inside a thought trace mid-task.

Anti-pattern 2: Count turns as primary stop

Using "if turns >= 10: break" as main logic. Too few for complex tasks (stops before done); too many for simple ones (wastes turns and money).

Correct pattern

Primary stop: stop_reason = "end_turn". Safety cap (20-50 turns): handles runaway loops. Handle cap-exceeded explicitly - log it, tell the user, never silently return partial results.

Concept 6 of 7
Pseudocode

Stop Condition Logic

-- Correct stopping pattern -- MAX_TURNS = 20 -- safety net, not primary stop turn = 0 LOOP: turn += 1 response = CALL_API(messages, tools) -- Primary: Claude decided it's done IF response.stop_reason == "end_turn": RETURN extract_text(response) -- Continue: Claude wants more tools IF response.stop_reason == "tool_use": run_tools_and_append(response) CONTINUE -- Safety net: cap exceeded IF turn >= MAX_TURNS: LOG("Safety cap reached - partial result") NOTIFY_USER("Task incomplete after max turns") RETURN partial_result
Concept 6 of 7
Misconceptions + Takeaway

Common Wrong Beliefs

Set max_turns to 10 so the agent doesn't run too long
Set max_turns high enough for legitimate tasks to finish (20-50). If you're hitting the cap regularly, the agent design is the problem. The cap should almost never trigger in normal operation.
The loop stops automatically when Claude finishes - I don't need to check stop_reason
The loop runs as long as your while condition is true. Nothing stops it automatically. You must check stop_reason after every API call and break when it equals "end_turn".
Stop rule: check stop_reason after every API call. "end_turn" means return the answer. "tool_use" means execute tools and loop. Iteration cap is a safety net only - handle it explicitly if triggered.
Concept 7 of 7
Big Idea

Manual Loop vs. Agent SDK

M12 is a Tier 2 module: you learn both the manual implementation (raw Messages API while loop) and the Agent SDK (@tool decorator + query() function). The goal is to understand what the SDK hides so you can debug it when something breaks.

The SDK handles: the loop, history management, tool dispatch, and stop-reason checking. You still control: tool implementations, system prompt, model selection, error handling inside tools, and the max-turns safety cap.

Concept 7 of 7
Analogy

SQL vs. the ORM

Everyday Analogy

Before: developers who only know ORMs and never learned SQL. They use the ORM fine until a complex query produces wrong results - and they have no idea what SQL the ORM generated or why it's wrong.

The pain: they can use the abstraction but can't debug or optimize it because they don't understand what's underneath.

The mapping: learning the manual ReAct loop first, then the SDK, is like learning SQL before the ORM. When the SDK produces unexpected behavior - wrong stop, missing tool call, strange output - you can look under the hood because you know what the loop is supposed to do at each step.

Concept 7 of 7
How It Works

What the SDK Abstracts

PieceManualAgent SDK
LoopYou write while loopSDK runs it
HistoryYou append to messages[]SDK manages it
Tool dispatchYou route tool_use blocksSDK routes to @tool functions
Stop checkYou check stop_reasonSDK checks it
Tool logicYou implementYou implement (in @tool)
System promptYou writeYou write
Concept 7 of 7
Pseudocode

Manual vs. SDK

-- MANUAL (you own everything) -- messages = [USER: question] LOOP: resp = CALL_API(messages, tools=TOOLS) APPEND resp TO messages IF resp.stop_reason == "end_turn": RETURN resp.text FOR EACH call IN resp: APPEND EXECUTE(call) TO messages -- AGENT SDK (SDK owns the loop) -- DEFINE tool web_search(query): -- your implementation -- RETURN search_results DEFINE tool read_url(url): -- your implementation -- RETURN page_text result = SDK.query( prompt = question, tools = [web_search, read_url], model = "claude-opus-4-7", max_turns = 20 ) RETURN result.final_text
Concept 7 of 7
Misconceptions + Takeaway

Common Wrong Beliefs

The Agent SDK does everything - I don't need to understand the loop
When the SDK produces unexpected results, you need to understand the loop to debug it. Skipping the manual implementation leaves you unable to explain why the agent stopped early or called the wrong tool.
Always use the SDK - manual loops are outdated
Manual loops give full control - useful for custom retry logic, non-standard stop conditions, or fine-grained logging. Know both; pick based on context.
Learn the manual loop to understand what's happening. Use the SDK for productivity. The SDK is a layer on top of the loop - not a replacement for understanding it.
Quick Quiz

Test Your Understanding

Tap each question to reveal the answer.

What's Next

Ready to Build?

You've covered all 7 core concepts. The desktop module has the complete hands-on lab where you build a working ReAct research agent with full runnable code, step-by-step instructions, and a Tier 2 SDK comparison.

Open the Full Module

Complete code - Hands-on lab - SDK comparison - 6-question quiz with detailed feedback

Open M12 on Desktop
Up Next
13
M13: Planning & Task Decomposition
When tasks are too complex for a single ReAct loop
Back to Mobile Course Index