← Volver al índice | Arquitectura IA | Arquitectura del Sistema
Pivote Arquitectónico: Quarkus + Dapr + Visual Workflows¶
Tipo: Investigación — Decisión Arquitectónica
Audiencia: Equipo de desarrollo, dirección técnica
Fecha: 20 de marzo de 2026
Relacionado con: Arquitectura del Sistema | Docker Compose
1. Contexto de la Decisión¶
El proyecto evoluciona hacia un sistema de integración cloud-native que necesita:
- Editor visual de flujos propio (React Flow) para orquestar integraciones, ETL y procesos IA
- Runtime cloud-native preparado para Docker → Kubernetes (DragonCloud / CSIC)
- IA integrada con soporte nativo para Ollama, embeddings, RAG
- Long-running processes para entrenamientos LoRA, batch embeddings, etc.
- Java 25 LTS como baseline (virtual threads, structured concurrency)
2. Quarkus vs Spring Boot — Análisis Comparativo¶
2.1 Tabla Comparativa¶
| Aspecto | Spring Boot 3.x | Quarkus 3.20 LTS | Veredicto |
|---|---|---|---|
| Startup nativo | ~2-5s (JVM), ~0.5s (GraalVM con limitaciones) | ~0.02s (nativo), ~1s (JVM) | Quarkus — 10-100× más rápido |
| Memoria | ~150-300 MB | ~30-80 MB (nativo) | Quarkus — 3-5× menos |
| Imagen Docker | ~200-400 MB | ~50-100 MB (nativo) | Quarkus — ideal para K8s |
| Dev Experience | Spring DevTools (restart) | Live coding (true hot-reload sin restart) | Quarkus |
| K8s nativo | Requiere Spring Cloud | Nativo (health probes, configmaps, etc.) | Quarkus |
| Java 25 | ✅ Soporte | ✅ Soporte | Empate |
| Virtual Threads | ✅ (desde Spring 6) | ✅ (desde Quarkus 3.x) | Empate |
| Ecosistema | Masivo (mayor comunidad) | Creciente (Red Hat + comunidad activa) | Spring (pero diferencia se reduce) |
| CDI | Spring DI (propio) | CDI estándar (Jakarta EE) | Quarkus (estándar) |
2.2 Ventajas Clave de Quarkus para IEO¶
- Cloud-native de nacimiento: Diseñado para contenedores y Kubernetes desde el día 1
- Compilación nativa GraalVM: Containers ultra-ligeros para escalar en DragonCloud
- Build-time optimization: Metadatos resueltos en compilación → arranque instantáneo
- Dev Services: Provisión automática de PostgreSQL, Redis, Kafka, ChromaDB en desarrollo
- Extensiones Quarkiverse: Ecosistema curado y cohesivo (LangChain4j, Dapr, gRPC, etc.)
[!IMPORTANT] Recomendación: Quarkus 3.20 LTS como runtime. La dirección es correcta: cloud-native → K8s → DragonCloud. Spring Boot no está diseñado originalmente para este modelo, Quarkus sí.
3. Quarkus + LangChain4j vs Spring AI — Para IA¶
3.1 Comparativa IA¶
| Capacidad | Spring AI 1.0 (Mayo 2025) | Quarkus LangChain4j | Veredicto |
|---|---|---|---|
| Ollama nativo | ✅ OllamaChatModel |
✅ quarkus-langchain4j-ollama + Dev Services auto-pull |
Quarkus (auto-provisión en dev) |
| RAG | ✅ ETL framework + VectorStore | ✅ Easy RAG + embedding stores (ChromaDB, pgvector) | Empate |
| Function calling | ✅ | ✅ con CDI annotations (@Tool) |
Quarkus (más declarativo) |
| Embeddings | ✅ multi-provider | ✅ multi-provider + CLIP | Empate |
| Structured output | ✅ POJO mapping | ✅ POJO mapping con validación Bean | Empate |
| Agentic patterns | 🟡 En desarrollo (roadmap 2025) | ✅ Router, agentes, guardrails | Quarkus (más avanzado) |
| Observabilidad IA | ✅ Micrometer | ✅ OpenTelemetry nativo (logs, métricas, traces) | Quarkus |
| Multi-modelo | ✅ | ✅ + configuración centralizada multi-LLM | Empate |
| GraalVM native | 🟡 Parcial (algunas restricciones) | ✅ Completo | Quarkus |
| Madurez | 1.0 GA (Mayo 2025) | Estable en producción desde 2024 | LangChain4j más probado |
3.2 Ejemplo: Servicio de Identificación IA con Quarkus¶
// Java 25 — Quarkus + LangChain4j + Ollama
@RegisterAiService(modelName = "qwen25-vl")
@SystemMessage("""
Eres un experto en identificación de especies marinas del IEO.
Analiza la imagen y proporciona: especie, familia, edad estimada.
Usa exclusivamente el contexto proporcionado por el Golden Knowledge.
""")
public interface IdentificadorEspecies {
@UserMessage("Identifica esta muestra: {prompt}")
record Identificacion(
String especieNombre,
String familia,
int edadEstimada,
double confianza,
List<String> fuentesConsultadas
) {}
Identificacion identificar(@V("prompt") String prompt, @ImageUrl String imagenUrl);
}
// Uso con virtual threads (Java 25)
@Path("/api/v1/identify")
public class IdentificacionResource {
@Inject IdentificadorEspecies ia;
@POST
@RunOnVirtualThread // Java 25 virtual threads
public Identificacion identificar(MuestraRequest req) {
return ia.identificar(req.descripcion(), req.imagenUrl());
}
}
[!TIP] LangChain4j con Quarkus permite definir servicios de IA como interfaces CDI declarativas — no hay boilerplate. Spring AI requiere más configuración manual.
4. Dapr como Middleware de Integración¶
4.1 ¿Por qué Dapr?¶
Dapr (Distributed Application Runtime) es el middleware perfecto para un sistema de integración como este:
flowchart TB
subgraph App ["Quarkus App (Java 25)"]
API["REST API"]
WF["Workflow Engine"]
AI["Motor IA"]
end
subgraph Dapr ["Dapr Sidecar"]
SI["Service Invocation"]
PS["Pub/Sub"]
SM["State Management"]
WFD["Workflows"]
BIND["Bindings"]
SEC["Secrets"]
end
subgraph Infra ["Infraestructura"]
PG["PostgreSQL"]
REDIS["Redis"]
MINIO["MinIO"]
OLLAMA["Ollama"]
CHROMA["ChromaDB"]
KAFKA["Apache Kafka"]
end
API --> SI
WF --> WFD
AI --> SI
SI --> OLLAMA
SI --> CHROMA
PS --> KAFKA
SM --> REDIS
SM --> PG
BIND --> MINIO
SEC --> PG
style Dapr fill:#9b59b6,color:#fff
style App fill:#2ecc71,color:#fff
4.2 Building Blocks de Dapr Aplicados al IEO¶
| Building Block | Uso en IEO | Ejemplo |
|---|---|---|
| Service Invocation | Comunicación entre microservicios | API → Ollama, API → ChromaDB |
| Pub/Sub | Eventos asíncronos | muestra.creada → genera embeddings → notifica |
| State Management | Estado de procesos largos | Estado del entrenamiento LoRA, progreso ETL |
| Workflows | Orquestación de procesos | Pipeline ETL, entrenamiento IA, carga incremental |
| Bindings | Integración con sistemas externos | SharePoint webhooks, GSheets polling, SIRENO CDC |
| Secrets | Gestión de credenciales | API keys M365, credenciales Oracle, tokens |
4.3 Dapr Workflows para Long-Running Processes¶
// Ejemplo: Workflow de entrenamiento LoRA con Dapr
@DaprWorkflow
public class EntrenamientoLoRAWorkflow extends Workflow {
@Override
public WorkflowStub create() {
return ctx -> {
// 1. Preparar dataset
var dataset = ctx.callActivity(PrepararDataset.class, ctx.getInput(Config.class));
// 2. Iniciar entrenamiento (long-running)
var resultado = ctx.callActivity(EjecutarEntrenamiento.class, dataset)
.withRetryPolicy(maxRetries(3).backoff(Duration.ofMinutes(1)));
// 3. Validar modelo resultante
var validacion = ctx.callActivity(ValidarModelo.class, resultado);
// 4. Si pasa validación → desplegar
if (validacion.precision() >= 0.80) {
ctx.callActivity(DesplegarModelo.class, resultado);
ctx.callActivity(NotificarEquipo.class, "Modelo desplegado con éxito");
} else {
ctx.callActivity(NotificarEquipo.class, "Precisión insuficiente: " + validacion.precision());
}
};
}
}
4.4 Extensión Quarkus-Dapr¶
<!-- pom.xml con Java 25 -->
<properties>
<java.version>25</java.version>
<quarkus.platform.version>3.20.0</quarkus.platform.version>
</properties>
<dependencies>
<!-- Quarkus Core -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest</artifactId>
</dependency>
<!-- IA: LangChain4j + Ollama -->
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-ollama</artifactId>
</dependency>
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-chroma</artifactId>
</dependency>
<!-- Dapr -->
<dependency>
<groupId>io.quarkiverse.dapr</groupId>
<artifactId>quarkus-dapr</artifactId>
</dependency>
<!-- Datos -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-reactive-panache</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-reactive-pg-client</artifactId>
</dependency>
</dependencies>
5. Editor Visual de Flujos (React Flow)¶
5.1 Tecnología: React Flow (@xyflow/react)¶
React Flow es la librería de referencia para editores de grafos/nodos en React. Ideal para construir un editor visual propio integrado en nuestra plataforma:
- Visualizar topologías de integración (fuente → ETL → destino)
- Monitorizar estado de cada nodo (running, success, error, waiting)
- Editar flujos arrastrando y conectando nodos
- Vista 2D con zoom, pan, mini-mapa y agrupación
5.2 Tipos de Nodos para IEO¶
| Categoría | Nodos | Icono |
|---|---|---|
| Fuentes | GSheet, SharePoint, SIRENO, IoT, Copernicus, Camera | 📥 |
| Procesamiento | Validación, Normalización, Chunking, Delta Detection | ⚙️ |
| IA | Embeddings, Ollama Inference, YOLOv11, Foto-ID | 🧠 |
| Almacenamiento | PostgreSQL, ChromaDB, MinIO, Redis | 💾 |
| Notificación | Email, Webhook, Pub/Sub Kafka, Alert | 🔔 |
| Control | Condicional, Loop, Timer, Wait, Approval | 🔀 |
5.3 Arquitectura del Editor Visual¶
flowchart LR
subgraph Frontend ["Frontend (React + React Flow)"]
EDITOR["Editor de Flujos"]
MONITOR["Monitor de Ejecución"]
TOPO["Vista Topología"]
end
subgraph Backend ["Backend (Quarkus + Dapr)"]
API2["API REST"]
ENGINE["Motor de Workflows"]
STATE["Estado (Dapr State)"]
end
EDITOR --> |"guardar flujo"| API2
API2 --> ENGINE
ENGINE --> STATE
STATE --> |"SSE/WebSocket"| MONITOR
MONITOR --> TOPO
style Frontend fill:#3498db,color:#fff
style Backend fill:#2ecc71,color:#fff
5.4 Ejemplo de Flujo Visual: Pipeline ECOMED¶
[GSheet Lance-47] → [Validar Esquema] → [Normalizar] → [Generar Embeddings] → [PostgreSQL]
↘ [ChromaDB]
↘ [Notificar Responsable]
Cada nodo muestra en tiempo real: estado (🟢/🟡/🔴), última ejecución, registros procesados, errores.
6. Java 25 LTS — Beneficios para el Stack¶
Java 25 (LTS, septiembre 2025) aporta capacidades críticas para este stack:
| Feature | JEP | Beneficio para IEO |
|---|---|---|
| Virtual Threads (estable) | JEP 444 (desde J21, maduro en J25) | 1M+ threads concurrentes para inferencias IA paralelas |
| Structured Concurrency | JEP 505 (preview) | Orquestación limpia de pipelines ETL multi-paso |
| Scoped Values | JEP 506 (final) | Contexto de departamento/usuario sin ThreadLocal |
| Pattern Matching | JEP 441+ | Parsing limpio de formatos heterogéneos (CSV, NetCDF, etc.) |
| Records | Estable | DTOs inmutables para respuestas IA, configuración |
| Sealed Classes | Estable | Modelar estados de workflows (Running, Completed, Failed) |
6.1 Sinergia Java 25 + Quarkus + Dapr¶
// Sealed classes para estados de workflow
sealed interface EstadoWorkflow permits Pendiente, Ejecutando, Completado, Error {
record Pendiente(Instant programado) implements EstadoWorkflow {}
record Ejecutando(float progreso, String paso) implements EstadoWorkflow {}
record Completado(int registros, Duration duracion) implements EstadoWorkflow {}
record Error(String mensaje, Instant timestamp) implements EstadoWorkflow {}
}
// Structured concurrency para ETL paralelo
try (var scope = StructuredTaskScope.ShutdownOnFailure()) {
var validacion = scope.fork(() -> validarEsquema(dataset));
var delta = scope.fork(() -> calcularDelta(dataset));
var embeddings = scope.fork(() -> generarEmbeddings(dataset));
scope.join().throwIfFailed();
return new ResultadoETL(validacion.get(), delta.get(), embeddings.get());
}
7. Stack Propuesto Final¶
flowchart TB
subgraph Client ["Cliente"]
WEB["React SPA + React Flow"]
MOBILE["React Native (Expo)"]
end
subgraph Gateway ["API Gateway"]
NGINX["Nginx"]
end
subgraph Core ["Core (Quarkus + Java 25)"]
API3["API REST"]
WF2["Workflow Engine"]
ETL2["ETL Service"]
IA2["IA Service (LangChain4j)"]
end
subgraph Dapr2 ["Dapr Sidecars"]
DS1["Service Invocation"]
DS2["Pub/Sub"]
DS3["State"]
DS4["Bindings"]
DS5["Workflows"]
end
subgraph AI ["Modelos IA"]
OLL2["Ollama (Qwen2.5-VL, OceanGPT)"]
CHR3["ChromaDB"]
end
subgraph Data ["Datos"]
PG2["PostgreSQL + pgvector"]
RD2["Redis"]
MIN2["MinIO"]
KFK["Kafka"]
end
subgraph External ["Fuentes Externas"]
M365["Microsoft 365 (Graph API)"]
SIR2["SIRENO (Oracle)"]
COP["Copernicus CMEMS"]
end
WEB --> NGINX --> API3
MOBILE --> NGINX
API3 --> DS1
WF2 --> DS5
ETL2 --> DS4
IA2 --> DS1
DS1 --> OLL2
DS1 --> CHR3
DS2 --> KFK
DS3 --> RD2
DS3 --> PG2
DS4 --> MIN2
DS4 --> M365
DS4 --> SIR2
DS4 --> COP
style Dapr2 fill:#9b59b6,color:#fff
style Core fill:#2ecc71,color:#fff
style AI fill:#e74c3c,color:#fff
7.1 Resumen del Stack¶
| Capa | Antes (propuesta original) | Ahora (pivote) |
|---|---|---|
| Runtime | Spring Boot / Pekko | Quarkus 3.20 LTS |
| Java | Java 21 | Java 25 LTS |
| Middleware | — | Dapr (sidecars) |
| IA | Spring AI (hipotético) | LangChain4j (nativo Quarkus) |
| Workflows | — | Dapr Workflows + React Flow |
| Messaging | — | Apache Kafka via Dapr Pub/Sub |
| Frontend grafos | — | React Flow (@xyflow/react) |
| Target deploy | Docker Compose | Docker → Kubernetes (DragonCloud) |
8. Respuesta: ¿Es Viable Quarkus + Dapr para IA?¶
[!IMPORTANT] Sí, es viable y en muchos aspectos superior a Spring AI. LangChain4j tiene integración nativa con Quarkus desde 2024, con soporte completo para Ollama, ChromaDB, pgvector, function calling y agentic patterns. El roadmap de Quarkus 4 (GA Nov 2026) prioriza IA como feature principal.
Ventajas clave de esta combinación:
- LangChain4j > Spring AI en madurez de patrones agénticos (ya estable vs roadmap)
- Dapr Workflows resuelve long-running processes (entrenamiento, ETL) sin código custom
- Dapr Bindings para integrar GSheets, SharePoint, SIRENO sin adaptadores propios
- Java 25 Virtual Threads + Quarkus = throughput masivo para inferencias IA paralelas
- Compilación nativa = microservicios de 30 MB que arrancan en 20ms en K8s
- Dapr Pub/Sub + Kafka = eventos asíncronos para pipelines de datos
Único riesgo menor: Spring tiene mayor comunidad, pero LangChain4j (respaldado por LangChain) y Dapr (respaldado por Microsoft/CNCF) son proyectos de primera línea.
Documentos Relacionados¶
| Nivel | Documento | Descripción |
|---|---|---|
| Arquitectura | Arquitectura del Sistema | Stack completo, backend, frontend |
| Arquitectura | Arquitectura IA | Pipeline CAG+RAG, modelos, métricas |
| Arquitectura | MLOps y Workflows Agénticos | MLOps, Dapr Workflow, LangChain4j, sistema agéntico |
| Arquitectura | Viabilidad Pekko→Dapr | Mapeo de actores, FSMs, análisis comparativo |
| Infraestructura | Docker Compose | Servicios Docker (Dapr, Kafka) |
| Investigación | Gobernanza Datasets | Fuentes de datos, carga incremental, auditoría |