Reason, act with a tool, observe the result. Repeat until solved.
ReAct (Reasoning + Acting) is a framework that combines:
This creates agents that can solve complex, multi-step problems reliably.
┌─────────────┐
│ Problem │
└──────┬──────┘
│
▼
┌─────────────────────────────────────┐
│ ReAct Loop │
│ │
│ ┌──────────────────────────────┐ │
│ │ 1. THOUGHT │ │
│ │ "What do I need to do?" │ │
│ └─────────────┬────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────┐ │
│ │ 2. ACTION │ │
│ │ Call tool with parameters │ │
│ └─────────────┬────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────┐ │
│ │ 3. OBSERVATION │ │
│ │ Receive tool result │ │
│ └─────────────┬────────────────┘ │
│ │ │
│ └──► Repeat or │
│ Final Answer │
└─────────────────────────────────────┘
The agent reasons about:
Example:
Thought: I need to calculate 15 × 8 to find revenue
The agent calls a tool with specific parameters:
Example:
Action: multiply(15, 8)
The agent receives and interprets the tool result:
Example:
Observation: 120
Problem: "If 15 items cost $8 each and 20 items cost $8 each,
what's the total revenue?"
Thought: First I need to calculate revenue from 15 items
Action: multiply(15, 8)
Observation: 120
Thought: Now I need revenue from 20 items
Action: multiply(20, 8)
Observation: 160
Thought: Now I add both revenues
Action: add(120, 160)
Observation: 280
Thought: I have the final answer
Answer: The total revenue is $280
User: "Calculate 15×8 + 20×8"
LLM: "The answer is 279" ❌ Wrong!
Problem: LLM calculates in head, makes errors
User: "Calculate 15×8 + 20×8"
LLM: "Let me think step by step:
15×8 = 120
20×8 = 160
120+160 = 279" ❌ Still wrong!
Problem: Shows work but still miscalculates
User: "Calculate 15×8 + 20×8"
Agent:
Thought: Calculate 15×8
Action: multiply(15, 8)
Observation: 120
Thought: Calculate 20×8
Action: multiply(20, 8)
Observation: 160
Thought: Add results
Action: add(120, 160)
Observation: 280
Answer: 280 ✅ Correct!
Success: Uses tools, gets accurate results
┌──────────────────────────────────────┐
│ User Question │
└──────────────┬───────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ LLM with ReAct Prompt │
│ │
│ "Think, Act, Observe pattern" │
└──────┬───────────────────────────────┘
│
├──► Generates: "Thought: ..."
│
├──► Generates: "Action: tool(params)"
│ │
│ ▼
│ ┌─────────────────┐
│ │ Tool Executor │
│ │ │
│ │ - multiply() │
│ │ - add() │
│ │ - divide() │
│ │ - subtract() │
│ └─────────┬───────┘
│ │
│ ▼
└───────── "Observation: result"
│
├──► Next iteration or Final Answer
│
▼
┌──────────────────────────────────────┐
│ Final Answer │
└──────────────────────────────────────┘
Force the LLM to follow structure:
systemPrompt: `CRITICAL: Follow this EXACT pattern:
Thought: [reasoning]
Action: [tool call]
Observation: [result]
...
Answer: [final answer]`
Prevent infinite loops:
maxIterations = 10 // Safety limit
Show progress in real-time:
onTextChunk: (chunk) => {
process.stdout.write(chunk);
}
Know when to stop:
if (response.includes("Answer:")) {
return fullResponse; // Done!
}
Each thought/action/observation cycle costs tokens and time.
Solution: Use efficient models, limit iterations
ReAct is only as good as its tools.
Solution: Build robust, well-tested tools
System prompt must be very clear.
Solution: Test extensively, iterate on prompt
Tools can fail or return unexpected results.
Solution: Add error handling, validation
Thought: That result seems wrong
Action: verify(previous_result)
Observation: Error detected
Thought: Let me recalculate
Action: multiply(15, 8) # Try again
Thought: I've used 5 iterations, I should finish soon
Action: summarize_progress()
Observation: Still need to add final numbers
Thought: One more step should do it
Thought: This is a division problem
Action: divide(10, 2) # Chooses right tool
Thought: Now I need to add
Action: add(5, 3) # Switches tools
ReAct was introduced in:
"ReAct: Synergizing Reasoning and Acting in Language Models"
Yao et al., 2022
Paper: https://arxiv.org/abs/2210.03629
Key insight: Combining reasoning traces with task-specific actions creates more powerful agents than either alone.
Nearly all production agent systems use ReAct or similar patterns.
Unlike black-box models, you see exactly what's happening.
Easy to add new tools and capabilities.
When things go wrong, you can see where and why.
This pattern scales from demos to real applications.
ReAct transforms LLMs from:
It's the bridge between language models and autonomous agents that can actually accomplish complex tasks reliably.
If the tool registry grows large, you can pre-filter which tools appear in each ReAct iteration (for example with embedding similarity over exemplar phrases); see Example 15: tool routing with embeddings.