Files
2026-07-13 13:30:30 +08:00

191 lines
12 KiB
Markdown

# Travel Booking Multi-Agent Assistant (LiveKit ADK)
An enterprise-grade multi-agent voice orchestrator system built on **Google's Agent Development Kit (ADK)** and **LiveKit**. This application establishes a low-latency WebRTC-to-Gemini-Live bridge allowing users to naturally converse with specialized travel agents to search, book, and manage flights and hotels in a single session.
---
## 1. System Architecture & Flow
The system coordinates high-performance WebRTC audio streams, translates them into real-time bidirectional ADK session events, and communicates with Gemini Live API models.
```
┌───────────────────────────────────────┐
│ Client Browser │
└───────────────────────────────────────┘
▲ │
WebRTC │ (Render Audio / │ (User Audio /
DataChannel │ Data Transcription) │ WebRTC Media)
│ ▼
┌──────────────────────┼───────────────────────────────────────────────────────┐
│ │ LiveKit Server │
│ │ │
│ └──────────────┬───────────────▲────────────────────────┘
│ │ │
│ Audio Frames │ │ Audio Frames
│ (Gemini -> LK) │ │ (LK -> Gemini)
│ ▼ │
│ ┌────────────────────────────────────────┴────────────┐ │
│ │ FastAPI Application Server │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ app/livekit_bridge.py │ │ │
│ │ │ - Converts 48kHz LK Audio -> 16kHz PCM │ │ │
│ │ │ - Feeds LiveRequestQueue │ │ │
│ │ └──────────────────────┬──────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────┐ │ │
│ │ │ LiveRequestQueue │ │ │
│ │ └──────────┬──────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────┐ │ │
│ │ │ ADK Runner │ │ │
│ │ └──────────┬──────────┘ │ │
│ └──────────────────────────┼──────────────────────────┘ │
└───────────────────────────────────────┼──────────────────────────────────────┘
│ Bidirectional WebSockets (v1alpha)
┌───────────────────────────────────────┐
│ Gemini Live API │
│ (gemini-live-2.5-flash) │
└───────────────────────────────────────┘
```
### Protocol Lifecycle:
1. **Session Establishment**: Client requests a token from `/token`, triggering the background instantiation of the `LiveKitGeminiBridge`.
2. **WebRTC Join**: The client browser joins the LiveKit room. The `LiveKitGeminiBridge` also connects a virtual audio participant into the room.
3. **Upstream Pipeline (User -> gemini)**:
- Client streams user audio to the LiveKit Room using **WebRTC**.
- `LiveKitGeminiBridge` subscribes to the track, extracts the 48kHz frames, downsamples to **16kHz mono PCM**, and pushes them to the ADK `LiveRequestQueue`.
- The ADK `Runner` streams the queue content to Gemini Live API via an underlying **secure WebSocket connection (`bidiGenerateContent` protocol)**.
4. **Downstream Pipeline (Gemini -> User)**:
- Gemini responds in real-time with audio buffers and textual transcriptions via the secure WebSocket.
- ADK `Runner` intercepts the events and passes them to the bridge.
- The bridge pushes the audio (resampled to 24kHz) back into LiveKit via the LocalAudioTrack, and publishes transcription text through WebRTC **DataChannels**.
---
## 2. The Booking Agents (Multi-Agent Orchestrator)
Inside the `app/travel_booking/` package, we implement a **three-tier hierarchical multi-agent orchestrator**:
```
┌──────────────────────┐
│ session_orchestrator │
│ (Central Router) │
└──────────┬───────────┘
┌──────────────────┴──────────────────┐
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ FlightBookingAgent │◀─────────────▶│ HotelBookingAgent │
│ (Flight search/book)│ A2A Transfer│ (Hotel search/book) │
└─────────────────────┘ └─────────────────────┘
```
1. **Session Orchestrator** (`app/travel_booking/agent.py`):
- The root agent. Listens to the user's intent and delegates control to the specialist sub-agents (`FlightBookingAgent` or `HotelBookingAgent`) via ADK's native agent-routing tool calls.
2. **FlightBookingAgent** (`app/travel_booking/agents/flight_booking.py`):
- Specialized in travel search and reservations.
- Equipped with 3 mock tools: `search_flights`, `book_flight`, `cancel_flight`.
- Configured with `HotelBookingAgent` as a sub-agent to enable a direct, silent handoff when the user switches context to hotel bookings.
3. **HotelBookingAgent** (`app/travel_booking/agents/hotel_booking.py`):
- Specialized in lodging discovery and booking.
- Equipped with 3 mock tools: `search_hotels`, `book_hotel`, `cancel_hotel`.
---
## 3. LiveKit Bridge & Configuration Overview
### `app/livekit_bridge.py` Overview
This class acts as the low-latency audio converter and routing engine.
- **Audio Buffering & Downsampling**: Standardizes LiveKit's high-fidelity audio stream (downsamples 48kHz stereo to 16kHz mono PCM) and sends it in small, optimized 20ms buffers (640 bytes) to reduce WebSocket latency.
- **Realtime Event Mapping**: Listens to `runner.run_live` event generators, translates model text outputs and prints them to the server console, and publishes data events onto WebRTC DataChannels.
### Runner Configuration (`app/main.py`)
- The `Runner` is configured with standard `InMemorySessionService` or `DatabaseSessionService` to persist dialogue histories.
- Integrated with a custom **`SessionResumptionIsolationPlugin`**: Clears the transparency resumption handles when transferring between sub-agents, preventing key-based Gemini API errors during sub-agent handoffs.
```python
runner = Runner(
app_name="livekit-adk",
agent=agent.root_agent,
session_service=session_service,
auto_create_session=True,
plugins=[SessionResumptionIsolationPlugin()]
)
```
### Run Configuration (`app/livekit_bridge.py`)
Configured specifically to handle high-performance native audio models over WebRTC:
```python
run_config = RunConfig(
streaming_mode=StreamingMode.BIDI,
response_modalities=["AUDIO"],
input_audio_transcription=types.AudioTranscriptionConfig(),
output_audio_transcription=types.AudioTranscriptionConfig(),
session_resumption=types.SessionResumptionConfig(),
enable_affective_dialog=True
)
```
- **`response_modalities=["AUDIO"]`**: Crucial for native audio Gemini models; enforces direct-to-audio responses to ensure natural voice cadence.
- **`output_audio_transcription`**: Tells Gemini to send text transcripts along with the audio stream so the bridge can display them on the UI.
---
## 4. Configuration & Run Instructions
### 1. Environment Setup (`app/.env`)
Create a file named `app/.env` inside the project. Configure the variables:
```bash
# Model selection
DEMO_AGENT_MODEL="gemini-live-2.5-flash-native-audio"
# LiveKit Settings (Local development values)
USE_LIVEKIT=true
LIVEKIT_URL=ws://localhost:7880
LIVEKIT_API_KEY=devkey
LIVEKIT_API_SECRET=secret
```
### 2. Installing & Running LiveKit (macOS)
For local development, you need a running LiveKit server instance. On macOS, install and run it using Homebrew:
```bash
# Install LiveKit Server
brew install livekit
# Start the server in development mode
livekit-server --dev
```
The `--dev` flag automatically starts the server on `localhost:7880` using the default credentials:
- **API Key**: `devkey`
- **API Secret**: `secret`
*(These credentials match the default `.env` template above.)*
### 3. Launching the Application
Ensure you are running commands using the project's virtual environment.
**Step 1: Sync dependencies**
```bash
uv sync
```
**Step 2: Start the Dev Server**
Navigate into the `app` folder and run:
```bash
uv run --project .. python3 -m uvicorn main:app --reload
```
The application starts a FastAPI server listening at `http://127.0.0.1:8000/static/livekit`. Open this URL in your browser to interact with the voice assistant!
---