✈️ TRAVEL PLANNER · MULTI-AGENT APP

Construcción de
Flujos
Multi-Agentes
en la Web

Gemini ADK · TypeScript · Node.js · React

✈️ → 🏨 → 🗺️ → 📋 → 🤖
Vanessa Aristizabal

@vanessamarely

Speaker

Vanessa
Aristizabal

[01]

Ingeniera de Sistemas & Magíster en Ingeniería

[02]

Google Developer Expert — Web Technologies & Angular

[03]

GitHub Star

[04]

Creadora de contenido

Código fuente

Escanea & clona
el repositorio

QR code — repositorio GitHub Travel Planner Multi-Agent

github.com · Travel Planner Multi-Agent

Concepto 1

¿Qué es un agente?

Un modelo de IA con un solo rol, instrucciones claras
y herramientas opcionales. Hace bien esa única cosa.

Especializado

Un rol, una responsabilidad. No intenta hacer todo — hace su parte excepcionalmente bien.

Autónomo

Recibe un input, razona internamente con el modelo y produce un output estructurado.

Componible

Se combina con otros agentes. Corre en paralelo, en secuencia o anidado.

En nuestro Travel Planner

Cada tarea del viaje
es un agente distinto

✈️

Flight Agent

Busca opciones de vuelo para el destino, duración y presupuesto indicados.

🏨

Hotel Agent

Recomienda hoteles según el nivel de presupuesto: Low, Medium o High.

🧭

Activity Agent

Sugiere actividades, restaurantes y experiencias según los días del viaje.

📋

Itinerary Agent

Espera los 3 resultados anteriores y construye el itinerario día a día.

Concepto 2

El Orquestador
es el director

Decide quién trabaja, cuándo,
y cómo combinar los resultados.

🎯 ParallelAgent
+ SequentialAgent
✈️ Flight Agent
🏨 Hotel Agent
🧭 Activity Agent
📋 Itinerary Agent

● Los 3 del centro corren en paralelo

● Itinerary Agent espera los 3 outputs

Por qué importa

Paralelo vs Secuencial

// Sin ParallelAgent — uno por uno

Flight Agent
2s
Hotel Agent
2s
Activity Agent
2s

Total: ~6 segundos

// Con ParallelAgent — al mismo tiempo

Flight Agent
2s
Hotel Agent
2s
Activity Agent
2s

Total: ~2 segundos ⚡

Gemini ADK

ADK te da
la infraestructura

Sin ADK escribes la coordinación desde cero.
ADK te da los bloques listos para usar.

LlmAgent

Define el agente: nombre, modelo, instrucción y herramientas.

ParallelAgent

Ejecuta múltiples agentes al mismo tiempo.

SequentialAgent

Encadena agentes: el output de uno es el input del siguiente.

terminal
# instalación oficial
$ npm install @google/adk
Gemini ADK · Definición

¿Qué es ADK
exactamente?

Framework para construir aplicaciones con LLMs.
Agentes que razonan, planifican, usan herramientas
y colaboran en equipo. Open source, multi-lenguaje.

TypeScript / JS

github.com/google/adk-js
Soportado desde v0.2.0

También disponible

Python · Go · Java · Kotlin

Documentación oficial

adk.dev

ADK · Tipos de Workflows

4 formas de
orquestar agentes

Template

Estructura fija: Sequential · Parallel · Loop. El más predecible — el que usamos en esta app.

Collaborative

Un agente coordinador dinámico decide a qué sub-agente delegar cada tarea en tiempo real.

Graph-based

Grafo de ejecución con bifurcaciones y nodos determinísticos. ADK 2.0+

Dynamic

Lógica de orquestación en código puro. Máxima flexibilidad programática. ADK 2.0+

Setup · TypeScript

Instalando ADK
en TypeScript

1

Crear proyecto

mkdir travel-planner && cd travel-planner && npm init -y
2

Instalar ADK — paquete oficial

npm install @google/adk
3

API Key — gratis en aistudio.google.com

GEMINI_API_KEY=tu_key     # leída automáticamente por @google/adk
4

TypeScript support

npm install -D typescript tsx    npx tsc --init
ADK · LlmAgent

Anatomía de
un LlmAgent

3 propiedades clave definen todo el comportamiento del agente:

name

Identifica al agente en el sistema. Único dentro del pipeline.

model

El LLM que razona. Gemini, Claude o GPT-4o vía LiteLLM.

instruction

El system prompt. Define el rol, el tono y los límites del agente.

Opcionales: description — para routing automático  ·  tools — funciones TS que el agente puede invocar

Código · LlmAgent

Así se define
un agente

travel-orchestrator.ts
1
2
3
4
5
6
7
8
9
10
import { LlmAgent } from '@google/adk'; export const flightAgent = new LlmAgent({ name: 'flight_agent', model: 'gemini-2.5-flash', instruction: `Eres experto en vuelos. Dado origen, destino y presupuesto (low/medium/high), sugiere 2-3 opciones de vuelo con precio estimado.`, outputKey: 'flight_results', // ADK guarda el output en session state });

nameIdentifica al agente en el sistema. Único dentro del pipeline.

modelEl modelo Gemini que usa: gemini-2.5-flash o gemini-2.5-pro.

outputKeyNombre de la clave donde ADK guarda la respuesta en session state.

Código · Orquestador

Coordinando agentes
con ParallelAgent

travel-orchestrator.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { ParallelAgent, SequentialAgent } from '@google/adk'; // Flight, Hotel y Activity corren AL MISMO TIEMPO const researchTeam = new ParallelAgent({ name: 'research_team', subAgents: [flightAgent, hotelAgent, activityAgent], }); // Itinerary Agent espera los 3 resultados export const travelPipeline = new SequentialAgent({ name: 'travel_pipeline', subAgents: [researchTeam, itineraryAgent], });

ParallelAgent — los 3 agentes corren simultáneamente. ADK sincroniza automáticamente.

SequentialAgent — el ItineraryAgent espera a los 3 y recibe todos sus outputs.

Arquitectura

Cómo se conectan
las piezas

⚛️

React — Frontend

Formulario · Estado de agentes en tiempo real · Resultado

↕ SSE (Server-Sent Events / fetch)

🟢

Node.js — Backend

Recibe petición · Llama al ADK Runner · Transmite eventos

↕ ADK Runner

🤖

ADK Agents — Orquestación

ParallelAgent + SequentialAgent + Gemini 2.5 Flash

Frontend · React

Cada agente muestra
su estado en vivo

✈️

Flight Agent

working...

🏨

Hotel Agent

working...

🗺️

Activity Agent

working...

📋

ItineraryAgent

idle

src/lib/api.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// React fetch + ReadableStream (SSE) const res = await fetch('/api/plan', {   method: 'POST',   headers: { 'Content-Type': 'application/json' },   body: JSON.stringify(request), }); const reader = res.body.getReader();   // Eventos SSE recibidos: type SSEEvent =   | { type: 'agent_update'; agent: string; status: 'idle'|'working'|'done' }   | { type: 'complete'; plan: { flights, hotels, activities, itinerary } };   // idle → working → done
Proyecto · Travel Planner

Estructura del
proyecto

EXPLORER
📁 travel-planner/
📂 server/
▸ travel-orchestrator.ts
▸ index.ts
📂 src/
📂 lib/
▸ api.ts
▸ types.ts
📂 components/
▸ AgentCard.tsx
▸ App.tsx
▸ .env

server/travel-orchestrator.ts

LlmAgent ×4 + ParallelAgent + SequentialAgent. Toda la lógica ADK aquí.

server/index.ts

Express + SSE. Ejecuta el Runner ADK y transmite eventos al frontend.

src/lib/api.ts

Cliente SSE con fetch + ReadableStream. Conecta React con el backend.

src/components/AgentCard.tsx

Muestra idle → working → done en tiempo real.

ADK · Cómo se pasan los datos

outputKey +
Session State

Los agentes paralelos no se comunican entre ellos directamente.
Cada uno escribe su resultado en el session state usando outputKey.

travel-orchestrator.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Cada agente guarda su output automáticamente en session state: const flightAgent = new LlmAgent({ ..., outputKey: 'flight_results' }); const hotelAgent = new LlmAgent({ ..., outputKey: 'hotel_results' }); const activityAgent = new LlmAgent({ ..., outputKey: 'activity_results' }); // El itinerary agent lee el state via InstructionProvider: const itineraryAgent = new LlmAgent({ instruction: (ctx) => { const flights = ctx.state.get('flight_results'); const hotels = ctx.state.get('hotel_results'); const activities = ctx.state.get('activity_results'); return `Crea el itinerario con: ${flights} ${hotels} ${activities}`; }, outputKey: 'itinerary_results', });

▶ outputKey → ADK escribe el texto en session.state[key] automáticamente  ·  el ItineraryAgent lo lee con ctx.state.get(key)

ADK · Runner

El Runner
ejecuta el pipeline

server/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { Runner, InMemorySessionService } from '@google/adk'; const runner = new Runner({ appName: 'travel-planner', agent: travelPipeline, // SequentialAgent raíz sessionService: new InMemorySessionService(), }); // AsyncGenerator de eventos — el backend lo transmite por SSE: for await (const event of runner.runAsync({ userId, sessionId, newMessage })) { if (isFinalResponse(event)) { // event.author → qué agente terminó // event.actions.stateDelta → texto guardado con outputKey sendSSE(res, { agent: event.author, status: 'done' }); } }

InMemorySessionService

Mantiene session state en memoria. Comparte datos entre agentes.

isFinalResponse(event)

Detecta cuando cada agente terminó su respuesta.

event.author

Identifica qué agente emitió el evento: flight_agent, etc.

Demo en vivo

✈️ Travel
Planner
Multi-Agent

✈️ 🏨 🗺️ 📋

Origen + destino + duración + presupuesto →
3 agentes en paralelo → itinerario completo

Low · Medium · High 1 – 14 días Cualquier origen → destino
Para llevar

Lo que aprendiste hoy

✓

Agente = función con rol, instrucciones y herramientas propias

✓

Orquestador = quien decide quién trabaja, cuándo y en qué orden

✓

outputKey → session state → InstructionProvider: así comparten datos los agentes

✓

Runner + SSE: Node.js ejecuta el pipeline y transmite eventos en tiempo real al frontend

✓

React consume · Node.js orquesta · ADK coordina · Gemini 2.5 razona

✓

npm install @google/adk  ·  API key gratuita en aistudio.google.com

google.github.io/adk-docs  ·  aistudio.google.com