Build a Travel Planner Agent with AutoGPT (Flights, Hotels)
Build an AutoGPT travel planner agent that searches flights, books hotels, and generates complete itineraries automatically. Full code with Skyscanner API integration.
Get more content like this on Telegram!
Daily AI tips, notes & resources β free
Planning a trip involves dozens of small research tasks β comparing flight prices, reading hotel reviews, mapping transit options, checking visa requirements, and building a day-by-day itinerary. That's hours of browser tabs and copy-pasting that an AI agent can handle in minutes.
This guide walks through building a travel planner agent using AutoGPT that handles the full research workflow: flight search via the Skyscanner API, hotel discovery, activity planning, and generating a complete itinerary as a formatted document.
We'll also be honest about what this agent does well and where it falls short β because overselling agent capabilities leads to broken production systems.
Architecture Overview
The travel planner agent coordinates four specialized tools:
- FlightSearchTool β Queries Skyscanner API for flight options
- HotelSearchTool β Queries booking APIs for accommodation
- ItineraryBuilderTool β Structures the trip plan
- WeatherTool β Fetches weather forecasts for the destination
AutoGPT orchestrates these tools based on the user's travel requirements, iterating until it has enough information to produce a complete itinerary.
Prerequisites
pip install autogpt requests python-dotenv openai
API accounts needed:
- OpenAI API key (GPT-4o recommended)
- Skyscanner RapidAPI key (search via
skyscanner-api.p.rapidapi.com) - OpenWeatherMap API key (free tier works fine)
- Amadeus API key (optional β better for hotel data)
OPENAI_API_KEY=sk-...
RAPIDAPI_KEY=...
OPENWEATHERMAP_API_KEY=...
AMADEUS_API_KEY=...
AMADEUS_API_SECRET=...
Step 1: Goal Configuration
A well-structured goal is what separates a useful travel agent from a frustrating one:
# travel_agent_config.yaml
ai_name: "TravelPlanner"
ai_role: "Expert travel research assistant specializing in finding cost-effective, well-reviewed itineraries"
ai_goals:
- "Search for the cheapest available direct and 1-stop flights from {origin} to {destination} for {departure_date} returning {return_date}, for {num_passengers} passenger(s)"
- "Find 3 highly-rated hotels in {destination} with good location scores, filtering for {hotel_preferences}"
- "Research 5-7 must-do activities and local dining recommendations for {destination}"
- "Check weather forecast for {destination} during the travel dates"
- "Generate a complete day-by-day itinerary in itinerary.md with all details, estimated costs, and booking links"
- "Include a budget breakdown table with realistic total trip cost estimate"
For the CLI invocation:
python -m autogpt \
--continuous \
--skip-reprompt \
--max-iterations 35 \
--ai-name "TravelPlanner" \
--workspace-directory ./trip_plans/nyc_to_paris \
-g "Search flights from New York (JFK) to Paris (CDG) for 2 adults, June 15-22, 2026" \
-g "Find 3 hotels in central Paris, budget under 200 USD per night, minimum 4-star rating" \
-g "Plan a 7-day Paris itinerary with daily schedule, restaurant recommendations, and transport tips" \
-g "Calculate estimated total trip cost and save complete itinerary to itinerary.md"
Step 2: Flight Search Tool
# tools/flight_search_tool.py
import requests
import os
from datetime import datetime
class FlightSearchTool:
def __init__(self):
self.api_key = os.getenv("RAPIDAPI_KEY")
self.base_url = "https://skyscanner-api.p.rapidapi.com/v3"
self.headers = {
"X-RapidAPI-Key": self.api_key,
"X-RapidAPI-Host": "skyscanner-api.p.rapidapi.com"
}
def get_iata_code(self, city: str) -> str:
"""Convert city name to IATA airport code."""
url = f"{self.base_url}/flights/auto-complete/search"
params = {"query": city, "locale": "en-US"}
response = requests.get(url, headers=self.headers, params=params)
data = response.json()
# Extract first airport result
results = data.get("data", {}).get("places", [])
for result in results:
if result.get("type") == "Airport":
return result["iataCode"]
return city.upper()[:3] # Fallback
def search_flights(
self,
origin: str,
destination: str,
departure_date: str, # YYYY-MM-DD
return_date: str = None,
adults: int = 1,
cabin_class: str = "economy"
) -> dict:
"""Search for flights and return top options."""
origin_code = self.get_iata_code(origin)
dest_code = self.get_iata_code(destination)
url = f"{self.base_url}/flights/search-roundtrip"
payload = {
"query": {
"market": "US",
"locale": "en-US",
"currency": "USD",
"queryLegs": [
{
"originPlaceId": {"iata": origin_code},
"destinationPlaceId": {"iata": dest_code},
"date": {"year": int(departure_date[:4]),
"month": int(departure_date[5:7]),
"day": int(departure_date[8:10])}
}
],
"adults": adults,
"cabinClass": f"CABIN_CLASS_{cabin_class.upper()}",
"nearbyAirports": True
}
}
if return_date:
payload["query"]["queryLegs"].append({
"originPlaceId": {"iata": dest_code},
"destinationPlaceId": {"iata": origin_code},
"date": {"year": int(return_date[:4]),
"month": int(return_date[5:7]),
"day": int(return_date[8:10])}
})
response = requests.post(url, headers=self.headers, json=payload)
data = response.json()
# Parse and format results
itineraries = data.get("content", {}).get("results", {}).get("itineraries", {})
flights = []
for flight_id, flight_data in list(itineraries.items())[:5]: # Top 5 options
price = flight_data.get("pricingOptions", [{}])[0].get("price", {}).get("amount", "N/A")
legs = flight_data.get("legs", [])
flight_info = {
"flight_id": flight_id,
"price_usd": float(price) / 1000 if price != "N/A" else None,
"outbound": self._parse_leg(legs[0]) if legs else None,
"return": self._parse_leg(legs[1]) if len(legs) > 1 else None,
"total_duration_mins": sum(leg.get("durationInMinutes", 0) for leg in legs),
"booking_url": f"https://www.skyscanner.com/transport/flights/{origin_code}/{dest_code}/"
}
flights.append(flight_info)
return {
"search_timestamp": datetime.utcnow().isoformat(),
"origin": origin_code,
"destination": dest_code,
"flights": sorted(flights, key=lambda x: x.get("price_usd") or float('inf'))
}
def _parse_leg(self, leg: dict) -> dict:
segments = leg.get("segments", [])
return {
"departure": leg.get("departure"),
"arrival": leg.get("arrival"),
"duration_mins": leg.get("durationInMinutes"),
"stops": len(segments) - 1,
"carriers": [s.get("marketingCarrier", {}).get("name") for s in segments]
}
Step 3: Hotel Search Tool
# tools/hotel_search_tool.py
import requests
import os
from amadeus import Client, ResponseError
class HotelSearchTool:
def __init__(self):
# Using Amadeus for hotel search β better coverage than Skyscanner
self.amadeus = Client(
client_id=os.getenv("AMADEUS_API_KEY"),
client_secret=os.getenv("AMADEUS_API_SECRET")
)
def search_hotels(
self,
city_code: str, # IATA city code, e.g., "PAR" for Paris
check_in: str, # YYYY-MM-DD
check_out: str,
adults: int = 2,
max_price: int = 200,
min_rating: int = 4
) -> list[dict]:
"""Search hotels with filters and return top options."""
try:
# Get hotels in the city
hotels_response = self.amadeus.reference_data.locations.hotels.by_city.get(
cityCode=city_code
)
# Get pricing for each hotel
hotel_ids = [h["hotelId"] for h in hotels_response.data[:20]]
offers_response = self.amadeus.shopping.hotel_offers_search.get(
hotelIds=",".join(hotel_ids),
adults=str(adults),
checkInDate=check_in,
checkOutDate=check_out,
currency="USD",
bestRateOnly=True
)
results = []
for offer in offers_response.data:
hotel = offer.get("hotel", {})
price = offer.get("offers", [{}])[0].get("price", {}).get("total")
rating = hotel.get("rating")
if price and rating:
daily_rate = float(price) / self._nights(check_in, check_out)
if daily_rate <= max_price and int(rating) >= min_rating:
results.append({
"name": hotel.get("name"),
"hotel_id": hotel.get("hotelId"),
"rating": rating,
"address": hotel.get("address", {}).get("lines", []),
"latitude": hotel.get("latitude"),
"longitude": hotel.get("longitude"),
"total_price_usd": float(price),
"per_night_usd": round(daily_rate, 2),
"amenities": hotel.get("amenities", [])[:5]
})
# Sort by rating then price
results.sort(key=lambda x: (-int(x["rating"]), x["per_night_usd"]))
return results[:5]
except ResponseError as e:
return [{"error": str(e)}]
def _nights(self, check_in: str, check_out: str) -> int:
from datetime import date
ci = date.fromisoformat(check_in)
co = date.fromisoformat(check_out)
return (co - ci).days
Step 4: Itinerary Builder
This is where the agent's intelligence shows β synthesizing flight options, hotel choices, and activity research into a coherent, practical travel plan:
# tools/itinerary_builder_tool.py
from openai import OpenAI
import json
client = OpenAI()
def build_itinerary(
destination: str,
travel_dates: dict, # {check_in, check_out}
selected_flight: dict,
selected_hotel: dict,
num_days: int,
preferences: list[str] = None
) -> str:
"""Generate a detailed day-by-day itinerary."""
preferences_str = ", ".join(preferences) if preferences else "general tourism, local food, culture"
prompt = f"""Create a detailed {num_days}-day travel itinerary for {destination}.
Travel Details:
- Arrival: {travel_dates['check_in']} via {selected_flight.get('outbound', {}).get('carriers', ['Unknown'])[0]}
- Departure: {travel_dates['check_out']}
- Hotel: {selected_hotel.get('name')} ({selected_hotel.get('rating')} stars)
- Preferences: {preferences_str}
Format the itinerary as:
# {destination} Travel Itinerary
## Flight Details
[outbound and return flight info]
## Accommodation
[hotel details and check-in/check-out times]
## Day-by-Day Schedule
### Day 1 - Arrival Day
Morning: [activity]
Afternoon: [activity]
Evening: [restaurant recommendation + estimated cost]
[Continue for all {num_days} days]
## Budget Breakdown
| Category | Estimated Cost |
|---|---|
| Flights | ${selected_flight.get('price_usd', 'TBD')} |
| Hotel ({num_days-1} nights) | ${(selected_hotel.get('per_night_usd', 0) * (num_days-1)):.0f} |
| Food & Dining | $[estimate] |
| Activities & Entrance Fees | $[estimate] |
| Local Transport | $[estimate] |
| **Total Estimate** | **$[total]** |
## Practical Notes
- Visa requirements: [check for your nationality]
- Currency: [local currency and exchange tips]
- Transport: [airport to hotel and local tips]
- Emergency contacts: [embassy, local emergency number]"""
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "You are an expert travel planner with deep knowledge of international destinations."},
{"role": "user", "content": prompt}
],
temperature=0.5
)
return response.choices[0].message.content
Complete Itinerary Output Example
Here's what the agent produces for a New York to Paris trip:
# Paris Travel Itinerary β June 15-22, 2026
## Flight Details
**Outbound:** JFK β CDG | June 15 | Air France AF007
- Departure: 22:05 EST | Arrival: 11:35+1 CET
- Duration: 7h 30m | Direct | Economy
- Price: $847/person
**Return:** CDG β JFK | June 22 | Delta DL262
- Departure: 14:00 CET | Arrival: 16:45 EST
- Duration: 8h 45m | Direct | Economy
## Accommodation
**Hotel Le Marais Central** ββββ
- 15 Rue de Bretagne, 75003 Paris
- Rate: $189/night Γ 7 nights = $1,323
- Check-in: 3pm | Check-out: 11am
## Day-by-Day Schedule
### Day 1 (June 15) β Arrival & Settling In
*Arrive CDG at 11:35am local time*
**Afternoon:** RER B train to city center (~45 min, β¬12.10)
Check in at hotel. Walk Le Marais neighborhood, visit Place des Vosges
**Evening:** Dinner at Breizh CafΓ© (classic Breton crΓͺpes, β¬25-35/person)
### Day 2 (June 16) β Iconic Paris
**Morning:** Louvre Museum (book skip-line tickets online, β¬17)
**Afternoon:** Tuileries Garden β Champs-ΓlysΓ©es walk β Arc de Triomphe climb (β¬13)
**Evening:** Seine river cruise (Bateaux Parisiens, β¬20) | Dinner near Notre-Dame
[Days 3-7 continue...]
## Budget Breakdown (2 adults)
| Category | Estimated Cost |
|---|---|
| Flights (2 Γ $847) | $1,694 |
| Hotel (7 nights) | $1,323 |
| Food & Dining | $700-900 |
| Activities | $200-300 |
| Local Transport | $100 |
| **Total Estimate** | **$4,017-$4,317** |
Step 5: Integrating with AutoGPT
Register the tools as AutoGPT plugins:
# autogpt_travel_plugin.py
from tools.flight_search_tool import FlightSearchTool
from tools.hotel_search_tool import HotelSearchTool
from tools.itinerary_builder_tool import build_itinerary
flight_tool = FlightSearchTool()
hotel_tool = HotelSearchTool()
TRAVEL_FUNCTIONS = [
{
"name": "search_flights",
"description": "Search for available flights between two cities",
"parameters": {
"type": "object",
"properties": {
"origin": {"type": "string", "description": "Departure city or airport code"},
"destination": {"type": "string", "description": "Destination city or airport code"},
"departure_date": {"type": "string", "description": "Date in YYYY-MM-DD format"},
"return_date": {"type": "string", "description": "Return date in YYYY-MM-DD format"},
"adults": {"type": "integer", "description": "Number of adult passengers"}
},
"required": ["origin", "destination", "departure_date"]
}
},
{
"name": "search_hotels",
"description": "Find hotels in a destination city",
"parameters": {
"type": "object",
"properties": {
"city_code": {"type": "string", "description": "IATA city code"},
"check_in": {"type": "string"},
"check_out": {"type": "string"},
"max_price": {"type": "number", "description": "Maximum price per night in USD"}
},
"required": ["city_code", "check_in", "check_out"]
}
},
{
"name": "build_itinerary",
"description": "Create a complete day-by-day itinerary from flight and hotel data",
"parameters": {
"type": "object",
"properties": {
"destination": {"type": "string"},
"travel_dates": {"type": "object"},
"selected_flight": {"type": "object"},
"selected_hotel": {"type": "object"},
"num_days": {"type": "integer"}
},
"required": ["destination", "travel_dates", "selected_flight", "selected_hotel", "num_days"]
}
}
]
Honest Limitations
The travel agent works well for standard research tasks. Here's where it runs into trouble:
What works reliably:
- Flight price comparison across carriers and dates
- Hotel discovery filtered by price, rating, and location
- Day-by-day itinerary generation with realistic recommendations
- Budget estimation with reasonable accuracy (Β±15-20%)
What doesn't work well:
- Real-time seat availability (API data can lag)
- Complex multi-city routing with tight connections
- Hotel-specific amenity verification (pool, gym availability)
- Price alerts or fare tracking over time
- Handling travel disruptions or rebooking
API limitations to know: Skyscanner's RapidAPI tier returns pricing data only β not actual bookable inventory. Actual booking requires commercial partnership agreements. The agent works best as a research tool that identifies options, with final booking done through the airline/hotel website directly.
For production deployment of this agent, see Deploy AI model to production. For combining this with a conversational interface, see Build AI chatbot Python.
The underlying research methodology β goal decomposition, tool use, structured output β applies to any domain where you're combining multiple data sources. See AI research agent build for a generalized research agent pattern.
FAQs
Can the AutoGPT travel agent actually book flights automatically?
With the right API access, yes β but this requires booking API credentials with transaction permissions, not just search access. Skyscanner's public API returns pricing data only; actual booking requires a commercial partner agreement. For personal use, the agent can find the best option and open the booking URL for final confirmation.
How accurate are the flight prices returned by the travel agent?
Prices are accurate at the time of the API call but change frequently. The agent should always note the timestamp of pricing data and recommend confirming prices before committing. Dynamic pricing means fares seen at 9am can differ significantly from the same search an hour later.
What are the biggest limitations of this travel planner compared to a human agent?
The AutoGPT travel agent lacks awareness of real-time disruptions (weather, strikes, airline issues), can't negotiate rates, doesn't know your personal preferences without explicit prompting, and can't handle complex multi-leg itineraries as reliably as experienced human agents. It works best for standard point-to-point trips with defined requirements.
Frequently Asked Questions
AiTechWorlds Team
β Verified WriterThe AiTechWorlds team is passionate about AI, technology, and education. We create high-quality, research-backed content to help you learn, grow, and succeed in the modern digital world.
Related Articles
10 AutoGPT Command Line Arguments (Continuous Mode, Speak)
Complete reference for AutoGPT's 10 most powerful CLI arguments. Master continuous mode, headless operation, and CI/CD integration for automated agent workflows.
10 AutoGPT Configuration Tweaks for Better Performance
10 proven AutoGPT configuration tweaks to improve speed, cut costs, and boost task success. Model selection, temperature, token limits, and workspace settings.
Build a Content Research Agent with AutoGPT (Trends, Outlines)
Build an AutoGPT content research agent that finds trending topics, analyzes SERPs, and generates SEO-ready outlines automatically β full workflow inside.
Build a Data Analysis Agent with AutoGPT (CSV, SQL, Plots)
Build a data analysis agent using AutoGPT that reads CSVs, queries SQL databases, and generates plots automatically. Full code with pandas and matplotlib.