Inspiration

Travel is one of the biggest household expenses, yet buying a flight remains a guessing game. Prices change dozens of times a day, and the "right moment" to book exists for only hours. Most people either buy too early and overpay, or wait too long and watch prices spike.

We asked: what if an AI agent just... handled this for you?** Not a price alert. Not a recommendation. An agent that watches, reasons, and books — autonomously — at the optimal moment, while you sleep.

That question became FlightAI Agent.

What it does

FlightAI Agent is a fully autonomous flight-booking system powered by Gemini 2.5 Flash on Vertex AI.

You set a route, a target price, and a travel date. The agent takes over from there:

  1. Price Watcher polls Amadeus live fare data every few hours and publishes price events to Cloud Pub/Sub
  2. Orchestrator (LangGraph StateGraph) wakes on each event and runs a multi-step reasoning chain:
    • XGBoost ML model scores the deal (trained on 3.3M historical fares from BigQuery)
    • Gemini 2.5 Flash reasons over price trend, ML score, days-to-departure, and historical average
    • If Gemini decides to book, it calls the book_flight MCP tool → Duffel API issues the ticket
    • A notify step fires SMS (Twilio) + email (SendGrid) with the booking confirmation
  3. React frontend shows real-time price history charts, AI decision logs with confidence scores, and a pending booking card with Apple Pay

Every agent decision — action, ML score, Gemini reasoning trace ID — is written to agent_logs and exported nightly to BigQuery.

The orchestrator implements the Model Context Protocol (MCP) — Gemini calls structured tools (check_price_trend, get_ml_score, book_flight) rather than outputting raw text. This keeps the agent's actions auditable and reversible.

ML pipeline

  • Training data: 3.3M fare records in BigQuery (flightai.fare_data)
  • Features:days_to_departure, day_of_week, month, historical_avg, price_ratio (current ÷ route average)
  • Model: XGBoost binary classifier — "is this price good enough to book?" — stored in GCS flightai-models
  • Feature pipeline: runs monthly via Cloud Scheduler; exports from BigQuery → GCS → retrains

AI reasoning (Gemini 2.5 Flash)

Each orchestration cycle builds a structured prompt with the live ML score, fare trend, and route context. Gemini returns a structured {action, reasoning} JSON via Vertex AI. The gemini_trace_id from every call is stored in agent_logs — giving judges a full, verifiable audit trail.

Frontend

React + TypeScript + Tailwind, built with Vite and served from nginx on Cloud Run. Key screens:

  • Dashboard— live route cards with AI status badges
  • Route Detail — Recharts AreaChart for price history, expandable AI decision log, "Deal ready — Pay with Apple Pay" banner when agent has found a booking
  • Admin— agent logs table, BigQuery export trigger

Challenges we ran into

Gemini model availability: The Gemini API (generativelanguage.googleapis.com) had gemini-1.5-flash and gemini-2.0-flash listed in docs but returning 404. We switched entirely to Vertex AI and gemini-2.5-flash, which worked reliably.

Asyncio + Pub/Sub threads: FastAPI's async event loop doesn't share a thread with the Pub/Sub message callback. We hit RuntimeError: no running event loop until we switched to asyncio.run_coroutine_threadsafe() to bridge the thread boundary.

XGBoost feature ordering: The training pipeline and the prediction endpoint built feature vectors in different orders. The model silently returned wrong scores until we enforced a canonical [days_to_departure, day_of_week, month, historical_avg, price_ratio] order at both sites.

Docker build + Vite env vars: Vite bakes VITE_API_URL at compile time from .env.production. Our .gcloudignore was excluding frontend/.env* — so Cloud Build built the bundle without the gateway URL. Every API call silently fell back to /api, and every login attempt returned "invalid credentials" even though the backend was healthy. Fixed by scoping the ignore to .env.local and .env.*.local only.

Agent getting stuck on PENDING bookings: When a Duffel booking call failed mid-flight, the booking stayed PENDING and blocked retries on future price events. We added an explicit status = FAILED write in the except path of book_node so the orchestrator retries cleanly.

What we learned

MCP makes AI agents auditable. Structured tool calls mean every agent decision maps to a logged, replayable action — not a free-form text output the system has to interpret. Pub/Sub is the right backbone for event-driven agents.Decoupling price events from the orchestrator let us scale and retry independently. BigQuery + XGBoost is a powerful combo for pricing ML.3.3M training rows, a 5-feature model, and we get a reliable signal in under 50ms at prediction time.

Microservices surface boundary bugs fast.Auth mismatches, enum case differences (frontend ACTIVE vs backend active), and env var gaps all became immediate errors — painful to debug but easy to fix cleanly.

What's next

  • Production Amadeus + Duffel keys— switch from test API to live fares and real ticket issuance
  • Vertex AI Vector Search— RAG over past booking history to personalize the agent's booking threshold per user
  • Monthly model retraining— Cloud Run Job is written; needs scheduling hookup
  • Push notifications— Firebase Cloud Messaging is wired; needs production VAPID key

Built With

Share this project:

Updates

Submission history