This section provides a hands-on example of building an agent that employs the ReAct (Reason and Act) pattern. We will guide you through creating an agent capable of performing a sequence of actions to achieve a specific goal. As you recall from our earlier discussion, the ReAct approach involves the agent iterating through a cycle of thinking (reasoning about the task), acting (deciding on an action, often involving a tool), and observing (processing the result of that action).
Our goal for this practical exercise is to build an agent that can:
This task requires at least two steps and the use of a (simulated) tool, making it a good candidate for the ReAct framework.
First, let's clearly define our agent's overall objective:
"Find the current weather in London, UK. Then, suggest one outdoor activity suitable for that weather."
To accomplish this, our agent will need a tool to get weather information. For simplicity in this beginner-level exercise, we'll define a Python function that simulates this tool. In a real-world scenario, this function would likely call an external weather API.
# A simple, simulated tool
def get_weather(city: str) -> str:
"""Simulates fetching weather for a city."""
print(f"TOOL_CALL: get_weather(city='{city}')")
if city.lower() == "london, uk":
# Let's make the weather variable for different runs, or fixed for simplicity.
# Fixed for now for predictable output in this example.
return "The weather in London, UK is 15°C and sunny."
elif city.lower() == "paris, fr":
return "The weather in Paris, FR is 18°C with scattered clouds."
else:
return f"Sorry, I don't have weather information for {city}."
# We also need a way for the agent to signal it's finished.
# This isn't a tool, but a special action format.
# Action: Finish[final_answer_string]
The core of our ReAct agent will be a loop. In each iteration of this loop, the agent will:
get_weather
) or, if the task is complete, using a special Finish
action.Finish
, the loop terminates.Let's visualize this core cycle:
The ReAct cycle: The agent uses the current state (including the latest observation) to prompt the LLM, which then generates a thought and an action. The action is executed, producing a new observation, and the cycle repeats.
The prompt is how we instruct the LLM to behave within the ReAct framework. It needs to tell the LLM:
Thought: ... Action: ...
).Action: Finish[...]
).Here's a template for our prompt:
# This is a Python string template, not executable code by itself
prompt_template = """
You are a helpful assistant. Your goal is: {goal}
You have access to the following tools:
- get_weather[city_name]: Returns the current weather for the specified city.
To provide the final answer when you have all the information, use the format:
Action: Finish[your_final_answer_string]
Always follow this cycle:
Thought: (your reasoning about the current state, what you have learned, and what to do next to achieve the goal)
Action: (the action to take, either using a tool or Finish)
Here's the history of your work so far (Thought/Action/Observation triplets):
{history}
Current Observation: {observation}
Thought:"""
The {goal}
, {history}
, and {observation}
placeholders will be filled in at each step of the loop. The LLM is expected to generate text that starts after Thought:
.
Let's sketch out the Python logic. Assume you have a function call_llm(prompt_text)
that sends the prompt to an LLM and returns its response.
# --- Agent Setup ---
agent_goal = "Find the current weather in London, UK. Then, suggest one outdoor activity suitable for that weather."
history_log = [] # To store (thought, action_str, observation) tuples
current_observation = "No observation yet. Let's start."
max_steps = 5 # To prevent infinite loops
# --- Mock LLM Call ---
# In a real application, this would be an API call to an LLM service.
# For this example, we'll simulate LLM responses for the first few steps
# to illustrate the flow without needing a live LLM.
def mock_llm_call(prompt_text):
# This mock function will simulate LLM behavior based on the prompt content.
# It's highly simplified for this example.
print("\n--- LLM PROMPT ---")
print(prompt_text)
print("--- END LLM PROMPT ---\n")
if "get_weather[London, UK]" not in prompt_text and "Thought:" in prompt_text.split("Current Observation:")[-1]:
# First step, LLM should decide to get weather
return "I need to find the weather in London, UK. I should use the get_weather tool.\nAction: get_weather[London, UK]"
elif "Observation: The weather in London, UK is 15°C and sunny." in prompt_text:
# Second step, LLM has weather, needs to suggest activity
return "The weather is 15°C and sunny. This is pleasant. A good outdoor activity would be a walk in a park.\nAction: Finish[The weather in London, UK is 15°C and sunny. A suitable outdoor activity is to take a walk in a park.]"
else:
# Fallback for unexpected prompts in this mock
return "Thought: I am unsure how to proceed.\nAction: Finish[Could not complete the task.]"
# --- Helper functions to parse LLM output ---
def parse_llm_response(response_text):
thought = ""
action_str = ""
if "Thought:" in response_text:
thought = response_text.split("Thought:")[1].split("Action:")[0].strip()
if "Action:" in response_text:
action_str = response_text.split("Action:")[1].strip()
return thought, action_str
# --- ReAct Loop ---
for step in range(max_steps):
print(f"\n--- STEP {step + 1} ---")
# 1. Construct the prompt
history_str = "\n".join([f"Thought: {t}\nAction: {a}\nObservation: {o}" for t, a, o in history_log])
current_prompt = prompt_template.format(
goal=agent_goal,
history=history_str if history_log else "No history yet.",
observation=current_observation
)
# 2. Get Thought and Action from LLM
llm_response_text = mock_llm_call(current_prompt) # Use mock_llm_call or your actual LLM
thought, action_str = parse_llm_response(llm_response_text)
print(f"LLM Thought: {thought}")
print(f"LLM Action: {action_str}")
# 3. Execute Action and Get Observation
if not action_str:
print("Error: LLM did not provide an action.")
current_observation = "Error: No action provided by LLM."
history_log.append((thought, "No Action", current_observation))
continue # or break
if action_str.startswith("Finish["):
final_answer = action_str[len("Finish["):-1]
print(f"\nFINAL ANSWER: {final_answer}")
break # Exit loop
elif action_str.startswith("get_weather["):
city_name = action_str[len("get_weather["):-1]
current_observation = get_weather(city_name)
else:
print(f"Error: Unknown action: {action_str}")
current_observation = f"Error: Unknown action '{action_str}'. Please use available tools or Finish."
print(f"Observation: {current_observation}")
history_log.append((thought, action_str, current_observation))
if step == max_steps - 1:
print("\nMax steps reached. Agent did not finish.")
Let's trace how our agent (with the mock_llm_call
) would operate:
Step 1:
goal
is set, history
is empty, observation
is "No observation yet...".You are a helpful assistant. Your goal is: Find the current weather in London, UK...
...
Current Observation: No observation yet. Let's start.
Thought:
I need to find the weather in London, UK. I should use the get_weather tool.\nAction: get_weather[London, UK]
Thought:
I need to find the weather in London, UK. I should use the get_weather tool.Action:
get_weather[London, UK]
get_weather("London, UK")
function is called.
TOOL_CALL: get_weather(city='London, UK')
(printed by our tool)The weather in London, UK is 15°C and sunny.
history_log
.Step 2:
goal
is the same, history
contains Step 1's triplet, observation
is "The weather in London, UK is 15°C and sunny."You are a helpful assistant. Your goal is: Find the current weather in London, UK...
...
History:
Thought: I need to find the weather in London, UK...
Action: get_weather[London, UK]
Observation: The weather in London, UK is 15°C and sunny.
Current Observation: The weather in London, UK is 15°C and sunny.
Thought:
The weather is 15°C and sunny. This is pleasant. A good outdoor activity would be a walk in a park.\nAction: Finish[The weather in London, UK is 15°C and sunny. A suitable outdoor activity is to take a walk in a park.]
Thought:
The weather is 15°C and sunny. This is pleasant. A good outdoor activity would be a walk in a park.Action:
Finish[The weather in London, UK is 15°C and sunny. A suitable outdoor activity is to take a walk in a park.]
Finish[
.FINAL ANSWER: The weather in London, UK is 15°C and sunny. A suitable outdoor activity is to take a walk in a park.
This walkthrough demonstrates how the ReAct agent uses the LLM's reasoning (Thought) to decide on an Action, executes it, gets an Observation, and then feeds this back into the LLM to continue the process until the goal is achieved.
Thought:
and Action:
parts. Regular expressions or more structured output formats (like JSON, if your LLM supports it well in chat mode) can be helpful.This hands-on exercise provides a foundational understanding of building a ReAct agent. By experimenting with different tasks, tools, and refining your prompts, you can create more sophisticated agents capable of tackling increasingly complex sequential problems. Remember that building agents is often an iterative process of design, implementation, and testing.
Was this section helpful?
© 2025 ApX Machine Learning