Think, act, observe

ReAct stands for Reason + Act. It is a prompting pattern where the LLM alternates between thinking (Thought), using a tool (Action), and seeing the result (Observation). This cycle repeats until it has enough information to give a Final Answer.

The React cycle: thought, action, observation

02-react-pattern.ipynb
python
REACT_SYSTEM_PROMPT = """You are a smart research assistant.
Use the following tools:
1. calculate(expression): Calculate mathematical expressions
2. get_weather(city): Get current weather for a city

For EVERY step, use this EXACT format:

Thought: <your reasoning>
Action: <tool name>
Action Input: <tool input>

When you have the final answer:
Final Answer: <your conclusion>
"""

The system prompt teaches the LLM the ReAct format: Thought, Action, Action Input, and Final Answer.

Now let us define the actual tool functions that the agent can call. These are plain Python functions that the agent will invoke when it parses an Action from the LLM output.

02-react-pattern.ipynb
python
def calculate(expression: str) -> str:
    try:
        result = eval(expression)
        return f"Result: {result}"
    except Exception as e:
        return f"Error: {str(e)}"

def get_weather(city: str) -> str:
    weather_data = {
        "tokyo": "25°C and sunny",
        "london": "15°C and rainy",
        "new york": "20°C and cloudy"
    }
    return weather_data.get(
        city.lower(),
        "Weather data not found for this city."
    )

tools = {
    "calculate": calculate,
    "get_weather": get_weather
}

Simple tool functions that the agent can call. The tools dict maps names to functions.

The system prompt lists the available tools with descriptions. The LLM reads this and reasons about which tool fits the task. It outputs "Action: calculate" or "Action: get_weather" as text. Then our Python code parses that text with regex to find the tool name and call it.

02-react-pattern.ipynb
python
import re

# Parse the LLM output to extract tool calls
action_match = re.search(r"Action: (\w+)", response_text)
input_match = re.search(r"Action Input: (.*)", response_text)

if action_match and input_match:
    tool_name = action_match.group(1)     # e.g., "calculate"
    tool_input = input_match.group(1).strip()  # e.g., "25 * 2"
    result = tools[tool_name](tool_input)  # Call the function!

Regex extracts the tool name and input from the LLM text output, then calls the matching function.

AI prompt: Try it with AI

Loading practice…

Quiz: Quiz

Loading practice…

Notice we're using regex to parse the LLM output. This works, but it is fragile. If the LLM formats its response slightly differently, the regex breaks. Later, we'll replace this with native function calling, a much more reliable approach.