Agentes IA Nativos Cross-Platform: Del Silo iOS/Android al Futuro Unificado

Como las nuevas tecnologías de IA cross-platform están revolucionando el desarrollo mobile: de mis migraciones iOS→Android a los agentes nativos unificados

kotlin-multiplatform ios android ai-agents compose-multiplatform swift coreml mobile-ai

Han pasado casi dos años desde que empecé a migrar aplicaciones iOS complejas a Android, y la industria acaba de dar un salto cuántico. Con el anuncio de la WWDC26 y iOS 27 enfocado en “avances de IA”, más las nuevas herramientas como Koog para Compose Multiplatform, estamos presenciando el fin de los silos de IA mobile.

Después de migrar más de 180K líneas de código entre Leonard AI (Swift → Kotlin) y ChutApp (dual development), tengo una perspectiva única sobre lo que significa este cambio. No es solo otra framework más — es la convergencia de arquitecturas que llevaba años esperando.

El Problema que Llevamos Arrastrando

Cuando arranqué la migración de Leonard AI de iOS a Android el año pasado, me enfrenté al problema clásico del desarrollo mobile con IA: duplicar todo. No solo la UI, sino toda la lógica de inferencia, manejo de modelos, pipelines de datos, y lo que más duele — la lógica de negocio específica de IA.

Leonard AI: El Caso Real

Leonard es un SaaS de gestión para centros de estética con 104K líneas de Swift. La app iOS incluye:

  • Reconocimiento de imagen para análisis de piel (CoreML)
  • Sistema de recomendaciones personalizadas (algoritmo propio + OpenAI)
  • Chat inteligente con contexto médico (RAG con embedding local)
  • Predicción de resultados de tratamientos (TensorFlow Lite)

Migrar esto a Android significó:

// iOS: CoreML + Vision framework
import CoreML
import Vision

func analyzeSkin(image: UIImage) async throws -> SkinAnalysis {
    let model = try SkinAnalysisModel(configuration: MLModelConfiguration())
    let request = VNCoreMLRequest(model: model.model) { request, error in
        // Procesamiento específico iOS
    }
    let handler = VNImageRequestHandler(ciImage: CIImage(image: image)!)
    try handler.perform([request])
}
// Android: TensorFlow Lite + ML Kit
import org.tensorflow.lite.Interpreter
import com.google.mlkit.vision.common.InputImage

class SkinAnalyzer {
    private val interpreter = Interpreter(loadModelFromAssets())
    
    suspend fun analyzeSkin(bitmap: Bitmap): SkinAnalysis {
        val inputImage = InputImage.fromBitmap(bitmap, 0)
        // Reimplementar toda la lógica de inferencia
        return processInference(inputImage)
    }
}

Dos codebases. Dos modelos. Dos pipelines. Dos sets de bugs.

Lo que más me frustró fue reescribir el sistema RAG para el chat médico. En iOS usaba CoreML para embeddings locales:

// iOS: Embeddings locales con CoreML
class MedicalRAG {
    private let embeddingModel: MLModel
    private let vectorStore: LocalVectorStore
    
    func generateResponse(query: String) async -> Response {
        let queryEmbedding = try await embeddingModel.prediction(from: query)
        let similarDocs = vectorStore.search(embedding: queryEmbedding)
        return generateWithContext(query: query, docs: similarDocs)
    }
}

En Android tuve que usar TensorFlow Lite y reinventar todo:

// Android: Mismo concepto, implementación desde cero
class MedicalRAG {
    private val embeddingInterpreter: Interpreter
    private val vectorStore: LocalVectorStore
    
    suspend fun generateResponse(query: String): Response {
        val queryEmbedding = computeEmbedding(query)
        val similarDocs = vectorStore.search(queryEmbedding)
        return generateWithContext(query, similarDocs)
    }
}

Seis meses de trabajo para llegar al mismo sitio.

La Convergencia que Estaba Esperando

Los anuncios de esta semana lo cambian todo. Apple confirma que iOS 27 tendrá “grandes avances en IA”, mientras JetBrains desvela Koog — un framework que permite construir agentes de IA que corren nativamente en Compose Multiplatform.

Pero esto va más allá del típico “write once, run anywhere”. Hablamos de arquitecturas de IA verdaderamente unificadas.

Koog: El Primer Vistazo

Según lo que se ha filtrado de KotlinConf 2026, Koog permite definir agentes de IA que se ejecutan nativamente en Android, iOS y desktop. La clave está en su arquitectura basada en subgrafos:

// Arquitectura unificada de agente con Koog
class UnifiedMedicalAgent : KoogAgent {
    override fun buildStrategy(): AgentStrategy = strategy {
        subgraph("skinAnalysis") {
            start { input -> 
                // Lógica de análisis que se adapta al runtime
                when (Platform.current) {
                    Platform.iOS -> useCoreMLAnalysis(input)
                    Platform.Android -> useTensorFlowAnalysis(input)
                    Platform.Desktop -> useONNXAnalysis(input)
                }
            }
            end { analysisResult -> 
                store("skinData", analysisResult)
            }
        }
        
        subgraph("generateRecommendation") {
            dependency("skinAnalysis")
            start { 
                val skinData = retrieve<SkinAnalysis>("skinData")
                generatePersonalizedPlan(skinData)
            }
        }
    }
}

La belleza de este enfoque es que la lógica de negocio del agente es una sola, pero la implementación específica se adapta al runtime.

Arquitectura Real: Leonard AI Reimaginado

Tomemos el caso real de Leonard AI y veamos cómo se vería con arquitecturas unificadas de IA.

Antes: Duplicación Total

iOS App (Swift)                 Android App (Kotlin)
├── SkinAnalysisService         ├── SkinAnalysisService  
├── RecommendationEngine        ├── RecommendationEngine
├── MedicalRAGChat             ├── MedicalRAGChat
├── TreatmentPredictor         ├── TreatmentPredictor
└── LocalVectorStore           └── LocalVectorStore

Después: Agente Unificado

// Compose Multiplatform + Koog
@Composable
fun LeonardMedicalApp() {
    val agent = remember { LeonardMedicalAgent() }
    val state by agent.state.collectAsState()
    
    LaunchedEffect(Unit) {
        agent.initialize()
    }
    
    when (state.currentPhase) {
        AgentPhase.SkinAnalysis -> SkinAnalysisScreen(
            onImageCaptured = { image -> 
                agent.process("analyzeSkin", image)
            }
        )
        AgentPhase.Recommendations -> RecommendationScreen(
            recommendations = state.recommendations,
            onTreatmentSelected = { treatment ->
                agent.process("selectTreatment", treatment)
            }
        )
    }
}

class LeonardMedicalAgent : KoogAgent {
    override fun buildStrategy(): AgentStrategy = strategy {
        // Análisis de imagen
        subgraph("skinAnalysis") {
            start { image: ImageData ->
                val analyzer = createPlatformAnalyzer()
                analyzer.analyze(image)
            }
            end { result -> 
                updateUI("analysisComplete", result)
            }
        }
        
        // Generación de recomendaciones
        subgraph("generateRecommendations") {
            dependency("skinAnalysis")
            start {
                val analysis = retrieve<SkinAnalysis>("analysisResult")
                val medical = RecommendationEngine()
                medical.generatePlan(analysis, getUserProfile())
            }
        }
        
        // Chat médico contextual
        subgraph("medicalChat") {
            start { query: String ->
                val rag = MedicalRAG()
                val context = buildContext(
                    skinAnalysis = retrieve("analysisResult"),
                    selectedTreatments = retrieve("treatments"),
                    userHistory = getUserMedicalHistory()
                )
                rag.chat(query, context)
            }
        }
    }
}

// Implementación específica por plataforma
expect fun createPlatformAnalyzer(): SkinAnalyzer

// iOS implementation
actual fun createPlatformAnalyzer(): SkinAnalyzer = 
    CoreMLSkinAnalyzer()

// Android implementation  
actual fun createPlatformAnalyzer(): SkinAnalyzer = 
    TensorFlowSkinAnalyzer()

El RAG Unificado

Una de las partes más potentes es cómo maneja el contexto médico:

class UnifiedMedicalRAG {
    private val embeddingEngine = createPlatformEmbedding()
    private val vectorStore = LocalVectorDB()
    
    suspend fun chat(query: String, context: MedicalContext): Response {
        // El contexto incluye análisis de piel, historial, tratamientos
        val enrichedQuery = """
        Pregunta del usuario: $query
        
        Análisis de piel actual: ${context.skinAnalysis.summary}
        Tratamientos recomendados: ${context.treatments.joinToString()}
        Historial relevante: ${context.history.lastTreatments}
        Contraindicaciones: ${context.contraindications}
        """
        
        val embedding = embeddingEngine.embed(enrichedQuery)
        val relevantDocs = vectorStore.search(embedding, limit = 5)
        
        return generateResponse(enrichedQuery, relevantDocs)
    }
}

// Contexto compartido entre plataformas
data class MedicalContext(
    val skinAnalysis: SkinAnalysis,
    val treatments: List<Treatment>,
    val history: UserMedicalHistory,
    val contraindications: List<String>
) {
    fun buildContext(): String = """
        Contexto médico completo:
        - Tipo de piel: ${skinAnalysis.skinType}
        - Problemas detectados: ${skinAnalysis.issues.joinToString()}
        - Tratamientos previos efectivos: ${history.effectiveTreatments}
        - Alergias conocidas: ${contraindications.joinToString()}
    """
}

Performance: Los Números Reales

En mis migraciones iOS→Android, siempre hay una pregunta: ¿el rendimiento se mantiene?

Leonard AI: Antes y Después

iOS nativo (Swift + CoreML):

  • Análisis de imagen: ~180ms
  • Embedding generación: ~50ms
  • RAG query completa: ~300ms

Android nativo (Kotlin + TensorFlow Lite):

  • Análisis de imagen: ~220ms (+22%)
  • Embedding generación: ~75ms (+50%)
  • RAG query completa: ~380ms (+27%)

Proyección con arquitectura unificada:

  • Análisis: ~180ms iOS, ~220ms Android (sin cambio)
  • Embedding: ~50ms iOS, ~75ms Android (sin cambio)
  • RAG query: ~300ms iOS, ~380ms Android (sin cambio)
  • Ventaja: 80% menos código, misma performance

La clave es que la abstracción está a nivel de arquitectura del agente, no a nivel de inferencia. Cada plataforma sigue usando sus motores nativos optimizados.

Migración Práctica: De Silos a Unified

Para equipos que ya tienen apps iOS/Android con IA, la migración no es trivial, pero es estratégica.

Paso 1: Identificar Lógica Compartible

No todo se puede unificar de inmediato. En Leonard AI identifiqué:

Unificable (80%):

  • Lógica de negocio del agente
  • Pipelines de datos
  • Contexto y estado
  • UI components básicos

Platform-specific (20%):

  • Modelos de inferencia (CoreML vs TensorFlow)
  • Acceso a cámara/sensores
  • Optimizaciones específicas de performance

Paso 2: Arquitectura por Capas

// Capa 1: Agente unificado (Koog)
class UnifiedMedicalAgent : KoogAgent { ... }

// Capa 2: Servicios platform-agnostic
class RecommendationEngine {
    fun generatePlan(analysis: SkinAnalysis): TreatmentPlan
}

// Capa 3: Abstracciones de plataforma
expect class InferenceEngine {
    suspend fun analyze(input: ImageData): AnalysisResult
}

// Capa 4: Implementaciones nativas
actual class InferenceEngine {
    // iOS: CoreML implementation
    // Android: TensorFlow implementation  
}

Paso 3: Migración Incremental

La belleza de Compose Multiplatform es que puedes migrar pantalla por pantalla:

// Pantalla migrada
@Composable
fun UnifiedSkinAnalysisScreen() {
    // Lógica compartida
}

// Pantalla legacy (iOS)
struct LegacySkinAnalysisViewController: UIViewController {
    // Seguir usando mientras migras
}

// Pantalla legacy (Android)
class LegacySkinAnalysisActivity : ComponentActivity {
    // Seguir usando mientras migras
}

Lecciones de ChutApp: Dual Development

ChutApp fue diferente — decidimos desarrollar iOS y Android en paralelo desde día uno. 42K LOC de Swift + 43K LOC de Kotlin para la misma funcionalidad.

La app incluye ML para análisis de jugadas de fútbol, predicción de resultados, y sistema de recomendaciones. Mantener dos implementaciones coherentes fue un infierno.

Lo que Aprendí

  1. Shared Business Logic es Crítico: El 70% del código era lógica de negocio duplicada
  2. Testing es 2x Más Complejo: Dos test suites, dos sets de bugs, dos deploys
  3. Feature Parity se Rompe Constantemente: iOS siempre 2-3 features adelante

Con una arquitectura unificada, esto sería:

// ChutApp reimaginado
class FootballAnalysisAgent : KoogAgent {
    override fun buildStrategy() = strategy {
        subgraph("playAnalysis") {
            start { videoClip: VideoData ->
                val analyzer = createPlatformVideoAnalyzer()
                analyzer.analyzePlay(videoClip)
            }
            end { playData -> 
                store("currentPlay", playData)
                emit("playAnalyzed", playData)
            }
        }
        
        subgraph("playerRecommendations") {
            dependency("playAnalysis") 
            start {
                val play = retrieve<PlayData>("currentPlay")
                val recommender = PlayerRecommendationEngine()
                recommender.generateSuggestions(play, getTeamData())
            }
        }
        
        subgraph("matchPrediction") {
            start { matchData: MatchContext ->
                val predictor = MatchPredictor()
                predictor.predict(matchData, getHistoricalData())
            }
        }
    }
}

Una codebase. Un modelo mental. Un deploy.

El Factor iOS 27

Apple no ha soltado detalles, pero el timing no es casualidad. Con Google empujando KMP + Compose Multiplatform, Apple necesita una respuesta.

Mi predicción es que iOS 27 traerá:

  • APIs unificadas para IA on-device
  • Mejor interop con frameworks cross-platform
  • Herramientas mejoradas para migración

Si esto se confirma, será el momento perfecto para arquitecturas híbridas: native performance + unified business logic.

Kunoa: El Laboratorio Real

Kunoa es mi aplicación más compleja de IA — salud/nutrición con RAG avanzado. iOS + Web + Python backend + OpenAI + Pinecone.

La app genera planes nutricionales personalizados basados en:

  • Historial médico del usuario
  • Preferencias alimentarias
  • Objetivos de salud
  • Restricciones/alergias
  • Datos biométricos (integración HealthKit)

Arquitectura Actual vs. Unificada

Actual (Fragmentada):

iOS App (Swift)          Web App (Next.js)     Backend (Python)
├── HealthKit           ├── Web APIs          ├── RAG Pipeline
├── Local RAG           ├── Client RAG        ├── OpenAI Integration
├── Nutrition Engine    ├── Nutrition UI      ├── Pinecone Vector DB
└── Plan Generator      └── Plan Display      └── Business Logic

Con Agentes Unificados:

class NutritionAgent : KoogAgent {
    override fun buildStrategy() = strategy {
        subgraph("gatherHealthData") {
            start { 
                val health = createPlatformHealthCollector()
                health.collectData(last30Days = true)
            }
        }
        
        subgraph("analyzeNeeds") {
            dependency("gatherHealthData")
            start { 
                val data = retrieve<HealthData>("healthMetrics")
                val analyzer = NutritionalNeedsAnalyzer()
                analyzer.analyze(data, getUserGoals())
            }
        }
        
        subgraph("generatePlan") {
            dependencies("gatherHealthData", "analyzeNeeds")
            start {
                val needs = retrieve<NutritionalNeeds>("analysis")
                val generator = PlanGenerator()
                val context = buildNutritionContext(needs, getRestrictions())
                generator.createPlan(context)
            }
        }
        
        subgraph("ragConsultation") {
            start { question: String ->
                val plan = retrieve<NutritionPlan>("currentPlan") 
                val rag = UnifiedNutritionRAG()
                rag.consult(question, buildPlanContext(plan))
            }
        }
    }
}

// Platform-specific health collectors
expect class HealthCollector {
    suspend fun collectData(last30Days: Boolean): HealthData
}

// iOS: HealthKit
actual class HealthCollector {
    suspend fun collectData(last30Days: Boolean): HealthData {
        val store = HKHealthStore()
        // HealthKit implementation
    }
}

// Android: Health Connect
actual class HealthCollector {  
    suspend fun collectData(last30Days: Boolean): HealthData {
        val client = HealthConnectClient.getOrCreate(context)
        // Health Connect implementation
    }
}

RAG Contextual Avanzado

La parte más potente de Kunoa es el sistema RAG que entiende contexto nutricional completo:

class UnifiedNutritionRAG {
    private val vectorStore = PineconeVectorStore()
    private val embeddingEngine = createPlatformEmbedding()
    
    suspend fun consult(
        question: String, 
        context: NutritionContext
    ): ConsultationResponse {
        
        val enrichedQuery = """
        Pregunta: $question
        
        Contexto del usuario:
        - Objetivos: ${context.goals.joinToString()}
        - Restricciones: ${context.restrictions.joinToString()}
        - Plan actual: ${context.currentPlan.summary}
        - Progreso reciente: ${context.recentProgress}
        - Métricas de salud: ${context.healthMetrics.summary}
        - Preferencias: ${context.foodPreferences.joinToString()}
        
        Historial de consultas previas: ${context.previousQuestions.takeLast(3)}
        """
        
        val embedding = embeddingEngine.embed(enrichedQuery)
        val relevantDocs = vectorStore.query(
            vector = embedding,
            filter = mapOf(
                "category" to context.relevantCategories,
                "user_restrictions" to context.restrictions
            ),
            topK = 8
        )
        
        return generateContextualResponse(enrichedQuery, relevantDocs, context)
    }
    
    private suspend fun generateContextualResponse(
        query: String,
        docs: List<Document>,
        context: NutritionContext  
    ): ConsultationResponse {
        
        val prompt = """
        Eres un nutricionista experto. Responde a la pregunta basándote en:
        
        1. Documentación médica relevante: ${docs.joinToString("\n")}
        
        2. Contexto específico del usuario:
           ${context.buildDetailedContext()}
        
        3. Plan nutricional actual:
           ${context.currentPlan.detailedBreakdown()}
        
        Pregunta: $query
        
        Proporciona una respuesta personalizada que:
        - Considere las restricciones específicas del usuario
        - Se alinee con sus objetivos de salud actuales  
        - Incluya recomendaciones actionables
        - Mencione cualquier ajuste necesario al plan actual
        """
        
        return OpenAIService.chat(prompt)
    }
}

Performance en Producción: Números Reales

Después de 18 meses con Leonard AI en producción (300 centros), tengo métricas concretas sobre performance de IA mobile.

Infraestructura Actual

iOS (CoreML + Local RAG):

  • Cold start: 1.2s
  • Análisis de imagen: 180ms
  • RAG query: 300ms
  • Memory footprint: 45MB

Android (TensorFlow Lite):

  • Cold start: 1.8s (+50%)
  • Análisis de imagen: 220ms (+22%)
  • RAG query: 380ms (+27%)
  • Memory footprint: 52MB (+16%)

Con Arquitectura Unificada (Proyección)

Benefits:

  • Codebase: -70% líneas de código
  • Development time: -60%
  • Bug surface: -50%
  • Performance: Sin degradación (usa engines nativos)

Trade-offs:

  • Binary size: +15% (Kotlin runtime)
  • Cold start: +200ms (KMP overhead)
  • Learning curve: Alta (nueva arquitectura)

Migración Real: Plan de 6 Meses

Para equipos que quieren migrar a arquitecturas unificadas, este es mi plan basado en experiencia real:

Mes 1-2: Foundation

// Setup inicial
commonMain {
    dependencies {
        implementation("org.jetbrains.compose:compose-multiplatform:$version")
        implementation("io.koog:koog-agent:$version") // Cuando esté disponible
        implementation("app.cash.sqldelight:sqlite-driver:$version")
    }
}

// Primeras abstracciones
expect class PlatformInferenceEngine
expect class PlatformVectorStore  
expect class PlatformHealthData

Mes 3-4: Core Agent

// Agent básico
class CoreMedicalAgent : KoogAgent {
    override fun buildStrategy() = strategy {
        // Migrar subgraph por subgraph
        subgraph("dataCollection") {
            start { collectBasicData() }
        }
    }
}

Mes 5-6: UI + Testing

// UI unificada 
@Composable
fun UnifiedMainScreen() {
    val agent = LocalAgent.current
    val state by agent.state.collectAsState()
    
    // Shared UI logic
}

// Testing cross-platform
class AgentTests {
    @Test
    fun testDataCollection() = runTest {
        val agent = TestAgent()
        agent.process("collectData")
        assertEquals(expected, agent.currentState)
    }
}

Errores que NO Cometas

Después de 180K líneas migradas, estos son los errores que más duelen:

1. Big Bang Rewrite

❌ No hagas esto:

// Migrar toda la app de una vez
class GiantUnifiedAgent : KoogAgent {
    override fun buildStrategy() = strategy {
        // 47 subgraphs que reimplementan todo
    }
}

✅ Haz esto:

// Migración incremental
class LegacyBridge {
    fun migrateScreen(screenName: String) {
        when (screenName) {
            "skinAnalysis" -> UseUnifiedAgent()
            else -> UseLegacyImplementation()
        }
    }
}

2. Abstracciones Prematuras

❌ No abstraigas todo:

// Súper genérico pero inútil
expect class UniversalAIEngine<T, R> {
    suspend fun process(input: T): R
}

✅ Abstracciones específicas:

// Específico para tu dominio
expect class MedicalImageAnalyzer {
    suspend fun analyzeSkin(image: ImageData): SkinAnalysis
}

3. Ignorar Platform Strengths

// iOS tiene CoreML optimizado, úsalo
actual class MedicalImageAnalyzer {
    suspend fun analyzeSkin(image: ImageData): SkinAnalysis {
        // Use CoreML, not a generic ONNX wrapper
        return CoreMLSkinAnalyzer().analyze(image)
    }
}

El Futuro: 2026 y Más Allá

Con WWDC26 en junio y iOS 27 prometiendo “grandes avances en IA”, más las herramientas como Koog madurando, veo tres escenarios:

Escenario 1: Apple Abraza Cross-Platform

Apple mejora la interop de CoreML con frameworks cross-platform. Resultado: performance nativa + unified development.

Escenario 2: Google Domina con KMP

Kotlin Multiplatform se convierte en el estándar de facto. Apple responde con mejores herramientas, pero KMP gana momentum.

Escenario 3: Híbrido Emergente

Arquitecturas híbridas donde la lógica de negocio es unified pero la inferencia permanece nativa para maximum performance.

Mi apuesta: Escenario 3. Performance matters demasiado en mobile AI para comprometerla por developer convenience.

Conclusión: El Punto de Inflexión

Hemos llegado al punto de inflexión. Después de años duplicando esfuerzos entre iOS y Android, finalmente tenemos la tecnología para unified AI architectures sin sacrificar performance.

No es solo about escribir menos código — es about pensar en agentes de IA como entidades coherentes que adaptan su comportamiento al runtime, no como implementaciones fragmentadas por plataforma.

Mi experiencia migrando Leonard AI y desarrollando ChutApp me dice que este es el momento. Las herramientas están maduras, la performance es viable, y la complejidad de nuestras apps de IA ya justifica el investment.

En Leonard AI, nuestro próximo sprint incluye un prototipo con Koog. Si los early results son prometedores, migraremos toda la lógica de agentes para Q3 2026.

¿El riesgo? Apostar por tecnologías que aún están en beta.

¿La recompensa? Unified AI agents que finalmente permiten que la lógica de negocio sea el foco, no las implementaciones platform-specific.

La era de los silos de IA mobile está terminando. Y era hora.


¿Estás planificando migrar a arquitecturas unificadas de IA? Los errores en este post me costaron 6 meses extra en Leonard AI. No los repitas.