Brownie — l'IA embarquée sur Android

Projet personnel · Kotlin, Jetpack Compose, LiteRT-LM · code source sur GitHub

Problème

Tout assistant IA réellement capable sur un téléphone est un client léger. Le modèle réside dans le datacenter d'un tiers, la conversation fait l'aller-retour, et l'ensemble cesse de fonctionner dans un avion ou derrière le pare-feu d'une entreprise. La confidentialité y est une promesse inscrite dans une politique, non une propriété du système.

Je voulais savoir ce qu'il restait vraiment si l'on refusait tout cela — non pas une démonstration de chatbot, mais un véritable agent qui appelle des outils, lit et écrit des fichiers, se souvient d'une session à l'autre et pilote l'appareil, en tournant entièrement sur le matériel que l'on a dans la poche.

Contrainte

Un téléphone n'est pas un serveur. Il n'y a pas de swap digne de ce nom, le budget mémoire est partagé avec toutes les autres applications en cours d'exécution, et une inférence soutenue se heurte directement à la limitation thermique. Les poids du modèle, la couche d'outils, l'historique de conversation et l'interface doivent tenir dans ce qu'un appareil Android de milieu de gamme peut céder — et l'interface doit rester réactive pendant que le modèle travaille.

La seconde contrainte était volontaire, et plus difficile : aucun recours au cloud. Une conception hybride qui appellerait discrètement un modèle distant dès que l'appareil peine aurait rendu chaque démonstration plus fluide et détruit la raison même de ce projet.

Décisions

Résultat

120 fichiers Kotlin répartis sur cinq modules, 200 commits. Appels d'outils multi-tours, jusqu'à dix itérations par message, réponses en streaming avec des étiquettes d'appel d'outil dans l'interface, outils de fichiers dans un espace de travail cloisonné, contacts, agenda, presse-papiers, tâches autonomes planifiées, lecture de l'écran et automatisation de l'appareil via les API d'accessibilité, extraction web via une WebView, et la parole dans les deux sens.

Sans cloud, sans clé d'API, sans aucune donnée qui quitte le téléphone. Après le téléchargement du modèle, effectué une seule fois, le moteur se charge en cinq à quinze secondes et l'application fonctionne réseau coupé.

Ce que je ferais autrement

La couche d'outils a fini par dépasser l'application. :core:tools est devenu plus gros que le module d'interface — quarante-quatre fichiers contre quarante et un — parce que chaque nouvelle capacité signifiait une implémentation de plus compilée dans le binaire. Le client MCP ajouté en v6 a la bonne forme, et c'est par là que je commencerais : un jeu réduit d'outils intégrés pour ce qui a réellement besoin d'un accès au processus, et tout le reste derrière un serveur d'outils modifiable sans publier d'APK. J'ai tracé cette frontière trop tard ; elle aurait dû être la première.