Modèle / jeu de données
trymirai/uzu avatar
trymirai/uzu

uzu : un moteur d'inférence Rust qui parie sur la mémoire unifiée Apple

A high-performance inference engine for AI models

1 796 étoiles82 forksRustMIT

En bref

De quoi s’agit-il ?
uzu est un moteur d'inférence pour modèles de langage distribué sous licence MIT, avec des liaisons Rust, Python, Swift et TypeScript. Sa promesse tient en trois points : latence locale, données qui ne quittent pas l'appareil, aucune facturation à l'inférence.
À qui s’adresse-t-il ?
uzu convient aux équipes qui embarquent un LLM dans une application iOS, macOS ou de bureau et qui acceptent le catalogue de modèles Mirai comme périmètre. Il ne convient pas à celles qui ont besoin de charger un checkpoint GGUF arbitraire ou de servir un parc de GPU Nvidia hétérogènes : rien dans le matériel fourni n'indique que ces cas soient couverts.
Puis-je l’utiliser commercialement ?
Oui. MIT est une licence permissive : vous pouvez utiliser, modifier et vendre un logiciel qui en dépend, à condition de conserver les mentions de droit d’auteur et de licence.
Est-il encore maintenu ?
Oui. Le dépôt a reçu de nouveaux commits au cours des dernières 24 heures.
En quel langage est-il écrit ?
Principalement Rust, d’après les statistiques de langage de GitHub.

Ces réponses reposent sur les données GitHub du projet (dernière synchronisation le 15 septembre 2026) et sur notre analyse. Elles ne constituent pas un avis juridique.

ANALYSE OPEN SOURCE APPROFONDIE

Le problème visé : sortir l'inférence du serveur

La plupart des intégrations de LLM dans une application passent par un appel réseau vers une API hébergée. Cela impose une connexion, ajoute un aller-retour avant le premier token, fait transiter les données utilisateur par un tiers et transforme chaque requête en ligne de facture. uzu prend le problème par l'autre bout : le modèle est téléchargé sur l'appareil, puis exécuté localement par un moteur écrit en Rust. Le README résume la promesse en trois formules : latence nulle, confidentialité des données, aucun coût d'inférence. Le public visé est donc l'éditeur d'application, pas l'équipe qui exploite un cluster. Les liaisons publiées (Rust, Python, Swift, TypeScript) montrent que la cible est l'application de bureau ou mobile, avec Swift et les plateformes iOS et macOS mis en avant dans les badges du dépôt.

Une API unique, quatre liaisons, un catalogue géré

L'architecture exposée par le README tient en quatre objets : un Engine, un modèle identifié par une chaîne, un downloader asynchrone, et une session de chat. L'Engine est créé une fois à partir d'un EngineConfig. Le modèle est demandé par identifiant, par exemple alibaba:qwen3.5:0.8b:mirai:mirai-m:4, et la méthode engine.model renvoie une option, donc un identifiant inconnu se traduit par une valeur absente plutôt que par une erreur. Le téléchargement est un flux : le code Rust itère sur downloader.next() et lit update.progress(), la version Python itère sur (await engine.download(model)).iterator() et lit update.progress, la version TypeScript fait un for await sur engine.download(model) et lit update.progress. La session de chat prend ensuite une liste de messages construits par des fabriques typées (ChatMessage::system(), ChatMessage::user()) et renvoie des réponses dont on peut extraire deux champs distincts : reasoning et text. Cette séparation entre le raisonnement et le texte final est explicite dans les quatre extraits. Le README mentionne aussi des configurations de modèle unifiées et des calculs traçables pour vérifier la conformité avec l'implémentation de référence, mais sans détailler le format de ces configurations ni le mécanisme de traçage. C'est une lacune documentaire réelle : on sait que le projet s'en sert, on ne sait pas comment l'étendre.

Mémoire unifiée Apple : le choix qui structure tout le reste

Le README indique que le moteur exploite la mémoire unifiée sur les appareils Apple, et les sujets du dépôt incluent metal. Sur une machine où le CPU et le GPU partagent le même espace mémoire, un modèle n'a pas besoin d'être copié d'un pool vers un autre avant l'inférence, ce qui simplifie le chemin de données et réduit la pression sur la mémoire. Ce choix a une contrepartie : il oriente le moteur vers une famille de plateformes. Le README ne décrit pas de backend CUDA, ROCm ou Vulkan, et ne mentionne pas de support Linux ou Windows dans les badges. Une équipe qui doit servir plusieurs GPU Nvidia depuis un binaire unique n'a donc aucune indication que uzu réponde à son besoin. À l'inverse, pour une application macOS ou iOS, ce choix est cohérent avec l'objectif affiché de latence locale.

Mise en route : ce que montrent réellement les extraits

En Rust, la dépendance s'ajoute en pointant sur la branche main du dépôt Git, avec package = "uzu". Les paquets publiés portent des versions : uv add uzu==0.5.26 pour Python, pnpm add @trymirai/uzu@0.5.26 pour TypeScript, et une dépendance Swift Package Manager sur from: "0.5.26". Le décalage entre la dépendance Rust (branche main) et les liaisons versionnées mérite d'être noté : la documentation Rust ne renvoie pas à une version figée du crate. Le flux d'exécution est le même partout. On construit un EngineConfig (EngineConfig::default() en Rust, EngineConfig.create() en Python, en TypeScript et en Swift), on crée l'Engine de façon asynchrone, on résout le modèle, on télécharge avec une boucle de progression, on ouvre une session via engine.chat, on envoie les messages avec session.reply, puis on lit reply.message.reasoning() et reply.message.text(). Le Rust exige un runtime asynchrone, l'extrait utilisant #[tokio::main]. La boucle de téléchargement écrit sur stdout avec un retour chariot et une séquence d'effacement de ligne, ce qui suppose un terminal ; dans une application graphique, cette boucle devra alimenter une barre de progression à la place.

Deux limites que la documentation ne masque pas

Première limite : le catalogue de modèles est celui de Mirai. L'identifiant a une forme normalisée (éditeur:modèle:taille:...), et le lien vers la liste des modèles locaux pointe sur trymirai.com, pas sur un dépôt communautaire. Rien dans le matériel fourni n'indique qu'un fichier de poids produit ailleurs soit chargeable. Pour une équipe qui a déjà converti et validé un modèle en interne, c'est un coût de migration, pas un détail. Deuxième limite : le téléchargement est une étape obligatoire du parcours documenté, pas une option. Le modèle est récupéré à l'exécution depuis le réseau avant la première inférence, ce qui suppose de gérer l'échec réseau, la reprise et l'espace disque. Le README ne décrit pas de mécanisme de reprise ni de vérification d'intégrité. Enfin, le rythme des publications est élevé : trois versions entre le 3 et le 6 septembre 2026, la 0.5.26 étant la plus récente. Un rythme de correctifs aussi serré sur une bibliothèque embarquée dans une application mobile se traduit par des mises à jour de paquet fréquentes côté client, ce qui n'est pas neutre quand la validation passe par une revue d'App Store.

Face à llama.cpp : deux philosophies de distribution

L'alternative la plus évidente pour exécuter un LLM en local est llama.cpp, qui charge des fichiers de poids au format GGUF fournis par l'utilisateur et couvre un large éventail de matériel, CPU comme GPU. La différence d'approche est nette. llama.cpp vous laisse la responsabilité du modèle : vous obtenez le fichier, vous le quantifiez, vous le versionnez. uzu prend cette responsabilité à votre place : le moteur résout un identifiant, télécharge ce que Mirai a préparé, et l'API de chat est déjà au niveau de la conversation avec messages système et utilisateur. Le premier vous donne le contrôle et l'absence de couplage à un catalogue ; le second vous donne un chemin court vers une application qui parle à un modèle. Le choix dépend donc de qui doit décider de l'artefact de poids. Si votre contrainte est de figer un modèle précis pour des raisons de conformité, le catalogue géré devient un obstacle. Si votre contrainte est de livrer une fonctionnalité de chat sans construire de pipeline de conversion, il devient un avantage.

Licence MIT et coût de maintenance

Le dépôt est publié sous licence MIT, et le badge de licence du README renvoie vers le fichier LICENSE. Cette licence est permissive : elle autorise la redistribution et la modification, y compris dans un produit propriétaire, à condition de conserver l'avis de copyright. Elle ne dit rien du statut des poids de modèles téléchargés à l'exécution, qui relèvent de leurs propres conditions, ni des conditions d'utilisation du catalogue Mirai. C'est un point à vérifier séparément avant une mise en production, et je ne peux pas le trancher à partir du matériel fourni. Sur la maintenance, le coût se lit dans la structure du dépôt : les liaisons Python, TypeScript et Swift sont rangées sous crates/legacy/uzu/bindings, ce qui suggère que ces liaisons sont considérées comme héritées par rapport au coeur Rust. Une équipe qui s'appuie sur la liaison Python ou TypeScript devrait donc s'attendre à ce que l'effort principal porte sur le crate Rust. La cadence de publication (0.5.23, 0.5.25, 0.5.26 en quatre jours) indique un projet actif, avec la contrepartie habituelle : un numéro de version qui bouge vite demande une politique de verrouillage de version explicite dans vos manifestes.

Conclusion éditoriale

uzu convient aux équipes qui embarquent un LLM dans une application iOS, macOS ou de bureau et qui acceptent le catalogue de modèles Mirai comme périmètre. Il ne convient pas à celles qui ont besoin de charger un checkpoint GGUF arbitraire ou de servir un parc de GPU Nvidia hétérogènes : rien dans le matériel fourni n'indique que ces cas soient couverts. Avant d'adopter, vérifiez deux points précis dans votre environnement : que Engine::new résout bien le cache de modèles sur le poste cible, et que la liste https://trymirai.com/local-models contient l'architecture que vous comptez exécuter.

Sources officielles

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. trymirai/uzu on GitHub
Notes de la communauté

Notes de la communauté