A hands-on example demonstrates 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. 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:Find the current weather in a specified city.Based on that weather, suggest a suitable outdoor activity.This task requires at least two steps and the use of a (simulated) tool, making it a good candidate for the ReAct framework.Setting the Stage: Agent Goal and ToolsFirst, 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 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 ReAct Loop: Thought, Action, ObservationThe core of our ReAct agent will be a loop. In each iteration of this loop, the agent will:Think (Reason): The LLM processes the current goal, any previous steps (history), and the latest observation. It then formulates a thought about what to do next.Act: Based on its thought, the LLM decides on an action. This could be using a tool (like get_weather) or, if the task is complete, using a special Finish action.Observe: The agent (our Python code) executes the action. If it's a tool call, the tool's output becomes the observation. If it's Finish, the loop terminates.Let's visualize this core cycle:digraph ReActLoop { rankdir=TB; bgcolor="transparent"; node [shape=box, style="rounded,filled", fontname="Arial", margin=0.2, color="#495057", width=2.8, height=0.9]; edge [fontname="Arial", color="#495057", fontsize=10]; State [label="Current State\n(Goal, History, Last Observation)", fillcolor="#a5d8ff"]; LLM_Thought [label="LLM Generates Thought\n(e.g., 'I need the weather for London.')", fillcolor="#ffec99"]; LLM_Action [label="LLM Chooses Action\n(e.g., get_weather['London, UK']\nor Finish['The answer is...'])", fillcolor="#ffd8a8"]; Execute_Action [label="Execute Action\n(Call get_weather tool or process Finish)", fillcolor="#fcc2d7"]; New_Observation [label="Get New Observation\n(e.g., 'Weather is 15°C and sunny.')", fillcolor="#eebefa"]; State -> LLM_Thought [label=" Input to LLM"]; LLM_Thought -> LLM_Action [label=" informs"]; LLM_Action -> Execute_Action; Execute_Action -> New_Observation; New_Observation -> State [label=" Update State & Loop (if not Finished)"]; }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.Crafting the Prompt for the LLMThe prompt is how we instruct the LLM to behave within the ReAct framework. It needs to tell the LLM:Its overall goal.The tools available and how to use them (their "signature" or format).The format for thinking and acting (e.g., Thought: ... Action: ...).How to signal completion (e.g., Action: Finish[...]).The history of previous thought-action-observation steps.The most recent observation.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:.Implementing the Agent Loop (Simplified Python Sketch)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.") Walking Through an Example ExecutionLet's trace how our agent (with the mock_llm_call) would operate:Step 1:Initial State: goal is set, history is empty, observation is "No observation yet...".Prompt Construction: The prompt is built with the goal, tool descriptions, and initial observation.LLM Call (Mocked):Input Prompt (simplified):You are a helpful assistant. Your goal is: Find the current weather in London, UK... ... Current Observation: No observation yet. Let's start. Thought:Mocked LLM Output: I need to find the weather in London, UK. I should use the get_weather tool.\nAction: get_weather[London, UK]Parse Output:Thought: I need to find the weather in London, UK. I should use the get_weather tool.Action: get_weather[London, UK]Execute Action: The get_weather("London, UK") function is called.TOOL_CALL: get_weather(city='London, UK') (printed by our tool)New Observation: The weather in London, UK is 15°C and sunny.Update History: The (Thought, Action, Observation) triplet is added to history_log.Step 2:State: goal is the same, history contains Step 1's triplet, observation is "The weather in London, UK is 15°C and sunny."Prompt Construction: The prompt now includes the history from Step 1 and the new observation.LLM Call (Mocked):Input Prompt (simplified):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:Mocked LLM Output: 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.]Parse Output: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.]Execute Action: The action starts with Finish[.Result: The agent prints the final answer and the loop terminates. 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.Points to Consider for Your Own ReAct AgentLLM Choice: The quality of the "Thought" and "Action" steps heavily depends on the LLM's capabilities.Prompt Engineering is Important: The structure and clarity of your prompt significantly influence the agent's performance. You might need to experiment and refine your prompts.Tool Design: Tools should be well-defined, with clear input parameters and predictable output formats. The LLM needs to understand how to use them based on their descriptions in the prompt.Parsing LLM Output: You'll need parsing for the 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.Error Handling: What if the LLM generates an invalid action? Or a tool fails? Your agent loop should have basic error handling (e.g., feeding an error message back as an observation).Managing History: For long conversations or many steps, the history can become very long. This might exceed the LLM's context window. More advanced agents use summarization techniques for history, which goes further than this introductory example.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.