Introduction to LLM Agents · Introduction to LLM Agents · 4 min read
Your first tool
An LLM on its own can only produce text. It cannot check the weather, search the web, or query a database. A tool bridges that gap: it is a Python function that the agent can call to get real information or take a real action.
A tool is a Python function with a precise description attached. The LLM reads the description to decide when to use it.
What a tool looks like
Here is a tool that fetches current weather for a city:
import json
import requests
def get_weather(city: str) -> str:
"""Get the current temperature and weather conditions for a city.
Args:
city: The name of the city, e.g. 'London' or 'Tokyo'.
Returns:
A short description of current conditions and temperature in Celsius.
"""
# wttr.in provides weather data as JSON at no cost
url = f"https://wttr.in/{city}?format=j1"
response = requests.get(url, timeout=5)
data = response.json()
temp_c = data["current_condition"][0]["temp_C"]
desc = data["current_condition"][0]["weatherDesc"][0]["value"]
return f"{city}: {desc}, {temp_c}°C"
On its own, before being connected to any agent, it returns the current conditions for a city:
print(get_weather("Tokyo"))
# Tokyo: Partly cloudy, 22°C
Every tool should work correctly as a plain Python function before it becomes part of an agent. If it breaks in isolation, it will break inside the agent and be harder to debug there.
The docstring is part of the contract
The LLM never sees your Python code. It only sees the tool’s name and description. That description is what it uses to decide whether to call the tool, what arguments to pass, and what to expect back.
A vague description produces wrong decisions:
def get_weather(city: str) -> str:
"""Gets weather.""" # too vague: when? what format? what cities?
A precise description produces correct ones:
def get_weather(city: str) -> str:
"""Get the current temperature and weather conditions for a city.
Args:
city: The name of the city, e.g. 'London' or 'Tokyo'.
Returns:
A short description of current conditions and temperature in Celsius.
"""
Write the docstring as if you are explaining the function to a colleague who can only read the description, not the code.
Describing the tool to the LLM
The OpenAI API expects tools to be described in a specific JSON format. You define each tool as a dictionary with a name, description, and a schema for its parameters:
# This is the description the LLM reads at inference time
TOOLS = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": (
"Get the current temperature and weather conditions for a city."
),
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "The name of the city, e.g. 'London' or 'Tokyo'.",
}
},
"required": ["city"],
},
},
}
]
This dictionary and the Python function are two separate things. The dictionary tells the LLM what the tool does. The Python function is what actually runs when the LLM decides to use it.
We will add a second tool in the next lesson and then show the LLM both, so it can decide which one a given task requires.