---
title: "Build a Travel Planning Agent: Destination Research, Itinerary Building, and Booking Assistance"
description: "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."
canonical: https://callsphere.ai/blog/build-travel-planning-agent-itinerary-building-booking-assistance
category: "Learn Agentic AI"
tags: ["Travel Planning", "AI Agent", "Python", "Itinerary Builder", "OpenAI Agents SDK"]
author: "CallSphere Team"
published: 2026-03-17T00:00:00.000Z
updated: 2026-05-06T01:02:44.324Z
---

# 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

```bash
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

```python
# 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.

```mermaid
flowchart LR
    INPUT(["User intent"])
    PARSE["Parse plus
classify"]
    PLAN["Plan and tool
selection"]
    AGENT["Agent loop
LLM plus tools"]
    GUARD{"Guardrails
and policy"}
    EXEC["Execute and
verify result"]
    OBS[("Trace and metrics")]
    OUT(["Outcome plus
next action"])
    INPUT --> PARSE --> PLAN --> AGENT --> GUARD
    GUARD -->|Pass| EXEC --> OUT
    GUARD -->|Fail| AGENT
    AGENT --> OBS
    style AGENT fill:#4f46e5,stroke:#4338ca,color:#fff
    style GUARD fill:#f59e0b,stroke:#d97706,color:#1f2937
    style OBS fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
    style OUT fill:#059669,stroke:#047857,color:#fff
```

```python
# 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  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

```python
# 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.

**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

---

Source: https://callsphere.ai/blog/build-travel-planning-agent-itinerary-building-booking-assistance
