Blog
Sécurité

IA air-gapped : exécuter des LLM entièrement hors ligne avec Ollama

Une architecture pratique pour une IA sans connectivité sortante : Ollama comme LLM local, LanceDB pour les vecteurs, rédaction DLP sur chaque prompt, le tout dans un conteneur hors ligne.

Simmetric Team7 min de lecture28/05/2026

Pourquoi l'air-gap est une forme de déploiement, pas un flag de fonctionnalité

La plupart des produits d'IA « self-hosted » laissent quand même fuir des données. Un appel à une API de modèle ici, une requête d'embedding là, un ping de télémétrie, une vérification de licence qui rentre à la maison - chacun défendable isolément, et ensemble ils signifient que vos documents internes, vos prompts et vos réponses traversent une frontière réseau que vous ne contrôlez pas. Pour les sous-traitants de la défense, les hôpitaux, les banques et toute organisation soumise à une obligation de résidence des données, c'est éliminatoire. L'exigence n'est pas « presque hors ligne » - c'est un système d'IA qui fonctionne avec le câble réseau débranché.

Simmetric Chat est construit autour de cette exigence. Le fonctionnement air-gapped n'est pas un mode à débloquer ni un plugin à acheter : la configuration par défaut de la plateforme communautaire est déjà celle du hors ligne - un LLM local, des embeddings locaux, un store vectoriel local basé fichier et une pipeline documentaire qui n'a jamais besoin d'Internet. Cet article déroule chaque couche qui rend fonctionnelle la connectivité zéro sortant, et ce à quoi vous renoncez - très peu - en fermant le périmètre.

La pile locale : chaque couche a un défaut hors ligne

Une chat IA a quatre dépendances externes dans une architecture SaaS typique : le modèle de langage, le modèle d'embedding, le store vectoriel et la pipeline documentaire. Les défauts de Simmetric Chat remplacent les quatre par des composants locaux :

  • Le LLM tourne dans Ollama. Le provider par défaut de la plateforme est Ollama sur le réseau local, et le modèle par défaut (gemma4:latest) est téléchargé au moment de l'installation pour que le chat fonctionne avant tout téléchargement de modèle à l'exécution. Ollama parle HTTP compatible OpenAI sur votre propre réseau, et la configuration du provider pointe vers lui avec une URL - pas un endpoint cloud.
  • Les embeddings tournent en local. Le provider d'embedding par défaut est un modèle transformers local (384 dimensions, exécuté in-process dans le collector), pas une API d'embeddings hébergée. Les embeddings locaux sont compatibles air-gap par construction, et la garde de mismatch d'embeddings signifie que passer de providers locaux à distants plus tard est sûr - le retrieval dégrade vers une recherche par mots-clés jusqu'à la fin de la ré-indexation plutôt que de servir des scores issus d'espaces mélangés.
  • Les vecteurs vivent dans LanceDB. Le store vectoriel par défaut est basé fichier, conservé dans le répertoire de stockage du déploiement, avec une collection par workspace. Pas de serveur de base de données vectorielle, pas de saut réseau. Qdrant, pgvector et Chroma restent disponibles pour les équipes dont l'échelle réclame un index en réseau, mais rien ne les impose.
  • Le parsing des documents se fait dans votre réseau. Le collector - le service qui parse, découpe et embedde les uploads - fait partie de votre déploiement. PDF, fichiers Word et Excel, présentations et transcriptions YouTube sont traités à l'intérieur du périmètre, y compris les documents scannés routés via la pipeline OCR à modèle vision côté serveur, qui utilise un modèle vision local.

Rien dans cette liste n'est traité de façon spéciale ni ajouté après coup. Le pattern stratégie à chaque frontière fait de l'option locale simplement le provider par défaut, sélectionné par configuration comme n'importe quel autre.

DLP : rédaction avant que quoi que ce soit ne sorte - ou avant même que ça ne bouge

Fermer la connectivité sortante ne ferme pas tous les chemins d'exfiltration, parce que les contenus circulent aussi à l'intérieur de votre réseau : les prompts entrent dans la plateforme, les réponses sortent vers les utilisateurs, et les deux traversent des interfaces de chat depuis lesquelles les gens copient. Le filtre data-loss-prevention de Simmetric Chat scanne les deux directions - le prompt entrant et la réponse sortante, y compris les flushs de streaming token par token - et rédige les correspondances avant que le contenu ne soit stocké ou affiché.

Le scanner reconnaît les classes de PII qui comptent dans un contexte de chat : adresses email, numéros de carte de crédit, clés API et clés privées, et - ajoutés en v0.22 - les identifiants européens structurés : Partita IVA italienne, codice fiscale et IBAN, semés comme patterns intégrés idempotents et ancrés sur l'étiquette pour que les nombres ordinaires ne les déclenchent jamais. La configuration des patterns est gérée par l'admin et adossée à la base de données : activez ou désactivez n'importe quel pattern, ajoutez jusqu'à cinquante patterns personnalisés avec validation de compilation en direct et aperçu de test, et inspectez un panneau d'historique des correspondances filtré par source.

L'intention de conception est que le DLP soit la dernière ligne, pas la première. La première ligne est l'architecture : avec des modèles locaux, des embeddings locaux et des vecteurs locaux, il n'existe aucun endpoint tiers où un contenu sensible puisse arriver en premier lieu. Le DLP couvre ensuite les chemins qui restent - le contenu qui quitte la plateforme vers vos propres utilisateurs, ou qu'un employé bien intentionné colle dans un prompt. Il couvre aussi la surface du widget, pour que les conversations destinées aux visiteurs sur votre site soient rédigées par la même chaîne de filtres, avec la trace d'audit qui distingue le trafic chat du trafic widget.

Le déploiement en conteneur unique : tout sur un seul hôte

Fermer le périmètre est une chose ; faire entrer le logiciel dans un périmètre en est une autre. Les environnements air-gapped ne peuvent généralement pas exécuter confortablement une pile compose à cinq services - ils font tourner un hôte avec une seule image, et moins il y a de pièces mobiles, moins il y a d'artefacts à vérifier et à transférer.

Simmetric Chat livre une image all-in-one en conteneur unique exactement pour ce cas. Un conteneur, supervisé par un gestionnaire de processus, exécute tout : PostgreSQL 16 (avec l'extension pgvector compilée depuis les sources au build de l'image, donc installée hors ligne), le serveur API, le collector documentaire et le service widget. Le conteneur expose trois ports - 3000 pour l'API, 3210 pour le collector, 3211 pour le widget - et sonde sa propre santé sur l'endpoint /api/health, qui rapporte l'état de la base, du collector et du disque.

Faire entrer l'image relève de la même discipline que n'importe quel autre artefact : transférez la tarball de l'image (ou le miroir de registry que vous avez validé), chargez-la et exécutez-la. Les défauts d'environnement de l'image sont des placeholders d'échafaudage - la production remplace JWT_SECRET, COLLECTOR_SECRET et la clé de chiffrement via la configuration d'environnement, et le serveur échoue bruyamment au boot si les secrets de production manquent, pour qu'un déploiement air-gap à moitié configuré ne démarre jamais en silence. Après le boot, les mises à jour logicielles sont de nouvelles versions d'image, pas des installations de paquets - aucun accès Internet requis à aucun moment du cycle de vie.

bash
# Transférez dans le périmètre, puis :
docker load -i simmetric-chat-all-in-one.tar
docker run -d \
-p 3000:3000 -p 3210:3210 -p 3211:3211 \
-v simmetric-storage:/app/storage \
-e JWT_SECRET=$(openssl rand -hex 32) \
-e COLLECTOR_SECRET=$(openssl rand -hex 32) \
simmetric-chat:all-in-one

Les poids des modèles suivent le même chemin. Les modèles Ollama sont téléchargés sur une machine connectée, enregistrés comme blobs et importés à l'intérieur du périmètre - la plateforme les traite ensuite comme n'importe quel autre modèle local. Rien dans la pile ne rentre à la maison pour vérifier un modèle, une licence ou lui-même : la télémétrie est désactivée par défaut, il n'y a aucune dépendance externe de remontée d'erreurs, et la validation de licence est une vérification locale de signature RS256 contre une clé publique embarquée.

Ce qui fonctionne encore hors ligne - et ce qui manque vraiment

Un déploiement air-gapped se doit d'être honnête sur ses marges. Ce qui fonctionne avec une connectivité zéro sortant :

  • Chat avec des LLM locaux via Ollama, streamé token par token en SSE
  • Upload et ingestion de documents - parsing, chunking, embeddings locaux, vecteurs LanceDB
  • Retrieval hybride avec citations, filtrage par métadonnées et pipelines de synthèse
  • RBAC, workspaces, projets, pistes d'audit et toute la surface d'administration
  • Webhooks (livrés à vos propres récepteurs), Web Push (VAPID depuis votre propre serveur) et clés API
  • Le widget embarquable, exécuté contre votre propre service widget

Ce qui manque vraiment : les providers LLM cloud, les embeddings hébergés, la recherche web externe et tout ce qui exige un appel sortant. La conception en dégradation gracieuse signifie que chacune de ces intégrations est un ajout de configuration, pas une modification de code - mais le défaut hors ligne est simplement livré sans elles. La plateforme démarre, sert les requêtes et traite les documents de manière identique, que le périmètre soit ouvert ou fermé.

Le résultat est un workspace IA dont la posture de sécurité ne dépend pas de la confiance dans la gestion des données d'un fournisseur, parce qu'il n'y a aucun fournisseur dans le chemin des données. Tout ce qui touche vos documents - le modèle, les embeddings, l'index vectoriel, le parser - tourne sur du matériel que vous possédez, à l'intérieur d'un réseau que vous contrôlez, dans une image de conteneur que vous pouvez auditer.

Lire le guide complet dans la doc →

Articles associés