Build a Holiday Cocktail Agent with TheCocktailDB
Create an AI bartender that suggests cocktails based on weather, searches by ingredient, and generates party menus with shopping lists.
The holidays are here, and nothing says “celebration” like a well-crafted cocktail. In this tutorial, we’ll build an AI bartender that searches real cocktail recipes, adapts suggestions to the weather, and can generate complete party menus with shopping lists.
This is a fun project that demonstrates practical agent patterns: multiple API integrations, context-aware responses, and structured output generation—all without any API keys or subscriptions.
What We’re Building
Our cocktail agent will:
- Search cocktails by name or ingredient using TheCocktailDB
- Check the weather to suggest appropriate drinks (hot toddies when cold, mojitos when warm)
- Generate party menus with batch cocktails, classics, and mocktails
- Create shopping lists with consolidated ingredients
Both APIs we’re using are completely free with no authentication required.
Project Structure
cocktail-agent/
├── agent.py # Main agent with system prompt
├── tools/
│ ├── __init__.py
│ ├── cocktails.py # TheCocktailDB API tools
│ └── weather.py # Open-Meteo weather integration
├── utils/
│ ├── __init__.py
│ └── cache.py # TTL-based response caching
└── requirements.txt
Setup
Create your project and virtual environment:
mkdir cocktail-agent && cd cocktail-agent
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
Install dependencies:
pip install strands-agents strands-agents-tools requests
Configure AWS credentials for Bedrock:
export AWS_ACCESS_KEY_ID=your_key
export AWS_SECRET_ACCESS_KEY=your_secret
export AWS_DEFAULT_REGION=us-west-2
Building the Cocktail Tools
TheCocktailDB provides a free API with thousands of cocktail recipes. Let’s build tools to search and retrieve them.
The Cache Utility
First, a simple cache to avoid hammering the API:
# utils/cache.py
from datetime import datetime, timedelta
from typing import Any, Optional
_cache: dict[str, tuple[Any, datetime]] = {}
TTL = {
"cocktail": timedelta(hours=24), # Recipes don't change
"search": timedelta(hours=1),
"weather": timedelta(minutes=30),
"random": timedelta(minutes=5),
}
def get(key: str) -> Optional[Any]:
"""Get cached value if not expired."""
if key in _cache:
value, expires = _cache[key]
if datetime.now() < expires:
return value
del _cache[key]
return None
def set(key: str, value: Any, cache_type: str = "cocktail") -> None:
"""Cache a value with TTL based on type."""
ttl = TTL.get(cache_type, timedelta(hours=1))
_cache[key] = (value, datetime.now() + ttl)
Cocktail Search Tools
The main cocktail tools wrap TheCocktailDB’s API:
# tools/cocktails.py
import requests
from strands import tool
from utils import cache
BASE_URL = "https://www.thecocktaildb.com/api/json/v1/1"
def _parse_cocktail(drink: dict) -> dict:
"""Parse API response into clean format."""
ingredients = []
for i in range(1, 16):
ingredient = drink.get(f"strIngredient{i}")
measure = drink.get(f"strMeasure{i}")
if ingredient and ingredient.strip():
ingredients.append({
"ingredient": ingredient.strip(),
"measure": measure.strip() if measure else ""
})
return {
"id": drink.get("idDrink"),
"name": drink.get("strDrink"),
"category": drink.get("strCategory"),
"glass": drink.get("strGlass"),
"instructions": drink.get("strInstructions"),
"ingredients": ingredients,
"alcoholic": drink.get("strAlcoholic"),
}
@tool
def search_cocktails(query: str, search_type: str = "name") -> dict:
"""
Search for cocktails by name or ingredient.
Args:
query: The search term (cocktail name or ingredient)
search_type: Either "name" or "ingredient"
Returns:
Dictionary with list of matching cocktails
"""
cache_key = f"search:{search_type}:{query.lower()}"
cached = cache.get(cache_key)
if cached:
return cached
if search_type == "ingredient":
url = f"{BASE_URL}/filter.php?i={query}"
else:
url = f"{BASE_URL}/search.php?s={query}"
response = requests.get(url, timeout=10)
response.raise_for_status()
data = response.json()
drinks = data.get("drinks") or []
if search_type == "ingredient":
results = [{"id": d["idDrink"], "name": d["strDrink"]} for d in drinks]
else:
results = [_parse_cocktail(d) for d in drinks]
result = {
"query": query,
"search_type": search_type,
"count": len(results),
"cocktails": results
}
cache.set(cache_key, result, "search")
return result
Add tools for getting full details and random suggestions:
@tool
def get_cocktail_by_id(cocktail_id: str) -> dict:
"""
Get full details for a specific cocktail by its ID.
Args:
cocktail_id: The cocktail's unique ID
Returns:
Full cocktail details including ingredients and instructions
"""
cache_key = f"cocktail:{cocktail_id}"
cached = cache.get(cache_key)
if cached:
return cached
url = f"{BASE_URL}/lookup.php?i={cocktail_id}"
response = requests.get(url, timeout=10)
response.raise_for_status()
data = response.json()
drinks = data.get("drinks")
if not drinks:
return {"error": f"Cocktail {cocktail_id} not found"}
result = _parse_cocktail(drinks[0])
cache.set(cache_key, result, "cocktail")
return result
@tool
def get_random_cocktail() -> dict:
"""Get a random cocktail for inspiration."""
url = f"{BASE_URL}/random.php"
response = requests.get(url, timeout=10)
response.raise_for_status()
data = response.json()
drinks = data.get("drinks")
if not drinks:
return {"error": "No random cocktail returned"}
return _parse_cocktail(drinks[0])
Adding Weather Awareness
Cold weather calls for warm drinks. Hot weather calls for refreshing ones. Let’s add weather context using Open-Meteo:
# tools/weather.py
import requests
from strands import tool
from utils import cache
GEOCODE_URL = "https://geocoding-api.open-meteo.com/v1/search"
WEATHER_URL = "https://api.open-meteo.com/v1/forecast"
@tool
def get_weather(location: str) -> dict:
"""
Get current weather to inform cocktail suggestions.
Args:
location: City name (e.g., "Miami", "New York")
Returns:
Weather data with temperature and drink suggestions
"""
cache_key = f"weather:{location.lower()}"
cached = cache.get(cache_key)
if cached:
return cached
# Geocode the location
geo_response = requests.get(
GEOCODE_URL,
params={"name": location, "count": 1},
timeout=10
)
geo_data = geo_response.json()
if not geo_data.get("results"):
return {"error": f"Location '{location}' not found"}
loc = geo_data["results"][0]
lat, lon = loc["latitude"], loc["longitude"]
# Get weather
weather_response = requests.get(
WEATHER_URL,
params={
"latitude": lat,
"longitude": lon,
"current": ["temperature_2m", "weather_code"],
"temperature_unit": "fahrenheit",
},
timeout=10
)
weather_data = weather_response.json()
current = weather_data.get("current", {})
temp = current.get("temperature_2m", 70)
# Suggest drink styles based on temperature
suggestions = _get_weather_suggestions(temp)
result = {
"location": f"{loc['name']}, {loc.get('admin1', '')}",
"temperature_f": temp,
"drink_suggestions": suggestions,
}
cache.set(cache_key, result, "weather")
return result
def _get_weather_suggestions(temp: float) -> dict:
"""Suggest drink types based on temperature."""
if temp < 40:
return {
"category": "warm",
"reason": "It's cold! Warm up with something cozy.",
"styles": ["Hot Toddy", "Irish Coffee", "Mulled Wine"]
}
elif temp < 60:
return {
"category": "cozy",
"reason": "Cool weather calls for warming spirits.",
"styles": ["Old Fashioned", "Manhattan", "Whiskey Sour"]
}
elif temp < 80:
return {
"category": "balanced",
"reason": "Perfect weather for classics.",
"styles": ["Martini", "Negroni", "Margarita"]
}
else:
return {
"category": "refreshing",
"reason": "Beat the heat with something cold!",
"styles": ["Mojito", "Pina Colada", "Frozen Margarita"]
}
The Agent
Now we wire everything together with a system prompt that knows how to be a great bartender:
# agent.py
from strands import Agent
from strands.models import BedrockModel
from tools.cocktails import search_cocktails, get_cocktail_by_id, get_random_cocktail
from tools.weather import get_weather
SYSTEM_PROMPT = """You are an expert bartender and party planner.
WORKFLOW:
1. If the user mentions a location, get the weather first
2. Use search_cocktails to find drinks by name or ingredient
3. Use get_cocktail_by_id for full recipes
4. Use get_random_cocktail for inspiration
PARTY MENU CREATION:
When asked to create a party menu, include:
- 1 BATCH COCKTAIL (make ahead, serves many)
- 1 SIGNATURE COCKTAIL (the showstopper)
- 1 CLASSIC (crowd-pleaser)
- 1 LIGHT/REFRESHING option
- 1 MOCKTAIL (for non-drinkers)
End with a consolidated SHOPPING LIST.
HOLIDAY FAVORITES:
- Christmas: Eggnog, Mulled Wine, Peppermint Martini
- New Year's: French 75, Champagne Cocktail, Bellini
- Winter: Hot Toddy, Irish Coffee, Bourbon Apple Cider
Be specific with measurements. Consider weather when suggesting drinks.
"""
def create_cocktail_agent():
return Agent(
model=BedrockModel(model_id="global.anthropic.claude-opus-4-5-20251101-v1:0"),
system_prompt=SYSTEM_PROMPT,
tools=[search_cocktails, get_cocktail_by_id,
get_random_cocktail, get_weather]
)
if __name__ == "__main__":
agent = create_cocktail_agent()
print("🍸 Holiday Cocktail Agent")
print("Type 'quit' to exit\n")
while True:
question = input("You: ").strip()
if question.lower() in ['quit', 'exit', 'q']:
break
response = agent(question)
print(f"\nBartender: {response}\n")
Running the Agent
python agent.py
🍸 Holiday Cocktail Agent Type ‘quit’ to exit
You: What cocktails can I make with vodka and lime?
Bartender: Great combination! Here are some classics you can make:
Moscow Mule
- 2 oz Vodka
- 1 oz Fresh lime juice
- 4 oz Ginger beer
- Lime wedge for garnish Serve in a copper mug over ice.
Vodka Gimlet
- 2 oz Vodka
- 3/4 oz Fresh lime juice
- 3/4 oz Simple syrup Shake with ice, strain into a chilled coupe.
Cosmopolitan
- 1.5 oz Vodka
- 1 oz Triple sec
- 1/2 oz Fresh lime juice
- 1 oz Cranberry juice Shake with ice, strain into a martini glass.
Try asking for a party menu:
You: Create a holiday party menu for 12 guests
Bartender: 🎄 HOLIDAY PARTY MENU 12 guests | Festive & Fun
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🍸 BATCH COCKTAIL Cranberry Moscow Mule Punch Make this ahead—guests serve themselves!
- 16 oz Vodka
- 8 oz Fresh lime juice
- 16 oz Cranberry juice
- 32 oz Ginger beer (add just before serving)
- Fresh cranberries and lime wheels
Mix vodka, lime, and cranberry in a punch bowl. Add ginger beer and ice when guests arrive.
🌟 SIGNATURE Peppermint Espresso Martini
- 2 oz Vodka
- 1 oz Kahlua
- 1 oz Fresh espresso
- 1/2 oz Peppermint schnapps
🥃 CLASSIC Old Fashioned
- 2 oz Bourbon
- 1 sugar cube
- 2-3 dashes Angostura bitters
🍋 LIGHT & REFRESHING French 75
- 1.5 oz Gin
- 3/4 oz Lemon juice
- 1/2 oz Simple syrup
- Champagne to top
🌿 MOCKTAIL Sparkling Cranberry Rosemary
- 4 oz Cranberry juice
- Sparkling water
- Fresh rosemary sprig
- Sugared rim
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🛒 SHOPPING LIST Spirits:
- Vodka (750ml)
- Bourbon (375ml)
- Gin (375ml)
- Kahlua (375ml)
Mixers:
- Ginger beer (4 bottles)
- Cranberry juice (48oz)
- Champagne (2 bottles)
- Sparkling water
Fresh:
- Limes (12)
- Lemons (6)
- Fresh cranberries
- Rosemary
Other:
- Peppermint schnapps
- Angostura bitters
- Sugar cubes
- Simple syrup
Weather-Aware Suggestions
The agent automatically adapts to local conditions:
You: What should I drink in Chicago tonight?
Bartender: Let me check the weather in Chicago…
It’s 28°F in Chicago—definitely Hot Toddy weather! 🥶
Here are my suggestions for a cold winter night:
Hot Toddy (my top pick)
- 2 oz Bourbon or Whiskey
- 1 tbsp Honey
- 1/2 oz Fresh lemon juice
- Hot water
- Cinnamon stick, lemon wheel
Irish Coffee
- 1.5 oz Irish Whiskey
- Hot coffee
- 1 tbsp Brown sugar
- Fresh whipped cream
Mulled Wine Perfect for a group—warm red wine with cinnamon, cloves, orange peel, and a touch of brandy.
Stay warm out there! 🔥
What’s Next
You now have a working cocktail agent that can:
- Search thousands of real recipes
- Adapt to weather conditions
- Generate party menus with shopping lists
Some ideas to extend it:
- Add a “what’s in my bar” inventory feature
- Include food pairing suggestions
- Add mocktail-only mode for dry parties
More agent tutorials:
- Fishing Report Agent — NOAA tides, weather, and marine conditions
- Christmas Tree Ornament Generator — AI image generation with Nova Canvas
Happy holidays, and drink responsibly! 🥂
Comments
to join the discussion.