What is the ReAct pattern
ReActReActA prompting pattern that alternates between reasoning steps and tool-use actions, enabling models to think through problems, take actions, observe results, and iterate.Learn more → (Reasoning and Acting) is a prompting and execution pattern where an LLMLLMLarge Language Model — a neural network trained on vast amounts of text data that can understand and generate human-quality language across a wide range of tasks.Learn more → alternates between thinking through a problem and taking actions (calling tools). Each step produces either a Thought (the model's reasoning), an Action (a tool call), an Observation (the tool result), or a Final Answer.
The pattern works because LLMs are better at single-step reasoning than multi-step planningPlanningAn agent's decomposition of a goal into an ordered set of steps or subgoals before or while acting to achieve complex objectives systematically.Learn more →. By breaking a complex task into small steps — each with an observation before the next step — the model avoids common planning errors and can adapt when tool results are unexpected.
Set up the environment
Install the OpenAI Python SDK: `pip install openai`. Set your API key: `export OPENAI_API_KEY=your_key`. For the web search tool in this example, also install: `pip install duckduckgo-search`.
The agentAgentAn LLM-powered system that can take actions, use tools, and pursue multi-step goals autonomously without human input at each step.Learn more → in this guide will use GPTGPTGenerative Pre-trained Transformer — the model architecture and family name behind OpenAI's most famous models, from GPT-2 to GPT-5.Learn more →-4o-mini for cost efficiency — it supports function callingFunction CallingA capability that allows language models to return structured calls to developer-defined functions or tools, enabling AI systems to interact with external APIs, databases, and services.Learn more → and is fast enough for interactive agent loops.
Define your tools
Create a `tools` list for the API and a corresponding `tool_implementations` dict that maps tool names to Python functions. For this example: `search(query)` calls DuckDuckGo and returns the top 3 results as a formatted string; `calculate(expression)` evaluates a safe math expression using Python's `eval` with a restricted namespace.
The tool descriptions must be precise. Instead of 'searches the web', write 'searches the web and returns the top 3 results as a list of title, URL, and snippet'. The model uses the description to decide which tool to call and how to use the result.
Build the agent loop
Initialise the messages list with a system promptSystem PromptA special instruction given to a language model before the user conversation begins, establishing the model's persona, capabilities, constraints, and context.Learn more → explaining the agent's role and a user message with the task. Call the OpenAI chat completions endpoint with your tools list. If the response has `tool_calls`, execute each tool, append the results as `tool` role messages, and call the API again.
Add a system promptPromptThe input text sent to a language model — the question, instruction, or context that triggers a response.Learn more → that encourages step-by-step reasoning: 'Think through the problem step by step before calling any tools. After each tool result, reflect on whether you have enough information to answer.' This significantly improves the quality of multi-step reasoning.
Handle errors gracefully
Wrap each tool execution in a try-except block. If a tool fails, pass the error message back to the model as the tool result — the model can then choose a different approach or ask for clarification rather than crashing the agent.
Implement a step counter and stop the loop after N iterations with a final message to the user. Most tasks complete in 2–5 steps; if an agent exceeds 10 steps it is usually stuck in a loop.
Test and extend
Test with questions that require multiple steps: 'What is the population of the capital of France divided by 1000?' This requires finding that Paris is the capital, finding its population, and doing the division.
Once the basic loop works, add more tools: a file reader, a code executor with sandboxing, or a database query tool. The architecture scales — each new tool is a Python function and a JSON Schema entry.