Saltar a contenido

← 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:

  1. Editor visual de flujos propio (React Flow) para orquestar integraciones, ETL y procesos IA
  2. Runtime cloud-native preparado para Docker → Kubernetes (DragonCloud / CSIC)
  3. IA integrada con soporte nativo para Ollama, embeddings, RAG
  4. Long-running processes para entrenamientos LoRA, batch embeddings, etc.
  5. 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

  1. Cloud-native de nacimiento: Diseñado para contenedores y Kubernetes desde el día 1
  2. Compilación nativa GraalVM: Containers ultra-ligeros para escalar en DragonCloud
  3. Build-time optimization: Metadatos resueltos en compilación → arranque instantáneo
  4. Dev Services: Provisión automática de PostgreSQL, Redis, Kafka, ChromaDB en desarrollo
  5. 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:

  1. LangChain4j > Spring AI en madurez de patrones agénticos (ya estable vs roadmap)
  2. Dapr Workflows resuelve long-running processes (entrenamiento, ETL) sin código custom
  3. Dapr Bindings para integrar GSheets, SharePoint, SIRENO sin adaptadores propios
  4. Java 25 Virtual Threads + Quarkus = throughput masivo para inferencias IA paralelas
  5. Compilación nativa = microservicios de 30 MB que arrancan en 20ms en K8s
  6. 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