Your First AI Agent: A Step-by-Step Tutorial to Make Gemini Fetch Live Weather Data
Alright, remember how excited we got in Part 1 about AI agents actually doing things instead of just chatting? Well, guess what? Today, we're diving in! This is where you'll build your very first AI agent, and trust me, it's going to be pretty awesome. We're stepping out of the theoretical discussions and into the hands-on fun of making AI truly functional. Get ready to see the power of autonomous action come to life right on your screen!
Our mission today? We're going to create a simple yet super effective "Weather Reporter" agent. This little AI will be able to fetch live (well, simulated live for our demo!) weather data for any city you ask it about. The secret sauce behind this magic is something called function calling, or as I like to call it, tool use. It's the key to bridging the gap between an AI's linguistic brilliance and its ability to interact with the real world's data and services.
Giving Your AI a "Toolbox": The Power of Function Calling
Think of it like this: your AI, Gemini, is super smart with language. It can understand what you're saying, generate creative text, and hold conversations. It's like having a brilliant conversationalist at your fingertips! But here's the kicker: it can't, by itself, magically know the current temperature in Tokyo right now. Why not? Because Large Language Models (LLMs) like Gemini have a "knowledge cut-off" – they're trained on data up to a certain point in time, and they don't inherently have real-time access to the internet or other external systems. That fresh, real-time information lives outside of its brain, in the real world (or at least, in web services that track weather!).
This is precisely where "tool use" comes in, and it's a game-changer. We can give Gemini a special "tool" – basically, a Python function you write – that does something specific, like getting weather data from an external source. Then, we tell Gemini, "Hey, when someone asks about the weather, you've got this cool get_current_weather tool in your arsenal that you can use!" It's like giving a highly intelligent person a specific instruction manual for a complex piece of equipment they've never seen before, but now know how to operate.
Here’s the cool part, and pay attention because this is the core loop of agentic behavior: When you ask Gemini a question like "What's the weather in London?", Gemini doesn't just try to answer from its general knowledge. Its super-smart brain figures out, "Aha! This user wants weather info! And look, I have a get_current_weather tool that's perfect for that!" Instead of just guessing or saying "I don't know," Gemini stops and tells us (your Python script), "Hey, I need you to run the get_current_weather tool for 'London'." Your script then takes over, actually runs the tool (our Python function that simulates fetching weather), gets the real weather data, and then gives that info back to Gemini. Gemini then takes that fresh, factual weather data and uses it to craft a helpful, natural-sounding response for you. Pretty neat, right? This two-step process – Gemini figuring out what tool to use, and your code actually using it and giving the result back – is fundamental to building any AI agent that interacts with the world.
Let's Build Our Weather Reporter!
To follow along and get your hands dirty, you'll need Python installed on your computer. If you don't have it yet, a quick search for "install Python" will guide you through it – it's pretty straightforward!
Once Python is ready, you'll need the google-generativeai library. This is the official Python library that lets us easily connect to and use Gemini's powerful models. If you don't have it, open your terminal or command prompt (that's the black window where you type commands) and run this simple command:
pip install google-generativeaiThis command tells Python's package installer (pip) to download and set up the necessary library on your system. Give it a moment to complete, and you'll be all set!
Now, let's get to the code! We'll break it down into a few simple steps, making it easy to understand each piece.
Step 1: Define Our "Tool" – The get_current_weather Function
For this tutorial, to keep things simple and get you up and running quickly, we're going to simulate getting live weather data. In a real-world, production-ready application, this get_current_weather function would make an actual call to an external weather API (like OpenWeatherMap, AccuWeather, or a similar service). These APIs are designed to give you real-time weather information for specific locations. But for now, we'll return some static, placeholder data to clearly show the core concept of function calling without getting bogged down in API keys and network requests.
import google.generativeai as genai
import json # We'll use this to pretty-print our mock data, makes it easier to read!
# --- Our "Tool" Function ---
# IMPORTANT: In a real app, this would make an API call to a live weather service.
# For this tutorial, we're returning mock data to demonstrate the concept clearly.
def get_current_weather(location: str, unit: str = "celsius"):
"""
Gets the current weather conditions for a specified location.
This function simulates fetching weather data. In a real application,
it would integrate with a third-party weather API.
Args:
location (str): The city or location (e.g., "London", "Tokyo").
This argument is crucial as it tells the function
*where* to get the weather for.
unit (str, optional): The unit for temperature. Can be "celsius" or "fahrenheit".
Defaults to "celsius" if not specified by Gemini.
Returns:
dict: A dictionary containing weather information (temperature, conditions).
Returns an error dictionary if the location is not in our mock data
or an invalid unit is requested.
"""
# This print statement is super helpful! It shows us *when* Gemini decided
# to use our tool and what arguments it passed to it. Great for debugging!
print(f"\nDEBUG: get_current_weather called for {location} in {unit}")
# Our mock weather data for demonstration purposes
weather_data = {
"London": {"temperature": {"celsius": 18, "fahrenheit": 64}, "conditions": "Partly cloudy"},
"Tokyo": {"temperature": {"celsius": 25, "fahrenheit": 77}, "conditions": "Sunny"},
"New York": {"temperature": {"celsius": 22, "fahrenheit": 72}, "conditions": "Light rain"},
"Mumbai": {"temperature": {"celsius": 30, "fahrenheit": 86}, "conditions": "Humid and hot"},
"Berlin": {"temperature": {"celsius": 15, "fahrenheit": 59}, "conditions": "Overcast"}, # Added another city!
}
if location in weather_data:
temp_value = weather_data[location]["temperature"].get(unit, None)
if temp_value is not None:
return {
"location": location,
"temperature": temp_value,
"unit": unit,
"conditions": weather_data[location]["conditions"]
}
else:
# Handle cases where Gemini requests a unit we don't support (though our schema prevents this)
return {"error": "Invalid unit specified for location."}
else:
# If the requested location isn't in our mock data, we return an error.
# In a real app, this would mean the weather API didn't have data, or the city was misspelled.
return {"error": f"Weather data not available for {location}. Please try a major city."}
# --- End of Tool Function ---
Notice how the location and unit arguments are defined in the function. These are the pieces of information Gemini will need to provide when it decides to call this tool. The docstring (the text in triple quotes) is also important; while it helps us understand the function, similar descriptions will be crucial when we define the tool for Gemini!
Step 2: Configure Gemini and Register the Tool
Now, the magical part! We need to officially tell Gemini about our get_current_weather tool. This isn't just about having the Python function; it's about creating a formal Tool object that describes our function's capabilities, its purpose, and what arguments it expects. This "declaration" is how Gemini's internal reasoning engine understands how and when to use your tool, based on the user's input.
# Configure your Gemini API key
# IMPORTANT: If you're running this in a Canvas environment (like where you're reading this!),
# the API key for Gemini models is usually managed by the environment itself.
# You typically won't need to set `genai.configure(api_key="YOUR_API_KEY")` explicitly.
# If you're running this locally on your own machine, you would uncomment and replace
# "YOUR_API_KEY" with your actual Gemini API key. Remember: NEVER hardcode your API key
# directly in production code or share it publicly!
# Create the tool definition that Gemini understands.
# This part is crucial for Gemini's "tool-use" capability.
weather_tool = genai.GenerativeModel.Tool(
function_declarations=[
genai.GenerativeModel.FunctionDeclaration(
name="get_current_weather", # This *must* match the Python function name
description="Gets the current weather conditions for a specified location.", # This description is key! Gemini uses this to decide if/when to call the tool. Make it clear!
parameters=genai.GenerativeModel.Schema(
type=genai.GenerativeModel.Type.OBJECT,
properties={ # Defines the arguments our Python function expects
"location": genai.GenerativeModel.Schema(
type=genai.GenerativeModel.Type.STRING,
description="The city or location (e.g., London, Tokyo)"
),
"unit": genai.GenerativeModel.Schema(
type=genai.GenerativeModel.Type.STRING,
description="The unit for temperature. Can be 'celsius' or 'fahrenheit'.",
enum=["celsius", "fahrenheit"] # This tells Gemini it can only pick from these two!
)
},
required=["location"] # 'location' is a must-have argument for our function
)
)
]
)
# Initialize the Gemini model with our new tool!
# We're telling the model, "Hey, here's a tool you know how to use!"
model = genai.GenerativeModel(model_name="gemini-pro", tools=[weather_tool])
# A quick note on models: "gemini-pro" is generally a great all-around model for
# conversational tasks and function calling. Sometimes, "gemini-2.0-flash" is also
# excellent and might be the default if you're using a specific environment like Canvas.
# Both are perfectly capable of handling tool use.This FunctionDeclaration is like a contract. It tells Gemini exactly how to interact with your get_current_weather function: what it's for, what inputs it needs, and what types those inputs should be. This structured information is what allows Gemini to intelligently reason about when to invoke your tool.
Step 3: Make the Request and Process the Tool Call
This is the core loop of our agent! You send a message (your user_query) to Gemini. Then, we check Gemini's response. Here's the magic: If Gemini's super-smart brain decides that your request can be best answered by using one of its registered tools, it won't give you a text response directly. Instead, it will tell you which tool it wants to use and what arguments to use with that tool. Your job, as the developer, is then to take that information, run your actual Python function (get_current_weather in our case), and send the result of that function back to Gemini. Only then can Gemini take that factual result and generate the final, human-friendly response for you.
# Start a chat session with the model
chat = model.start_chat(enable_automatic_function_calling=False)
# We set `enable_automatic_function_calling=False` here on purpose!
# If we set it to `True`, Gemini would try to call the tool directly (which is awesome for production!).
# But for learning, we want to manually see the tool call request and then pass its result back to Gemini.
# This gives you a clear understanding of the "handshake" process.
def get_weather_report(user_query: str):
"""
Sends a query to the AI agent and processes potential tool calls to get weather.
This function demonstrates the full lifecycle of a user query leading to a tool call.
"""
print(f"\n--- User: {user_query} ---")
# Send the user's query to Gemini
response = chat.send_message(user_query)
# Check if Gemini wants to call a tool. `response.candidates` holds potential responses.
# If Gemini wants a tool, `function_calls` will be present.
if response.candidates and response.candidates[0].function_calls:
print("DEBUG: Gemini wants to call a tool!")
# Grab the details of the tool Gemini wants to call
function_call = response.candidates[0].function_calls[0]
tool_name = function_call.name # The name of the function (e.g., "get_current_weather")
tool_args = function_call.args # The arguments Gemini decided to pass (e.g., {'location': 'Tokyo'})
print(f"DEBUG: Tool requested: {tool_name} with args: {tool_args}")
# Now, we manually execute the tool based on Gemini's request!
if tool_name == "get_current_weather":
# Call our actual Python function with the arguments Gemini provided
tool_result = get_current_weather(**tool_args) # The `**` unpacks the dictionary into keyword arguments
print(f"DEBUG: Tool result: {json.dumps(tool_result, indent=2)}")
# CRITICAL STEP: Send the tool's result *back* to Gemini.
# Without this, Gemini doesn't know what happened after it requested the tool.
# This is how Gemini gets the actual weather data to formulate its final response.
final_response = chat.send_message(
genai.protos.Part(
function_response=genai.protos.FunctionResponse(
name="get_current_weather", # Must match the tool name Gemini requested
response=tool_result # Pass the dictionary result from our function
)
)
)
print(f"--- Agent: {final_response.text}")
else:
# If Gemini somehow requests a tool we haven't defined or aren't handling
print(f"ERROR: Unknown tool requested: {tool_name}")
print(f"--- Agent: I'm sorry, I don't know how to use that specific tool yet. Can I help with something else?")
else:
# If no tool is called (e.g., the user asked a general question like "What's 5 + 3?"),
# Gemini will respond directly with text.
print(f"--- Agent: {response.text}")
# --- Let's try out our Weather Reporter Agent! ---
# Try asking for weather in a city we have data for, various ways
get_weather_report("What's the weather like in Tokyo?")
get_weather_report("Tell me the temperature in London in Fahrenheit.")
get_weather_report("How's the weather in Mumbai?")
get_weather_report("What's the weather in New York right now?")
get_weather_report("Can you tell me the weather in Berlin?")
get_weather_report("London weather in Celsius, please.")
# Try asking a general question that shouldn't trigger the tool
get_weather_report("What's the capital of France?")
get_weather_report("Tell me a fun fact about giraffes.")
# Try asking for weather in a city we don't have mock data for
get_weather_report("Is it raining in Paris?")
get_weather_report("What's the forecast for Sydney?")
get_weather_report("Can you get me the weather for some small town called Aardvarkville?")Putting It All Together: The Full Code!
Here's the complete Python script you can run. Copy and paste this into a file named weather_agent.py (or whatever you like!) and run it using python weather_agent.py in your terminal. You'll see the "DEBUG" messages in your terminal, showing you when Gemini requests a tool and what data it gets back – this is super helpful for understanding the flow!
import google.generativeai as genai
import json
# --- Our "Tool" Function ---
# In a real app, this would call a weather API.
# For this tutorial, we'll return some mock data.
def get_current_weather(location: str, unit: str = "celsius"):
"""
Gets the current weather conditions for a specified location.
Args:
location (str): The city or location (e.g., "London", "Tokyo").
unit (str, optional): The unit for temperature. Can be "celsius" or "fahrenheit".
Defaults to "celsius".
Returns:
dict: A dictionary containing weather information (temperature, conditions).
Returns None if location is not found (in a real scenario).
"""
print(f"\nDEBUG: get_current_weather called for {location} in {unit}") # Helps us see when the tool is used!
# Simulate fetching data for a few specific locations
weather_data = {
"London": {"temperature": {"celsius": 18, "fahrenheit": 64}, "conditions": "Partly cloudy"},
"Tokyo": {"temperature": {"celsius": 25, "fahrenheit": 77}, "conditions": "Sunny"},
"New York": {"temperature": {"celsius": 22, "fahrenheit": 72}, "conditions": "Light rain"},
"Mumbai": {"temperature": {"celsius": 30, "fahrenheit": 86}, "conditions": "Humid and hot"},
"Berlin": {"temperature": {"celsius": 15, "fahrenheit": 59}, "conditions": "Overcast"},
}
if location in weather_data:
temp_value = weather_data[location]["temperature"].get(unit, None)
if temp_value is not None:
return {
"location": location,
"temperature": temp_value,
"unit": unit,
"conditions": weather_data[location]["conditions"]
}
else:
return {"error": "Invalid unit specified for location."}
else:
return {"error": f"Weather data not available for {location}. Please try a major city."}
# --- Configuration and Tool Registration ---
# Configure your Gemini API key. In the Canvas environment, this is often handled automatically.
# For local development, you might need: genai.configure(api_key="YOUR_API_KEY")
# IMPORTANT: DO NOT hardcode your API key in production code!
# The default model for Gemini API in Canvas is gemini-2.0-flash, which works well for function calling.
# If you encounter issues, try explicitly setting the API key or model name.
# Create the tool definition that Gemini understands
weather_tool = genai.GenerativeModel.Tool(
function_declarations=[
genai.GenerativeModel.FunctionDeclaration(
name="get_current_weather",
description="Gets the current weather conditions for a specified location.",
parameters=genai.GenerativeModel.Schema(
type=genai.GenerativeModel.Type.OBJECT,
properties={
"location": genai.GenerativeModel.Schema(
type=genai.GenerativeModel.Type.STRING,
description="The city or location (e.g., London, Tokyo)"
),
"unit": genai.GenerativeModel.Schema(
type=genai.GenerativeModel.Type.STRING,
description="The unit for temperature. Can be 'celsius' or 'fahrenheit'.",
enum=["celsius", "fahrenheit"]
)
},
required=["location"] # 'unit' is optional
)
)
]
)
# Initialize the Gemini model with our new tool
# Using 'gemini-pro' model for general purpose, but 'gemini-2.0-flash' also works great for tools.
model = genai.GenerativeModel(model_name="gemini-pro", tools=[weather_tool])
# --- Chat Interaction Loop ---
# Start a chat session with the model.
# enable_automatic_function_calling=False means we handle the tool execution manually,
# which is great for understanding how it works!
chat = model.start_chat(enable_automatic_function_calling=False)
def get_weather_report(user_query: str):
"""
Sends a query to the AI agent and processes potential tool calls to get weather.
"""
print(f"\n--- User: {user_query} ---")
response = chat.send_message(user_query)
# Check if Gemini wants to call a tool
if response.candidates and response.candidates[0].function_calls:
print("DEBUG: Gemini wants to call a tool!")
function_call = response.candidates[0].function_calls[0]
tool_name = function_call.name
tool_args = function_call.args
print(f"DEBUG: Tool requested: {tool_name} with args: {tool_args}")
# Manually execute the tool based on Gemini's request
if tool_name == "get_current_weather":
# Call our Python function with the arguments Gemini provided
tool_result = get_current_weather(**tool_args)
print(f"DEBUG: Tool result: {json.dumps(tool_result, indent=2)}")
# Send the tool's result back to Gemini.
# This is critical! Gemini needs to know what the tool *returned*
# so it can generate the final human-readable response.
final_response = chat.send_message(
genai.protos.Part(
function_response=genai.protos.FunctionResponse(
name="get_current_weather",
response=tool_result # Pass the dictionary result
)
)
)
print(f"--- Agent: {final_response.text}")
else:
# Handle cases where Gemini requests an unknown tool
print(f"ERROR: Unknown tool requested: {tool_name}")
print(f"--- Agent: I'm sorry, I don't know how to use that tool.")
else:
# If no tool is called (e.g., a general question), Gemini responds directly
print(f"--- Agent: {response.text}")
# --- Let's try out our Weather Reporter Agent! ---
# Try asking for weather in a city we have data for
get_weather_report("What's the weather like in Tokyo?")
get_weather_report("Tell me the temperature in London in Fahrenheit.")
get_weather_report("How's the weather in Mumbai?")
get_weather_report("What's the weather in New York?")
get_weather_report("Can you tell me the weather in Berlin?")
get_weather_report("London weather in Celsius, please.")
# Try asking a general question that shouldn't trigger the tool
get_weather_report("What's the capital of France?")
get_weather_report("Tell me a fun fact about giraffes.")
# Try asking for weather in a city we don't have mock data for
get_weather_report("Is it raining in Paris?")
get_weather_report("What's the forecast for Sydney?")
get_weather_report("Can you get me the weather for some small town called Aardvarkville?")
