freedzhost.cloud

Réseau agentique IA module 3 : agents, orchestration, routage, RAG et mémoire

Niveau IntermédiaireTemps estimé 15 hÀ lire avant Réseau agentique IA module 2 : prompts, sortie structurée, outils et MCPUn mot inconnu ? Lexique

Quinze séances pour passer d'un modèle avec outils à plusieurs agents qui se partagent le travail. Vous écrivez vous-même une boucle d'agent, puis voyez ce qu'ajoutent les vrais harnais, apprenez les patrons qui gardent le travail en plusieurs étapes prévisible, envoyez chaque tâche au modèle le moins cher capable de la faire, donnez aux agents une mémoire interrogeable avec embeddings et recherche, et reliez des agents qui tournent sur des machines différentes. Le module se termine par un réseau de deux agents, documenté par un schéma.

Les adresses des exemples sont locales ou réservées à la documentation (192.0.2.10, 198.51.100.20) : remplacez-les par vos machines, et gardez les vraies hors de tout ce que vous publiez.

Jour 30 · 02/12 — La boucle d'agent

Objectif : définir précisément un agent, et le distinguer d'un workflow.

Théorie 1/2 : raisonner, agir, observer

Un agent est une boucle où un modèle décide de l'action suivante, un programme l'exécute, et le résultat revient au modèle, jusqu'à une condition d'arrêt. Yao et ses collègues ont nommé ce patron ReAct en 2022 (reasoning and acting) : alterner des traces de raisonnement et des actions comme des recherches. La boucle écrite au jour 21 en est déjà une. Ce qui la rend fiable est hors du modèle : un plafond d'étapes, une limite de temps, un budget, des outils autorisés, et un signal clair de fin.

Quel élément garantit qu'un agent s'arrête ?

  1. Le modèle qui décide qu'il a fini
  2. Un bon prompt système
  3. Un plafond d'étapes, de temps ou de budget appliqué par le programme
Réponse

Le modèle peut ne jamais décider ; le plafond du programme marche toujours.

Théorie 2/2 : workflows contre agents

Le guide d'Anthropic « Building effective agents » (décembre 2024) distingue les workflows, où modèles et outils suivent des chemins de code prédéfinis, des agents, où le modèle dirige lui-même son déroulement. Son conseil : commencer par la solution la plus simple, souvent un seul appel avec un bon contexte, et n'ajouter de l'autonomie que si nécessaire, car elle coûte en latence et en argent et se teste plus mal.

« Chaque nuit, résumer les nouvelles lignes de journal et publier le résumé » se construit le mieux comme…

  1. un workflow : étapes fixes, un appel au modèle
  2. un agent autonome avec tous les outils
Réponse

Les étapes sont connues d'avance : inutile que le modèle les choisisse.

model(step) renvoie 'tool' ou 'done'. Écrivez runAgent(model, maxSteps) : appelez-le avec 0, 1, 2… ; arrêtez sur 'done' ou quand maxSteps appels ont été faits. Renvoyez {steps, stopped} avec stopped égal à 'done' ou 'cap'.

function fakeModel(script) { return step => script[step] || 'tool'; }
function runAgent(model, maxSteps) {
}
Réponse
function fakeModel(script) { return step => script[step] || 'tool'; }
function runAgent(model, maxSteps) {
  for (let step = 0; step < maxSteps; step++) {
    if (model(step) === 'done') return { steps: step + 1, stopped: 'done' };
  }
  return { steps: maxSteps, stopped: 'cap' };
}

Pratique (30 min)

  1. Lisez en entier « Building effective agents » ; listez ses patrons dans le carnet.
  2. Pour cinq tâches à vous (trier des mails, répondre depuis des notes, réparer un test en échec…), décidez workflow ou agent et justifiez en une ligne.
  3. Ajoutez à votre boucle du jour 21 une limite de temps et un budget de tokens, à côté du plafond d'étapes.

Avec votre IA : « Voici cinq tâches que je veux automatiser : [collez]. Pour chacune, pose-moi deux questions sur la prévisibilité des étapes, puis dis-moi si tu construirais un workflow ou un agent, et quel plafond (étapes, temps, tokens) tu fixerais. Je défendrai ou changerai mon propre choix. »

Synthèse (10 min)

Trois lignes : la boucle, les garanties d'arrêt, workflow contre agent. Refaites runAgent sans notes.

Jour 31 · 03/12 — Votre agent minimal

Objectif : écrire un petit agent qui répond à des questions sur vos notes avec vos outils MCP, et journaliser chaque étape.

Théorie 1/2 : les pièces

Un agent minimal a : un prompt système (rôle, règles, quand s'arrêter), une liste d'outils, la boucle avec ses plafonds, une trace (chaque message et résultat d'outil, écrits en lignes JSON) et un format de réponse finale. La trace est ce que vous lirez quand ça tourne mal, et ce sur quoi vous testerez (module 4).

Pourquoi écrire la trace en lignes JSON ?

  1. C'est plus joli
  2. Un programme peut la rejouer, la compter et la tester
Réponse

Des traces lisibles par une machine rendent l'évaluation possible.

Théorie 2/2 : une réponse qui cite

Demandez à l'agent de nommer la note d'où vient chaque affirmation. Une citation permet au code de vérifier que la note existe, et à vous de vérifier qu'elle le dit. « Je ne l'ai pas trouvé » doit être une réponse permise, écrite dans le prompt ; sinon le modèle comble le vide.

L'agent ne trouve pas la réponse dans les notes. Le comportement voulu est…

  1. dire qu'il ne l'a pas trouvée
  2. répondre de culture générale sans le dire
Réponse

Le dire. Autorisez-le explicitement dans le prompt système.

Pratique (30 min)

  1. Écrivez agent_notes.py : prompt système dans prompts/notes-agent.txt, outils de ainet/tools.py (ou via votre serveur MCP avec le client du SDK), plafonds de 6 étapes et 60 secondes, un fichier de trace par essai dans runs/.
  2. La réponse finale est du JSON : {"answer": ..., "sources": [noms de notes]}, validé dans le code ; le programme vérifie que chaque source existe.
  3. Lancez-le sur cinq questions, dont une sans réponse dans les notes.

Avec votre IA : « Voici la trace d'un essai de mon agent de notes, en lignes JSON : [collez]. Parcours-la étape par étape et dis-moi où il a perdu une étape, si chaque source citée contient vraiment l'affirmation (cite le résultat d'outil), et un changement du prompt système qui aurait économisé une étape. »

Le faire faire par un agent : maintenant que votre agent marche, un agent de code peut ajouter un outil de relecture : « Écris runs/replay.py qui affiche un fichier de trace comme une conversation lisible, avec numéros d'étape, noms d'outils et durées, et un test sur une trace d'exemple. » Vérifiez-le sur une vraie trace que vous avez lue vous-même.

Synthèse (10 min)

Trois lignes : les pièces de votre agent, pourquoi des traces, pourquoi des citations. Redessinez de mémoire la structure de l'agent.

Jour 32 · 04/12 — Les harnais : ce qu'ils ajoutent

Objectif : savoir ce que fait un harnais au-delà de votre boucle, et en choisir un par usage.

Théorie 1/2 : le harnais autour du modèle

Un harnais est le programme qui fait d'un modèle un agent qui travaille : il lit des fichiers, lance des commandes, demande la permission, gère le contexte (résumer, élaguer), traite les erreurs et décide quand s'arrêter. Votre boucle est un minuscule harnais. Le guide du site ce qu'est un harnais d'agent, et comment choisir le vôtre en compare six utilisés au quotidien ; d'autres articles décrivent Claude Code, Kimi Code et OpenFox, conçu pour les modèles locaux.

Lequel de ces rôles revient au harnais, pas au modèle ?

  1. Choisir un mot
  2. Écrire un plan
  3. Vous demander avant de lancer une commande qui supprime des fichiers
Réponse

Les permissions sont appliquées par le harnais.

Théorie 2/2 : choisir

Critères : quels modèles il prend en charge (locaux, hébergés), son modèle de permissions (listes d'autorisation, bac à sable, confirmations), le support de MCP, la gestion des longs contextes, le coût, la licence, la possibilité de tourner sans interface (scripts, serveurs). Un harnais conçu pour les modèles de pointe peut peiner avec un petit modèle local, et inversement.

Pour une tâche de nuit sur un serveur sans écran, le critère clé est…

  1. une belle interface
  2. un mode non interactif avec des permissions fixées
Réponse

Personne n'est là pour cliquer sur « autoriser ».

Pratique (30 min)

  1. Lisez le guide des harnais.
  2. Installez un harnais capable d'utiliser votre modèle local (OpenFox, ou un autre avec un réglage compatible OpenAI) et branchez-y votre serveur MCP.
  3. Donnez-lui les cinq questions d'hier ; comparez étapes, temps et réponses dans un tableau.

Avec votre IA : « Je veux choisir un harnais d'agent pour [mon usage : coder sur un portable / tâches de nuit sur un serveur]. Voici mes contraintes : [modèles, confidentialité, budget]. Fais un tableau de trois harnais selon ces critères : modèles pris en charge, modèle de permissions, support MCP, mode sans interface, licence, avec le lien de documentation pour chaque case. Écris « inconnu » plutôt que deviner. »

Le faire faire par un agent : vous venez de comparer des essais à la main ; un harnais avec votre serveur MCP peut désormais répondre chaque jour aux questions sur les notes à votre place. Donnez-lui : « Réponds uniquement avec les outils de notes, cite les noms de notes, dis 'non trouvé' sinon. » Continuez à vérifier vous-même une note citée par réponse.

Synthèse (10 min)

Trois lignes : ce qu'ajoute un harnais, vos critères, le résultat de votre comparaison. Refaites le deuxième exercice sans notes.

Jour 33 · 05/12 — L'ingénierie du contexte

Objectif : décider ce qui entre dans le contexte à chaque tour, et garder les longs essais dans la fenêtre.

Théorie 1/2 : le contexte est un budget

Chaque tour renvoie instructions, descriptions d'outils, historique et résultats. Les longs essais remplissent la fenêtre et ralentissent (prefill), et les modèles exploitent moins bien l'information placée au milieu d'un très long contexte (Liu et al., 2023, « Lost in the Middle »). Les leviers : moins d'outils exposés par tâche, des sorties d'outils courtes, résumer les anciens tours, sortir les longs contenus (un fichier que l'agent lit à la demande), et un préfixe stable pour le cache. Le site a mesuré où passaient les tokens d'un agent dans le plancher de contexte.

Un agent a 40 outils mais chaque tâche en utilise trois. Le meilleur levier ?

  1. Un contexte plus grand
  2. N'exposer que les outils dont la tâche a besoin
Réponse

Chaque description se paie à chaque tour et peut brouiller le choix.

Théorie 2/2 : résumer sans perdre les faits

Quand l'historique est trop long, remplacez les anciens tours par un résumé écrit par un modèle, mais gardez les faits exacts (chemins, nombres, décisions) dans une note structurée tenue par le programme, pas en prose. Un résumé peut perdre ou altérer un chiffre.

Chaque message a un compte de tokens t. Écrivez trim(messages, budget) : gardez les messages les plus récents dont le total tient dans le budget, dans leur ordre d'origine.

function trim(messages, budget) {
}
Réponse
function trim(messages, budget) {
  const kept = [];
  let total = 0;
  for (let i = messages.length - 1; i >= 0; i--) {
    if (total + messages[i].t > budget) break;
    total += messages[i].t;
    kept.unshift(messages[i]);
  }
  return kept;
}

Pratique (30 min)

  1. Mesurez votre agent de notes : tokens par tour (dans usage), répartis en prompt système, outils, historique.
  2. Réduisez : sorties d'outils plus courtes, moins d'outils, prompt système plus court. Relancez les cinq questions et comparez tokens et réponses.
  3. Ajoutez un budget d'historique avec votre logique trim (en gardant le prompt système et le premier message user).

Avec votre IA : « Voici la répartition des tokens d'un tour d'agent : système [n], outils [n], historique [n], résultats d'outils [n]. Propose trois changements classés par tokens économisés par tour, estime l'économie de chacun avec le calcul, et nomme le risque de chacun. »

Le faire faire par un agent : après avoir mesuré à la main, demandez à un agent de code : « Ajoute à agent_notes.py un décompte des tokens par tour (système, outils, historique, résultats) écrit dans la trace, et un script qui affiche la moyenne sur runs/. » Vérifiez vous-même un tour contre les chiffres de usage.

Synthèse (10 min)

Trois lignes : ce qui coûte des tokens, trois leviers, pourquoi les faits restent structurés. Refaites trim sans notes.

Jour 34 · 06/12 — Les patrons de workflow

Objectif : reconnaître les cinq patrons standard et en choisir un pour une tâche.

Théorie 1/2 : cinq patrons

Le même guide nomme cinq patrons de workflow :

  • Chaînage de prompts : des étapes fixes, chaque appel nourrit le suivant, avec des vérifications entre elles.
  • Routage : classer l'entrée, puis l'envoyer à un prompt ou un modèle spécialisé.
  • Parallélisation : découper une tâche en parties indépendantes (sectionnement), ou demander plusieurs fois et voter.
  • Orchestrateur-exécutants : un modèle planifie des sous-tâches à l'exécution et les délègue.
  • Évaluateur-optimiseur : un appel produit, un autre évalue et demande des améliorations, en boucle.

« Traduire, puis vérifier la traduction contre un glossaire, puis corriger », c'est…

  1. du routage
  2. du chaînage de prompts (avec une étape de vérification)
  3. un vote
Réponse

Des étapes séquentielles fixes : le chaînage.

« Demander trois fois et garder la réponse majoritaire », c'est…

  1. orchestrateur-exécutants
  2. du chaînage
  3. de la parallélisation par vote
Réponse

Le vote échange du coût contre de la constance.

Théorie 2/2 : des vérifications entre les étapes

La valeur d'un workflow, c'est que le code peut vérifier chaque étape : un schéma, un compte, un test. Une chaîne sans vérification ne fait que multiplier les erreurs.

Écrivez vote(answers) : renvoyez la réponse la plus fréquente (la première à atteindre le compte maximal en cas d'égalité).

function vote(answers) {
}
Réponse
function vote(answers) {
  const counts = {};
  let best = answers[0];
  for (const a of answers) {
    counts[a] = (counts[a] || 0) + 1;
    if (counts[a] > counts[best]) best = a;
  }
  return best;
}

Pratique (30 min)

  1. Construisez une chaîne dans chain_digest.py : (1) extraire d'une note les actions à faire en JSON, validé ; (2) classer chacune par urgence avec votre prompt de tri ; (3) écrire un court récapitulatif. Vérifications par code entre les étapes.
  2. Ajoutez un vote (trois essais) à l'étape 2 et mesurez si le score de tri s'améliore sur votre banc.
  3. Notez le coût (tokens) face au gain.

Avec votre IA : « Voici une tâche que je veux automatiser : [décrivez]. Propose lequel des cinq patrons (chaînage, routage, parallélisation, orchestrateur-exécutants, évaluateur-optimiseur) convient, écris les étapes en liste numérotée, et pour chaque étape nomme la vérification que le code peut faire sur sa sortie. »

Synthèse (10 min)

Trois lignes : les cinq patrons, pourquoi des vérifications entre étapes. Refaites vote sans notes.

Jour 35 · 07/12 — Orchestrateur et exécutants

Objectif : répartir le travail entre un agent qui planifie et des agents exécutants, avec un contrat pour chaque passage de relais.

Théorie 1/2 : qui fait quoi

Un orchestrateur découpe une demande en sous-tâches et confie chacune à un exécutant au rôle plus étroit, avec moins d'outils, parfois un plus petit modèle. Le passage de relais est le point faible : l'exécutant ne sait que ce qu'on lui donne. Chaque passage doit indiquer le but, les entrées, les outils permis, la sortie attendue (schéma) et le critère de fin. Les systèmes multi-agents coûtent plus de tokens et ajoutent des points de panne : utilisez-les quand les sous-tâches sont vraiment séparables ou demandent des permissions différentes.

Une bonne raison de séparer en deux agents est…

  1. une partie a besoin d'écrire et l'autre doit rester en lecture seule
  2. ça fait plus avancé
Réponse

Des permissions différentes sont une bonne raison ; la mode, non.

Théorie 2/2 : le code décide

Laissez les modèles proposer ; laissez le code trancher ce qui a une seule bonne réponse (le test passe-t-il, le JSON est-il valide, l'exécutant a-t-il droit à cet outil). Les articles du site la doctrine déterministe et BMAD avec de petits modèles le montrent en production : des stories avec un schéma, des scénarios exécutés par des tests, une seule story vivante à la fois.

L'exécutant dit « les tests passent ». L'orchestrateur doit…

  1. le croire
  2. lancer lui-même les tests, par code
Réponse

Une affirmation n'est pas un résultat. Vérifiez par code.

Pratique (30 min)

  1. Écrivez orchestrator.py : l'orchestrateur reçoit une question, décide par un plan JSON quel exécutant appeler (l'exécutant de notes du jour 31, ou un exécutant « calculatrice » avec seulement un outil d'arithmétique), et compose la réponse.
  2. Définissez le passage de relais comme un JSON Schema : goal, inputs, allowed_tools, output_schema ; validez chaque plan dans le code.
  3. Journalisez les deux niveaux dans la trace ; lancez cinq questions mêlées.

Avec votre IA : « Voici mon schéma de passage de relais entre un orchestrateur et ses exécutants : [collez], et un plan qu'il a produit et qui a mal tourné : [collez]. Dis-moi quel champ manquait ou était vague et a causé l'échec, et propose une règle de schéma plus stricte que le code pourrait vérifier. »

Le faire faire par un agent : après avoir câblé un orchestrateur à la main, demandez à un agent de code : « Ajoute un troisième exécutant, summarise_note, à orchestrator.py, avec ses propres outils permis, un passage de relais validé par le schéma existant, et un test où l'orchestrateur le planifie. » Vérifiez en essayant que l'exécutant ne peut pas utiliser d'outils hors de sa liste.

Synthèse (10 min)

Trois lignes : orchestrateur, exécutant, contrat de passage de relais. Refaites le deuxième exercice sans notes.

Jour 36 · 08/12 — Le routage entre modèles

Objectif : envoyer chaque demande au modèle le moins cher capable de la traiter, le local d'abord, l'hébergé quand ça vaut le coup.

Théorie 1/2 : une passerelle

Une passerelle donne à tous les clients une seule adresse compatible OpenAI et associe des noms de modèles à de vrais moteurs (locaux, API hébergées), avec relances, replis et journaux. Le proxy de LiteLLM en est une, libre et répandue. Les articles du site une passerelle pour tous vos modèles et les modèles cloud gratuits derrière votre passerelle décrivent une installation réelle.

Le principal avantage d'une passerelle est…

  1. des modèles plus rapides
  2. une adresse et un nommage pour tous les clients, avec des replis
Réponse

Les clients ne savent plus quel moteur répond ; vous le changez à un seul endroit.

Théorie 2/2 : décider de la route

Les routes se décident par des règles (type de tâche, longueur), par un petit classifieur, ou par escalade (essayer en local, vérifier, escalader en cas d'échec). Les mots-clés font un mauvais routeur : le site les a mesurés sous la base triviale « toujours répondre default » dans router les requêtes avec un petit classifieur. L'escalade hybride montre une file qui essaie d'abord l'agent le moins cher, avec des plafonds quotidiens.

Écrivez route(task) : 'large' si la tâche est code ou dépasse 8 000 tokens ; sinon 'small' pour classify ; sinon 'default'.

function route(task) {
}
Réponse
function route(task) {
  if (task.kind === 'code' || task.tokens > 8000) return 'large';
  if (task.kind === 'classify') return 'small';
  return 'default';
}

Pratique (30 min)

  1. Installez le proxy LiteLLM (voir sa documentation) avec un config.yaml qui déclare deux noms, small et large, pointant vers vos modèles llama.cpp et Ollama (ou deux tailles) ; les clés éventuelles viennent de variables d'environnement.
  2. Faites pointer ainet/llm.py vers la passerelle ; votre orchestrateur utilise small pour planifier et trier, large pour la réponse finale.
  3. Mesurez temps total et tokens sur vos cinq questions face à « tout sur large ».

Avec votre IA : « Voici mon config.yaml LiteLLM, secrets retirés : [collez]. Vérifie-le par rapport à la documentation du proxy LiteLLM : noms de modèles, moteurs, replis, provenance des clés. Liste ce qui empêcherait le démarrage ou ferait fuiter une clé, en citant la ligne, et donne le lien de documentation de chaque point. »

Le faire faire par un agent : une fois vos deux routes faites à la main, un agent peut ajouter un repli : « Ajoute à config.yaml un repli de large vers default quand large échoue, redémarre le proxy, et prouve-le en arrêtant le moteur large et en lançant une requête ; rends les lignes de journal. » Vérifiez le journal vous-même.

Synthèse (10 min)

Trois lignes : ce que fait une passerelle, trois façons de router, votre gain mesuré. Refaites route sans notes.

Jour 37 · 09/12 — Des petits juges pour les petites décisions

Objectif : répondre à des questions typées oui/non ou à choix avec un tout petit modèle, et utiliser correctement sa confiance.

Théorie 1/2 : la bonne taille pour la décision

Beaucoup de décisions d'agent sont petites : ce mail est-il un spam, laquelle de ces trois files, cette réponse est-elle dans le sujet. Un modèle de moins de 1B sur processeur peut y répondre en une fraction de seconde, si le code pose une question typée et lit une probabilité plutôt que de la prose. Le site en décrit un dans un tout petit juge local, et une version en deux passes dans Tev1 d'abord, Nimble en cas de doute.

Pour « ce message parle-t-il de facturation ? oui/non », la meilleure sortie est…

  1. un paragraphe qui explique la réponse
  2. une seule étiquette avec une probabilité
Réponse

Le code peut seuiller une probabilité ; il ne peut pas analyser un paragraphe de façon fiable.

Théorie 2/2 : confiance n'est pas justesse

Une probabilité mesure à quel point la réponse du modèle est concentrée, pas si elle est juste. Calibrez sur vos propres cas étiquetés : choisissez un seuil, et envoyez ce qui tombe dessous à un plus gros modèle ou à un humain. Deux options de probabilités presque égales sont en concurrence : escaladez, ne choisissez pas en silence.

Écrivez decide(probs, threshold) : renvoyez l'étiquette de plus forte probabilité si elle atteint le seuil, sinon 'escalate'.

function decide(probs, threshold) {
}
Réponse
function decide(probs, threshold) {
  let best = null;
  for (const k in probs) if (best === null || probs[k] > probs[best]) best = k;
  return probs[best] >= threshold ? best : 'escalate';
}

Pratique (30 min)

  1. Servez un très petit modèle (par exemple qwen3.5:0.8b dans Ollama) sur le processeur.
  2. Posez-lui votre question de tri, contrainte à une seule étiquette ; obtenez des probabilités avec l'option n_probs de llama-server sur /completion (voir le README du serveur) ou en tirant dix fois et en comptant.
  3. Sur vos 10 cas étiquetés, trouvez le seuil au-dessus duquel il a toujours raison ; notez combien de cas tombent dessous.

Avec votre IA : « Voici les résultats de mon juge sur vingt cas étiquetés : étiquette, probabilité, juste ou non : [collez]. Aide-moi à choisir un seuil : pour 0,6, 0,7, 0,8 et 0,9, calcule combien de cas sont acceptés et combien parmi eux sont faux, dans un tableau. Ne choisis pas à ma place ; explique le compromis. »

Le faire faire par un agent : maintenant que vous avez calibré un juge à la main, un agent peut le brancher : « Dans orchestrator.py, appelle d'abord le petit juge pour le tri, accepte son étiquette au-dessus du seuil de la configuration, et escalade vers la route 'large' en dessous ; journalise le chemin pris ; ajoute un test pour chaque chemin. » Vérifiez que le seuil vient de la configuration, pas du code.

Synthèse (10 min)

Trois lignes : quelles décisions sont petites, pourquoi des réponses typées, ce que signifie la confiance. Refaites decide sans notes.

Jour 38 · 10/12 — Les embeddings

Objectif : transformer des textes en vecteurs et trouver les plus proches par similarité cosinus.

Théorie 1/2 : le sens comme un vecteur

Un modèle d'embeddings associe à un texte un vecteur de quelques centaines ou milliers de nombres, de sorte que des textes de sens proche aient des vecteurs proches. Sentence-BERT (Reimers et Gurevych, 2019) a rendu cela pratique pour la recherche de phrases. En local, Ollama sert des modèles d'embeddings comme embeddinggemma sur /api/embed ; llama-server le fait avec --embedding et /v1/embeddings. Le classement MTEB compare les modèles, mais c'est votre propre test de recherche qui tranche.

Peut-on comparer des vecteurs produits par deux modèles d'embeddings différents ?

  1. Oui
  2. Non : chaque modèle a son espace ; indexez et interrogez avec le même modèle
Réponse

Changer de modèle, c'est tout ré-encoder.

Théorie 2/2 : la similarité cosinus

La proximité se mesure en général par le cosinus de l'angle entre deux vecteurs : le produit scalaire divisé par le produit de leurs longueurs, de −1 à 1.

Écrivez cosine(a, b) pour deux tableaux de même longueur.

function cosine(a, b) {
}
Réponse
function cosine(a, b) {
  let dot = 0, na = 0, nb = 0;
  for (let i = 0; i < a.length; i++) {
    dot += a[i] * b[i]; na += a[i] * a[i]; nb += b[i] * b[i];
  }
  return dot / (Math.sqrt(na) * Math.sqrt(nb));
}

Pratique (30 min)

  1. ollama pull embeddinggemma, puis :
    curl -s http://localhost:11434/api/embed -d '{"model": "embeddinggemma", "input": ["le ventilateur du GPU est bruyant", "la carte graphique fait du bruit", "acheter du pain"]}'
  2. En Python, calculez le cosinus entre les trois vecteurs ; vérifiez que les deux premiers sont les plus proches.
  3. Encodez chaque note de votre carnet et enregistrez les vecteurs avec les noms de notes dans index/notes.json.

Avec votre IA : « Explique la similarité cosinus avec un exemple en deux dimensions que je peux dessiner, puis donne-moi trois paires de phrases courtes et demande-moi de les classer par similarité attendue avant que je la calcule. Quand je donnerai mes cosinus mesurés, discutons des cas où l'intuition et le modèle divergent. »

Synthèse (10 min)

Trois lignes : ce qu'est un embedding, pourquoi un seul modèle par index, le cosinus. Refaites cosine sans notes.

Jour 39 · 11/12 — RAG 1 : chercher, puis répondre

Objectif : comprendre la génération augmentée par la recherche et ses trois choix de conception : morceaux, recherche, prompt.

Théorie 1/2 : l'idée

Le RAG (Lewis et al., 2020) répond à partir de documents plutôt que de mémoire : découper les documents en morceaux (chunks), les encoder, et pour chaque question retrouver les morceaux les plus proches et les mettre dans le prompt avec la consigne de ne répondre qu'à partir d'eux et de les citer. Il donne au modèle un savoir frais et privé sans entraînement, et rend les réponses vérifiables.

Que change le RAG dans le modèle ?

  1. Rien : il change ce qu'il y a dans le prompt
  2. Ses poids, en l'entraînant sur vos documents
Réponse

Pas d'entraînement : la recherche nourrit le contexte.

Théorie 2/2 : le découpage

Des morceaux trop petits perdent le contexte ; trop grands, ils diluent la correspondance et gaspillent des tokens. Découpez selon la structure (titres, paragraphes) avec une taille limite et un léger chevauchement, et gardez la source et la position de chaque morceau pour les citations. Le RAG sur votre propre journal du site montre la taille de morceau qui a compté et trois façons dont un RAG sert en silence des réponses périmées.

Écrivez chunks(text, size, overlap) : coupez le texte en morceaux d'au plus size caractères, chacun commençant size - overlap caractères après le précédent ; arrêtez quand la fin est atteinte.

function chunks(text, size, overlap) {
}
Réponse
function chunks(text, size, overlap) {
  const out = [];
  for (let start = 0; start < text.length; start += size - overlap) {
    out.push(text.slice(start, start + size));
    if (start + size >= text.length) break;
  }
  return out;
}

Pratique (30 min)

  1. Lisez l'article sur le RAG du journal.
  2. Écrivez ainet/rag.py : découpez chaque note par titres, puis en morceaux d'environ 800 caractères avec 100 de chevauchement ; gardez {source, start, text}.
  3. Encodez les morceaux, enregistrez-les dans index/chunks.json, et écrivez search(question, k=4) qui renvoie les morceaux les plus proches.

Avec votre IA : « Voici trois morceaux que ma recherche a renvoyés pour la question '[question]' : [collez]. Dis-moi pour chacun s'il aide vraiment à répondre, et si les bornes du morceau coupent une phrase importante. Propose un changement à ma règle de découpage. »

Synthèse (10 min)

Trois lignes : les étapes du RAG, pourquoi la taille des morceaux compte, ce que garde chaque morceau. Refaites chunks sans notes.

Jour 40 · 12/12 — RAG 2 : le construire et le mesurer

Objectif : répondre avec citations depuis votre index et mesurer la recherche avec le rappel@k.

Théorie 1/2 : mesurer la recherche à part

Une mauvaise réponse de RAG a deux causes possibles : le bon morceau n'a pas été trouvé, ou le modèle ne s'en est pas servi. Mesurez la recherche seule avec un petit jeu de questions dont vous connaissez la source : le rappel@k (recall@k) est la proportion de questions dont la bonne source figure parmi les k premiers résultats. Réparez la recherche avant d'accuser le modèle.

Écrivez recallAtK(results, expected, k) : results[i] est la liste classée des sources pour la question i, expected[i] sa bonne source.

function recallAtK(results, expected, k) {
}
Réponse
function recallAtK(results, expected, k) {
  let hit = 0;
  results.forEach((r, i) => { if (r.slice(0, k).includes(expected[i])) hit++; });
  return hit / expected.length;
}

Théorie 2/2 : stocker les vecteurs

Quelques milliers de morceaux tiennent dans un fichier JSON et une boucle. Au-delà, utilisez un index vectoriel : sqlite-vec ajoute la recherche vectorielle à SQLite ; des bases dédiées existent pour les millions. Quel que soit le stockage, réindexez quand les documents changent, et notez quel modèle d'embeddings a construit l'index.

Votre rappel@4 vaut 0,5. Avant d'essayer un plus gros modèle de chat, vous…

  1. en achetez un
  2. travaillez le découpage, le modèle d'embeddings ou la requête
Réponse

Une fois sur deux, le modèle ne voit jamais la réponse.

Pratique (30 min)

  1. Écrivez bench/rag.jsonl : dix questions avec la note qui répond à chacune.
  2. Calculez le rappel@1 et le rappel@4 de votre index ; essayez un changement (taille des morceaux ou modèle d'embeddings) et comparez.
  3. Ajoutez un outil search_index(question) à votre serveur MCP et laissez l'agent de notes s'en servir ; les réponses doivent citer source.

Avec votre IA : « Voici mes dix questions de test de recherche et, pour chacune, les quatre premières sources renvoyées et celle attendue : [collez]. Calcule le rappel@1 et le rappel@4 en montrant le calcul ; puis regroupe les échecs par cause probable (vocabulaire différent, borne de morceau, question ambiguë) et propose une correction par groupe. »

Le faire faire par un agent : maintenant que vous avez mesuré le rappel à la main, un agent peut lancer la grille de comparaison : « Pour des morceaux de 400, 800 et 1 600 caractères, reconstruis l'index, calcule le rappel@1 et le rappel@4 sur bench/rag.jsonl, et écris un tableau dans bench/rag-results.md ; ne modifie pas rag.jsonl. » Vérifiez une ligne en la relançant vous-même.

Synthèse (10 min)

Trois lignes : deux causes d'une mauvaise réponse, le rappel@k, votre résultat. Refaites recallAtK sans notes.

Jour 41 · 13/12 — La mémoire

Objectif : donner aux agents une mémoire qui survit à une session, sans la laisser pourrir.

Théorie 1/2 : les sortes de mémoire

Dans une session, la mémoire, c'est le contexte. D'une session à l'autre, c'est ce que le code écrit et relit : fichiers de notes, base de données, index RAG des essais passés. MemGPT (Packer et al., 2023) l'a pensé comme un système d'exploitation : un petit « contexte principal » rapide et une grande mémoire externe que l'agent charge et décharge avec des outils. Des versions simples marchent bien : un fait par fichier, un court index chargé au démarrage, le reste cherché à la demande.

Où vit la mémoire d'un agent entre deux sessions ?

  1. Dans des fichiers ou des bases écrits par du code
  2. Dans les poids du modèle, qui apprennent en travaillant
Réponse

Les poids ne changent pas pendant qu'on utilise le modèle.

Théorie 2/2 : la mémoire se périme

Un fait mémorisé peut être dépassé, et un modèle qui le lit le répétera avec une totale assurance. Donnez à chaque souvenir une date et une source ; quand un fait change, mettez la note à jour en gardant l'historique dessous ; faites expirer ce qui peut expirer. Les paquets de connaissances du site ajoutent un test et une date d'expiration à chaque affirmation ; l'état d'un agent en fichier portable garde un agent entier en fichiers texte.

Une note de mémoire dit « le serveur est en version 2 ». Il est maintenant en version 3. La meilleure correction ?

  1. Ajouter à côté une seconde note « version 3 »
  2. Mettre à jour la note avec l'état actuel en tête, daté, et garder l'ancien état comme historique daté
Réponse

Deux notes contradictoires font choisir l'agent au hasard.

Pratique (30 min)

  1. Créez memory/ avec un fichier Markdown par fait (en-tête : date, source) et memory/INDEX.md, une ligne par fait.
  2. Ajoutez deux outils à votre serveur MCP : remember(name, text, source) (écrit ou met à jour un fichier, daté) et recall(query) (cherche dans le dossier de mémoire).
  3. Faites tourner l'agent sur trois sessions ; vérifiez ce qu'il a écrit ; corrigez à la main un fait périmé.

Avec votre IA : « Voici l'index du dossier de mémoire de mon agent et trois de ses notes : [collez]. Trouve les notes qui se contredisent, celles sans source ni date, et celles qui affirment quelque chose qui a pu changer. Pour chacune, cite-la et propose la note corrigée. »

Le faire faire par un agent : après avoir nettoyé la mémoire une fois à la main, un agent peut l'auditer chaque semaine : « Liste les notes de mémoire de plus de 30 jours ou sans source, et pour chacune propose garder, mettre à jour ou supprimer, sans modifier aucun fichier. » Vous décidez et vous modifiez.

Synthèse (10 min)

Trois lignes : la mémoire dans et entre les sessions, pourquoi les notes se périment, comment les dater. Refaites le deuxième exercice sans notes.

Jour 42 · 14/12 — Prompter pour l'orchestration : les intentions

Objectif : écrire la tâche confiée à un agent exécutant pour qu'il puisse réussir et que vous puissiez vérifier.

Théorie 1/2 : intention faible et corrigée

Intention faible confiée à un exécutant de code : « Améliore le RAG, il est pas terrible. » Ce qui ne va pas : aucun objectif mesurable, aucun fichier, aucune donnée, aucune limite, aucune preuve. Intention corrigée :

Objectif : faire passer le rappel@4 sur bench/rag.jsonl de 0,6 à au moins 0,8.
Contexte : le découpage est dans ainet/rag.py (fonction split_note) ; l'index est reconstruit par scripts/index.py.
Fichiers que tu peux modifier : ainet/rag.py, tests/test_rag.py. Rien d'autre.
Données : voici les deux questions manquées et leurs sources attendues : [collez les vraies lignes].
Contraintes : garde le modèle d'embeddings ; aucune nouvelle dépendance.
Livrable : la modification, un test qui exécute split_note sur une note d'exemple, et les nouveaux chiffres de rappel.
Fini quand : uv run pytest -q passe et scripts/recall.py affiche un rappel@4 >= 0,8.

Le site a mesuré ce qui fait marcher ces passages de relais avec des agents de code locaux dans confier du code à un agent local : quatre livrables au plus, les vraies données collées, un test qui s'exécute, et une pull request que quelqu'un lit.

Quelle ligne d'une intention compte le plus pour vérifier le résultat ?

  1. L'objectif écrit poliment
  2. La liste des fichiers de contexte
  3. « Fini quand » avec une commande et un seuil
Réponse

Elle transforme « mieux » en quelque chose que le code peut vérifier.

Théorie 2/2 : corrigez cette intention

« Regarde dans l'autre dépôt le format JSON et adapte l'analyseur. » La correction la plus utile est…

  1. ajouter « attentivement »
  2. coller un vrai échantillon JSON et dire de ne pas le chercher ailleurs
Réponse

Donnez la donnée, pas sa description : un exécutant peut brûler tout son budget à chercher.

Pratique (30 min)

  1. Écrivez trois intentions dans intents/ pour de vraies améliorations de votre labo (une par fichier), chacune avec objectif, fichiers de contexte, fichiers permis, données, contraintes, livrable, « fini quand ».
  2. Confiez-en une à un agent de code (harnais du jour 32) et laissez-le travailler.
  3. Vérifiez le résultat uniquement par la commande « fini quand », puis lisez le diff.

Avec votre IA : « Voici une intention que j'ai écrite pour un agent de code : [collez]. Vérifie-la selon sept parties : objectif chiffré, fichiers de contexte, fichiers autorisés à changer, vraies données collées, contraintes, livrables (quatre au plus), commande « fini quand ». Pour chaque partie absente ou vague, propose la ligne exacte à ajouter. »

Le faire faire par un agent : cette séance est le passage de relais lui-même : vous avez écrit l'intention à la main, l'agent fait le travail. Ce que vous faites encore vous-même : lancer la commande « fini quand », lire chaque ligne du diff, et refuser tout ce qui sort des fichiers permis.

Synthèse (10 min)

Trois lignes : les sept parties d'une intention, pourquoi les vraies données, pourquoi une commande « fini quand ». Réécrivez de mémoire l'intention faible.

Jour 43 · 15/12 — Des agents sur plusieurs machines

Objectif : relier agents et modèles sur deux machines sans rien exposer à Internet.

Théorie 1/2 : ce qui traverse le réseau

Un réseau d'agents domestique typique : une machine avec GPU sert les modèles ; un portable fait tourner l'orchestrateur ; un petit boîtier toujours allumé fait tourner l'automatisation. Entre eux circulent des appels à l'API des modèles (HTTP), du MCP en Streamable HTTP, et du SSH pour les commandes. Les règles : les services n'écoutent que sur une interface privée, jamais sur toutes les interfaces d'une machine joignable depuis Internet ; chaque service HTTP exige une clé d'API (llama-server a --api-key) ; le trafic entre machines passe par un réseau privé chiffré.

Vous lancez llama-server avec --host 0.0.0.0 sur une machine à adresse publique, sans clé. Le risque ?

  1. Aucun
  2. Quiconque trouve le port peut utiliser votre GPU et lire vos prompts
Réponse

Écoutez sur une interface privée et exigez une clé.

Théorie 2/2 : réseaux privés et SSH

WireGuard est un protocole VPN moderne ; des outils de maillage construits dessus, comme Tailscale, relient vos machines comme si elles étaient sur un même réseau local. SSH reste l'outil des commandes, et les agents qui lancent beaucoup de commandes SSH gagnent à partager les connexions ; le SSH pour un poste d'agents du site liste quatre pièges, dont celui de ne jamais passer de texte libre en argument d'une commande distante.

Le serveur de modèles doit écouter…

  1. sur l'interface du réseau privé seulement, avec une clé d'API
  2. sur toutes les interfaces, par commodité
Réponse

Exposition minimale, plus authentification.

Pratique (30 min)

  1. Avec deux machines : reliez-les par un réseau privé (WireGuard ou un outil de maillage), lancez llama-server sur l'une avec --host sur son adresse privée et --api-key lue dans une variable d'environnement, et appelez-le depuis l'autre. Avec une seule machine : simulez avec deux ports sur 127.0.0.1 et une clé.
  2. Sur la machine serveur, vérifiez avec ss -tlnp sur quelle adresse écoute chaque service ; notez le tableau dans le carnet (avec des adresses de documentation comme 192.0.2.10 si vous le publiez).
  3. Essayez un appel sans la clé et notez l'erreur.

Avec votre IA : « Voici la sortie de ss -tlnp sur mon serveur de modèles, adresses remplacées par des adresses de documentation : [collez]. Pour chaque service en écoute, dis s'il est joignable depuis la machine seule, le réseau privé ou partout, et lesquels ont besoin d'une clé d'API ou d'une règle de pare-feu. Explique comment tu lis chaque ligne. »

Le faire faire par un agent : une fois vos ports vérifiés à la main, un agent peut refaire l'audit sur chaque machine : « En SSH, lance ss -tlnp en lecture seule sur ces hôtes, liste chaque service qui écoute sur une adresse autre que la boucle locale, et signale ceux sans authentification. » Vérifiez vous-même tout service signalé avant de le modifier.

Synthèse (10 min)

Trois lignes : ce qui circule entre machines, où écoutent les services, pourquoi une clé. Refaites le premier exercice sans notes.

Jour 44 · 16/12 — Livrable du module 3 : un réseau de deux agents

Objectif : publier un orchestrateur et un exécutant qui coopèrent, avec routage, recherche, traces et schéma.

Théorie 1/2 : ce qu'il faut montrer

Un relecteur veut voir : l'architecture (qui appelle qui, par quel protocole, avec quelles permissions), le parcours d'une demande, comment décide le routage, ce qui est mesuré (rappel, étapes, tokens, temps), et les modes d'échec rencontrés. Un schéma et trois chiffres en disent plus qu'une page d'adjectifs.

Qu'est-ce qui a sa place sur votre schéma d'architecture ?

  1. Les logos de chaque outil
  2. Chaque processus, le protocole entre eux, et ce que chacun peut lire ou modifier
Réponse

Flux et permissions, c'est ce que vérifie un relecteur.

Théorie 2/2 : nommer les modes d'échec

Notez les échecs rencontrés et ce qui les attrape maintenant : un exécutant qui invente une source (attrapé par la vérification des sources), une boucle qui ne s'arrêtait pas (attrapée par le plafond), une route qui envoyait du code au petit modèle (attrapée par la règle). Cette liste est le début du jeu de tests du module 4.

Votre agent a un jour bouclé en appelant le même outil. Qu'est-ce qui va dans le README ?

  1. L'échec, sa cause, et le garde-fou qui l'arrête désormais
  2. Rien : c'est réparé
Réponse

Les échecs connus et leurs garde-fous montrent que vous comprenez le système.

Pratique (30 min)

  1. Dessinez le schéma (du Mermaid dans du Markdown suffit) : utilisateur → orchestrateur → passerelle → modèles ; orchestrateur → exécutants → serveur MCP → notes, index, mémoire.
  2. Écrivez docs/network.md : composants, protocoles, permissions par composant, règles de routage, mesures des jours 36 et 40, modes d'échec et garde-fous.
  3. Faites passer les cinq questions de référence de bout en bout, enregistrez les traces dans runs/module-3/, faites un commit, posez l'étiquette module-3.

Avec votre IA : « Voici mon document d'architecture pour un réseau de deux agents : [collez]. Joue un relecteur attentif à la sécurité : pour chaque composant, demande ce qu'il peut lire, modifier et joindre sur le réseau, et signale tout composant dont les permissions ne sont pas écrites. Puis liste les trois questions que tu me poserais en entretien à son sujet. »

Le faire faire par un agent : maintenant que vous avez écrit le document vous-même, un agent peut le confronter au code : « Lis docs/network.md et le code ; liste chaque affirmation du document que le code contredit ou qui n'a pas de code derrière elle, avec fichier et ligne. » Corrigez vous-même le document ou le code.

Synthèse (10 min)

Trois lignes : ce que vous avez construit, votre meilleure mesure, votre pire échec. Refaites sans notes l'exercice runAgent du jour 30.

Sources

Utile ? Dites-nous ce qu'il faut mesurer ensuite.