Build a Holiday Cocktail Agent with TheCocktailDB

Open Seas 25 min read December 22, 2025 |
0

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:

  1. Search cocktails by name or ingredient using TheCocktailDB
  2. Check the weather to suggest appropriate drinks (hot toddies when cold, mojitos when warm)
  3. Generate party menus with batch cocktails, classics, and mocktails
  4. 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
Output

🍸 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:

Output

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:

Output

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:

Happy holidays, and drink responsibly! 🥂

Found this helpful?
0

Comments

Loading comments...