Créer avec l’IA

Comment transformer un point de contrôle de modèle en application fonctionnelle?

Écrit en date du · Publié le · Mis à jour le · Par Robert Scales, avec l’aide d’outils d’IA · 5 min de lecture

Réponse courte

Emballez les poids dans un format sûr avec une configuration, une version et une empreinte, vérifiez qu’ils donnent les mêmes nombres que le point de contrôle d’entraînement, puis enveloppez le tout dans un petit serveur avec des limites d’entrée et une vérification d’état, et mesurez la latence sous charge. Dans une exécution mesurée, un tout petit modèle a servi six requêtes par seconde et, avec 16 personnes en même temps, chacune a attendu 2,6 secondes en valeur médiane.

Un point de contrôle est un fichier de nombres qui n’a de sens qu’avec le code et les réglages exacts qui l’ont produit. Une application est quelque chose qu’une personne peut utiliser un mauvais jour sans lire votre carnet de notes. L’écart entre les deux est mince pour un petit modèle, et il relève surtout de soins logiciels ordinaires.

Ce projet prend le tout petit modèle du projet six et lui fait traverser cet écart. Le script 14_checkpoint_to_app.py fait chaque étape, puis arrête son serveur, en n’utilisant que la bibliothèque standard de Python, PyTorch et safetensors, à l’adresse locale de cet ordinateur (127.0.0.1). Il a pris 26 secondes sur un Apple M5 Max.

Étape 1 : l’emballer

Un point de contrôle créé avec torch.save utilise le format pickle de Python, et charger un pickle peut exécuter du code arbitraire. safetensors ne stocke que les tenseurs. Le script y enregistre les poids et écrit une petite description à côté.

import hashlib, json
from pathlib import Path
from safetensors.torch import load_file, save_file

def sha(path):
    return hashlib.sha256(Path(path).read_bytes()).hexdigest()

def package(state, cfg, chars, folder):
    Path(folder).mkdir(parents=True, exist_ok=True)
    state = {k: v.clone() for k, v in state.items() if k != "out.weight"}   # partagé avec tok.weight
    save_file(state, f"{folder}/model.safetensors")
    meta = {"name": "mini-gpt-anne", "version": "1.0.0", "cfg": cfg, "chars": chars,
            "limits": "Écrit du charabia façon roman. Pas pour les faits.",
            "sha256": sha(f"{folder}/model.safetensors")}
    Path(f"{folder}/model.json").write_text(json.dumps(meta, ensure_ascii=False))

La ligne limits compte. Quiconque reprendra ce modèle plus tard doit apprendre par le fichier lui-même à quoi il ne doit pas servir. Si vous prévoyez de le partager, la licence et la fiche du modèle ont leurs propres étapes.

La taille a à peine changé : 3,29 Mo pour le point de contrôle d’entraînement et 3,28 Mo une fois emballé. Les points de contrôle plus gros qui stockent aussi l’état de l’optimiseur rétrécissent davantage, puisque l’application n’a besoin que des poids.

Étape 2 : prouver que c’est le même modèle

Trois tests, tous courts. Gardez-les avec l’application et exécutez-les à chaque changement.

TestMéthodeMesuré ici
Mêmes nombresComparer les sorties du point de contrôle et du modèle emballé sur une entrée aléatoirePlus grand écart : 0,0
Même texteMême prompt et même graine, deux foisIdentique
Refus des dommagesInverser un bit dans une copie du fichier, puis chargerRefusé : l’empreinte ne correspond pas

Étape 3 : l’envelopper dans un petit serveur

Le serveur a trois routes : / pour une petite page Web, /health pour vérifier l’état et /generate pour le modèle. L’essentiel de son code ne concerne pas du tout le modèle. Il concerne ce qu’une requête a le droit de demander.

MAX_CHARS, MAX_PROMPT = 400, 200

def do_POST(self):
    length = int(self.headers.get("Content-Length", 0))
    if self.path != "/generate":
        return self.send(404, {"error": "introuvable"})
    if length > 2000:
        return self.send(413, {"error": "requête trop volumineuse"})
    try:
        req = json.loads(self.rfile.read(length))
        prompt, n, seed = str(req.get("prompt", "")), int(req.get("chars", 100)), int(req.get("seed", 1))
    except (ValueError, TypeError):
        return self.send(400, {"error": "envoyez du JSON avec prompt et chars"})
    if not prompt or len(prompt) > MAX_PROMPT or not 1 <= n <= MAX_CHARS:
        return self.send(422, {"error": f"prompt de 1 à {MAX_PROMPT} caractères, chars de 1 à {MAX_CHARS}"})
    with LOCK:                               # une génération à la fois; les autres attendent
        text = generate(model, meta, prompt, n, seed)
    self.send(200, {"text": text, "version": meta["version"]})

Sans les limites, une demande de 99 999 caractères monopoliserait la machine aux dépens de tout le monde. Résultats des tests sur le vrai serveur : une bonne requête a renvoyé 200, un prompt vide 422, trop de caractères 422 et un chemin inconnu 404. La réponse passée par le serveur correspondait exactement au texte enregistré plus tôt, ce qui prouve aussi que toute la chaîne fonctionne.

La documentation de Python prévient que http.server n’est pas recommandé en production, puisqu’il n’applique que des contrôles de sécurité de base. C’est un bon outil d’apprentissage, sur votre propre machine. Ne l’exposez pas à Internet.

Étape 4 : le mesurer avec plusieurs personnes à la fois

Une seule personne ne vous apprend pas grand-chose. Mesuré ici sur le processeur, avec 100 caractères générés par requête. p50 est l’attente médiane : la moitié des requêtes ont été plus rapides. p95 est l’attente subie par la plus lente sur vingt.

Personnes en même tempsRequêtesAttente médianeAttente p95Requêtes par secondeErreurs
1200,164 s0,169 s6,170
4400,707 s0,745 s5,600
16802,642 s2,813 s6,090

Le débit reste stable à environ six par seconde et l’attente croît avec le nombre de personnes. Cela vient directement de la ligne LOCK : les requêtes font la file et rien n’échoue. C’est la première forme normale d’un modèle en service. Vos options sont de regrouper plusieurs requêtes en lot, d’exécuter plusieurs copies ou de générer moins de caractères. Le processus a culminé à 250 Mo. Pour un vrai modèle de langage, un serveur spécialisé comme vLLM ou llama.cpp s’occupe des lots et de la diffusion en continu, et ces quatre mêmes étapes s’appliquent toujours.

À essayer : retirez le LOCK du serveur, relancez le test de charge et comparez les requêtes par seconde et les erreurs au tableau. Décidez ensuite si vous le garderiez et notez pourquoi.

Que manque-t-il encore avant que de vraies personnes l’utilisent?

Ce projet s’arrête à une démonstration locale, et rien de ce qui suit n’a été testé. Avant de laisser quiconque de l’extérieur utiliser une application de ce genre, il vous faut :

DomaineQuoi ajouter
AccèsUne connexion ou une clé, des limites par personne et un serveur de production avec connexions chiffrées
Vie privéeUne décision sur ce que vous journalisez. Les prompts peuvent contenir des renseignements personnels : gardez-en le moins possible et, au Québec, vérifiez vos obligations en vertu de la Loi 25
SécuritéUn énoncé clair de la raison d’être du modèle. Des tests avec des entrées hostiles et bizarres. Une personne à joindre
Mises à jourLa version dans chaque réponse, un moyen de revenir à la version précédente, des tests à réussir d’abord
SurveillanceLa latence, les erreurs et un échantillon humain régulier des sorties. Un score d’entraînement vieillit à mesure que l’usage réel dérive
HonnêtetéDire aux gens que le texte vient d’un modèle et qu’il peut se tromper

Le modèle est la plus petite partie de ce tableau. C’est le constat habituel à la fin de ce genre de projet : l’entraînement est l’étape visible, et la fiabilité de l’application repose sur tout le travail ordinaire qui l’entoure. La série se termine ici, et la feuille de route plus large peut vous aider à choisir la suite.

Téléchargez le code de cette série (zip), avec tous les scripts et les résultats enregistrés.

Sources

  1. safetensors README — Hugging Face (GitHub), 2 novembre 2026
  2. http.server: HTTP servers — Python
  3. nanoGPT (README) — Andrej Karpathy (GitHub), 12 novembre 2025

Tiré du Guide de l’intelligence artificielle, par Robert Scales, publié par Holistic Hybrid inc. Partage et adaptation permis selon la licence CC BY-NC-SA 4.0 : citez le guide, mettez un lien vers https://guidetoartificialintelligence.com/fr/apprendre/du-point-de-controle-a-application/, pas d’usage commercial sans permission, et gardez la même licence.

Recevez gratuitement le Guide de l’intelligence artificielle

Abonnez-vous à l’infolettre et recevez le guide gratuit : ce qui a changé en IA, une leçon, un prompt à essayer. Désabonnement en un clic.

Ce que nous faisons de votre adresse

Retour en haut

Affichage

Vos choix sont enregistrés dans ce navigateur seulement. Aucune donnée n’est transmise.

Taille du texte
100 %
Couleurs
Lecture
Autres réglages
Déclaration d’accessibilité

Obtenir l’appli

Ajoutez le guide à votre écran d’accueil. Il s’ouvre comme une application, et les pages déjà lues restent disponibles hors ligne.

Lire sans connexion : télécharger les articles

iPhone et iPad (Safari, Chrome, Edge)

  1. Touchez le bouton Partager (le carré avec une flèche). Dans Chrome et Edge, il est dans la barre d’adresse ou le menu.
  2. Choisissez « Sur l’écran d’accueil ».
  3. Touchez « Ajouter ».

Android (Chrome, Edge, Samsung Internet, Firefox)

  1. Ouvrez le menu du navigateur (⋮ ou ☰).
  2. Choisissez « Installer l’application » ou « Ajouter à l’écran d’accueil ».
  3. Confirmez avec « Installer ».

Ordinateur (Chrome, Edge)

  1. Cliquez sur l’icône d’installation au bout de la barre d’adresse, ou ouvrez le menu du navigateur (⋮ ou …).
  2. Dans Chrome, choisissez « Caster, enregistrer et partager », puis « Installer la page en tant qu’application ». Dans Edge, choisissez « Applications », puis « Installer ce site en tant qu’application ».
  3. Cliquez sur « Installer ».

Mac (Safari)

  1. Ouvrez le menu Fichier.
  2. Choisissez « Ajouter au Dock ».
  3. Cliquez sur « Ajouter ».

Firefox sur ordinateur ne peut pas installer un site comme application. Utilisez plutôt Chrome, Edge ou Safari.