Overview
The ReAct (Reason + Act) pattern combines explicit reasoning with iterative action. Rather than thinking through an entire plan before acting, or blindly taking actions without reflection, ReAct agents alternate between reasoning about what to do next and actually doing it.
Core Loop
Thought → Action → Observation → Thought → Action → ...
Example Trace
User: What's the weather in Tokyo and should I bring an umbrella?
Thought: I need to check Tokyo's current weather. Let me use the weather tool.
Action: get_weather(location="Tokyo")
Observation: {"temp": 18, "conditions": "light rain", "humidity": 85%}
Thought: It's raining in Tokyo. I should recommend bringing an umbrella.
Action: respond("It's currently 18°C with light rain in Tokyo.
Yes, you should definitely bring an umbrella!")
Key Principles
Interleaved Reasoning
Each action is preceded by explicit reasoning about why it's being taken. This creates transparency and enables debugging.
Observation-Driven Adaptation
Actions produce observations that inform the next reasoning step. The agent adapts based on what it learns.
Grounded Decisions
Actions are grounded in actual data retrieved through tools, not fabricated from training data.
When to Use ReAct
Good fit:
- Complex, unpredictable tasks
- Tasks requiring external data
- Situations where transparency matters
- Debugging and development
Consider alternatives for:
- Simple, well-defined tasks (overkill)
- Tasks requiring extensive upfront planning
- Latency-critical applications
ReAct vs. Other Patterns
| Pattern | Planning | Execution | Best For |
|---|---|---|---|
| ReAct | Incremental | Interleaved | Adaptive tasks |
| Plan-then-Execute | Upfront | Sequential | Predictable tasks |
| Reflection | Post-hoc | Iterative refinement | Quality improvement |
Implementation Tips
- Start with ReAct as your default for complex tasks
- Include observation parsing to handle tool errors
- Set maximum iteration limits to prevent infinite loops
- Log reasoning traces for debugging