Activité pratique
Durée3h45Consignes globales
Le fil conducteur de cette activité est un petit projet uv, comme ceux des séances 2 et 3. Vous n’allez pas y écrire un gros programme : le but n’est pas le programme, c’est ce que vous observez en le faisant écrire par des IA.
À partir de cette séance, vous serez autorisé(e)s à utiliser des agents IA pour vous aider à coder au semestre 5 (hors exceptions mentionnées explicitement). Cependant, il est nécessaire de bien comprendre comment ils fonctionnent avant de les utiliser, c’est pourquoi nous allons passer cette séance à observer leurs comportements. N’oubliez pas de consulter les fiches de la séance, notamment celle sur la responsabilité.
Contenu de l’activité
Repérer l’IA dans votre éditeur
Avant de se servir d’une IA, il faut savoir où elle est. Cette partie est un inventaire : vous allez déclencher les quatre formes d’assistance une par une et relever ce qu’elles coûtent.
Préparer le projet
À faire
Dans votre dossier IMT/S5/info/env/session4, initialisez un projet uv. Ouvrez ensuite ce répertoire en tant que dossier courant dans VS Code.
Vérifier son compte
À faire
Connectez-vous à votre compte GitHub depuis l’icône de compte, en bas de la barre latérale de VS Code. Vérifiez que l’activation de GitHub Education est bien passée : le menu de choix du modèle, dans la fenêtre de discussion, doit proposer plusieurs entrées.
Si votre demande GitHub Education n’est pas encore validée, installez l’extension Continue depuis la marketplace : son offre gratuite suffit pour toute l’activité. La partie sur le choix du modèle sera simplement moins démonstrative, faute de pouvoir changer de modèle.
Les quatre intégrations IA
À faire
Dans un fichier inventaire.py, déclenchez successivement les quatre formes d’assistance décrites dans la fiche L’IA dans l’IDE, rappelées ci-dessous. Pour chacune des quatre formes, regardez où elle se déclenche dans l’interface, ce qu’elle a modifié sur votre disque, et si on vous a demandé une validation avant.
- La complétion : tapez
def moyenne(valeurs):puis passez à la ligne et attendez. Regardez le texte grisé sans l’accepter. - La discussion : ouvrez la fenêtre de chat et demandez à quoi sert
uv.lock. - L’édition en place : sélectionnez votre fonction, appelez Ctrl+I (Cmd+I sur macOS), et demandez d’ajouter des annotations de type.
- Le mode agent : basculez la fenêtre de discussion en mode agent et demandez de créer un fichier
bonjour.pyqui affiche l’heure.
Le compteur
À faire
Ouvrez le compteur de requêtes depuis l’icône Copilot de la barre d’état, en bas de la fenêtre. Notez sa valeur : vous la regarderez de nouveau à la fin de la partie sur le choix du modèle, puis à la fin de la partie sur le mode agent.
Le choix du modèle
On va ici chercher à comparer le code produit par deux modèles, afin d’évaluer leurs différences.
L’énoncé
On veut ranger des notes d’étudiant(e)s dans des tranches via la fonction suivante :
def repartition (notes: list[float], bornes: list[float]) -> dict[str, list[float]]
bornesest une liste de nombres, fournie dans un ordre quelconque.- Chaque tranche va d’une borne à la suivante, fermée à gauche, ouverte à droite : $[b0, b1[$, $[b1, b2[$, …
- La dernière tranche est fermée des deux côtés : $[b(n-1), b(n)]$.
- Les notes hors de l’intervalle total sont rangées à part, sous la clé “hors bornes”.
- Le dictionnaire associe à chaque clé la liste des notes correspondantes. Toutes les tranches y figurent, même vides, ainsi que la clé “hors bornes”.
- Le dictionnaire est ordonné par borne croissante, et ses clés sont des chaînes décrivant les tranches, du type
"[0, 10[","[10, 20]"et"hors bornes".
Le juge
À faire
Créez test_repartition.py à la racine du projet, avec le contenu ci-dessous. C’est votre juge : il servira à départager les deux versions de la fonction, et il ne doit pas entrer dans le contexte de l’assistant avant la fin de la comparaison (voir ci-dessous).
Si l’assistant lit les tests, il écrit du code pour les faire passer, et la comparaison ne mesure plus sa capacité à suivre l’énoncé. Or, comme expliqué dans la fiche Le contexte, plusieurs mécanismes peuvent y faire entrer le juge sans que vous le demandiez :
- Le fichier actif dans l’éditeur est joint automatiquement à vos demandes, et les autres onglets ouverts peuvent l’être aussi.
- Les recherches dans le projet (
#codebase,@workspace, et celles que le mode agent lance de lui-même) peuvent tomber dessus.
À faire
Une fois test_repartition.py enregistré :
- Fermez son onglet, et ne le rouvrez pas avant d’avoir obtenu les deux versions de la fonction.
- Excluez-le de l’espace de travail, en créant un fichier
.vscode/settings.jsonavec le contenu ci-dessous. Le juge disparaît de l’explorateur et des recherches de l’assistant, mais il est toujours sur le disque : les tests s’exécutent normalement depuis le terminal. - Restez en mode discussion pour toute cette partie, sans utiliser
#codebaseni@workspace.
Plus simplement, vous pouvez également déplacer le fichier dans un dossier hors du projet le temps d’utiliser vos agents, par exemple sur votre bureau. Pensez également à fermer l’onglet.
Générer la fonction avec deux modèles différents
À faire
Dans la fenêtre de discussion, choisissez le modèle le plus rapide proposé par le menu. Demandez-lui d’écrire la fonction, en donnant l’énoncé ci-dessus. Enregistrez le résultat dans repartition_rapide.py.
Puis recommencez dans un nouveau chat, avec exactement la même demande, en choisissant cette fois le modèle de raisonnement le plus performant du menu. Enregistrez dans repartition_raisonnement.py.
Vous pouvez maintenant rouvrir le juge : retirez l’exclusion de .vscode/settings.json, ou remettez le fichier dans votre projet si vous l’aviez déplacé.
À faire
Faites passer les tests aux deux versions, l’une après l’autre, en adaptant l’import en tête de test_repartition.py (par exemple from repartition_rapide import repartition). Les tests se lancent avec la commande ci-dessous.
Regardez pour chaque version le nombre de tests qui passent, et lesquels échouent le cas échéant.
Regardez de nouveau le compteur de requêtes. Combien cette partie a-t-elle consommé ?
Le contexte
La complétion imite votre style
Vous allez maintenant vérifier, en le provoquant, que la complétion reproduit ce qu’elle lit juste au-dessus du curseur.
Poser un style
À faire
Créez stats.py et recopiez-y les deux fonctions ci-dessous à la main, sans accepter aucune suggestion. Leur style est délibérément marqué : annotations de type, docstring en français au format NumPy, espace avant les deux-points, garde explicite sur la liste vide, et une seule sortie en fin de fonction.
Observer la contagion
À faire
À la suite, tapez uniquement la ligne suivante, puis passez à la ligne et attendez sans rien taper :
Regardez la proposition sans l’accepter. Puis acceptez-la et lisez-la en entier.
Regardez ce qui a été imité et ce qui ne l’a pas été : l’espace avant les deux-points ? la docstring NumPy en français ? la garde sur la liste vide ? la variable resultat et la sortie unique ?
À faire
Maintenant l’expérience inverse. Créez un fichier vide stats_bis.py, et tapez-y la même ligne def variance (valeurs : list[float]) -> float :.
Comparez la proposition à la précédente. Qu’est-ce qui change, et pourquoi ?
Réutiliser ou réécrire
C’est l’expérience la plus importante de la séance. Vous allez poser la même demande à deux endroits : dans l’éditeur, et dans un onglet de navigateur. Puis vous comparerez le code obtenu.
La demande
On veut ajouter à stats.py une fonction resume(valeurs) qui renvoie un dictionnaire contenant la moyenne, l’étendue et le nombre de valeurs.
Cette fonction n’a aucune raison de recalculer quoi que ce soit : moyenne et etendue existent déjà, juste au-dessus.
Chat externe Vs. Assistant intégré
À faire
Ouvrez un assistant dans votre navigateur (ChatGPT, Le Chat, Claude, celui que vous utilisez). Demandez-lui la fonction resume, en décrivant ce qu’elle doit renvoyer, sans lui donner votre fichier.
Collez sa réponse dans resume_externe.py.
À présent, comparons avec le chat intégré à VS Code pour voir l’importance du contexte.
À faire
Dans VS Code, ouvrez la fenêtre de discussion, joignez explicitement votre fichier avec #file:stats.py, et faites la même demande, mot pour mot.
Collez sa réponse dans resume_integre.py, puis comparez les deux fichiers.
Rendre le contexte durable
Répéter « réutilise les fonctions existantes » à chaque demande est fastidieux. On peut l’écrire une fois pour toutes.
À faire
Créez .github/copilot-instructions.md à la racine du projet, avec quelques consignes correspondant au style de stats.py : annotations de type obligatoires, docstrings NumPy en français, réutilisation des fonctions existantes, pas de nouvelle dépendance.
Puis demandez, dans une nouvelle discussion et sans joindre de fichier cette fois, une fonction mediane(valeurs). Le style est-il respecté sans que vous l’ayez redemandé ?
Découvrir le mode agent
Dans la première partie, vous avez déclenché le mode agent sur une tâche triviale. Vous allez maintenant lui confier une vraie tâche sur votre projet, qui demande de lire du code existant, de créer plusieurs fichiers et d’exécuter une commande. Le but n’est pas tant le résultat que ce que l’agent fait pour y arriver, à comparer avec la boucle décrite dans la fiche L’IA dans l’IDE.
Confier une tâche à l’agent
À faire
Notez la valeur du compteur de requêtes. Puis, dans une nouvelle discussion, passez en mode agent et formulez la demande ci-dessous.
Crée un script
main.pyqui lit des notes dans un fichiernotes.txt(une note par ligne), puis affiche leur moyenne et leur étendue en réutilisant les fonctions destats.py. Crée aussi un fichiernotes.txtd’exemple, puis exécutemain.pypour vérifier que tout fonctionne.
Observer ce qu’il fait
À faire
Pendant que l’agent travaille, ne cliquez sur rien sans avoir lu, et relevez les éléments suivants.
- Les fichiers qu’il lit, et comment il les trouve : les avez-vous désignés, ou les a-t-il cherchés lui-même ?
- Les fichiers qu’il crée ou modifie. En a-t-il touché un que vous n’aviez pas mentionné ?
- Les commandes qu’il veut exécuter, et le moment où il vous demande votre accord. Lisez chaque commande avant d’accepter. Utilise-t-elle
uv run, ou appelle-t-ellepythondirectement ? - Le nombre de tours : combien de fois a-t-il agi, lu un résultat, puis agi de nouveau ?
Relire avant de conserver
À la fin, VS Code liste les fichiers modifiés par l’agent, et propose de conserver ou d’annuler les modifications de chacun. Tant que vous n’avez pas tranché, rien n’est définitivement validé.
À faire
Relisez le diff de chaque fichier avant de conserver quoi que ce soit. En particulier, considérez les points suivants.
main.pyappelle-t-ilmoyenneetetendue, ou recalcule-t-il de son côté ?- Le style de
stats.pyet les consignes de.github/copilot-instructions.mdsont-ils respectés ? - Que se passe-t-il si
notes.txtcontient une ligne vide, ou une ligneabc? Ajoutez-en une, et lancez vous-même le script avecuv run python main.py.
Demander une correction
À faire
Dans la même discussion, demandez à l’agent d’ignorer les lignes vides, et de lever une ValueError indiquant le numéro de la ligne en cas de ligne invalide. Observez de nouveau ce qu’il fait, et relisez le diff.
Regardez enfin le compteur de requêtes. Combien cette partie a-t-elle consommé, comparée à une simple question dans la fenêtre de discussion ?
Pour aller plus loin
Le harnais : ce que l’agent peut vérifier lui-même
Un agent seul ne peut que produire du texte plausible. Ce qui le rend réellement utile, c’est le harnais : l’ensemble des outils qu’on lui donne pour vérifier son propre travail : exécuter les tests, lire une erreur, relancer. Sans harnais, il devine. Avec, il itère.
Vous allez mesurer la différence sur le même énoncé.
Sans harnais
À faire
Dans un dossier sans_harnais/, en mode discussion (pas agent), demandez une fonction parse_duree(texte) qui transforme une durée écrite en chaîne vers un nombre de secondes, en acceptant les formats "90", "1m30", "1h05m", "2h", et en levant ValueError sur une entrée invalide.
Collez le résultat dans sans_harnais/duree.py. Puis écrivez vous-même, dans sans_harnais/test_duree.py, des tests unittest couvrant ces quatre formats et un cas invalide (pour ce dernier, utilisez self.assertRaises(ValueError)). Lancez-les depuis le dossier sans_harnais/ :
Combien passent du premier coup ?
Avec harnais
À faire
Dans un dossier avec_harnais/, écrivez d’abord le fichier de tests test_duree.py, seul, avec unittest (vous pouvez reprendre celui de sans_harnais/). Puis passez la fenêtre de discussion en mode agent et formulez la demande ainsi :
Écris
parse_dureedansavec_harnais/duree.pypour queavec_harnais/test_duree.pypasse entièrement. Après chaque modification, lance les tests avecuv run python -m unittest test_duree.pydepuis le dossieravec_harnais/, et corrige jusqu’à ce que tous les tests passent. Ne modifie pas le fichier de tests.
Laissez l’agent travailler, et regardez ce qu’il fait : les commandes qu’il lance, les sorties qu’il lit, les corrections qu’il enchaîne. Combien de tours lui a-t-il fallu ? Sur quoi s’est-il repris ?
À faire
Comparez les deux situations : qu’est-ce qui a changé entre les deux, du point de vue du modèle ? La dernière consigne (« ne modifie pas le fichier de tests ») vous paraît-elle nécessaire ? Que se passerait-il sans elle ?
Regardez une dernière fois le compteur de requêtes. Quelle partie de l’activité a le plus consommé ? Est-ce celle qui vous a le plus servi ?
Pour aller encore plus loin
-
Une étude d’Anthropic sur l’effet de l’assistance sur l’apprentissage de la programmation, et sur les usages qui consolident ou érodent les compétences (en anglais). À lire avant de prendre vos habitudes pour le projet.
-
La liste de référence des failles propres aux applications construites autour d’un modèle : injection de prompt, fuite de données, chaîne d’approvisionnement (en anglais).
-
Ce qui distingue un enchaînement d’appels bien conçu d’un agent autonome, et pourquoi la solution la plus simple qui marche est presque toujours la bonne (en anglais). Le prolongement direct de la partie sur le harnais.
-
Une série d’articles de Simon Willison sur une vulnérabilité structurelle des agents : un agent qui lit un fichier, une page web ou un ticket peut y trouver des instructions et les suivre (en anglais).