Réseau agentique IA module 1 : comprendre et faire tourner un modèle
Quatorze séances pour arrêter de voir un modèle comme de la magie. Vous apprenez ce qu'il calcule vraiment, ce que coûtent un token et une fenêtre de contexte, pourquoi la même question donne deux réponses, comment un fichier de 16 Go en devient un de 5 Go, et vous faites tourner deux moteurs locaux sur votre machine en les mesurant. Tout le reste du parcours repose là-dessus.
Les commandes sont écrites pour Linux ou macOS ; sous Windows, utilisez WSL ou leurs équivalents PowerShell. Toutes les adresses des exemples sont locales (127.0.0.1) ou réservées à la documentation (192.0.2.0/24). Les noms de modèles sont des exemples d'actualité en novembre 2026 : vérifiez la page du modèle avant de télécharger, et prenez-en un plus petit si la mémoire manque.
Jour 1 · 03/11 — Ce qu'est un modèle de langage
Objectif : expliquer en deux phrases ce que calcule un grand modèle de langage (LLM), et préparer votre carnet et votre dépôt.
Théorie 1/2 : un prédicteur du token suivant
Un LLM lit une suite de tokens (des morceaux de mots) et produit, pour la position suivante, une probabilité pour chaque token de son vocabulaire. Un programme choisit alors un token, l'ajoute, et redemande. Une réponse entière, c'est cette boucle répétée, un token à la fois. Le modèle n'a pas de base de faits : il a des milliards de nombres (ses poids, ou paramètres) réglés pendant l'entraînement pour que ses prédictions collent à un immense corpus de texte.
L'architecture qu'utilisent presque tous les modèles actuels, le Transformer, a été publiée par des chercheurs de Google en 2017 dans « Attention Is All You Need ». Son idée clé, l'attention, permet à chaque position de pondérer toutes les positions précédentes pour calculer sa prédiction.
Que produit un modèle de langage à chaque étape ?
- Une phrase finie
- Une probabilité pour chaque token suivant possible
- L'adresse d'un fait dans sa base
Réponse
Une distribution de probabilités sur son vocabulaire. Y choisir un token, c'est le travail de l'échantillonneur, hors du modèle.
Quelle architecture, publiée en 2017, utilisent presque tous les LLM actuels ?
Réponse
Le Transformer (« Attention Is All You Need »).
Théorie 2/2 : pourquoi c'est important pour les agents
Deux conséquences vous suivront tout le parcours. D'abord, un modèle produit du texte plausible, pas du texte vérifié : tout ce qui doit être juste (un nombre, un chemin de fichier, le résultat d'une commande) est vérifié par du code. Ensuite, le modèle ne sait que ce qui est dans ses poids et dans le texte que vous lui envoyez maintenant. Un agent est un programme qui donne au modèle le bon texte, le laisse demander des actions, et vérifie ce qu'il fait.
Un modèle annonce avec assurance la version d'une bibliothèque. Vous…
- la vérifiez dans la documentation officielle
- le croyez : il a été entraîné sur la documentation
Réponse
Vérifiez. Plausible n'est pas vérifié, et ses données d'entraînement s'arrêtent à une date.
Pratique (30 min)
- Créez le carnet : un dossier
ainet-notes/, un fichier Markdown par jour (jour-01.md…). - Créez le dépôt où vivra votre code tout le parcours :
mkdir ainet-lab && cd ainet-lab && git init. - Installez uv (gestionnaire de projets Python), puis
uv initdansainet-lab. - Regardez la première partie de « Intro to Large Language Models » d'Andrej Karpathy (2023, en anglais, sous-titres disponibles) et notez trois idées avec vos mots.
- Lisez la section « Apprendre avec une IA comme tuteur » de la page du parcours et écrivez dans
jour-01.mdla règle que vous suivrez.
Avec votre IA : « Tu es un tuteur patient. Je commence un cours sur les LLM locaux et les agents. Pose-moi cinq questions, une à la fois, pour vérifier que je comprends ce que calcule un modèle de langage à chaque étape. Ne donne pas la réponse avant la mienne ; après chaque réponse, dis-moi ce qui est juste, ce qui est faux, et une source que je peux vérifier. »
Synthèse (10 min)
Trois lignes : ce que produit le modèle, ce que fait l'échantillonneur, pourquoi un agent vérifie les résultats par du code. Puis refaites le premier exercice sans notes.
Jour 2 · 04/11 — Les tokens
Objectif : compter des tokens, savoir pourquoi ce ne sont pas des mots, et transformer un nombre de tokens en coût.
Théorie 1/2 : des sous-mots
Les modèles ne lisent ni lettres ni mots, mais des tokens : des fragments fréquents appris sur le texte d'entraînement. La plupart des tokenizers descendent du byte-pair encoding (BPE), appliqué à la traduction neuronale par Sennrich et ses collègues en 2015 (arXiv 1508.07909) : partir des caractères (ou des octets) et fusionner les paires les plus fréquentes jusqu'à une taille de vocabulaire fixée. Un mot anglais courant fait souvent un token ; un mot rare, un mot français accentué, du code ou un long nombre se découpent en plusieurs. Chaque famille de modèles a son tokenizer : le même texte n'a pas le même compte d'un modèle à l'autre.
Le même paragraphe est envoyé à deux familles de modèles. Son nombre de tokens est…
- toujours identique
- souvent différent : chaque famille a son tokenizer
Réponse
Tokenizers différents, comptes différents. Mesurez avec celui du modèle que vous utilisez.
Théorie 2/2 : le token est l'unité de tout
La taille du contexte, la vitesse (tokens par seconde) et les prix des modèles hébergés se comptent en tokens. Les API hébergées facturent en général l'entrée et la sortie à des prix différents, exprimés par million de tokens. En local, vous payez en temps et en électricité, mais le compte décide toujours de ce qui tient.
Écrivez cost(tokensIn, tokensOut, priceIn, priceOut) : les prix sont par million de tokens ; renvoyez le coût.
function cost(tokensIn, tokensOut, priceIn, priceOut) {
}
Réponse
function cost(tokensIn, tokensOut, priceIn, priceOut) {
return (tokensIn * priceIn + tokensOut * priceOut) / 1000000;
}Quel texte coûte en général le plus de tokens par caractère ?
- Une longue empreinte hexadécimale
- Une phrase simple en anglais
Réponse
L'empreinte : des caractères aléatoires correspondent à peu de fragments appris, donc beaucoup de tokens.
Pratique (30 min)
- Regardez les 20 premières minutes de « Let's build the GPT Tokenizer » de Karpathy (2024).
- Ouvrez le chapitre sur les tokenizers du cours LLM de Hugging Face (existe en français) et lisez la partie BPE.
- Dans le carnet, prédisez si chacun fait un token ou plusieurs :
the,anticonstitutionnellement,2026-11-04,def,4f3a9c1e. Vous vérifierez au jour 8 avec le point/tokenizede votre serveur. - Calculez avec votre fonction
costce que coûteraient 200 requêtes de 3 000 tokens en entrée et 500 en sortie, à 1 par million en entrée et 4 par million en sortie.
Avec votre IA : « Explique le byte-pair encoding à un débutant avec un exemple déroulé sur la chaîne 'low lower lowest', en montrant chaque fusion. Puis donne-moi trois chaînes et demande-moi laquelle se découpe en le plus de tokens, et pourquoi. Précise que les vrais comptes dépendent du tokenizer et que je dois les vérifier avec mon modèle. »
Synthèse (10 min)
Trois lignes : ce qu'est un token, pourquoi les comptes diffèrent entre modèles, ce qu'on paie par token. Puis refaites l'exercice cost sans notes.
Jour 3 · 05/11 — La fenêtre de contexte et le cache KV
Objectif : savoir ce qui tient dans un contexte, pourquoi un long prompt est lent avant le premier mot, et ce que garde le cache KV.
Théorie 1/2 : la fenêtre
La fenêtre de contexte est le nombre maximal de tokens que le modèle prend en compte à la fois : vos instructions, la conversation, les résultats d'outils et sa propre réponse, tout ensemble. Au-delà, il faut couper. Un moteur permet aussi de choisir un contexte plus petit que le maximum du modèle (-c dans llama.cpp), car la mémoire grandit avec lui. Tout ce qu'un agent sait pendant un tour est dans cette fenêtre : il n'y a pas d'autre mémoire, sauf si du code en ajoute.
Qu'est-ce qui compte dans la fenêtre de contexte ?
- Seulement votre question
- Seulement la réponse du modèle
- Instructions, historique, résultats d'outils et réponse, ensemble
Réponse
Tout ce qui est dans la conversation, dans les deux sens.
Théorie 2/2 : deux phases, un cache
Répondre se fait en deux phases. Le traitement du prompt (prefill) lit tous les tokens d'entrée d'un coup, en parallèle ; la génération produit les tokens de sortie un par un. Pour ne pas tout recalculer à chaque nouveau token, le moteur garde des résultats intermédiaires pour chaque token passé : le cache KV (les clés et valeurs de l'attention). Il prend une mémoire proportionnelle à la longueur du contexte. Quand le début du prompt suivant est identique, le moteur peut réutiliser la partie en cache et sauter l'essentiel du prefill : c'est pour cela que les agents gardent leurs longues instructions tout au début, sans jamais les changer en cours de session. L'article du site le piège du cache KV montre un cas où une seule option a rendu les réponses 21 fois plus lentes.
Un agent attend 40 secondes avant le premier mot, puis écrit vite. Le coupable probable est…
- une génération lente
- un long prompt en traitement, peut-être sans réutilisation du cache
Réponse
Le prefill. Mesurez le temps jusqu'au premier token à part des tokens par seconde (jour 11).
Pour profiter au mieux du cache, les instructions stables d'un agent vont…
- à la fin de chaque prompt
- tout au début, inchangées
Réponse
Au début : la réutilisation porte sur un préfixe identique.
Pratique (30 min)
- Lisez le piège du cache KV et le plancher de contexte, qui a mesuré où passent les tokens d'un agent.
- Dans le carnet, dessinez un tour d'agent comme une barre : instructions système, descriptions d'outils, historique, nouveau message, réponse. Estimez chaque partie en tokens.
- Notez le contexte maximal de deux modèles que vous pourriez utiliser (sur leur page Hugging Face).
Avec votre IA : « J'apprends le fonctionnement de l'inférence des LLM. Explique la différence entre le traitement du prompt et la génération de tokens, et ce que stocke le cache KV, en moins de 200 mots. Puis teste-moi avec trois affirmations vrai-ou-faux sur les fenêtres de contexte, et corrige-moi en justifiant. »
Synthèse (10 min)
Trois lignes : ce qui remplit la fenêtre, les deux phases, pourquoi un préfixe stable compte. Refaites le deuxième exercice sans notes.
Jour 4 · 06/11 — L'échantillonnage : température, top-p, min-p
Objectif : prévoir l'effet de chaque réglage d'échantillonnage, et choisir les réglages d'un agent.
Théorie 1/2 : des scores à un choix
Le modèle produit un score (logit) par token ; un softmax transforme les scores en probabilités. La température divise les scores avant le softmax : sous 1, la distribution se resserre (le favori gagne plus souvent), au-dessus de 1, elle s'aplatit. La température 0 est en général traitée comme « toujours le token le plus probable » (glouton). Puis des filtres coupent la traîne : top-k garde les k meilleurs, top-p (nucleus sampling, Holtzman et al., 2019) garde le plus petit ensemble dont les probabilités totalisent p, min-p écarte les tokens beaucoup moins probables que le meilleur. La graine (seed) fixe le tirage pour rejouer un essai. Par défaut, llama-server utilise une température de 0,8, top-p 0,95 et min-p 0,05.
Écrivez softmax(logits, t) : divisez chaque logit par la température t, prenez l'exponentielle, normalisez pour que la somme fasse 1.
function softmax(logits, t) {
}
Réponse
function softmax(logits, t) {
const scaled = logits.map(x => x / t);
const max = Math.max(...scaled);
const exps = scaled.map(x => Math.exp(x - max));
const sum = exps.reduce((a, b) => a + b, 0);
return exps.map(x => x / sum);
}Théorie 2/2 : les réglages d'un agent
Un agent qui doit produire un JSON valide ou une commande précise veut peu de hasard : température basse, graine fixe pendant les tests. L'écriture créative en veut plus. Les éditeurs recommandent souvent des réglages sur la page du modèle : partez de ceux-là. Une température basse ne rend pas le modèle juste ; elle le rend constant, y compris constamment faux.
Baisser la température…
- fait gagner plus souvent le token le plus probable
- rend le modèle plus exact
- raccourcit la réponse
Réponse
Elle resserre la distribution. L'exactitude est une autre affaire.
Quel réglage permet de rejouer exactement le même tirage ?
Réponse
La graine (--seed dans llama.cpp).
Pratique (30 min)
- Appliquez votre
softmaxà la main sur[2, 1, 0]aux températures 0,5, 1 et 2 ; notez les trois distributions. - Sur la distribution à 1,0, appliquez top-p 0,9 sur papier : quels tokens restent ?
- Cherchez des réglages d'échantillonnage recommandés sur la fiche du modèle que vous avez choisi (les éditeurs en donnent souvent) et recopiez-les avec le lien, ou notez qu'il n'y en a pas.
Avec votre IA : « Donne-moi cinq situations (extraction en JSON, remue-méninges, génération de code, classification, écriture d'histoire) et demande-moi quelle plage de température je choisirais pour chacune et pourquoi. Puis dis-moi où tu n'es pas d'accord, et rappelle que les réglages recommandés par la fiche du modèle priment sur ton avis. »
Synthèse (10 min)
Trois lignes : ce que font température, top-p et graine. Refaites l'exercice softmax sans notes.
Jour 5 · 07/11 — Les fichiers de modèle : poids, GGUF, licences
Objectif : lire une page de modèle, estimer sa mémoire à partir de son nombre de paramètres, et vérifier sa licence.
Théorie 1/2 : paramètres et octets
Un modèle « 7B » a environ sept milliards de poids. Stockés sur 16 bits (2 octets) chacun, cela fait environ 14 Go avant tout le reste. Les modèles se publient surtout sur le Hub Hugging Face. Pour les moteurs locaux, le format courant est GGUF, introduit par le projet llama.cpp en 2023 : un seul fichier qui contient les poids, le tokenizer et des métadonnées comme le gabarit de chat. Certains modèles sont des mélanges d'experts (MoE), notés par exemple « 35B-A3B » : 35 milliards de poids au total, environ 3 milliards actifs pour chaque token. Tous doivent être en mémoire, mais chaque token calcule avec peu d'entre eux, donc il tourne plus vite qu'un 35B dense.
Écrivez sizeGB(paramsBillion, bitsPerWeight) : la taille des poids en gigaoctets (109 octets).
function sizeGB(paramsBillion, bitsPerWeight) {
}
Réponse
function sizeGB(paramsBillion, bitsPerWeight) {
return paramsBillion * bitsPerWeight / 8;
}Théorie 2/2 : licences et provenance
« Poids ouverts » ne veut dire ni open source, ni libre pour tout usage. Chaque page de modèle indique une licence : Apache 2.0 et MIT sont permissives ; d'autres ajoutent des conditions (seuils d'usage, mention obligatoire, politique d'usage acceptable). Lisez-la avant de construire dessus. Préférez les fichiers de l'éditeur ou d'un convertisseur reconnu, et notez le fichier exact téléchargé.
Un modèle est « à poids ouverts ». Pouvez-vous l'utiliser commercialement ?
- Oui, toujours
- Cela dépend de sa licence : lisez-la
Réponse
La licence décide. « Poids ouverts » dit seulement qu'on peut les télécharger.
Un modèle « 35B-A3B »…
- ne demande la mémoire que de 3 milliards de poids
- demande la mémoire de 35 milliards de poids mais en calcule environ 3 milliards par token
Réponse
Tous les experts sont en mémoire ; seuls quelques-uns travaillent pour chaque token.
Pratique (30 min)
- Ouvrez la page ggml-org/Qwen3.5-0.8B-GGUF et listez ses fichiers et leurs tailles.
- Trouvez la licence du modèle de base Qwen3.5 et notez-la avec le lien.
- Avec
sizeGB, estimez la taille en 16 bits d'un modèle de 0,8B, de 4B et de 9B. Comparez aux vrais fichiers.
Avec votre IA : « Voici le texte d'une licence de modèle : [collez]. Liste en puces ce qu'elle autorise, ce qu'elle interdit et ce qu'elle exige (mention, seuils). Cite la phrase exacte pour chaque point afin que je vérifie. Si quelque chose n'est pas clair, dis-le au lieu de deviner. »
Synthèse (10 min)
Trois lignes : des paramètres aux octets, ce que contient un GGUF, pourquoi la licence compte. Refaites sizeGB sans notes.
Jour 6 · 08/11 — La quantification
Objectif : choisir un niveau de quantification en sachant ce qu'on gagne en mémoire et ce qu'on risque en qualité.
Théorie 1/2 : moins de bits par poids
La quantification stocke les poids sur moins de bits : 8, 6, 5, 4, parfois moins, avec une échelle par petit bloc pour rester proche des valeurs. llama.cpp nomme ses formats Q8_0, Q5_K_M, Q4_K_M (les formats « K » datent de 2023). Sa propre documentation les mesure sur Llama 3.1 8B : 16,0 bits par poids et 14,96 Gio en F16, 8,50 bits et 7,95 Gio en Q8_0, 4,89 bits et 4,58 Gio en Q4_K_M. On n'obtient pas exactement 4 bits parce que les échelles des blocs prennent aussi de la place.
D'après le tableau de llama.cpp, Q4_K_M sur un modèle 8B pèse environ…
- 15 Gio
- 8 Gio
- 4,6 Gio
Réponse
4,58 Gio, contre 14,96 en F16.
Théorie 2/2 : ce qu'on perd
Moins de bits, c'est un peu plus d'erreur sur chaque poids. Autour de 4 à 5 bits, la perte est en général faible pour la conversation ; sous 4 bits elle grandit plus vite, et les tâches précises (code, appels d'outils, calcul) souffrent en premier. Un modèle plus gros en Q4 bat souvent un plus petit en Q8 à mémoire égale, mais seul votre propre test (jour 12) le dit pour votre usage.
Quelle tâche montre en général en premier les dégâts de la quantification ?
- La conversation courante
- Les appels d'outils exacts et le code
Réponse
Les sorties précises : un seul mauvais token casse un appel JSON ou une commande.
Écrivez fits(modelGB, cacheGB, memoryGB) : vrai si le modèle et son cache tiennent dans la mémoire.
function fits(modelGB, cacheGB, memoryGB) {
}
Réponse
function fits(modelGB, cacheGB, memoryGB) {
return modelGB + cacheGB <= memoryGB;
}Pratique (30 min)
- Lisez les tableaux de quantification du README quantize de llama.cpp.
- Sur unsloth/Qwen3.5-4B-GGUF, notez les tailles de Q4_K_M et Q8_0.
- Écrivez dans le carnet quel fichier vous téléchargerez au jour 8 pour votre mémoire, et pourquoi.
Avec votre IA : « Ma machine a [X] Go de RAM et [Y] Go de VRAM (ou aucune). Je veux un modèle pour appeler des outils. Pose-moi trois questions sur mon usage, puis propose deux tailles de modèle et niveaux de quantification, chacun avec la mémoire estimée, et dis-moi quel test lancer pour les départager. N'affirme pas que l'un est meilleur sans test. »
Synthèse (10 min)
Trois lignes : ce qu'échange la quantification, les tailles du tableau, comment vous choisirez. Refaites le premier exercice sans notes.
Jour 7 · 09/11 — Le matériel : VRAM, RAM, processeur
Objectif : savoir ce qui limite la vitesse sur votre machine, et comment un moteur répartit un modèle entre carte graphique et processeur.
Théorie 1/2 : la bande passante mémoire commande la génération
Pour générer chaque token, le moteur lit une fois tous les poids actifs. La vitesse de génération est donc limitée surtout par la bande passante mémoire : la mémoire d'une carte graphique (VRAM) est plusieurs fois plus rapide que la RAM du système, d'où un même modèle qui écrit bien plus vite sur GPU. Le traitement du prompt dépend davantage de la puissance de calcul. Une machine sans GPU fait tourner les petits modèles sur son processeur : plus lentement, mais pour de vrai.
La vitesse de génération des tokens dépend surtout…
- de la bande passante mémoire
- de la vitesse du disque
- de la résolution de l'écran
Réponse
De la bande passante : chaque poids actif est lu pour chaque token.
Théorie 2/2 : répartir les couches
Un modèle est une pile de couches. Quand il ne tient pas en VRAM, llama.cpp place une partie des couches sur le GPU et le reste sur le processeur : c'est l'option -ngl (--n-gpu-layers). Chaque couche laissée au processeur ralentit l'ensemble. N'oubliez pas que le cache KV prend aussi de la mémoire. Sur les cartes NVIDIA, nvidia-smi montre la mémoire utilisée ; les articles du site Docker avec accès au GPU et libérer vos cartes pour l'IA vont plus loin.
Quelle option de llama.cpp fixe le nombre de couches envoyées sur le GPU ?
Réponse
-ngl (--n-gpu-layers).
Pratique (30 min)
- Décrivez votre machine dans le carnet : processeur et cœurs (
lscpuou infos système), RAM (free -h), GPU et VRAM (nvidia-smi, ou l'outil de votre constructeur), disque libre. - Décidez votre plan : GPU, processeur seul ou mixte. Choisissez une taille de modèle qui tient avec 1 à 2 Go de marge pour le cache.
- Si vous avez une carte NVIDIA et voulez des conteneurs, suivez Docker avec accès à votre GPU ; sinon, vous utiliserez demain les binaires précompilés.
Avec votre IA : « Voici la sortie de lscpu, free -h et nvidia-smi sur ma machine : [collez]. Résume ce que j'ai dans un tableau (cœurs, RAM, GPU, VRAM). Dis-moi quelles tailles de modèle tournent entièrement sur GPU, lesquelles demandent une répartition, lesquelles seulement sur processeur, en montrant tes calculs pour que je les vérifie. »
Le faire faire par un agent : maintenant que vous avez lu ces sorties vous-même, un agent de code avec accès au shell (Claude Code, Kimi Code, OpenFox) peut les rassembler : « Lance lscpu, free -h, nvidia-smi et df -h, en lecture seule, et écris dans hardware.md un tableau Markdown des ressources de cette machine. » Vérifiez chaque chiffre contre les sorties brutes : un agent peut mal lire une colonne.
Synthèse (10 min)
Trois lignes : ce qui limite la génération, ce que fait -ngl, le plan de votre machine. Refaites le premier exercice sans notes.
Jour 8 · 10/11 — llama.cpp : votre premier serveur
Objectif : servir un modèle local avec llama.cpp, lui parler dans le navigateur et avec curl.
Théorie 1/2 : le projet
llama.cpp a été lancé par Georgi Gerganov en mars 2023 pour faire tourner le LLaMA de Meta sur un portable, en C/C++ pur ; c'est aujourd'hui le moteur de nombreux outils locaux, sous licence MIT. Son llama-server expose une API HTTP compatible avec les chat completions d'OpenAI, plus une interface web. La documentation actuelle propose aussi une commande unifiée llama (llama serve, llama cli). Installation par les binaires publiés, l'installeur officiel, Docker, ou compilation (guide de compilation).
L'API de llama-server est compatible avec…
- rien d'autre, elle est maison
- le format chat completions d'OpenAI
Réponse
Compatible OpenAI : la plupart des clients et bibliothèques fonctionnent avec.
Théorie 2/2 : la ligne de commande
Les options essentielles : -m un fichier GGUF local, ou -hf un dépôt Hugging Face avec un :quant facultatif ; -c la taille du contexte ; -ngl les couches sur GPU ; --host et --port. Le serveur écoute par défaut sur 127.0.0.1, joignable seulement depuis votre machine : gardez-le ainsi jusqu'au module 4. Le port par défaut actuel est 9931 ; nous passons --port explicitement pour que les commandes ne dépendent pas de la version.
Pourquoi garder --host 127.0.0.1 pour l'instant ?
- Seule votre machine peut joindre le modèle
- C'est plus rapide
Réponse
Rien sur le réseau ne peut l'utiliser ni en abuser.
Pratique (30 min)
- Installez llama.cpp (binaire publié pour votre système, ou la méthode de votre premier modèle local).
- Lancez un petit modèle :
Ajoutezllama-server -hf ggml-org/Qwen3.5-0.8B-GGUF -c 8192 --host 127.0.0.1 --port 8080-ngl 99si vous avez un GPU. Prenez le 4B choisi au jour 6 s'il tient. - Ouvrez
http://127.0.0.1:8080et discutez. - Vérifiez la santé, puis tokenisez vos chaînes du jour 2 :
Comparez à vos prédictions.curl -s http://127.0.0.1:8080/health curl -s http://127.0.0.1:8080/tokenize -H 'Content-Type: application/json' -d '{"content": "anticonstitutionnellement"}'
Avec votre IA : « Voici le journal de démarrage de llama-server : [collez]. Explique chaque ligne qui parle du modèle, de la taille de contexte, des couches GPU et du gabarit de chat. Signale tout avertissement et ce que je dois vérifier. N'invente pas de sens pour les lignes que tu ne reconnais pas : dis que tu n'es pas sûr. »
Synthèse (10 min)
Trois lignes : la commande utilisée et le rôle de chaque option. Relancez le serveur de mémoire.
Jour 9 · 11/11 — Ollama : un second moteur
Objectif : faire tourner la même famille de modèle avec Ollama, et la comparer à llama.cpp.
Théorie 1/2 : ce qu'ajoute Ollama
Ollama enveloppe un moteur dérivé de llama.cpp dans un service avec une bibliothèque de modèles : ollama pull, ollama run, des modèles chargés et déchargés à la demande. Son API écoute sur http://localhost:11434, avec ses routes sous /api et une route compatible OpenAI sous /v1 (documentation). Le confort a un prix : moins de réglages, et des valeurs par défaut (la longueur de contexte, par exemple) à vérifier.
Sur quel port l'API d'Ollama écoute-t-elle par défaut ?
Réponse
11434.
Théorie 2/2 : une API, plusieurs moteurs
Comme les deux parlent le format OpenAI sur /v1, votre code change de moteur en changeant une URL de base et un nom de modèle. C'est la première brique du routage (module 3). Gardez l'URL et le modèle dans la configuration, jamais dans le code.
Votre script doit passer de llama.cpp à Ollama. Que faut-il changer ?
- Tout le code
- L'URL de base et le nom du modèle, lus dans la configuration
Réponse
Même format d'API : seule la configuration change.
Pratique (30 min)
- Installez Ollama depuis sa page de téléchargement.
- Lancez
ollama run qwen3.5:0.8b(ouqwen3.5:4b), posez une question, quittez avec/bye. - Appelez la route compatible OpenAI :
curl -s http://localhost:11434/v1/chat/completions -H 'Content-Type: application/json' \ -d '{"model": "qwen3.5:0.8b", "messages": [{"role": "user", "content": "Say hello in French."}]}' - Faites un tableau dans le carnet : llama.cpp contre Ollama, installation, port, choix du modèle, réglage du contexte, ce que vous avez aimé.
Avec votre IA : « J'utilise llama-server de llama.cpp et Ollama. Fais un tableau comparant comment chacun règle la longueur de contexte, le nombre de couches GPU et le modèle à charger, avec le lien de documentation pour chaque affirmation. Marque « à vérifier » toute ligne dont tu n'es pas sûr. »
Synthèse (10 min)
Trois lignes : ce qu'ajoute Ollama, son port, pourquoi un format d'API commun compte. Refaites l'appel curl de mémoire.
Jour 10 · 12/11 — L'API de chat, et prompter 1
Objectif : appeler l'API de chat depuis Python avec des rôles, et écrire un prompt vérifiable.
Théorie 1/3 : messages et rôles
Une requête de chat est une liste de messages, chacun avec un rôle : system (consignes permanentes), user (la demande), assistant (les réponses précédentes du modèle). L'API est sans état : vous renvoyez tout l'historique à chaque appel. Les options comme temperature, max_tokens et stream voyagent avec la requête. La réponse porte le texte et un bloc usage avec les comptes de tokens.
Le serveur se souvient-il de votre requête précédente ?
- Oui, il garde la conversation
- Non : vous renvoyez l'historique à chaque fois
Réponse
Sans état. L'historique est l'affaire de votre programme.
Théorie 2/3 : prompter pour ce métier, l'anatomie
Prompt faible : « Parle-moi de mon GPU. » Ce qui ne va pas : pas de rôle, pas d'entrée (quel GPU ?), pas de tâche vérifiable, pas de format. Prompt corrigé :
Rôle : tu es un assistant matériel pour quelqu'un qui fait tourner des LLM en local.
Contexte : voici la sortie de nvidia-smi : [collez].
Tâche : donne le nom de la carte, sa mémoire totale, la mémoire utilisée et la version du pilote.
Contraintes : n'utilise que des valeurs présentes dans la sortie ; sinon écris "absent".
Format : un objet JSON avec les clés name, total_mib, used_mib, driver.
Vérification : je comparerai chaque valeur avec la sortie brute.
Six parties : rôle et contexte, tâche, contraintes, entrées, format de sortie, comment vous vérifierez. Ajoutez un exemple quand le format sort de l'ordinaire.
Quel prompt est le meilleur pour un agent ?
- « Résume ce journal. »
- « Dans le journal ci-dessous, liste l'heure et le message de chaque ligne ERROR en lignes JSON ; ignore les WARN ; réponds 'aucune' s'il n'y a pas d'erreur. »
Réponse
Le second : entrée, tâche, contrainte, format et cas vide défini, tout est vérifiable.
Théorie 3/3 : corrigez ce prompt
« Écris-moi un bon script. » Quelle est la pièce manquante la plus importante ?
- La politesse
- Une phrase plus longue
- La tâche elle-même : ce que fait le script, sur quelle entrée, dans quel langage, et comment vous le testez
Réponse
Sans tâche et sans test définis, rien n'est vérifiable.
Pratique (30 min)
- Dans
ainet-lab:uv add openai. - Écrivez
chat.py:import os from openai import OpenAI client = OpenAI(base_url=os.environ.get("LLM_BASE_URL", "http://127.0.0.1:8080/v1"), api_key=os.environ.get("LLM_API_KEY", "none")) reply = client.chat.completions.create( model=os.environ.get("LLM_MODEL", "local"), messages=[{"role": "system", "content": "Answer in one sentence."}, {"role": "user", "content": "What is a token?"}], temperature=0.2) print(reply.choices[0].message.content) print(reply.usage) - Lancez-le contre llama.cpp, puis contre Ollama en changeant seulement les variables d'environnement.
- Réécrivez le prompt « Parle-moi de mon GPU » avec les six parties pour votre machine, et testez-le.
Avec votre IA : « Voici un prompt que j'ai écrit : [collez]. Passe-le en revue selon six parties : rôle et contexte, tâche, contraintes, entrées, format de sortie, comment je vérifierai la réponse. Pour chaque partie, dis si elle est présente, absente ou vague, et propose une correction concrète. Ne réécris pas tout le prompt à ma place. »
Le faire faire par un agent : après avoir écrit chat.py vous-même, demandez à un agent de code : « Ajoute à chat.py une option --stream qui affiche les tokens à leur arrivée, en gardant les variables d'environnement ; ajoute un test qui lance le script contre un faux serveur. » Vérifiez en lisant le diff et en le lançant contre votre vrai serveur.
Synthèse (10 min)
Trois lignes : les trois rôles, pourquoi l'API est sans état, les six parties d'un prompt. Réécrivez le prompt GPU de mémoire.
Jour 11 · 13/11 — Mesurer la vitesse
Objectif : mesurer la vitesse du prompt, celle de la génération et le temps jusqu'au premier token, et les noter proprement.
Théorie 1/2 : trois nombres
Donnez trois nombres, jamais un seul : le traitement du prompt en tokens par seconde (pp), la génération de texte en tokens par seconde (tg), et le temps jusqu'au premier token pour un prompt réaliste. llama.cpp fournit llama-bench, qui mesure pp et tg avec des répétitions (5 par défaut) et affiche une moyenne et un écart. Notez avec chaque résultat le fichier du modèle, la quantification, les options et la version du moteur : un nombre sans ses conditions ne se compare à rien.
Écrivez tps(tokens, ms) : des tokens par seconde à partir d'un compte et d'une durée en millisecondes.
function tps(tokens, ms) {
}
Réponse
Une ligne suffit :
function tps(tokens, ms) {
return tokens / (ms / 1000);
}Théorie 2/2 : mesurer honnêtement
Faites un tour de chauffe (le premier charge le modèle), répétez, gardez l'écart, changez une seule chose à la fois. Fermez les autres programmes lourds. Souvenez-vous qu'un outil de mesure mesure la machine autant que le modèle : la note du site quel modèle local pour quel travail montre pourquoi le vrai travail a préféré un autre modèle que la vitesse brute.
Vous changez à la fois la quantification et le nombre de couches GPU, et la vitesse double. Que concluez-vous ?
- La quantification a doublé la vitesse
- Rien sur l'un ou l'autre seul : une chose à la fois
Réponse
Deux changements, un résultat : impossible d'attribuer.
Pratique (30 min)
- Lancez
llama-bench -m <votre fichier de modèle>(ajoutez-ngl 99avec un GPU). Le fichier est dans le cache de llama.cpp si vous avez utilisé-hf; le journal du serveur affiche son chemin. - Relancez avec moitié moins de couches GPU, ou une autre quantification. Un seul changement.
- Chronométrez une vraie requête avec
curl -w '%{time_starttransfer}\n'et"stream": truepour obtenir le temps jusqu'au premier token. - Écrivez un tableau de résultats dans
bench/results.md: modèle, fichier, options, version, pp, tg, TTFT.
Avec votre IA : « Voici mes résultats llama-bench : [collez le tableau]. Explique ce que signifient pp et tg dans ce tableau, quelles différences restent dans l'écart et lesquelles sont réelles, et quelle mesure unique serait la plus instructive ensuite. Montre ton raisonnement avec les chiffres. »
Le faire faire par un agent : une fois le banc lancé à la main, un agent peut faire le balayage : « Lance llama-bench sur ce modèle avec -ngl 0, 16 et 99, en sortie JSON, et ajoute un tableau Markdown à bench/results.md avec la version donnée par llama-server --version. » Vérifiez que les conditions du tableau correspondent à ce qui a réellement tourné.
Synthèse (10 min)
Trois lignes : les trois nombres, pourquoi une chose à la fois, ce qui accompagne chaque résultat. Refaites tps sans notes.
Jour 12 · 14/11 — Un banc qui mesure votre métier
Objectif : construire un test de dix questions où c'est le code, pas vous, qui décide si chaque réponse est juste.
Théorie 1/2 : les bancs publics ne sont pas votre métier
Les classements publics mesurent des compétences générales sur des questions publiques, qui ont pu fuiter dans les données d'entraînement. Ce qu'il vous faut, c'est savoir si un modèle fait vos tâches de façon fiable : extraire ce champ, choisir cet outil, respecter ce format. Un petit jeu personnel, vérifié par code, lancé sur chaque modèle candidat, vaut mieux que n'importe quel classement pour cette décision.
Pour choisir un modèle qui extrait des dates de factures, la meilleure preuve est…
- son rang dans un classement général
- son score sur vingt de vos factures, vérifié par code
Réponse
Votre tâche, vos données, une vérification automatique.
Théorie 2/2 : des vérifications par code
Écrivez chaque cas comme une entrée plus une vérification qu'un programme peut exécuter : une valeur exacte, une expression régulière, un JSON valide avec telles clés, un nombre dans un intervalle. Évitez les vérifications qui demandent votre jugement : elles ne passent pas à l'échelle et varient avec votre humeur.
Écrivez score(answers, expected) : la proportion de réponses égales à la valeur attendue, sans tenir compte de la casse ni des espaces autour.
function score(answers, expected) {
}
Réponse
function score(answers, expected) {
const norm = s => String(s).trim().toLowerCase();
let ok = 0;
answers.forEach((a, i) => { if (norm(a) === norm(expected[i])) ok++; });
return ok / expected.length;
}Pratique (30 min)
- Écrivez
bench/cases.jsonl: dix cas d'une tâche qui vous importe (par exemple « extrais le montant de cette phrase »), chacun avecpromptetexpected. - Écrivez
bench/run.pyqui envoie chaque prompt au modèle (température 0), compare àexpectedpar code, et affiche le score et les échecs. - Lancez-le sur deux modèles ou deux quantifications ; notez scores et temps dans
bench/results.md.
Avec votre IA : « Voici mes dix cas de banc : [collez]. Pour chacun, dis-moi si la vérification peut se faire par code sans ambiguïté, et sinon propose une réponse attendue plus stricte. Puis suggère trois cas limites supplémentaires (entrée vide, deux candidats, un piège), avec leurs valeurs attendues. »
Le faire faire par un agent : maintenant que votre lanceur existe, un agent peut l'étendre : « Ajoute une option --model à bench/run.py, lance-le sur ces deux noms de modèles, et écris un tableau comparatif ; ne modifie pas cases.jsonl. » Vérifiez que les cas sont intacts (git diff bench/cases.jsonl doit être vide) et relancez un cas vous-même.
Synthèse (10 min)
Trois lignes : pourquoi votre propre banc, ce qu'est une bonne vérification, vos deux scores. Refaites score sans notes.
Jour 13 · 15/11 — Gabarits de chat et modèles qui réfléchissent
Objectif : comprendre comment les messages deviennent des tokens, et gérer les modèles qui « réfléchissent » avant de répondre.
Théorie 1/2 : le gabarit de chat
Le modèle voit un seul long texte, pas une liste de messages. Un gabarit de chat (chat template), écrit en général en Jinja et stocké dans le GGUF, transforme les rôles en marqueurs spéciaux appris à l'entraînement. Un mauvais gabarit donne des réponses étranges ou des appels d'outils cassés. llama-server applique le gabarit du modèle avec son moteur Jinja (actif par défaut dans les versions actuelles ; option --jinja), et vous pouvez le remplacer avec --chat-template-file. Sa documentation sur l'appel de fonctions liste les formats qu'il reconnaît.
Un modèle répond bien dans son application mais casse ses appels d'outils dans votre moteur. Une cause probable est…
- le modèle est trop petit
- un gabarit de chat faux ou absent
Réponse
Le gabarit décide comment outils et rôles sont écrits pour le modèle.
Théorie 2/2 : les modèles qui raisonnent
Certains modèles sont entraînés à écrire une partie de raisonnement avant la réponse (la famille Qwen3.5 a un mode « thinking », d'après sa page Ollama). Cela aide souvent sur les tâches difficiles et coûte des tokens et du temps. Les moteurs peuvent renvoyer cette partie dans un champ séparé. Pour un agent : laissez-la hors de l'historique renvoyé sauf indication contraire de la documentation du modèle, et coupez-la pour les décisions simples.
Pour une décision de routage oui/non répétée mille fois par jour, une longue phase de réflexion est…
- en général du temps et des tokens perdus
- toujours nécessaire
Réponse
Les décisions simples n'en ont pas besoin ; mesurez en cas de doute.
Pratique (30 min)
- Appelez
curl -s http://127.0.0.1:8080/propset trouvez le gabarit de chat dans la réponse. - Repérez-y les marqueurs de rôle et notez-les.
- Posez la même question piège avec la réflexion activée puis coupée (voir la fiche du modèle pour la méthode), comparez longueur, temps et justesse, et notez-le.
Avec votre IA : « Voici un gabarit de chat Jinja : [collez]. Montre-moi quel texte il produit pour un message system, un message user et un message assistant, en écrivant la sortie exacte. Puis demande-moi de prédire la sortie d'une conversation de deux tours et corrige-moi. »
Synthèse (10 min)
Trois lignes : ce que fait un gabarit, le symptôme d'un mauvais, quand couper la réflexion. Refaites le premier exercice sans notes.
Jour 14 · 16/11 — Livrable du module 1 : la fiche de votre machine
Objectif : publier une « fiche machine » documentée et mesurée : ce que votre machine fait tourner, à quelle vitesse, et avec quelle réussite sur votre tâche.
Théorie 1/2 : ce que lit un recruteur
Un bon livrable technique montre les conditions, les chiffres et les limites. Il dit ce qui a été mesuré, comment le reproduire, et ce qu'il ne prouve pas. Une affirmation sans commande pour la reproduire est une opinion.
Quelle ligne a sa place dans une fiche machine ?
- « Ce modèle est le meilleur. »
- « Qwen3.5-4B Q4_K_M, -ngl 99, -c 8192 : tg 42 t/s ±1 (llama-bench, 5 essais), 8/10 sur bench/cases.jsonl. »
Réponse
Conditions, chiffre, écart, méthode. (Les chiffres sont un exemple, pas une mesure.)
Théorie 2/2 : relire vos propres prompts
Relisez les prompts écrits ces quinze jours. Pour chacun, posez la question des six parties. Un prompt gardé dans le dépôt (prompts/) se versionne comme du code : on voit pourquoi il a changé.
Où doivent vivre les prompts de votre banc ?
- Seulement dans votre tête
- Dans un historique de chat
- Dans le dépôt, versionnés avec le code
Réponse
Versionnés, pour qu'un changement s'explique et s'annule.
Pratique (30 min)
- Écrivez le
README.mddeainet-lab: la machine (jour 7), les moteurs et leur installation, les modèles testés avec fichiers et licences, le tableau de vitesse, le score du banc, comment tout relancer, et trois limites. - Ajoutez un petit schéma (du texte suffit) : client → moteur → fichier du modèle → matériel.
- Faites un commit, et poussez sur une forge publique si vous voulez le montrer (retirez d'abord tout ce qui est personnel).
Avec votre IA : « Voici mon README de fiche machine pour LLM locaux : [collez]. Joue un relecteur technique qui recrute un ingénieur IA junior. Liste ce qui n'est pas clair, ce qui n'est pas reproductible, et toute affirmation sans mesure. Pas de compliments ; au plus cinq changements concrets. »
Le faire faire par un agent : maintenant que vous connaissez chaque partie, un agent de code peut vérifier la reproductibilité : « Suis README.md depuis un shell propre, lance chaque commande, et signale toute étape qui échoue ou est ambiguë, sans modifier les fichiers. » Lisez son rapport et corrigez le README vous-même.
Synthèse (10 min)
Trois lignes dans le carnet : ce que vous savez faire maintenant, ce qui reste flou, ce que vous attendez du module 2. Refaites sans notes le premier exercice du jour 4.
Sources
- Vaswani et al. (2017), Attention Is All You Need
- Sennrich, Haddow, Birch (2015), Neural Machine Translation of Rare Words with Subword Units
- Holtzman et al. (2019), The Curious Case of Neural Text Degeneration (nucleus sampling)
- llama.cpp, ses README server, quantize et llama-bench
- Documentation d'Ollama
- Hugging Face — GGUF
- Cours LLM de Hugging Face
- Andrej Karpathy, Intro to Large Language Models et Let's build the GPT Tokenizer
Utile ? Dites-nous ce qu'il faut mesurer ensuite.