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
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í
- Shared Business Logic es Crítico: El 70% del código era lógica de negocio duplicada
- Testing es 2x Más Complejo: Dos test suites, dos sets de bugs, dos deploys
- 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.