Back to blog
Building LLM Weather Agent from Scratch

Building LLM Weather Agent from Scratch

A simple guide to creating an AI agent that can fetch, interpret, and communicate weather data using Python and OpenAI.

Introduction

In 2024, AI agents went mainstream, marking an exciting development in the use of Large Language Models (LLMs) as reasoning engines for autonomous agents. Looking ahead, 2025 is anticipated to be the year where AI agents will be the dominant force in the world of automation.

In this guide, we'll build a practical AI agent using the ReAct pattern. Our focus will be creating a weather agent that interacts with a weather API using Python and OpenAI's API.

Understanding AI Agents

AI agents are still a hot topic in the tech world, kind of like how "websites" were back in the day when the internet was just taking off. Asking someone to define an AI agent is like agreeing on the best pizza toppings - it's subjective,

At their core, AI agents are entities powered by large language models (LLMs) and designed to perform tasks autonomously. Agents can plan, reason, and take action to achieve specific goals.

Building block

The basic building block of agentic systems is an LLM enhanced with augmentations such as retrieval, tools, and memory. In our current project, we focus on utilizing tools only.

  • The Loop: Ensuring tasks are completed or system-defined limits are reached.
  • Memory: Essential for recalling previous actions.
  • The Brain (LLM): The core processor, responsible for generating insights and formulating action plans.
  • Tools: Functional extensions of the agent, Analogous to human tools like calculators, Hammers, etc.

alt text
Image SourceπŸ”—

AI Agent Patterns

Just as there are different approaches to solving a puzzle, AI agents can be implemented using various patterns. Each pattern is like a different problem-solving strategy:

  1. ReAct Agent: Like a detective who thinks, acts, and observes in a continuous cycle, gathering clues until the mystery is solved.
  2. Task-Planner Agent: Similar to a project manager who breaks down complex tasks into manageable steps before execution.
  3. Multi-Agent Orchestration: Think of it as a specialized team where different experts collaborate to solve complex problems.

The ReAct Pattern Explained

We will implement the ReACT (reason + act) methodology to manage our system. This process entails prompting the brain to generate a thought and an action for each iteration in the loop. Upon receiving the action, Our system will execute it on brains’s behalf and relay the observations back to it. This cycle will continue in subsequent iterations until we achieve the goal or reach the predefined threshold limit.

  1. Thought: Like checking the recipe and available ingredients
  2. Action: Selecting and using the right cooking technique
  3. Observation: Tasting and adjusting seasonings
  4. Repeat: Continuing this cycle until the dish is perfectly prepared

Building Our Weather AI Agent

Now let's roll up our sleeves and build our weather agent. Think of this as assembling a specialized weather station that can not only gather data but interpret and communicate it effectively.

Project Structure

weather-agent/
β”œβ”€β”€ requirements.txt      # Our shopping list of dependencies
β”œβ”€β”€ .env                 # Secure storage for our API keys
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ prompt_template.py  # The agent's instruction manual
β”‚   β”œβ”€β”€ tools.py           # Our weather-reading instruments
β”‚   └── main.py           # The control center
└── README.md            # Project documentation

Setting Up the Environment

First, create a new project directory and set up your virtual environment:

mkdir weather-agent
cd weather-agent
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

Install the required dependencies:

pip install openai==1.3.0 python-dotenv==1.0.0 requests==2.31.0

Implementing the Core Components

1. Environment Setup

Create a (.env) file to store your API keys:

OPENAI_API_KEY=your_openai_api_key
OPENWEATHER_API_KEY=your_openweather_api_key

2. The Agent's Brain: Prompt Template

The prompt template is like the agent's training manual - it defines how our agent thinks and responds. Just as a good teacher provides clear instructions and examples, our prompt template guides the agent's behavior: we need to guide our agent on how to handle user questions using the get_weather tool effectively. To do that, we set up a system prompt that defines the agent’s behavior, tools, and how it should think.

SYSTEM_PROMPT = '''You are a helpful AI agent that can use tools to find weather information and answer questions.

IMPORTANT: You must ALWAYS respond with a single line of valid JSON with NO additional text or formatting.

Available actions:
1. get_weather - Get current weather for a city (use this FIRST)
2. user_answer - Provide final answer to user (use this AFTER getting weather)

Workflow:
1. First response: Use get_weather to get current weather
2. After receiving weather data: Use user_answer to provide the information to the user

Your response must be a JSON object with exactly these fields:
{
  "thought": "your reasoning (string)",
  "action": "either get_weather or user_answer (string)",
  "action_input": "city name for get_weather or final answer for user_answer (string)"
}

Examples of valid responses:

First response:
{"thought":"I need to check the weather","action":"get_weather","action_input":"Tokyo"}

After receiving weather:
{"thought":"I have the weather data for Tokyo","action":"user_answer","action_input":"The current weather in Tokyo is few clouds with a temperature of 7.26Β°C and humidity at 40%"}

After receiving weather (with historical context):
{"thought":"I have current and historical weather data for Tokyo","action":"user_answer","action_input":"The current weather in Tokyo is few clouds with a temperature of 7.26Β°C. Based on historical data, this is similar to conditions observed earlier today when it was also cloudy with temperatures around 7Β°C."}

Remember:
- Response must be a single line of JSON
- No text before or after the JSON
- No line breaks or extra spaces
- Use double quotes for strings
- ALWAYS use user_answer after receiving weather data
- When available, incorporate historical context in your final answer'''

3. Weather Tool (tools.py)

Our weather tool uses the OpenWeather API to fetch real-time information:

import os
import requests
from dotenv import load_dotenv

load_dotenv()

def get_weather(city: str) -> str:
    """Fetch current weather data for a city."""
    api_key = os.getenv("OPENWEATHER_API_KEY")
    if not api_key:
        return "Error: API key not found"

    url = "http://api.openweathermap.org/data/2.5/weather"
    params = {
        "q": city,
        "appid": api_key,
        "units": "metric"
    }

    try:
        response = requests.get(url, params=params)
        response.raise_for_status()
        data = response.json()

        description = data["weather"][0]["description"]
        temperature = data["main"]["temp"]
        humidity = data["main"]["humidity"]

        return f"Current weather in {city}: {description}. Temperature: {temperature}Β°C, Humidity: {humidity}%"
    except Exception as e:
        return f"Error fetching weather data: {str(e)}"

4. Main Application (main.py)

Create a main.py to run the agent:

This section imports necessary modules and initializes the OpenAI client using the API key from environment variables.

import os
from typing import Dict, Any
from openai import OpenAI
from dotenv import load_dotenv
from tools import get_weather
from prompt_template import  SYSTEM_PROMPT
import json

# Load environment variables
load_dotenv(override=True)

# Initialize OpenAI client
client = OpenAI(
    api_key=os.getenv("OPENAI_API_KEY")
)

The execute_tool function is responsible for calling the appropriate tool based on the agent's decision.

def execute_tool(tool_name: str, tool_input: str) -> str:
    """Execute the specified tool with the given input."""
    if tool_name == "get_weather":
        return get_weather(tool_input)
    return f"Error: Unknown tool '{tool_name}'"

The run_agent function orchestrates the agent's behavior, handling the conversation flow and executing the tools.

def run_agent(user_input: str) -> str:
    """Run the agent with the given question."""

    # Create conversation with system and user messages
    messages = [
        {"role": "system", "content": SYSTEM_PROMPT},
        {"role": "user", "content": user_input.strip()}
    ]

    max_steps = 3  # Prevent infinite loops
    step = 0

    while step < max_steps:
        # Get response from OpenAI
        response = client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=messages,
            temperature=0,
        )

        content = response.choices[0].message.content.strip()
        print(f"Raw response: {content}")

        try:
            # Parse the JSON response
            content_json = json.loads(content)

            # Validate required fields
            required_fields = ['thought', 'action', 'action_input']
            if not all(field in content_json for field in required_fields):
                return "Error: Missing required fields in response"

            # Check if we have a user answer
            if content_json['action'] == 'user_answer':
                return content_json['action_input']

            # Execute tool
            observation = execute_tool(content_json['action'], content_json['action_input'])

            # Add both the assistant's response and the observation to the conversation
            messages.append({"role": "assistant", "content": content})
            messages.append({"role": "user", "content": f"Weather data: {observation}"})

        except json.JSONDecodeError as e:
            print(f"Error parsing JSON: {e}")
            print(f"Invalid JSON: {content}")
            return "Error: Invalid JSON response format"
        except KeyError as e:
            print(f"Error accessing JSON key: {e}")
            return "Error: Missing required fields in response"

        step += 1

    return "Error: Maximum number of steps reached"

And finally, the main function that orchestrates the agent's behavior:

def main():
    """Main function to run the AI agent."""
    print("\n=== Weather Assistant ===")
    print("Example questions:")
    print("- What's the weather in Tokyo?")
    print("- How's the weather in New York?")
    print("\nType 'quit' to exit\n")

    while True:
        user_input = input("\nAsk about weather: ").strip()
        if user_input.lower() == 'quit':
            print("Goodbye!")
            break
        if not user_input:
            print("Please enter a question.")
            continue

        answer = run_agent(user_input)
        print(f"\nAnswer: {answer}")

if __name__ == "__main__":
    main()

Running the Agent

To run the weather agent:

  1. Ensure all files are in place
  2. Configure your API keys in (.env)
  3. Run the main script:
python src/main.py

Try these example queries:

  • "What's the weather like in Tokyo?"
  • "Is it raining in London?"
  • "Should I bring an umbrella in New York?"

Conclusion

This project demonstrates how to build a practical AI agent using the ReAct pattern.

Remember that the key to success lies in finding the right balance between capability and complexity. Start simple, test thoroughly, and gradually enhance your agent's abilities based on real-world usage and feedback.

For the complete source code and updates, visit the GitHub repositoryπŸ”—.

Additional Resources