ReAct Pattern
ReAct combines Reasoning (thinking aloud) and Acting (using tools). The LLM thinks about what to do, takes an action, observes the result, and thinks again. It is the core loop of autonomous agents.
Why Does This Exist?
Prior to 2022, Large Language Models were separated into two distinct categories of research:
- Reasoning: Using techniques like Chain of Thought (CoT) to solve math and logic problems.
- Acting: Training models to play text-based games or navigate web browsers by outputting commands (like
move_forwardorclick_button).
The breakthrough of the ReAct (Reason + Act) paper was combining these two domains. If an LLM just acts without reasoning, it clicks randomly and fails. If an LLM just reasons without acting, it cannot fetch real-time information or affect the outside world.
ReAct interleaves reasoning and acting. By forcing the LLM to "think out loud" before it takes an action, the LLM creates an actionable plan, executes it, and then evaluates the result. This simple loop is the foundational architecture for almost all modern AI agents (including Agentic RAG systems).
Think of It Like This
Cooking in a new kitchen
Acting Only: You walk into the kitchen, open a random drawer, pull out a whisk, turn on the oven, and grab an egg. Chaos ensues.
Reasoning Only: You sit at the kitchen table and write a brilliant, detailed plan for baking a cake. But you never actually stand up to bake it.
ReAct (Reason + Act): (Thought) "I want to bake a cake. First, I need to see if I have flour." (Action) Open pantry. (Observation) I see sugar and baking soda, but no flour. (Thought) "I cannot bake a cake without flour. I need to go to the store." (Action) Leave house.
You are constantly evaluating the environment and adjusting your plan.
How It Actually Works
Implementing ReAct requires a specific prompt structure and a Python execution loop (the "orchestrator").
1. The Prompt (The Rules of the Game)
The system prompt defines the tools available to the LLM and strictly enforces the formatting of the output. The LLM is instructed to output exactly one Thought: followed by one Action:.
You are a helpful AI assistant. You have access to the following tools:- Wikipedia(query): Searches Wikipedia and returns a summary.- Calculator(expression): Evaluates a math expression.
Use the following format:Question: the input question you must answerThought: you should always think about what to doAction: the action to take, should be one of [Wikipedia, Calculator]Action Input: the input to the actionObservation: the result of the action... (this Thought/Action/Observation can repeat N times)Thought: I now know the final answerFinal Answer: the final answer to the original input question2. The Orchestrator Loop
The LLM generates text. As soon as it generates the Action: and Action Input: lines, the Python orchestrator stops the LLM.
The orchestrator reads the action (e.g., Calculator(5 * 8)), executes the Python code for that tool, and gets the result (40).
The orchestrator appends Observation: 40 to the text and sends the whole block back to the LLM.
The LLM reads the observation, generates its next Thought:, and the loop continues until the LLM outputs Final Answer:.
Show Me the Code
This is a conceptual, simplified version of a ReAct orchestrator loop. Libraries like LangChain handle this parsing automatically, but seeing the raw loop is instructive.
import openaiimport re
def execute_tool(action, action_input): print(f" [Executing Tool]: {action} with input: '{action_input}'") if action == "WeatherAPI": if "Seattle" in action_input: return "65 degrees and raining." return "72 degrees and sunny." return "Tool not found."
def react_loop(question, max_iterations=3): system_prompt = """ You can use the tool: WeatherAPI(city). You must format your response exactly as: Thought: <your thought> Action: <tool name> Action Input: <input> """ # We maintain a running log of the conversation (the "scratchpad") conversation = [ {"role": "system", "content": system_prompt}, {"role": "user", "content": question} ] print(f"Question: {question}\n") for i in range(max_iterations): # 1. Call the LLM to get the next Thought + Action response = openai.chat.completions.create( model="gpt-4o", messages=conversation, stop=["Observation:"] # VERY IMPORTANT: Stop generation before it hallucinates the observation! ) llm_output = response.choices[0].message.content print(llm_output) # Add the LLM's thought/action to the conversation history conversation.append({"role": "assistant", "content": llm_output}) # 2. Check if the LLM reached the final answer if "Final Answer:" in llm_output: return # 3. Parse the action and execute it action_match = re.search(r'Action:\s*(.*)', llm_output) input_match = re.search(r'Action Input:\s*(.*)', llm_output) if action_match and input_match: action = action_match.group(1).strip() action_input = input_match.group(1).strip() # Execute the python tool observation = execute_tool(action, action_input) print(f"Observation: {observation}\n") # Add the observation back to the conversation as if the user said it conversation.append({"role": "user", "content": f"Observation: {observation}"}) else: print("Error parsing action. Exiting loop.") break
# --- Execution ---react_loop("What should I wear in Seattle today?")
# -> Question: What should I wear in Seattle today?# -> # -> Thought: I need to find the current weather in Seattle to recommend clothing.# -> Action: WeatherAPI# -> Action Input: Seattle# -> [Executing Tool]: WeatherAPI with input: 'Seattle'# -> Observation: 65 degrees and raining.# -> # -> Thought: It is raining and mild. A raincoat and layers are appropriate.# -> Final Answer: You should wear a raincoat and carry an umbrella since it's 65 degrees and raining.Watch Out For
The Parsing Nightmare
If you build a ReAct loop from scratch, you will quickly discover that LLMs constantly disobey formatting instructions. They will output Action: [WeatherAPI] (Seattle) instead of Action: WeatherAPI, crashing your regex parser. Modern agent frameworks rely heavily on strict JSON schemas or OpenAI's native Tool Calling API rather than pure text parsing to solve this fragility.
The Quick Version
- ReAct combines "Chain of Thought" reasoning with environmental "Actions".
- The LLM is placed inside a
whileloop orchestrated by Python code. - The LLM outputs a
Thoughtand anAction. - The Python code halts the LLM, executes the requested tool (like a DB search or API call), and hands the result back to the LLM as an
Observation. - The LLM repeats this loop until it has enough information to output the
Final Answer.
What to Read Next
- Read Agentic RAG to see how ReAct is applied to complex document retrieval.
- Read Chain of Thought to understand the purely analytical reasoning that powers ReAct.
- Read Prompt Chaining for an alternative way to build multi-step workflows without handing autonomous control to the LLM.