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:
- Price Watcher polls Amadeus live fare data every few hours and publishes price events to Cloud Pub/Sub
- 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_flightMCP tool → Duffel API issues the ticket - A notify step fires SMS (Twilio) + email (SendGrid) with the booking confirmation
- 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
AreaChartfor 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
Log in or sign up for Devpost to join the conversation.