23 septembre 2026
Cactus : l'IA locale sur smartphone, mon POC et ses limites

Cactus fait tourner des LLM sur smartphone avec repli vers le cloud. Mon POC : compilation ARM seulement, télémétrie active par défaut, licence payante au-delà de 2 M$.
11 min de lecture
Faire tourner un modèle de langage directement sur un téléphone, sans appel réseau, et n'envoyer au cloud que les questions trop difficiles : c'est la promesse de Cactus, un moteur d'inférence écrit en C/C++ par une startup du batch S25 de Y Combinator (Y Combinator). J'ai cloné le dépôt, tenté de le compiler et lu le code qui compte avant de l'intégrer quelque part. Voici ce que j'en retiens, chiffres de l'éditeur et retours de la communauté à l'appui — dans la même logique que notre guide sur l'adoption de l'IA en 5 étapes d'évaluation : tester avant de généraliser.
À retenir
- Cactus exécute des LLM, de la vision et de la transcription en local sur mobile, avec un repli automatique vers le cloud quand le modèle local doute
- Il ne cible que l'ARM : sur mon serveur Linux x86, la compilation échoue dès le premier fichier, et aucun paquet x86 n'est publié
- La télémétrie est envoyée par défaut ; elle se coupe avec
CACTUS_NO_CLOUD_TELE=1- Ce n'est pas de l'open source au sens strict : gratuit sous 2 M$ de chiffre d'affaires et 2 M$ de levée de fonds, licence commerciale au-delà
- Les chiffres de vitesse viennent de l'éditeur : à revérifier sur vos propres terminaux
Cactus, c'est quoi exactement ?
Cactus se présente comme un « moteur d'IA hybride edge-cloud pour mobiles et objets connectés ». Concrètement, le dépôt empile quatre couches (README) :
- Cactus Engine : l'API haut niveau, compatible avec le format OpenAI, pour le chat, l'appel d'outils, la transcription, les embeddings, le RAG et la vision ;
- Cactus Graph : un graphe de calcul « zero-copy » (sans recopie mémoire entre opérations) ;
- Cactus Kernels : des noyaux de calcul SIMD ARM NEON optimisés pour les puces Apple, Samsung, Pixel ;
- Cactus Quants : une quantification maison par rotation et dictionnaire, de 4 bits jusqu'à 1 bit.
Côté intégration, des bindings existent pour Swift, Kotlin, Flutter, React Native, Python et Rust. Sur Mac, deux commandes suffisent : brew install cactus-compute/cactus/cactus puis cactus run. N'importe quel modèle Hugging Face peut en théorie être converti (cactus convert), mais l'éditeur qualifie lui-même la fonction d'expérimentale ; les familles Gemma, Qwen, Liquid, Whisper et Parakeet sont les plus testées.
Le projet a changé de nature en un an. Lors de son premier Show HN en juillet 2025, présenté comme un « Ollama pour smartphones », il reposait sur llama.cpp embarqué, ce qu'un commentateur n'avait pas manqué de relever (Hacker News). L'équipe répondait alors qu'elle migrerait vers ses propres noyaux. C'est chose faite : je n'ai trouvé aucune trace de llama.cpp ni de ggml dans les sources actuelles.
Le vrai sujet : le routage hybride local/cloud
La partie la plus intéressante n'est pas la vitesse, c'est la décision de quand appeler le cloud. Cactus attache au modèle local une petite sonde d'environ 65 000 paramètres qui lit ses états internes après génération et estime la probabilité que la réponse soit fausse. Au-dessus d'un seuil, la requête part vers un modèle cloud ; en dessous, la réponse locale est servie (docs Cactus Hybrid).
L'éditeur explique pourquoi il n'utilise pas simplement l'entropie des tokens : sur la transcription et les QCM visuels, une forte entropie signale souvent plusieurs réponses valides, pas une erreur. Il annonce une AUROC (capacité à séparer bonnes et mauvaises réponses, 0,5 = hasard, 1 = parfait) de 0,79 à 0,88 sur l'audio, alors que la sonde n'a été entraînée que sur du texte et de l'image. Le modèle cloud de référence de ses tests est Gemini 3.1 Pro.
Ce que j'ai vérifié dans le code (cactus-engine/src/cloud.cpp) : sans clé API configurée (cactus auth ou variable CACTUS_CLOUD_KEY), le moteur journalise un avertissement et garde la réponse locale. Rien ne part vers le cloud par surprise. Avec une clé, les requêtes routées partent par défaut vers l'API de Cactus Compute, modifiable via CACTUS_CLOUD_API_BASE, et CACTUS_DISABLE_CLOUD_HANDOFF=1 coupe le repli. Pour un projet soumis au RGPD, c'est le point à documenter : les requêtes routées quittent le terminal, avec leur contenu — la même vigilance que celle détaillée dans notre article sur le RAG en entreprise sans fuite de données vers un LLM externe.
Les chiffres annoncés
Le README publie ses propres mesures, en quantification CQ4 (4 bits), sans décodage spéculatif. Ce sont des chiffres de l'éditeur, que je n'ai pas pu reproduire faute de matériel ARM dans mon POC :
| Appareil | LLM (prefill / décodage) | Transcription 20 s | RAM |
|---|---|---|---|
| Mac M4 Pro | 1 963 / 101 tok/s | 0,21 s | 1 225 Mo |
| iPhone 17 Pro | 729 / 37 tok/s | 0,51 s | 644 Mo |
| iPhone 15 Pro | 517 / 26 tok/s | 0,82 s | 633 Mo |
Modèle Gemma-4-E2B-CQ4 pour le LLM, Parakeet-TDT-0.6B-CQ4 pour la transcription. Source : README Cactus.
Côté qualité, la quantification 4 bits tient bien : sur Gemma-4-E2B, le score MMLU passe de 62,33 (FP16) à 59,45 en CQ4, et l'appel de fonctions (BFCL Simple) reste à 92. En 2 bits, en revanche, le raisonnement s'effondre : GSM8K tombe de 73,67 à 0,40. Le 1 et 2 bits sont une curiosité, pas une option de production.
Pour un repère extérieur, InfoQ relevait fin 2025, sur la v1 et d'après les chiffres de Cactus, 136 tok/s sur iPhone 17 Pro, 91 sur Galaxy S25 Ultra et 24 sur Raspberry Pi 5, avec de petits modèles de 172 Mo à 1,1 Go (InfoQ). Les écarts avec le tableau ci-dessus s'expliquent par des modèles plus petits : comparer des tok/s sans le modèle et le contexte n'a aucun sens.
Mon POC : ARM ou rien
J'ai cloné le dépôt au commit ec1c106 du 8 septembre 2026 et lancé la compilation des noyaux sur mon serveur de test, un Linux x86_64 à 4 cœurs et 15 Go de RAM, sans GPU. Résultat immédiat :
cc1plus: error: bad value 'armv8.2-a+fp16+simd+dotprod+i8mm' for '-march=' switch
Le CMakeLists.txt des noyaux impose -march=armv8.2-a+fp16+simd+dotprod+i8mm, et les sources incluent arm_neon.h sans alternative x86. Ce n'est pas un bug, c'est un choix assumé :
- le paquet Python
cactus-compute2.2.0 n'est publié que pour macOS arm64 et Linux aarch64 (PyPI) ; - la CI du projet tourne sur des runners
ubuntu-24.04-arm; - le build Android refuse toute ABI autre que
arm64-v8a.
Pour tester, il faut donc un Mac Apple Silicon, un téléphone ARM64 récent ou un serveur ARM (Graviton, Ampere). Un conteneur CI x86 classique ne suffit pas, ce qui compte si vous voulez faire tourner des tests d'intégration.
Télémétrie : activée par défaut
C'est le point qui m'a le plus surpris en lisant cactus-engine/src/telemetry_impl.cpp. À l'initialisation du moteur, la télémétrie s'active et envoie des lots d'événements vers un projet Supabase dont l'adresse est codée en dur dans le moteur. La documentation du moteur le dit d'ailleurs : la télémétrie est « opt-out ».
Ce qui part, d'après le code :
- un identifiant d'appareil (UUID aléatoire stocké localement), le modèle, la marque et la version du système de l'appareil ;
- le nom du modèle d'IA utilisé et les métriques de performance (temps au premier token, tok/s, RAM, score de confiance, nombre de tokens, recours au cloud ou non) ;
- un identifiant de projet dérivé de l'URL du dépôt git, l'identifiant d'application et la version de Cactus.
Je n'ai pas trouvé de prompt ni de réponse dans ces envois. Mais un identifiant d'appareil persistant reste une donnée à déclarer dans la politique de confidentialité d'une app. Pour couper : variable d'environnement CACTUS_NO_CLOUD_TELE=1, ou --no-cloud-tele en ligne de commande. À noter : l'aide de la CLI annonce une option --enable-telemetry « désactivée par défaut », mais elle ne concerne que la commande cactus test.
La licence : le piège pour une entreprise
Cactus se décrit comme « open source », mais sa licence ne l'est pas au sens de l'OSI. L'usage gratuit est réservé aux particuliers, à l'éducation, aux associations et aux organisations qui cumulent moins de 2 M$ de financement total ET moins de 2 M$ de chiffre d'affaires annuel. Au-delà, licence commerciale obligatoire, et si vous franchissez un seuil en cours de route, vous avez 30 jours pour régulariser (LICENSE).
Le changement a fait du bruit. Lors du Launch HN de septembre 2025, plusieurs commentateurs ont relevé que le projet était passé d'Apache 2.0 à une licence restrictive deux semaines plus tôt, parlant de « bait and switch » ; un autre ne trouvait aucune grille tarifaire sur le site (Hacker News). Un développeur d'app payante s'inquiétait aussi du risque juridique en tirant une mise à jour des dépendances.
Pour une TPE, les seuils laissent de la marge. Pour une ESN qui livre une app à un client plus gros, c'est le client final qui compte, et la question doit être tranchée avant d'écrire la première ligne. Le même arbitrage licence/coût revient dans notre comparatif sur l'open source et la réduction du coût d'une pile logicielle PME.
Needle : les petits modèles et leurs limites
L'équipe publie aussi Needle, un modèle de 26 millions de paramètres dédié à l'appel d'outils, lancé via cactus run Cactus-Compute/needle. Sur le Show HN de Needle2 en août 2026, les tests de la communauté sont instructifs : un utilisateur tape « HN » et obtient un appel à lock_door, un autre écrit « I'm hungover » et obtient… lock_door (Hacker News). L'équipe répond que le score de confiance (0 dans l'exemple « HN ») sert justement à filtrer, et un cofondateur résume : « descriptions précises + périmètre d'outils étroit = succès ». Des commentateurs doutent que ce score soit bien calibré sans benchmark publié.
La leçon vaut au-delà de Cactus : un micro-modèle ne sait pas dire « je n'ai pas compris ». Si vous l'utilisez, le seuil de confiance et la liste d'outils fermée font partie du produit, pas du réglage. C'est le même écueil que celui qu'on documente pour les agents IA en développement web : un périmètre mal cadré coûte plus cher à corriger après coup qu'à définir dès le départ.
Pour qui c'est pertinent ?
- Apps mobiles avec données sensibles (santé, notes, documents) : le traitement local par défaut est un vrai argument, à condition de couper la télémétrie et de maîtriser le repli cloud — voir aussi notre article sur l'IA locale en entreprise et la confidentialité des données.
- Usages hors ligne : terrain, transport, zones blanches.
- Coûts d'API à grande échelle : chaque requête servie localement ne coûte rien.
- Moins pertinent si votre stack de test et de déploiement est x86 uniquement, ou si votre client dépasse les seuils de licence sans budget pour une licence commerciale.
Plan d'action
- Vérifiez la licence : chiffre d'affaires et financement de l'entité qui distribuera l'app, pas seulement de votre structure.
- Prévoyez du matériel ARM : un Mac Apple Silicon pour prototyper, un runner CI ARM64 pour les tests.
- Coupez la télémétrie dès l'intégration (
CACTUS_NO_CLOUD_TELE=1), ou déclarez-la dans votre politique de confidentialité. - Lancez
cactus benchmark --iosou--androidsur les vrais téléphones de vos utilisateurs, pas sur un flagship, et comparez aux chiffres du README. - Décidez du repli cloud par écrit : quel fournisseur, quelles données, quel seuil de confiance, et ce que l'app affiche quand le réseau manque.
Vous évaluez une brique d'IA embarquée ou locale pour un projet client ? Parlons-en : 15 minutes suffisent pour cadrer les points de vigilance avant d'écrire la première ligne.
Questions fréquentes
Les réponses courtes aux questions que ces sujets soulèvent le plus souvent.