DEV Community

Cover image for I Let an AI Plan My Vacation (Here's What It Built)
Anannya Roy Chowdhury
Anannya Roy Chowdhury

Posted on

I Let an AI Plan My Vacation (Here's What It Built)

I Had 47 Browser Tabs Open. So I Built an AI Travel Agent with Strands SDK + Amazon Bedrock ✈️

Okay, so real talk.

I had 47 browser tabs open.

47.....

Flights on a Flights App. Hotels on a Booking website. Weather on some sketchy website that was 40% ads. A spreadsheet I made at 11 PM that somehow had three separate columns all labeled "maybe hotel??" and one row that just said:

"check vibes"

All I wanted was to plan a week-long trip to Thailand.

And then — because I am a developer, and developers solve problems with code even when they absolutely should not — I closed all 47 tabs, opened Kiro's spec-driven mode, and said:

"Fine. I'll build the travel agent myself with Strands SDK."

Two hours later, I typed one sentence into my chat window and got back:

  • Flights
  • Hotels
  • Weather warnings
  • A complete 7-day itinerary
  • Budget breakdowns
  • Packing recommendations
  • VISA options

And honestly?

I haven’t touched that spreadsheet since.

So let’s build the thing. 👇


Wait… What Even Is Strands SDK?

Before we dive in:

Strands SDK is AWS’s open-source Python framework for building AI agents.

Think of it like this:

  • You write Python functions (tools)
  • Add a @tool decorator
  • Connect it to a model on Amazon Bedrock
  • The model decides:

    • which tools to call
    • in what order
    • with what inputs

That’s… basically it.

No YAML facades.
No 400-page orchestration configs.
No dependency graphs that look like a subway map.

Just Python functions and an LLM smart enough to use them.

Here’s the mental model that helped me:

Your Agent = A Smart Intern
Your Tools = What the Intern Can Do
Your Prompt = The Instructions
Bedrock = The Intern's Brain
Enter fullscreen mode Exit fullscreen mode

Except this intern:

  • never misses deadlines

10/10 would hire again.


What We’re Building

Our AI travel planner should:

  • ✈️ Find flights
  • 🏨 Find hotels
  • 🌦️ Check weather
  • 📋 Check Budgets and Build a full itinerary

One agent.
Four tools.
One prompt.

Done.


Architecture Overview

Stack Used

Yes, this is production-friendly.

We’ll get there.


Step 0 — Setup

Install dependencies:

pip install strands-agents strands-agents-tools boto3
Enter fullscreen mode Exit fullscreen mode

Enable Claude 3.5 Sonnet inside Amazon Bedrock.

Takes ~2 minutes.


🚨 Please Don’t Hardcode API Keys

I know.

You’re “just testing.”

That API key will end up in a public GitHub repo eventually.

And then you will land up with a bill that burns your wallet.

Use AWS Secrets Manager instead.

import boto3
import json

def get_secret(secret_name: str) -> str:
    """Fetch API keys securely from AWS Secrets Manager."""

    client = boto3.client(
        "secretsmanager",
        region_name="us-east-1"
    )

    response = client.get_secret_value(
        SecretId=secret_name
    )

    return json.loads(
        response["SecretString"]
    )["api_key"]
Enter fullscreen mode Exit fullscreen mode

One function call.
Sleep peacefully.


Tool #1 — Search Flights ✈️

One thing that blew my mind about Strands:

Your docstring is part of the prompt.

Not for developers. For the model.

The LLM reads your tool descriptions to decide:

  • when to call them
  • how to call them
  • what arguments to pass

Good docstrings = smart agents.
Bad docstrings = chaos.

from strands import tool

@tool
def search_flights(
    origin: str,
    destination: str,
    departure_date: str,
    return_date: str,
    num_passengers: int
) -> dict:
    """
    Search for available flights between cities.

    Returns:
    - airline
    - price
    - duration
    - stops
    """

    api_key = get_secret(
        "travel-agent/flight-api-key"
    )

    return {
        "flights": [
            {
                "airline": "Thai Airways",
                "price_per_person": 510,
                "stops": 0,
                "vibe": "Direct. Fancy. Worth it."
            },
            {
                "airline": "Indigo",
                "price_per_person": 440,
                "stops": 1,
                "vibe": "One stop. Still emotionally stable."
            }
        ]
    }
Enter fullscreen mode Exit fullscreen mode

Yes, I added a "vibe" field.

No, the model doesn’t need it.

Yes, it made me happy and my decision making, faster....


Tool #2 — Hotels That Aren’t Secretly Hostels 🏨

You know what I hate?

The hotel listing that says:

"$89/night!"

And then somehow becomes:

  • $89 base price
  • taxes
  • resort fee
  • “service charge”
  • “convenience fee”
  • emotional damage

My tool doesn’t do that.

@tool
def search_hotels(
    destination: str,
    check_in: str,
    check_out: str,
    budget_per_night: float
) -> dict:
    """
    Search hotels within budget.
    """

    return {
        "hotels": [
            {
                "name": "Veranda Resort",
                "price_per_night": $155,
                "rating": 4.8
            },
            {
                "name": "Pacific Club Hotel",
                "price_per_night": $120,
                "rating": 4.5
            }
        ],
        "note": "No hidden fees. Unlike some websites."
    }
Enter fullscreen mode Exit fullscreen mode

Tool #3 — Weather Check 🌧️

Because packing goggles for Northern lights was a character-building experience I never want again.

@tool
def get_weather(
    destination: str,
    travel_month: str
) -> dict:
    """
    Get weather info and packing advice.
    """

    return {
        "avg_temp_celsius": 26,
        "conditions": "Mild with dry heat",
        "packing_must_haves": [
            "Light coloured t-shirts",
            "beach flip flops",
            "Umbrella",
            "sunscreen",
        ]
    }
Enter fullscreen mode Exit fullscreen mode

Tiny tool. Massive usefulness.


Tool #4 — Build the Itinerary 📋

This is where everything comes together.

Flights ✅
Hotels ✅
Weather ✅

Now the agent can finally build a realistic itinerary.

And yes — we save it to S3.

Because my Notes app cannot be trusted.

from datetime import datetime

@tool
def build_itinerary(
    destination: str,
    duration_days: int,
    interests: list,
    budget_remaining: float
) -> dict:
    """
    Build a day-by-day itinerary.
    """

    itinerary = {
        "destination": destination,
        "days": duration_days,
        "interests": interests,
        "daily_plan": [
            {
                "day": 1,
                "theme": "Land and Eat Immediately"
            },
            {
                "day": 2,
                "theme": "Markets and Sunset Beach Walks"
            }
        ]
    }

    s3 = boto3.client("s3")

    s3.put_object(
        Bucket="travel-itineraries",
        Key="thai-trip.json",
        Body=json.dumps(itinerary)
    )

    return itinerary
Enter fullscreen mode Exit fullscreen mode

Assemble the Agent

Now the fun part.

from strands import Agent
from strands.models import BedrockModel

model = BedrockModel(
    model_id="anthropic.claude-3-5-sonnet",
    region_name="us-east-1",
    temperature=0.3
)

SYSTEM_PROMPT = """
You are a smart AI travel planner.

Always:
1. Search flights first
2. Search hotels second
3. Check weather
4. Build itinerary for given budget last
"""

travel_agent = Agent(
    model=model,
    system_prompt=SYSTEM_PROMPT,
    tools=[
        search_flights,
        search_hotels,
        get_weather,
        build_itinerary
    ]
)

response = travel_agent(
    """
    Plan a 5-day Thailand trip for 2 people under $3000.
    """
)

print(response)
Enter fullscreen mode Exit fullscreen mode

Terminal Output

[Tool Call] search_flights
✓ Thai Airways selected

[Tool Call] search_hotels
✓ Veranda Resort selected

[Tool Call] get_weather
✓ Mild weather detected

[Tool Call] build_itinerary
✓ Saved to S3

━━━━━━━━━━━━━━━━━━
YOUR THAILAND TRIP
━━━━━━━━━━━━━━━━━━

Flights:   $1020
Hotel:     $775
Activities: $1200

TOTAL:     $2995 ✅
Enter fullscreen mode Exit fullscreen mode

That ✅ Under budget hit different.


Production Lessons (Learned the Hard Way)

Here’s the honest truth:

Your local demo is not your production system.

Things that will hurt you eventually:

Problem Fix
Hardcoded keys Secrets Manager
Infinite tool loops Max tool-call limits
No observability CloudWatch logging
Surprise Bedrock bill max_tokens + alarms
Zero error handling try/except everywhere
Unsafe prompts Bedrock Guardrails

Add Logging with CloudWatch

import logging
from strands.handlers import CallbackHandler

logger = logging.getLogger("travel-agent")

class LoggingHandler(CallbackHandler):

    def on_tool_call(
        self,
        tool_name,
        tool_input
    ):
        logger.info(
            f"Calling {tool_name}"
        )

    def on_error(self, error):
        logger.error(str(error))
Enter fullscreen mode Exit fullscreen mode

This is the difference between:

  • “cool demo”
  • and “actual software”

My Biggest Takeaways

1. Your Docstrings Matter More Than You Think

The model uses them as instructions.

Treat them seriously.

2. Tool Order Matters

Without ordering rules, my agent built itineraries before knowing hotel costs.

Beautiful plans. Completely wrong budget.

3. Lower Temperature = Better Planning

High temperature is great for creativity.

Not for budgeting.

4. Persist Everything

S3. DynamoDB. Databases.

Conversation memory disappears eventually.

Your data shouldn’t.

5. The Demo → Production Gap Is Real

Prototypes and demos are magical.

Production systems are where reality shows up with a baseball bat.

Build responsibly.


FAQ

Do I Need a Strands Certification?

Nope.

Just:

  • Python
  • Bedrock access
  • Functions

That’s enough to start.


Can I Use Other Models?

Absolutely.

Swap Claude for:

  • Llama
  • Mistral
  • Titan
  • Anything available on Bedrock

My Agent Calls Tools in Weird Orders

Fix your system prompt.

Be explicit.

LLMs love explicit instructions.


What’s Next?

You can extend this into:

That’s where things get really interesting.


I started this journey with:

  • 47 browser tabs
  • one broken spreadsheet
  • and travel-planning rage

I ended it with:

  • a functioning AI travel agent
  • a Thailand itinerary
  • and a permanently closed spreadsheet

Honestly?

Worth it.


If you enjoyed this post:

  • ❤️ Drop a reaction
  • 🔁 Share it with another developer
  • 👀 Follow for more AI agent tutorials

And if you build something cool with Strands SDK — I genuinely want to see it. Hit the comments box or reach out over LinkedIn. I work for AWS and love building and exchanging views on AI!

Happy building. ✈️

Top comments (0)