Serko Northsky AI Orchestration
The Serko Northsky AI orchestration layer powers the conversational travel planning experience, coordinating multiple AI agents and tools to deliver personalized trip recommendations.
Architecture Overview
┌─────────────────────────────────────────────────────────────────────────────┐
│ Chat Endpoint │
│ (WebSocket / SSE Stream) │
└─────────────────────────────────┬───── ──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ Chat Orchestrator │
│ Coordinates conversation flow and agent execution │
└───────────────┬────────────────────────────────────────┬────────────────────┘
│ │
┌────────▼────────┐ ┌──────────▼──────────┐
│ Context Agent │ │ Conversational Agent │
│ (Trip Context) │ │ (User Dialogue) │
└────────┬────────┘ └──────────┬───────────┘
│ │
│ ┌──────────▼───────────┐
│ │ Trip Planner Agent │
│ │ (Search & Plan) │
│ └──────────┬───────────┘
│ │
└────────────────┬───────────────────────┘
│
┌────────────▼─────────────┐
│ Search Orchestrators │
│ (Flight / Accommodation) │
└────────────┬─────────────┘
│
┌──────────────────┼──────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ QPX │ │ Booking │ │ Sabre │
│ Connect │ │ .com │ │ GDS │
└──────────┘ └──────────┘ └──────────┘
Core Components
Chat Orchestrator
The ChatOrchestrator is the central coordinator that manages the conversation flow.
The orchestrator executes a multi-step response flow:
- Load Context — Fetch user, conversation history, trip state, preferences
- Run Context Agent — Extract and update trip requirements from user message
- Run Conversational Agent — Generate response and trigger planning tools
- Save Messages — Persist assistant messages to database
- Update Traces — Send observability data to Langfuse
AI Agents
The system uses three specialized agents built with Pydantic AI.
Source Code Locations
| Component | Location |
|---|---|
| Context Agent | core/agents/context_agent/ |
| Conversational Agent | core/agents/conversational_agent/ |
| Trip Planner Agent | core/agents/trip_planner_agent/ |
Context Agent
Extracts and maintains trip context from the conversation.
| Responsibility | Description |
|---|---|
| Trip Information | Extract dates, destinations, purpose |
| Trip Steps | Create flight and accommodation requirements |
| Preferences | Capture user preferences for scoring |
Toolsets — See context_agent/toolsets/:
TripEditionContextAgentToolset— Create/update trip stepsPreferenceEditionContextAgentToolset— Manage trip preferences
Conversational Agent
Manages user dialogue and orchestrates trip planning.
| Responsibility | Description |
|---|---|
| User Interaction | Respond to questions, provide recommendations |
| Planning Triggers | Invoke trip planner when search is needed |
| Result Presentation | Format and explain search results |
Toolset — See ConversationalAgentToolset:
plan_trip— Initiate search for all trip stepsnew_trip_step_search— Run additional searches for specific steps
Trip Planner Agent
Executes searches and generates recommendations.
| Responsibility | Description |
|---|---|
| Search Execution | Call flight and accommodation APIs |
| Result Retrieval | Fetch and sort search results by score |
| Recommendations | Select and highlight top options |
Toolset — See TripPlannerAgentToolset:
search_accommodations— Search Booking.com and Sabresearch_flights— Search QPX Connectget_search_results— Retrieve ranked resultsrecommend_options— Select top 3 recommendations
Agent Tools
Each toolset implements BaseAgentToolset which exposes tools to the Pydantic AI agent.
Tool Reference Table
| Agent | Tool | Purpose | Source |
|---|---|---|---|
| Context | update_trip_info | Update trip name, purpose, dates | trip_edition_context_agent_toolset.py |
| Context | create_trip_step | Add flight or accommodation step | trip_edition_context_agent_toolset.py |
| Context | update_trip_step | Modify existing trip step | trip_edition_context_agent_toolset.py |
| Context | delete_trip_step | Remove a trip step | trip_edition_context_agent_toolset.py |
| Context | add_preference | Add trip-specific preference | preference_edition_context_agent_toolset.py |
| Context | update_preference | Modify preference weight/value | preference_edition_context_agent_toolset.py |
| Context | delete_preference | Remove a preference | preference_edition_context_agent_toolset.py |
| Conversational | plan_trip | Trigger search for all trip steps | conversational_agent_toolset.py |
| Conversational | new_trip_step_search | Run new search for specific step | conversational_agent_toolset.py |
| Trip Planner | search_accommodations | Search Booking.com + Sabre | trip_planner_agent_toolset.py |
| Trip Planner | search_flights | Search QPX Connect | trip_planner_agent_toolset.py |
| Trip Planner | get_search_results | Retrieve sorted results | trip_planner_agent_toolset.py |
| Trip Planner | recommend_options | Select top recommendations | trip_planner_agent_toolset.py |
Search Orchestrators
Orchestrators coordinate multi-provider searches. See detailed documentation:
| Orchestrator | Source | Purpose |
|---|---|---|
FlightSearchOrchestrator | core/orchestrators/flight_search_orchestrator.py | QPX Connect flight search |
AccommodationSearchOrchestrator | core/orchestrators/accommodation_search_orchestrator.py | Multi-provider hotel search |
Data Flow
Complete Search Flow
User: "I need a flight from Montreal to Paris next month"
│
├── 1. Context Agent extracts requirements
│ └── Creates TripStep (flight: YUL → CDG, March 15-22)
│
├── 2. Conversational Agent triggers planning
│ └── Calls plan_trip tool
│
├── 3. Trip Planner Agent executes search
│ ├── Creates TripSearch entity
│ ├── Calls search_flights tool
│ │ └── FlightSearchOrchestrator → QPX API
│ ├── Calls get_search_results tool
│ │ └── Returns scored, sorted options
│ └── Calls recommend_options tool
│ └── Selects top 3 with highlights
│
└── 4. Conversational Agent presents results
└── "I found 47 flights. Here are my top 3 picks..."
Agent Dependencies
Agents receive dependencies via typed Deps dataclasses. See source files:
| Dependency Class | Source |
|---|---|
ContextAgentDeps | context_agent/agent_runner.py |
ConversationalAgentDeps | conversational_agent/agent_runner.py |
TripPlannerAgentDeps | trip_planner_agent/agent_runner.py |
Key dependencies include:
event_sender— SSE streaming to frontendtrip/trip_step— Current trip contexttrip_preferences— User preferences for scoringcompany_policy_rules— Policy constraints
Error Handling
Tools use Pydantic AI's ModelRetry exception to handle recoverable errors. The LLM receives the error message and can retry or explain to the user.
Observability
All agent operations are traced with Langfuse using the @observe decorator:
- Agent execution spans
- Individual tool calls
- LLM token usage
- Errors and retries
Transaction Management
Agent tools run outside the request-scoped UoW. They create their own UoW using the factory and wrap operations in background_context().
See Unit of Work for details.
Agent tools must create their own UoW via the factory to avoid race conditions with the request-scoped UoW.
Related Documentation
- Backend Architecture — Overall architecture
- Unit of Work — Transaction management
- TTV Scoring — How options are scored
- Flight Search — Flight search details
- Accommodation — Accommodation search details