Encore de l’IA, désolé mais c’est le mot valise à la mode … mais là, on parle d’IA à la maison, celle qui tourne sur une machine, dans mon lab, et qui n’envoie rien à personne. Vous le savez, je suis transparent là-dessus depuis le début : j’utilise Mistral et Claude (anciennement Mammouth) pour accélérer, corriger, relire le blog, et pour coder mes petits outils. Mais au fond, ça me titille depuis un moment (et j’expérimente depuis plusieurs mois) : Est-ce qu’un simple Mac mini peut faire tourner un modèle correct ? Et surtout, est-ce que je peux me passer d’un abonnement et garder mes données chez moi (souveraineté, quand tu nous tiens ^^) ?

Alors j’ai décidé d’apprendre pas à pas, et de vous embarquer avec moi dans une petite série d’articles. J’ai d’ailleurs déjà fait une première install un peu à l’arrache il y a quelques jours, ça marchait… mais j’avais envie de comprendre en détail ce que je faisais. Donc j’ai tout effacé, et on repart de zéro, proprement. Au programme de ce premier chapitre : Ollama pour faire tourner le modèle, Open WebUI pour avoir une jolie interface de chat façon ChatGPT, mais chez soi, et SearXNG pour que tout ce petit monde puisse chercher sur le web.

Beaucoup de gens se diront qu’on connait tous ça depuis des années … mais encore une fois, à défaut d’une vraie formation, un série d’articles qui rentrent pas à pas dans le mise en oeuvre d’une infra sur lequel on va progresser tous en semble me parait une bonne idée aujourd’hui. Ne serait-ce que pour maîtriser toute la terminologie et les concepts associés à ce domaine encore nouveau mais qui amorce déjà une vraie rupture technologique et sociétale.

Le plan de bataille

L’idée est simple, et elle parlera à tous ceux qui font de l’infra : on sépare le moteur et l’interface. D’un côté, jarvis, mon Mac mini M4, fait tourner le modèle avec Ollama ; de l’autre, viviane, mon hôte Docker habituel, sert l’interface Open WebUI en Docker Compose. Comme ça, les 16 Go de jarvis sont réservés au modèle, et l’interface vit tranquillement avec le reste de mes conteneurs.

Un Mac mini, vraiment ?

Sur un PC classique, le modèle doit tenir dans la mémoire de la carte graphique (la VRAM), souvent 8 ou 12 Go sur une carte grand public. Sur un Mac Apple Silicon, la mémoire est unifiée : le CPU et le GPU piochent dans la même RAM. Mon M4 a 16 Go, et le GPU peut en utiliser une bonne partie pour le modèle. Ce n’est pas une bête de course (on en reparlera dans un chapitre dédié au matériel), mais pour démarrer, c’est largement suffisant.

À garder en tête : un modèle de 8 milliards de paramètres, quantifié en 4 bits, pèse environ 5 Go. Il faut ajouter la mémoire du contexte (la « mémoire de travail » de la conversation en général sur Mac Mini on estime que 8k ou 12k est pas mal), et laisser de la place à macOS. Sur 16 Go, un 8B est confortable, un 14B commence à être juste.

Ollama : natif, et pas en conteneur (bouh …)

Moi qui adore les conteneurs, ça me fend le cœur, mais là, non. Sur Mac, Docker tourne dans une petite VM Linux qui n’a pas accès au GPU Apple (à voir avec le nouveau Containerization Framework de Switft depuis Mac OS 26 et 27 ^^). Un Ollama en conteneur ne tournerait que sur le CPU, autant dire au ralenti (je n’ai pas fait de bench, mais à mon avis en inférence ça doit être horrible). Installé en natif, Ollama utilise le GPU via Metal, l’API graphique d’Apple. Donc Ollama en natif, installé avec Homebrew, et tout le reste en Docker sur une deuxième machine (Viviane pour les intimes ^^)

Pour l’install, j’ai voulu le faire entièrement en ligne de commande, pour vraiment comprendre l’outil. Ollama propose aussi une application à télécharger (le fichier Ollama.dmg), c’est le chemin le plus simple si vous débutez, mais vous passerez à côté de pas mal de choses.

Un gros log des commandes, pour les affreux nerds que nous sommes :

Premier modèle

Pour démarrer, j’ai choisi qwen3:8b, de chez Alibaba (5,2 Go). Il sait raisonner (le mode « thinking ») et appeler des outils, et il tient largement dans 16 Go. Ceux qui font du Docker vont se sentir à la maison :

Et la première conversation, avec les statistiques :

À la fin de chaque réponse, Ollama affiche ses stats. Les deux chiffres à regarder : prompt eval rate (la vitesse de lecture de votre question) et eval rate (la vitesse d’écriture de la réponse, en tokens par seconde).

Pendant que le modèle est chargé, dans un autre terminal :

La colonne PROCESSOR doit afficher « 100% GPU ». Si vous voyez du CPU, c’est que le modèle ne tient pas entièrement en mémoire GPU. Les colonnes SIZE et CONTEXT montrent la mémoire prise et la taille du contexte.

Le mode interactif, plein de petites surprises

Dans ollama run, les commandes commencent par un / :

Le test qui m’a le plus appris : poser la même question avec et sans raisonnement.

On peut aussi s’en servir directement depuis le shell, sans mode interactif, et là ça devient scriptable :

Le point qu’on peut retenir ici c’est que le mode « reasoning » est globalement beaucoup plus performant qu’une réponse « sans réflexion » …. ben en fait c’est comme les humains, si on parle sans réfléchir, on a vite fait de dire des co…neries. Et bien c’est vrai pour l’IA et ça se vérifie pour les petits modèles aussi bien que pour les gros ! N’accordez jamais une confiance aveugle à une réponse de l’IA, aussi bluffante soit-elle (et même en code … des exemples perso tous les jours). Le revers de la médaille c’est que ça met plus de temps, forcément.

Gérer ses modèles

Sans stop, Ollama décharge le modèle tout seul après 5 minutes d’inactivité. C’est pour cela que vous pouvez trouver bizarre qu’après une longue période d’inactivité il mette du temps à répondre à sa première question.

Mon propre modèle, avec un Modelfile

Là, je suis surpris par la ressemblance avec Docker : une base, des réglages, un nom.

Mon petit modèle à moi, avec son prompt système spécifique ^^

Ollama est aussi accessible via API, un nouveau monde s’ouvre à vous !

Ollama, c’est surtout une API sur le port 11434. C’est elle qu’utiliseront Open WebUI, et plus tard … (teasing). Elle existe en deux saveurs : l’API native d’Ollama, et une API compatible OpenAI, que la plupart des outils savent déjà utiliser, forcément.

你好 🙂

Les réglages qui changent pas mal le comportement

Par défaut, Ollama n’écoute que sur la machine et utilise un contexte de 4096 tokens. C’est trop court dès qu’on colle un texte un peu long ou des résultats de recherche. On arrête le serveur (Ctrl+C) et on le relance avec nos réglages :

En clair : OLLAMA_HOST le fait écouter sur toutes les interfaces, pour qu’Open WebUI puisse le joindre depuis viviane ; OLLAMA_CONTEXT_LENGTH passe le contexte par défaut à 8192 pour tous les clients ; OLLAMA_FLASH_ATTENTION et OLLAMA_KV_CACHE_TYPE stockent la mémoire du contexte en 8 bits au lieu de 16, soit environ moitié moins de mémoire pour le contexte.

Attention : Ollama n’a AUCUNE authentification. À partir de là, n’importe quelle machine du réseau peut utiliser votre modèle. Et on n’expose évidemment rien sur Internet (ou alors vous savez ce que vous faites ^^).

Pour les mises à jour, RTFM… ou plus simplement : brew upgrade ollama (sur mac en tout cas …)

Open WebUI : l’interface, en Docker Compose sur viviane

Bon, Ollama c’est bien, mais discuter avec un modèle dans un terminal, ça dure deux minutes mais guère plus 🙂 . Open WebUI, c’est l’interface web façon ChatGPT (qu’on connaît depuis le début en 2022), open source, qui se branche sur l’API d’Ollama. On revient en terrain connu, là : Docker Compose, sur la machine Viviane (qui tourne sous Debian Trixie).

Un dossier, un compose, un .env, rien de plus :

Le docker-compose.yml :

Et le .env qui va avec :

Quelques choix assumés : l’image est épinglée sur une version (v0.12.5) et pas sur :main, qui bouge tout le temps, on ne se refait pas ; la WEBUI_SECRET_KEY est fixe ; les données (comptes, conversations, réglages) vivent dans un volume nommé ; et OLLAMA_BASE_URL pointe vers jarvis. Évidemment, le .env ne part jamais dans un dépôt Git (et ne se colle pas dans un article de blog non plus, hein ^^).

Et ils sont … partis !

Une minute de téléchargement, et direction http://viviane:3000.

Premier réflexe, TRÈS important : créer son compte tout de suite. Le premier inscrit devient administrateur. Et dans la foulée, on coupe les inscriptions : Panneau d’administration, Réglages, Général, « Enable New Sign Ups » sur Off.

À savoir : il existe bien une variable ENABLE_SIGNUP=false, mais Open WebUI enregistre ce genre de réglage dans sa base au premier démarrage (ils appellent ça une « PersistentConfig »), et ensuite la variable est ignorée. Donc sur une instance déjà lancée, c’est dans l’interface que ça se passe. Si vous voulez vraiment piloter par l’environnement, il faut ajouter ENABLE_PERSISTENT_CONFIG=false, mais alors plus rien de ce que vous réglez dans l’interface n’est sauvegardé … pas cool.

Le modèle jarvis-qwen3, celui créé plus haut avec le Modelfile, est directement proposé dans le sélecteur.

Au passage, le mode « think » de Qwen3 se règle aussi ici : dans un chat, icône des réglages en haut à droite, Advanced Params, paramètre think (Ollama) ; ou par défaut pour un modèle, dans Panneau d’administration, Réglages, Modèles. Et pour une seule réponse, Qwen3 comprend aussi /no_think à la fin du message.

SearXNG : on donne des yeux à notre IA

Un modèle local, c’est bien, mais il ne connaît que ce qu’il a appris pendant son entraînement. Demandez à Qwen3 la dernière version d’Ollama, il vous répondra avec aplomb… une version d’il y a un an (ou il en inventera une). Pour qu’il sache ce qui se passe dans le monde, il lui faut un moteur de recherche. Et pas question d’aller brancher une API Google ou Bing : on reste chez nous, avec SearXNG, un métamoteur open source auto-hébergé qui interroge plein de moteurs à la fois sans vous pister.

SearXNG rejoint la stack d’Open WebUI, dans le même compose. Pas de port publié : Open WebUI le joint par son nom de service, sur le réseau privé de la stack. On ajoute ce service au docker-compose.yml :

Sans oublier un depends_on: [searxng] sur Open WebUI et le volume searxng-cache: en bas du fichier. SearXNG publie une image par build, avec un tag daté : on épingle, comme pour Open WebUI.

Deux lignes de plus dans le .env :

Et le searxng/settings.yml, réduit au strict nécessaire :

Le vrai test, c’est depuis le conteneur Open WebUI, pour vérifier qu’il joint bien SearXNG par son nom :

Un 200, c’est gagné. Un 403, retour au json ci-dessus.

La recherche web dans Open WebUI, en mode automatique

Reste à dire à Open WebUI de se servir de SearXNG. Là encore, ce sont des réglages enregistrés en base, donc on passe par l’interface plutôt que par des variables.

D’abord, brancher le moteur : Panneau d’administration, Réglages, Web Search. On active la recherche web, on choisit searxng comme moteur, on met http://searxng:8080/search comme URL de requête, et on commence avec 3 résultats (chaque résultat est lu et injecté dans le contexte, donc plus de résultats, c’est plus de mémoire consommée et une réponse plus lente).

Ensuite, le piège dans lequel je suis tombé tête la première lors de ma première install : le Function Calling. En mode « Native », c’est le modèle qui doit décider lui-même d’appeler l’outil de recherche, et avec Qwen3 8B, ça ne marchait pas du tout : il me répondait gentiment (en fait pas vraiment ^^) qu’il ne pouvait pas accéder aux URLs. En mode « Default », c’est Open WebUI qui fait le boulot : il génère la requête, interroge SearXNG, lit les pages et injecte les résultats dans la conversation. Le modèle n’a plus qu’à rédiger. Pour un 8B, c’est nettement plus fiable. Donc : Admin Settings, Models, jarvis-qwen3, Advanced Params, Function Calling sur Default. Attention, ce réglage existe à trois niveaux (modèle, chat, utilisateur) et c’est le plus local qui gagne : vérifiez qu’aucun n’est resté sur Native.

Enfin, pour ne pas avoir à cliquer sur « Web Search » dans chaque conversation, on l’active par défaut sur le modèle, toujours dans Modèles, jarvis-qwen3 : on coche Web Search dans les Capabilities, et on l’active aussi dans les Default Features. Désormais, chaque nouvelle conversation avec ce modèle part avec la recherche web allumée.

Et … ça marche 🙂

Un chouïa laborieux 🙂 … et soyons honnêtes : Open WebUI cherche à chaque message, même pour un simple « bonjour ». Une IA qui décide toute seule quand chercher, ce sera pour plus tard, avec un modèle plus costaud… ou un peu plus de bidouille ^^.

Et cadeau bonus : taper # suivi d’une URL dans le message (par exemple #https://docs.ollama.com/faq) demande à Open WebUI de lire la page pour en discuter. Là, ce n’est pas SearXNG qui travaille, mais le « Web Loader » d’Open WebUI.

Les soucis qui m’ont pris du temps …

Parce qu’un tuto sans galère, ça n’existe pas :

– Dans les logs de SearXNG, des erreurs ahmia: can't register engine et torch: can't register engine. Rien de grave : ce sont deux moteurs du réseau Tor, qui ne peuvent pas se charger sans proxy Tor. On les retire avec inactive: true dans le settings.yml.
– Toujours dans les logs, missing config file: /etc/searxng/limiter.toml. Sans gravité non plus, puisque le limiter est désactivé. Un touch searxng/limiter.toml fait taire l’avertissement.
– SearXNG qui répond 403 à Open WebUI : le format json n’est pas activé.
– ENABLE_SIGNUP qui ne fait rien : le réglage est déjà en base, c’est l’interface qui commande.
– Qwen qui jure ne pas pouvoir lire les URLs : Function Calling en Native, à passer en Default.
– Les réponses qui ignorent la moitié des résultats de recherche : contexte trop court, d’où OLLAMA_CONTEXT_LENGTH=8192 côté Ollama.

On passe à la suite ?

Pour résumer ce premier chapitre : un Mac mini qui fait tourner Qwen3 8B sur son GPU grâce à Ollama, une interface Open WebUI en Docker Compose sur mon autre petit serveur, et un SearXNG à côté pour que tout ce petit monde puisse chercher sur le web, sans qu’aucune donnée ne sorte de chez moi (enfin, à part les requêtes de recherche elles-mêmes). Oui c’est laborieux (je l’ai déjà dit), oui tout ça pour ça … mais en fait c’est le début qui ne donne pas grand chose. Les prochains chapitres seront beaucoup plus intéressants, je vous le promets !

Si je vous dis workflow … n8n … notifications d’alerte de logs suspects sur le canal de votre choix … c’est déjà plus sexy, non ? … et toujours via une IA locale bien entendu…

Je suis en train d’écrire les chapitres 2 et 3 qui sortiront au fur et à mesure, sans doute la semaine prochaine.

Références :

– Ollama : https://ollama.com (documentation macOS : https://docs.ollama.com/macos
– FAQ Ollama : https://docs.ollama.com/faq)
– Modèle qwen3 : https://ollama.com/library/qwen3
– Open WebUI : https://docs.openwebui.com
– Open WebUI sur GitHub : https://github.com/open-webui/open-webui
– SearXNG : https://docs.searxng.org
– vBlog.io : Le gardien des parchemins numériques et son UDM Beast !

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *