Sí, en 2026 puedes meter un modelo de lenguaje dentro de una app Flutter y que responda sin tocar internet. Los modelos pequeños (1B a 4B parámetros), la cuantización a 4 bits y las NPU de los móviles actuales lo han vuelto viable para un conjunto concreto de casos. El paquete flutter_edge_ai acaba de publicar su versión 2.0, que unifica bajo una sola API lo que antes estaba repartido entre plugins sueltos. La pregunta ya no es si se puede, sino si a tu producto le compensa. Y la respuesta honesta, en la mayoría de productos, sigue siendo que no. Este artículo sirve para distinguir los casos en los que sí.
Qué cambió para que esto deje de ser un experimento
Hace dos años, "LLM on-device" significaba modelos de juguete o demos que calentaban el teléfono hasta apagarlo. Lo que ha cambiado es la combinación de tres cosas.
Primero, los modelos pequeños han mejorado mucho. Gemma 3 1B ocupa 529 MB cuantizado a 4 bits y hace prefill a unos 2.585 tokens por segundo en un Samsung Galaxy S24 Ultra, con una ventana de contexto de 2.048 tokens. No es un modelo de frontera, pero para tareas acotadas cumple.
Segundo, los runtimes de inferencia on-device maduraron. LiteRT-LM (el antiguo TensorFlow Lite), MediaPipe y ONNX Runtime corren hoy en iOS, Android y escritorio, y usan GPU y NPU además de CPU.
Tercero, las herramientas de Flutter se consolidaron. flutter_gemma, que fue durante un tiempo la vía habitual, se ha fusionado en flutter_edge_ai: su última versión bajo el nombre antiguo fue la 1.11.4, y a partir de ahí todo vive en el paquete nuevo, ya en la 2.0. Importa menos por el nombre y más por lo que señala: la capa de herramientas dejó de ser un campo de pruebas.
Cuándo tiene sentido y cuándo no
Esta es la parte que decide el proyecto, así que va antes que el código.
On-device gana de verdad en cuatro situaciones. La primera, cuando los datos no pueden salir del dispositivo: historiales médicos, notas personales, documentos internos. Si el dato no viaja, el cumplimiento del RGPD se simplifica, porque no hay un encargado del tratamiento al que auditar ni una transferencia internacional que justificar. No lo elimina, pero reduce la superficie. La segunda, cuando la app tiene que funcionar sin conexión: trabajo de campo, logística, entornos industriales, barcos, zonas sin cobertura. Un modelo en la nube no existe cuando no hay red. La tercera, cuando el coste marginal tiene que ser cero: una vez cargado el modelo, cada inferencia es gratis, y si tienes un volumen alto de llamadas sencillas (clasificar, resumir, extraer), la factura de tokens de un proveedor cloud se dispara mientras la local no se mueve. Y la cuarta, cuando la latencia de ida y vuelta se nota: para autocompletar o sugerir mientras el usuario escribe, el salto a un servidor se percibe y lo local responde al instante.
No te conviene cuando se da cualquiera de estas otras, y aquí es donde toca ser sincero con el cliente. Si necesitas razonamiento complejo o contexto largo, un modelo de 1B a 4B no es Claude ni GPT; cuando la tarea pide seguir instrucciones intrincadas, razonar en varios pasos o tragar documentos enteros, la calidad se queda corta, y la ventana de 2.048 tokens de Gemma 3 1B se llena en nada. Si tienes que soportar gama baja, el runtime pide 4 GB de RAM para ir fino, iOS 15 o superior y minSdk 30 en Android para las features de LiteRT; con una base de usuarios de teléfonos de hace cinco años, los dejas fuera o les das una experiencia peor. Si no puedes permitirte el peso, sumar varios cientos de MB a la descarga tiene un coste de conversión real: cada megabyte extra en la ficha de la store se paga en instalaciones que no ocurren. Y si la nube ya te vale, con una latencia aceptable y un volumen que no te arruina, un modelo grande en servidor te dará mejor calidad con menos dolor de mantenimiento. No te compliques por moda.
La regla que usamos es sencilla: on-device es una decisión de producto, no de tecnología. Si no puedes nombrar cuál de los cuatro motivos de arriba aplica a tu caso, probablemente no lo necesitas.
Cómo se hace, en la práctica
El flujo con flutter_edge_ai 2.0 tiene cuatro pasos: dependencia, inicialización, instalación del modelo e inferencia.
En el pubspec.yaml declaras el paquete y el motor que vayas a usar:
dependencies:
flutter_edge_ai: ^2.0.0
flutter_edge_ai_litertlm: ^1.8.7 # el motor; hay otros (MediaPipe, ONNX)
Inicializas una vez al arrancar, indicando los motores de inferencia:
await FlutterEdgeAi.initialize(
inferenceEngines: const [LiteRtLmEngine()],
);
Descargas e instalas el modelo, desde una URL o empaquetado en la app:
await FlutterEdgeAi.installModel(
modelType: ModelType.gemmaIt,
fileType: ModelFileType.litertlm,
).fromNetwork(
'https://huggingface.co/litert-community/Gemma3-1B-IT/...',
).install();
Y ya puedes abrir una conversación y generar respuesta, con streaming token a token:
final model = await FlutterEdgeAi.getActiveModel(maxTokens: 2048);
final chat = await model.createChat();
await chat.addQueryChunk(Message.text(text: 'Resume este ticket', isUser: true));
await for (final token in chat.generateChatResponseAsync()) {
// pinta cada token según llega
}
Dos trampas que cuestan una tarde si no las sabes de antemano. La primera: maxTokens es la ventana de contexto completa, no la longitud de la respuesta, así que si quieres acotar la salida tienes que limitarla aparte. La segunda: en Message, el campo isUser vale false por defecto, de modo que si se te olvida marcarlo el modelo trata tu pregunta como si la hubiera dicho él y la conversación se descarrila.
Los números con los que decides
| Modelo | Tamaño (cuant.) | Function calling | Visión/audio | Notas |
|---|---|---|---|---|
| Gemma 3 1B | ~529 MB | — | — | 2.048 tokens de contexto, ~2.585 tok/s prefill |
| Gemma 4 E2B / E4B | mayor | sí | sí | modo "thinking" disponible |
| Gemma 3n E2B / E4B | mayor | — | sí | multimodal |
| Qwen3 0.6B | el más ligero | sí | — | thinking; buen punto de partida |
| DeepSeek R1 | grande | sí | — | razonamiento; pesa |
La matriz de plataformas también condiciona. LiteRT-LM cubre Android, iOS, macOS, Windows y Linux, y la web solo a medias; MediaPipe añade web pero se queda en móvil; ONNX Runtime cubre casi todo. En web con .litertlm te quedas solo con texto y function calling, sin visión, audio ni LoRA. Elige el motor por la plataforma que de verdad vas a enviar, no por la que suena mejor.
Más allá del chat
Correr el modelo es lo fácil. Lo que convierte esto en producto es el resto.
Para que el modelo responda sobre tus datos sin inventarse nada necesitas RAG, y aquí también es local: flutter_edge_ai_rag con flutter_edge_ai_qdrant o SQLite para los embeddings y la búsqueda vectorial, todo en el dispositivo. Es la misma arquitectura que montarías en servidor, pero sin servidor. Si vienes de implementar RAG en la nube, el modelo mental es idéntico.
El function calling permite que el modelo invoque funciones de tu app (buscar en la agenda, crear un evento) en vez de solo generar texto. Lo soportan Gemma 4, Qwen3 y DeepSeek R1. Sumado a la voz on-device, con reconocimiento, síntesis y un bucle de push-to-talk que trae el propio paquete, tienes la base de un asistente que funciona en modo avión. Es el mismo patrón de agentes que aplicamos en proyectos de empresa, llevado al borde.
El coste que no aparece en el tutorial
Ningún tutorial te cuenta la parte cara, así que la decimos nosotros.
El tamaño de la app se dispara: varios cientos de MB entre runtime y modelo. O lo empaquetas y la descarga inicial duele, o lo bajas en el primer arranque y gestionas el estado de "aún descargando" sin frustrar al usuario.
La fragmentación de dispositivos multiplica el QA. Un modelo que vuela en un iPhone reciente puede arrastrarse o quedarse sin memoria en un Android de gama media. Hay que probar en hardware real y variado, no en el emulador.
La batería y el calor son reales. La inferencia sostenida consume y calienta el dispositivo. Para ráfagas cortas no pasa nada; para uso continuo, hay que medir antes de prometer.
Y actualizar el modelo no se parece a cambiar un endpoint. Mejorar la calidad implica distribuir pesos nuevos a cada dispositivo, con su descarga y su versionado. Lo que en la nube es un despliegue, en local es una actualización que viaja hasta el bolsillo del usuario.
Qué haríamos nosotros
Para la mayoría de los productos, hoy, un modelo en la nube sigue siendo la respuesta correcta: mejor calidad, mantenimiento más simple y nada de arrastrar medio gigabyte. On-device sigue siendo un nicho con casos muy concretos, aunque el marketing lo pinte como el futuro por defecto de las apps.
Cuando el caso cae en uno de los cuatro motivos (privacidad dura, offline real, volumen que hace sangrar la factura, latencia de interacción inmediata), deja de ser una curiosidad y pasa a ser la decisión de arquitectura acertada. El error habitual es tratarlo como un adorno de marketing, "IA en tu bolsillo", en vez de como lo que es: una restricción de producto que se resuelve con la herramienta adecuada.
Si estás en ese punto y dudas entre on-device, nube o un híbrido (modelo pequeño local para lo inmediato, grande en servidor para lo difícil), es exactamente la conversación que tenemos con los equipos antes de escribir una línea. Somos Partner oficial de Flutter de Google desde 2017 y trabajamos la IA aplicada a producto, no a la demo. Si quieres contrastar tu caso, hablemos.




