Let's build a weather agent step by step.
An agent that can:
- Check weather for any city
- Give clothing recommendations
- Handle errors gracefully
Takes 15 minutes.
Start simple. A tool that returns fake weather:
from miiflow_agent.core.tools import tool
@tool("get_weather", "Get current weather for a city")
def get_weather(city: str) -> str:
return f"Weather in {city}: sunny, 22°C"That's it. The @tool decorator makes your function available to agents.
What happens:
- Function name becomes tool name
- Docstring becomes tool description
- Type hints define parameters
- Return type shows what comes back
Now hook it up:
from miiflow_agent import LLMClient, Agent
from miiflow_agent.core import AgentType
import asyncio
client = LLMClient.create("openai", model="gpt-4o-mini")
agent = Agent(client=client, agent_type=AgentType.REACT)
agent.add_tool(get_weather)
result = asyncio.run(agent.run("What's the weather in Paris?", deps={}))
print(result.data)Run it. The agent will:
- See your question
- Decide to call
get_weather - Pass
city="Paris" - Get "sunny, 22°C"
- Answer you
Replace fake data with real API:
import httpx
@tool("get_weather", "Get current weather for a city")
def get_weather(city: str) -> str:
response = httpx.get(
"https://api.openweathermap.org/data/2.5/weather",
params={"q": city, "appid": "YOUR_KEY", "units": "metric"}
)
if response.status_code == 404:
return f"City '{city}' not found"
response.raise_for_status()
data = response.json()
temp = data["main"]["temp"]
description = data["weather"][0]["description"]
return f"{city}: {temp}°C, {description}"Same interface. Agent doesn't know you changed anything.
Clothing recommendations based on temperature:
@tool("recommend_clothing", "Suggest what to wear based on temperature")
def recommend_clothing(temperature: float) -> str:
if temperature < 10:
return "Wear a heavy coat, it's cold"
elif temperature < 20:
return "Light jacket recommended"
else:
return "T-shirt weather, no jacket needed"Add both tools:
agent.add_tool(get_weather)
agent.add_tool(recommend_clothing)
result = asyncio.run(agent.run(
"What should I wear in Paris today?",
deps={}
))The agent will:
- Call
get_weather("Paris")→ "22°C, sunny" - Extract temperature: 22
- Call
recommend_clothing(22)→ "T-shirt weather" - Combine info: "In Paris it's 22°C and sunny. T-shirt weather, no jacket needed."
Add validation:
@tool("get_weather", "Get current weather for a city")
def get_weather(city: str) -> str:
if not city or len(city) < 2:
raise ValueError("City name must be at least 2 characters")
try:
response = httpx.get(
"https://api.openweathermap.org/data/2.5/weather",
params={"q": city, "appid": "YOUR_KEY", "units": "metric"},
timeout=5.0
)
if response.status_code == 404:
raise ValueError(f"City '{city}' not found")
response.raise_for_status()
data = response.json()
return f"{city}: {data['main']['temp']}°C, {data['weather'][0]['description']}"
except httpx.TimeoutError:
raise ValueError("Weather service timeout, try again")
except httpx.HTTPError as e:
raise ValueError(f"Weather service error: {e}")When errors happen, the agent sees them and can respond appropriately.
Pass database connections or config:
@tool("save_weather", "Save weather to database")
def save_weather(city: str, weather: str, deps: dict) -> str:
db = deps["database"]
db.execute(
"INSERT INTO weather (city, data) VALUES (?, ?)",
(city, weather)
)
return f"Saved weather for {city}"
# Provide deps when running
result = asyncio.run(agent.run(
"Check and save weather for London",
deps={"database": my_db_connection}
))import httpx
import asyncio
from miiflow_agent import LLMClient, Agent
from miiflow_agent.core import AgentType
from miiflow_agent.core.tools import tool
@tool("get_weather", "Get current weather for a city")
def get_weather(city: str) -> str:
response = httpx.get(
"https://api.openweathermap.org/data/2.5/weather",
params={"q": city, "appid": "YOUR_KEY", "units": "metric"}
)
response.raise_for_status()
data = response.json()
return f"{city}: {data['main']['temp']}°C, {data['weather'][0]['description']}"
@tool("recommend_clothing", "Suggest clothing for temperature")
def recommend_clothing(temperature: float) -> str:
if temperature < 10:
return "Heavy coat needed"
elif temperature < 20:
return "Light jacket recommended"
else:
return "T-shirt weather"
async def main():
client = LLMClient.create("openai", model="gpt-4o-mini")
agent = Agent(
client=client,
agent_type=AgentType.REACT,
system_prompt="You help with weather and clothing advice."
)
agent.add_tool(get_weather)
agent.add_tool(recommend_clothing)
result = await agent.run(
"What should I wear in Tokyo today?",
deps={}
)
print(result.data)
if __name__ == "__main__":
asyncio.run(main())- Tools are just functions - Decorate and done
- Type hints matter - They define the schema
- Raise exceptions - Don't return error strings
- One tool, one job - Keep them focused
- Test independently - Make sure they work before giving to agent
- API Reference - All tool options
- Agent Tutorial - Build complex agents
- Examples - More tool patterns