Skip to main content

Flight Search

The flight search system provides intelligent flight recommendations by integrating with QPX Connect and applying user preferences and company policies.

Architecture Overview

┌─────────────────────────────────────────────────────────────┐
│ Frontend (React) │
│ Chat Interface → Results Display │
└──────────────────────────┬──────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│ Chat Endpoint (SSE Stream) │
│ ChatOrchestrator │
└──────────────────────────┬──────────────────────────────────┘

┌────────────┴────────────┐
▼ ▼
┌────────────────────────┐ ┌────────────────────────────────┐
│ Context Agent │ │ Conversational Agent │
│ (Trip Requirements) │ │ (User Dialogue) │
└────────────────────────┘ └──────────────┬─────────────────┘


┌────────────────────────────────┐
│ Trip Planner Agent │
│ search_flights tool (PydanticAI)│
└──────────────┬─────────────────┘


┌────────────────────────────────┐
│ FlightSearchOrchestrator │
│ Coordinates QPX, scoring, DB │
└──────────────┬─────────────────┘

┌─────────────┴─────────────┐
▼ ▼
┌────────────────────┐ ┌────────────────────┐
│ QPX Service │ │ Insight Service │
│ External API │ │ Scoring & insights│
└────────────────────┘ └────────────────────┘

Key Components

AI Agent Tool

The flight search is exposed as a tool for the Trip Planner Agent (built with PydanticAI):

class TripPlannerAgentToolset(BaseAgentToolset):
@observe(name=ToolName.SEARCH_FLIGHTS, as_type="tool")
async def search_flights(
self,
ctx: RunContext[TripPlannerAgentDeps],
user_explanation: str,
trip_search_id: str,
return_trip_search_id: str | None = None,
) -> dict[str, Any]:
uow = self._unit_of_work_factory()
async with uow.background_context():
outbound_search, return_search = await self._flight_search_orchestrator.search_flights(
uow=uow,
outbound_trip_search_id=UUID(trip_search_id),
return_trip_search_id=UUID(return_trip_search_id) if return_trip_search_id else None,
)
return {"outbound_options_count": len(outbound_search.trip_options), ...}

The @observe decorator is from Langfuse for observability tracing.

Flight Orchestrator

Coordinates the search workflow:

  1. Fetch trip search parameters from database
  2. Call QPX Connect API with search criteria
  3. Map API response to internal entities
  4. Apply scoring based on preferences and policies
  5. Generate insights for each flight option
  6. Persist results to database

QPX Service

Handles communication with QPX Connect:

class QPXService:
async def search(self, request: QPXSearchRequest) -> list[Flight]:
response = await self.client.post("/search", json=request.model_dump())
return self.mapper.map_response(response.json())

Data Flow

  1. User Message → Frontend sends chat message via SSE stream
  2. Context Agent → Extracts trip requirements, creates TripStep and TripSearch entities
  3. Conversational Agent → Decides to plan trip, calls plan_trip tool
  4. Trip Planner Agent → Executes search_flights tool
  5. OrchestrationFlightSearchOrchestrator coordinates services
  6. API CallQPXService queries QPX Connect
  7. Mapping → Response mapped to Flight, FlightLeg, Fare entities
  8. Scoring → Features extracted and scored against user preferences and company policies
  9. Insights → Natural language explanations generated via InsightService
  10. Persistence → Results saved as TripOption entities with insights
  11. Recommendations → Trip Planner calls recommend_options to select top 3
  12. Response → Conversational Agent presents ranked options to user