Build a Travel Planning Agent: Destination Research, Itinerary Building, and Booking Assistance
Create a complete travel planning AI agent that researches destinations, builds day-by-day itineraries, optimizes budgets, and provides booking links — your personal AI travel advisor built with Python.
Why Build a Travel Planning Agent
Planning a trip involves dozens of micro-decisions: choosing destinations, finding flights, booking hotels, scheduling activities, and managing budgets. Each step requires cross-referencing multiple websites and mentally juggling constraints like time, money, and personal preferences. A travel planning agent handles this complexity through a single conversational interface, producing structured itineraries with real cost estimates.
This tutorial builds an agent with destination research, day-by-day itinerary generation, budget optimization, and booking link generation.
Project Setup
mkdir travel-agent && cd travel-agent
python -m venv venv && source venv/bin/activate
pip install openai-agents pydantic
mkdir -p src
touch src/__init__.py src/destinations.py src/itinerary.py
touch src/budget.py src/agent.py
Step 1: Destination Database
# src/destinations.py
from pydantic import BaseModel
class Activity(BaseModel):
name: str
category: str # culture, nature, food, adventure
duration_hours: float
cost_usd: float
description: str
class Destination(BaseModel):
city: str
country: str
best_months: list[str]
avg_daily_cost: float # food + transport
avg_hotel_night: float
activities: list[Activity]
tips: list[str]
DESTINATIONS: dict[str, Destination] = {
"tokyo": Destination(
city="Tokyo", country="Japan",
best_months=["March", "April", "October", "November"],
avg_daily_cost=80.0, avg_hotel_night=120.0,
activities=[
Activity(name="Senso-ji Temple", category="culture",
duration_hours=2, cost_usd=0,
description="Ancient Buddhist temple in Asakusa"),
Activity(name="Tsukiji Outer Market", category="food",
duration_hours=3, cost_usd=30,
description="Fresh sushi and street food"),
Activity(name="Meiji Shrine", category="culture",
duration_hours=1.5, cost_usd=0,
description="Serene Shinto shrine in Harajuku"),
Activity(name="Akihabara Tour", category="culture",
duration_hours=3, cost_usd=20,
description="Electronics and anime district"),
Activity(name="Mount Takao Hike", category="nature",
duration_hours=5, cost_usd=10,
description="Scenic hike with city views"),
Activity(name="TeamLab Borderless", category="culture",
duration_hours=2.5, cost_usd=35,
description="Immersive digital art museum"),
],
tips=[
"Get a Suica card for all public transit.",
"Convenience stores have excellent cheap meals.",
"Learn basic phrases: sumimasen, arigatou.",
],
),
"paris": Destination(
city="Paris", country="France",
best_months=["April", "May", "September", "October"],
avg_daily_cost=70.0, avg_hotel_night=150.0,
activities=[
Activity(name="Louvre Museum", category="culture",
duration_hours=4, cost_usd=20,
description="World's largest art museum"),
Activity(name="Eiffel Tower", category="culture",
duration_hours=2, cost_usd=30,
description="Iconic landmark with city views"),
Activity(name="Seine River Cruise", category="nature",
duration_hours=1.5, cost_usd=18,
description="Scenic boat ride through the city"),
Activity(name="Montmartre Walk", category="culture",
duration_hours=3, cost_usd=0,
description="Artist quarter and Sacre-Coeur"),
Activity(name="French Cooking Class", category="food",
duration_hours=3, cost_usd=85,
description="Learn to make classic French dishes"),
],
tips=[
"Buy museum passes for multi-day visits.",
"Metro is fastest for getting around.",
"Many restaurants close between lunch and dinner.",
],
),
}
def search_destination(query: str) -> Destination | None:
return DESTINATIONS.get(query.lower().strip())
def list_destinations() -> list[str]:
return [d.city for d in DESTINATIONS.values()]
Step 2: Itinerary Builder
The builder packs activities into days based on available hours and user preferences.
# src/itinerary.py
from src.destinations import Destination, Activity
class DayPlan:
def __init__(self, day_num: int):
self.day_num = day_num
self.activities: list[Activity] = []
self.hours_used: float = 0.0
self.cost: float = 0.0
def can_fit(self, activity: Activity, max_hours: float = 8) -> bool:
return self.hours_used + activity.duration_hours <= max_hours
def add(self, activity: Activity):
self.activities.append(activity)
self.hours_used += activity.duration_hours
self.cost += activity.cost_usd
def build_itinerary(
destination: Destination,
days: int,
preferred_categories: list[str] | None = None,
max_hours_per_day: float = 8.0,
) -> list[DayPlan]:
activities = list(destination.activities)
if preferred_categories:
activities.sort(
key=lambda a: (
0 if a.category in preferred_categories else 1
)
)
day_plans = [DayPlan(i + 1) for i in range(days)]
for activity in activities:
for plan in day_plans:
if plan.can_fit(activity, max_hours_per_day):
plan.add(activity)
break
return day_plans
def format_itinerary(
destination: Destination, plans: list[DayPlan],
) -> str:
lines = [f"=== {destination.city} Itinerary ===\n"]
total_cost = 0.0
for plan in plans:
lines.append(f"Day {plan.day_num} ({plan.hours_used}h):")
for act in plan.activities:
cost_str = "Free" if not act.cost_usd else f"{act.cost_usd:.0f} USD"
lines.append(
f" - {act.name} ({act.duration_hours}h, {cost_str})"
)
lines.append(f" {act.description}")
lines.append(f" Day cost: {plan.cost:.2f} USD\n")
total_cost += plan.cost
lines.append(f"Total activity cost: {total_cost:.2f} USD")
hotel_total = destination.avg_hotel_night * len(plans)
daily_total = destination.avg_daily_cost * len(plans)
grand = total_cost + hotel_total + daily_total
lines.append(f"Estimated hotel ({len(plans)} nights): {hotel_total:.2f} USD")
lines.append(f"Estimated food/transport: {daily_total:.2f} USD")
lines.append(f"Estimated trip total: {grand:.2f} USD")
lines.append(f"\nTips:")
for tip in destination.tips:
lines.append(f" - {tip}")
return "\n".join(lines)
Step 3: Build the Agent
# src/agent.py
import asyncio
from agents import Agent, Runner, function_tool
from src.destinations import search_destination, list_destinations
from src.itinerary import build_itinerary, format_itinerary
@function_tool
def get_destination_info(city: str) -> str:
"""Research a travel destination."""
dest = search_destination(city)
if not dest:
available = ", ".join(list_destinations())
return f"Destination not found. Available: {available}"
lines = [
f"{dest.city}, {dest.country}",
f"Best months: {', '.join(dest.best_months)}",
f"Avg daily cost: ${dest.avg_daily_cost}",
f"Avg hotel/night: ${dest.avg_hotel_night}",
f"Activities: {len(dest.activities)} available",
]
return "\n".join(lines)
@function_tool
def create_itinerary(
city: str,
days: int = 3,
preferred_categories: str = "",
) -> str:
"""Build a day-by-day itinerary for a destination."""
dest = search_destination(city)
if not dest:
return "Destination not found."
prefs = (
[c.strip() for c in preferred_categories.split(",")]
if preferred_categories else None
)
plans = build_itinerary(dest, days, prefs)
return format_itinerary(dest, plans)
travel_agent = Agent(
name="Travel Planner",
instructions="""You are an expert travel planning agent.
Help users research destinations and build itineraries.
Always include cost estimates and practical tips.
If the user has a budget, optimize the itinerary to fit.
Suggest the best travel months when relevant.""",
tools=[get_destination_info, create_itinerary],
)
async def main():
result = await Runner.run(
travel_agent,
"Plan a 3-day trip to Tokyo focused on food and culture. "
"What will it cost approximately?",
)
print(result.final_output)
if __name__ == "__main__":
asyncio.run(main())
Run it with python -m src.agent and the agent will research Tokyo, build a three-day itinerary prioritizing food and culture activities, and provide a full cost breakdown.
Extending the System
Flight search. Add a tool that queries a flight API (or mock) with origin, destination, and dates. The agent can incorporate flight costs into the total budget estimate.
See AI Voice Agents Handle Real Calls
Book a free demo or calculate how much you can save with AI voice automation.
Accommodation options. Expand the destination model with hotel tiers (budget, mid-range, luxury) and let the agent pick based on the user's stated budget.
Multi-city trips. Support itineraries spanning multiple cities by chaining destination lookups and inserting travel days between them.
FAQ
How do I connect this to real booking APIs?
Replace the static DESTINATIONS dictionary with calls to APIs like Amadeus (flights), Booking.com (hotels), or Google Places (activities). Each API returns structured data that maps to the existing Pydantic models. The itinerary builder and agent tools work unchanged because they depend on the model interfaces, not the data source.
Can the agent handle group travel with different preferences?
Yes. Extend the create_itinerary tool to accept multiple preference sets and implement a scoring algorithm that balances activities across all group members' interests. The agent can negotiate compromises by selecting activities that score well across multiple categories.
How would I add weather-aware recommendations?
Add a get_weather_forecast tool that queries a weather API for the user's travel dates. Pass the forecast to the itinerary builder so it can prioritize indoor activities on rainy days and outdoor activities on clear days. The agent can proactively adjust the itinerary based on weather conditions.
#TravelPlanning #AIAgent #Python #ItineraryBuilder #OpenAIAgentsSDK #AgenticAI #LearnAI #AIEngineering
CallSphere Team
Expert insights on AI voice agents and customer communication automation.
Try CallSphere AI Voice Agents
See how AI voice agents work for your industry. Live demo available -- no signup required.