Les nouvelles technologies pour l’enseignement des mathématiques
Intégration des TICE dans l’enseignement des mathématiques

MathémaTICE, première revue en ligne destinée à promouvoir les TICE à travers l’enseignement des mathématiques.

Intelligence artificielle et NSI

NDLR : Dans cet article Jean-Philippe Vanroyen et Arnaud Moragues nous font part de leur expérience et réflexion sur les usages de modèles d’intelligence artificielle générative dans le cadre de l’enseignement en spécialité NSI. Les IA génératives sont elles efficaces pour la résolution de problèmes de programmation ? Sont-elles un outil efficace pour aider l’enseignant ? Dans quelles mesures peuvent-elles être une aide dans les apprentissages des élèves ?

Article mis en ligne le 1er mai 2024
dernière modification le 7 mai 2024

par Arnaud Moragues, Jean-Philippe Vanroyen


 Introduction

Pour écrire cet article, nous avons utilisé ChatGPT 4 car il est plus performant que la version gratuite de ChatGPT et donne selon nous une image de ce que proposera rapidement le ChatGPT3 futur.
Les progrès de l’IA sont déconcertants. Nous avons proposé à ChatGPT 4 de résoudre trois exercices du « sujet 1 juin Métropole 2022 » de NSI (en 2022, le candidat devait choisir et traiter trois exercices parmi les cinq proposés). Pour y parvenir, il suffit de copier une à une chaque question, plus précisément en faire une image, puis de coller l’image dans le chat. Après analyse des images, l’IA répond donc progressivement aux questions collées. La note de cette copie virtuelle est de l’ordre de 17/20. Non seulement les réponses sont exactes, mais les explications fournies en font également une excellente copie du point de vue de la rédaction, comme en témoigne l’exemple suivant.

Question 3 de l’exercice 1
BAC NSI : sujet 1 juin Métropole 2022

L’objectif étant de déterminer si une expression est correctement parenthésée, la question demande de compléter un code. Étant en début de sujet et d’exercice, la question est très simple. On appréciera donc davantage ici la qualité de la rédaction ainsi que le souci de clarté de la réponse proposée par ChatGPT (pour la clarté de la présentation de l’article, les réponses de ChatGPT qui ne sont pas du code sont en italique).

ChatGPT
La question 3 vous demande de compléter les tests dans la fonction parenthesage_correct pour vérifier si une expression contenant uniquement des parenthèses est correctement parenthésée. Les tests doivent vérifier :
Si à un moment donné le « contrôleur » devient négatif, cela signifie qu’une parenthèse fermante a été rencontrée sans qu’il y ait une parenthèse ouvrante correspondante. Dans ce cas, la fonction doit retourner False.
Après avoir vérifié toutes les parenthèses, si le « contrôleur » n’est pas revenu à zéro, cela signifie qu’il y a des parenthèses ouvrantes sans les parenthèses fermantes correspondantes. La fonction doit aussi retourner False dans ce cas.
Sinon, si ces deux conditions ne sont pas remplies, cela signifie que chaque parenthèse ouvrante a une parenthèse fermante correspondante, et la fonction doit retourner True.

Voici le code complété :

def parenthesage_correct(expression):
   """ fonction retournant True si l'expression arithmétique simplifiée (str) est correctement         parenthésée, False sinon. Condition: expression ne contient que des parenthèses ouvrantes
      et fermantes ""
   controleur = 0
   for parenthese in expression: # pour chaque parenthèse
       if parenthese == '(':
           controleur = controleur + 1
       else  # parenthese == ')'
           controleur = controleur - 1
       if controleur < 0: # test 1 (à recopier et compléter)
           return False # parenthèse fermante sans parenthèse ouvrante
       if controleur == 0: # test 2 (à recopier et compléter)
           return True # le parenthésage est correct
       else:
           return False # parenthèse(s) fermante(s) manquante(s)

Avec ce code, la fonction parenthesage_correct retournera True si l’expression est correctement parenthésée, et False si elle ne l’est pas, conformément aux règles énoncées dans l’exercice.)

On rêverait d’une copie pareillement rédigée !
Outre ChatGPT, nous avons opté pour le modèle propriétaire le plus performant (au début de l’écriture de l’article, d’autres sont déjà sortis depuis !) de l’entreprise Française Mistral : mistral-medium. Comme il est dépourvu de chatbot et même d’interface graphique, nous l’avons interrogé directement via l’API d’Open AI, à l’aide d’un gestionnaire libre d’API, Bruno (usebruno.com).

Un point très important à noter immédiatement est que l’IA de ChatGPT permet un dialogue avec l’utilisateur et donc dans certains cas une approche progressive vers la résolution d’un problème dans la mesure où un dialogue « constructif » est possible grâce à la mémorisation réelle des échanges. On peut d’ailleurs demander à ChatGPT d’oublier tout ce qui précède. Pour les curieux, et pour illustrer ce point, nous joignons à l’article une « discussion » avec ChatGPT dont l’objet est de résoudre une énigme (voir le document enigme_et_gpt.pdf).

Cependant, lorsque l’interactivité n’est pas possible, comme sur les modèles de langage de l’éditeur Français Mistral AI qui ne disposaient pas encore de la fonctionnalité Chat au début de l’écriture de cet article, les réponses de l’IA peuvent rester bluffantes, au prix de prompts (questions) plus précis et exhaustifs.

Pour commencer notre étude, nous avons choisi de soumettre ces deux IA à une batterie de tests, dans le but d’en évaluer leurs compétences et leurs impacts dans notre enseignement de NSI. Si les premiers constats sont encourageants, nous verrons que des problèmes sérieux subsistent.
Dans la plupart des cas, nous n’avons pas pu utiliser des prompts identiques sur les deux modèles. En effet, la présence ou l’absence de dialogue avec l’IA change considérablement la donne : là où il est possible de demander à ChatGPT de corriger ou d’affiner une réponse, l’absence de mémoire de mistral-medium oblige à produire d’emblée le meilleur prompt possible.

Dans la pratique, nous avons d’abord posé toutes les questions à ChatGPT, puis avons cherché à obtenir des réponses au moins d’un même niveau à l’aide de mistral-medium : là où ChatGPT nécessitait plusieurs étapes, nous les avons de manière préventive condensées dans notre unique prompt.

Au delà des performances des deux IA, on trouve la question de l’élève pour qui l’utilisation « intelligente » de ces systèmes peut poser problème. On peut questionner également l’intérêt pédagogique de ces outils pour le professeur.
Il nous faudra donc nous prononcer sur la pertinence de son utilisation, tant pour les élèves que pour l’enseignant.

 L’IA et la programmation en Python

Afin de donner une première idée des capacités de l’IA, voici six exemples de questions simples auxquelles répond correctement et très clairement ChatGPT.

1) Écrire en Python une fonction moyennecarressentiers demandant un paramètre entier n et renvoyant la moyenne (1+2²+…..+n²)/n.

2) Écrire en Python une fonction divisibilite1 demandant un paramètre entier n et renvoyant soit « n est pair » , soit « n est divisible par 3 et non par 2 », soit « je ne sais pas » dans tous les autres cas.

3) La suite de Fibonnacci est la suite suivante : 1 – 1 – 2 – 3 – 5 – 8 – 13 – 21 – 34 – ….
Quand on additionne les 9 premiers termes, on obtient 88.
a) Écrire une fonction Fibo1 demandant un paramètre entier n et renvoyant la somme des n premiers termes
de la suite de Fibonacci.
b) Écrire une fonction Fibo2 demandant un paramètre entier A et renvoyant le plus petit entier n tel que la
somme des n premiers termes soit supérieure à A.

4) Peux-tu m’expliquer ce que fait cette fonction ?

  1. def mystere3(uneliste):
  2. # uneliste est une liste de nombres
  3. for element in uneliste :
  4.     if element < 0 :
  5.         element = element**2
  6. return uneliste

Télécharger

5) Écrire une fonction rechercheliste demandant en paramètre une liste de chaînes et renvoyant l’indice de la chaîne la plus longue (si on a plusieurs chaînes de même longueur, alors on renvoie l’indice de la dernière). Si la liste est vide, elle renvoie -1.

6) Écrire une fonction compose demandant deux paramètres mot1 et mot2 de type string et renvoyant la chaîne alternant les lettres de chaque mot.

Voici à titre d’exemple les réponses à la question 6.

ChatGPT
Pour réaliser une fonction compose qui alterne les lettres de deux mots donnés en paramètres mot1 et mot2, vous pouvez utiliser la fonction intégrée zip pour itérer simultanément sur les deux chaînes. Si les mots n’ont pas la même longueur, il faut s’assurer que les lettres restantes du mot le plus long sont ajoutées à la fin du résultat.
Voici comment vous pourriez écrire cette fonction en Python :

def compose(mot1, mot2):
   resultat = []
   # Itérer sur les deux mots en même temps avec zip
   for lettre1, lettre2 in zip(mot1, mot2):
       resultat.append(lettre1)
       resultat.append(lettre2)
   
   # Ajouter les lettres restantes du mot le plus long
   resultat.extend(mot1[len(mot2):])
   resultat.extend(mot2[len(mot1):])
   
   # Convertir la liste en chaîne de caractères et la renvoyer
   return ''.join(resultat)

Cette fonction fonctionne de la manière suivante :
• La boucle for parcourt les deux mots tant qu’il y a des lettres dans les deux mots.
• Les lettres sont ajoutées alternativement à la liste resultat.
• Après la fin de la boucle, les lettres restantes dans le mot le plus long sont ajoutées à la fin du resultat.
• Enfin, la liste resultat est convertie en une chaîne de caractères à l’aide de join et renvoyée.
Voici un exemple d’utilisation :

print(compose("chat", "chien"))  # Exemple d'entrée

La réponse est exacte. Mais voilà déjà un point important qu’il faut noter. Nous sommes en Terminale et certaines instructions sont étrangères aux élèves (et au bac !) comme par exemple zip ou encore extend.
Il convient donc d’être vigilant et de demander une solution n’utilisant pas ces instructions.

Voici le code proposé (le code est correct) alors par ChatGPT :

ChatGPT

def compose(mot1, mot2):
   # Initialisation de la chaîne résultante
   resultat = ""
   # Calcul de la longueur maximale des deux mots
   longueur_max = max(len(mot1), len(mot2))
   
   # Boucle sur la longueur maximale des deux mots
   for i in range(longueur_max):
       # Ajout de la lettre de mot1 à resultat si i est dans la plage valide pour mot1
       if i < len(mot1):
           resultat += mot1[i]
       # Ajout de la lettre de mot2 à resultat si i est dans la plage valide pour mot2
       if i < len(mot2):
           resultat += mot2[i]
   
   return resultat

# Exemple d'utilisation
resultat = compose("chat", "chien")
print(resultat)  # Affiche 'cchhaiten'

La réponse de mistral-medium est intéressante dans la mesure où l’IA propose deux solutions, remédiant à un énoncé volontairement lacunaire :

échange avec mistral-medium
NDLR : bien que les fonctions proposées par l’IA soient correctes, leur exécution sur les exemples choisis par cette dernière ne produit pas les résultats annoncés. Cliquer pour en savoir plus…

Pour la première fonction :

  1. compose("bonjour","monde")
  2.  
  3. Traceback (most recent call last):
  4.   File "<input>", line 1, in <module>
  5.   File "<input>", line 3, in compose
  6. ValueError: Les deux mots doivent être de la ,même longueur

Télécharger

Pour la deuxième fonction :

  1. compose("bonjour","monde")
  2.  
  3. 'bmoonnjdoeu-r-'
  4.  
  5. compose("bonjour","moi")
  6.  
  7.  
  8. 'bmoonij-o-u-r-'

Télécharger

On notera cependant que la réponse de ChatGPT est davantage détaillée avec comme toujours une volonté de clarté dans les réponses.

Les questions peuvent être plus complexes. En voici un exemple avec ChatGPT. Elle concerne la notation polonaise inversée (NPI [1]) et l’évaluation des expressions à l’aide de piles implémentées en Programmation Orientée Objet. Les piles constituent un pilier très important dans le programme de Terminale.
Dans la notation NPI, 4 5 + 2 * se lit de gauche à droite. À chaque fois que l’on rencontre un opérateur, on évalue avec les deux nombres le précédant.
Ainsi 4 5 + 2 * devient 9 2 * qui devient 18.
Autre exemple : 2 5 8 6 - * / devient 2 5 2 * / qui devient 2 10 / qui devient 0,2.

Voici la question.

You
Nous disposons de l’interface suivante :

class Pile:
def __init__(self):
   # crée un pile vide
def est_vide(self):
   # renvoie True si la pile est vide
def empiler(self,a):
   # ajoute l'élément a à la pile
def depiler(self):
   # retire l'élément au sommet de la pile et le renvoie
def nbelement(self)
   # retourne le nombre d'éléments de la pile
def copie(self):
    # retourne une pile qui est une copie de la pile appelant la méthode

En utilisant cette classe, je voudrais une fonction evalue_npi(expression) évaluant une expression NPI et renvoyant sa valeur.
Par exemple,
evalue_npi("4,5,+,13,8,-,*’) renvoie 45

ChatGPT
Pour créer une fonction evalue_npi(expression) qui évalue une expression en notation polonaise inversée (NPI) et renvoie sa valeur, nous devons suivre quelques étapes logiques :
Diviser l’expression : Commencez par diviser l’expression en éléments individuels.
Dans votre exemple, les éléments sont séparés par des virgules.
Parcourir chaque élément : Ensuite, parcourez chaque élément de l’expression.
Si l’élément est un nombre, empilez-le.
Si c’est un opérateur, dépilez les deux éléments supérieurs, appliquez l’opérateur, puis empilez le résultat.
Utiliser la classe Pile : Utilisez la classe Pile fournie pour gérer les empilements et les dépilements des éléments.
Renvoyer le résultat : À la fin de l’expression, le résultat sera au sommet de la pile.

def evalue_npi(expression):
   pile = Pile()
   for elem in expression.split(','):
       if elem in ['+', '-', '*', '/']:
           b = pile.depiler()
           a = pile.depiler()
           if elem == '+':
               pile.empiler(a + b)
           elif elem == '-':
               pile.empiler(a - b)
           elif elem == '*':
               pile.empiler(a * b)
           elif elem == '/':
               pile.empiler(a / b)
       else:
               pile.empiler(int(elem))
       return pile.depiler()

# Exemple d'utilisation
resultat = evalue_npi("4,5,+,13,8,-,*")
print(resultat)

Dans cet exemple, evalue_npi(« 4,5,+,13,8,-,* ») devrait bien renvoyer 45, comme dans votre exemple.

La solution proposée, très classique, est correcte.

Voici maintenant un exemple tiré du passage de l’écriture en chiffres romains à l’écriture décimale.
Le code suivant (que nous avons écrit) permet de le faire mais comporte volontairement une erreur.

  1. CR = { 'M' : 1000, 'D' : 500, 'C' : 100, 'L' : 50, 'X' : 10, 'V' : 5, 'I' : 1}
  2. def CR_to_DEC(ch,dernier=None):
  3.     if ch == "" :
  4.         return 0
  5.     else :
  6.         valeur_en_cours = CR[ch[0]]
  7.         if dernier == None:
  8.             return valeur_en_cours+CR_to_DEC(ch[1:],valeur_en_cours)
  9.         else :
  10.             if dernier < valeur_en_cours:
  11.                 return -dernier+valeur_en_cours+CR_to_DEC(ch[1:],None)
  12.             else :
  13.                 return valeur_en_cours+CR_to_DEC(ch[1:],valeur_en_cours)

Télécharger

Sans entrer dans les détails, on peut expliquer rapidement l’erreur. Quand on rencontre la chaîne IV par exemple, alors on ajoute d’abord 1, mais au moment d’ajouter 5, on réalise qu’il ne faut ajouter que 3 (pour ajouter 4 globalement) car le I précédant est soustractif.
Après avoir ajouté 1 ; il faut donc ajouter -2 * 1 + 5 et non pas écrire -1 + 5
Il manque donc un 2 * ici :
return -2*dernier+valeur_en_cours+CR_to_DEC(ch[1:],None)

Nous avons donc proposé ce code et demandé de le corriger en expliquant ce qui ne va pas.

Voici un extrait de la réponse de ChatGPT :

Lorsque vous détectez qu’une soustraction est nécessaire (if dernier < valeur_en_cours), vous devez soustraire deux fois la dernière valeur car elle a été ajoutée précédemment lors de l’appel récursif. Par exemple, pour "IV", lors du traitement de ’I’, 1 est ajouté, puis, lors du traitement de ’V’, il faut soustraire deux fois 1 avant d’ajouter 5.

Pour qui n’est pas habitué, la réponse est assez bluffante...
Voici un exemple plus difficile, même s’il s’agit d’un problème très classique. C’est une question qui a été posée à un concours d’informatique à destination des élèves de lycée.
Avant de présenter la question posée, voici de quoi il s’agit :

Considérons le tableau ci-contre :

Nous sommes en haut à gauche et devons rejoindre la case en bas à droite. Deux déplacements seulement sont autorisés : vers la droite et vers le bas. Il s’agit de trouver le chemin de somme minimale.
Par exemple, le chemin 7 – 1 – 6 – 4 – 5 – 10 a pour somme 33 , mais ce n’est pas le minimum.

You
Voici un problème à résoudre en Python.
On considère un quadrillage comportant n lignes et p colonnes.
Chaque case contient un entier positif. Par exemple, voici un quadrillage de 3 lignes et 5 colonnes :
7 , 1 , 2 , 1 , 4 , 6 , 3 , 1 , 6 , 4 , 5 , 10
On part de la case en haut à gauche (dans l’exemple ci-dessus 7), et à chaque étape on avance vers la droite ou en descend afin d’atteindre la case en bas à droite (dans l’exemple ci-dessus 10).
On cherche le chemin donnant une somme minimale.
On représente le quadrillage à l’aide d’une liste de chaînes de caractères, chacun des éléments étant une ligne du quadrillage.
recherche_chemin([« 7,1,2,1 »,« 4,6,3,1 »,« 6,4,5,10 »]) doit renvoyer 22 et « droite,droite,droite,bas,bas »
Comment résoudre ce problème ? Tu peux utiliser si nécessaire plusieurs fonctions.

ChatGPT
Pour résoudre ce problème, vous pouvez utiliser l’algorithme de programmation dynamique. L’idée principale est de créer une grille auxiliaire où chaque case représente le coût minimum pour atteindre cette case à partir de la case de départ en haut à gauche. Ensuite, vous pouvez retracer le chemin à partir de la case d’arrivée en bas à droite pour déterminer le chemin spécifique qui a mené à ce coût minimum.
Voici comment vous pouvez procéder :
1. Initialisation : Créer une grille auxiliaire de même taille que le quadrillage d’entrée. La première case (en haut à gauche) de cette grille auxiliaire sera égale à la première case du quadrillage d’entrée.
2. Remplissage de la grille auxiliaire : Pour chaque case, le coût minimum pour y parvenir est soit le coût minimum pour parvenir à la case juste au-dessus (si on vient de bas), soit le coût minimum pour parvenir à la case juste à gauche (si on vient de droite), plus la valeur de la case actuelle.
3. Retrouver le chemin : Une fois la grille auxiliaire complétée, commencez par la case d’arrivée en bas à droite et remontez vers la case de départ, en choisissant à chaque étape de se déplacer soit vers le haut, soit vers la gauche, selon le coût minimum.
Voici une implémentation possible en Python :

def recherche_chemin(grille):
   def parse_grid(grid):
       return [[int(num) for num in row.split(',')] for row in grid]

   def min_cost_path(grid):
       n, m = len(grid), len(grid[0])
       cost = [[0 for _ in range(m)] for _ in range(n)]

       cost[0][0] = grid[0][0]
       for i in range(1, n):
           cost[i][0] = cost[i-1][0] + grid[i][0]
       for j in range(1, m):
           cost[0][j] = cost[0][j-1] + grid[0][j]

       for i in range(1, n):
           for j in range(1, m):
               cost[i][j] = min(cost[i-1][j], cost[i][j-1]) + grid[i][j]

       return cost

   def find_path(cost):
       path = []
       i, j = len(cost) - 1, len(cost[0]) - 1
       while i > 0 and j > 0:
           if cost[i-1][j] < cost[i][j-1]:
               path.append('bas')
               i -= 1
           else:
               path.append('droite')
               j -= 1
       while i > 0:
           path.append('bas')
           i -= 1
       while j > 0:
           path.append('droite')
           j -= 1

       return path[::-1]

   grid = parse_grid(grille)
   cost = min_cost_path(grid)
   path = find_path(cost)

   return cost[-1][-1], ','.join(path)

# Test de la fonction
print(recherche_chemin(["7,1,2,1","4,6,3,1","6,4,5,10"]))

Dans ce code, la fonction principale recherche_chemin est divisée en trois sous-fonctions pour une meilleure organisation et compréhension :
1. parse_grid : Convertit le format d’entrée (chaînes de caractères) en une grille de nombres pour faciliter le calcul.
2. min_cost_path : Remplit une grille auxiliaire avec le coût minimum pour atteindre chaque case, en commençant par la case en haut à gauche et en se déplaçant soit vers le bas, soit vers la droite.
3. find_path : Retrace le chemin à partir de la case en bas à droite jusqu’à la case en haut à gauche, en choisissant à chaque étape la direction qui avait le coût minimum.
Finalement, ces fonctions sont utilisées dans recherche_chemin pour calculer et renvoyer le coût minimum et le chemin correspondant.

La solution proposée par ChatGPT n’est pas récursive. Or la version récursive est très élégante. D’où la question suivante :

You
Existe-t-il une version RECURSIVE permettant de résoudre ce problème ?

ChatGPT
Oui, il est possible de résoudre ce problème de manière récursive. La version récursive se base sur le principe de la division du problème en sous-problèmes plus petits. Pour chaque case, vous pouvez calculer le coût minimum pour y arriver en choisissant le plus petit des coûts pour arriver à la case juste au-dessus ou à la case juste à gauche, puis en ajoutant la valeur de la case actuelle. Cette approche est souvent moins efficace en termes de temps d’exécution que la programmation dynamique car elle peut impliquer de nombreux calculs répétitifs, mais elle est plus intuitive et plus simple à comprendre.
Voici comment vous pouvez procéder :
1. Créez une fonction récursive qui calcule le coût minimum pour atteindre une case donnée (i, j) dans la grille.
2. Si la case est la première case (en haut à gauche), retournez simplement sa valeur.
3. Si la case est sur la première ligne ou la première colonne, il n’y a qu’un seul chemin pour y arriver (tout droit depuis le haut ou depuis la gauche).
4. Pour les autres cases, le coût minimum est la valeur de la case actuelle plus le minimum entre le coût pour atteindre la case juste au-dessus et le coût pour atteindre la case juste à gauche.
5. Utilisez la récursion pour calculer ces coûts.
Voici une implémentation possible en Python :

def recherche_chemin_recursive(grille):
   def parse_grid(grid):
       return [[int(num) for num in row.split(',')] for row in grid]

   def min_cost(grid, i, j):
       # Cas de base: première cellule
       if i == 0 and j == 0:
           return grid[0][0]
       
       # Si on est sur la première ligne, on ne peut venir que de la gauche
       if i == 0:
           return grid[i][j] + min_cost(grid, i, j - 1)

       # Si on est sur la première colonne, on ne peut venir que d'en haut
       if j == 0:
           return grid[i][j] + min_cost(grid, i - 1, j)

       # Pour les autres cases, choisir le minimum entre venir de gauche ou d'en haut
       return grid[i][j] + min(min_cost(grid, i - 1, j), min_cost(grid, i, j - 1))

   grid = parse_grid(grille)
   n, m = len(grid), len(grid[0])
   return min_cost(grid, n - 1, m - 1)

# Test de la fonction
print(recherche_chemin_recursive(["7,1,2,1","4,6,3,1","6,4,5,10"]))


Cette version récursive calcule le coût minimum pour atteindre la case en bas à droite de la grille. Notez que cette implémentation peut être inefficace pour de grandes grilles en raison de calculs répétitifs. Pour améliorer l’efficacité, vous pouvez implémenter la technique de mémorisation, qui stocke les résultats des appels de fonction récursifs précédents.

La réponse, exacte, est classique. Le lecteur appréciera encore le grand souci de fournir des explications détaillées.
Mistral-medium, quant à lui, propose directement, avec le même prompt initial, une implémentation récursive. Mais celle-ci est plus complexe, et surtout, ne fonctionne pas : la fonction appelée récursivement ne comporte pas de cas de base... Elle peut cependant être corrigée.


Enfin voici un exemple nettement plus difficile, tiré des annales de concours internationaux en programmation à destination des lycéens.

Voici le problème :

You
Nous disposons de N livres et de X euros.
Les prix des N livres sont dans une liste Prix.
Le nombre de pages des N livres sont une liste Pages
Exemple N = 3 , X = 4 , Prix = [1,2,3] , Pages = [4,7,6]
Le problème demande le maximum de pages que l’on peut lire.
Dans l’exemple, ce maximum est 11 car j’achète les livres 1 et 2, respectivement de 4 et 7 pages.
Autre exemple N = 4 , X = 10 , Prix = [4,8,5,3] , Pages = [5,12,8,1]
Ici ce maximum est 13 car j’achète les livres 1 et 3, respectivement de 5 et 8 pages.
Ecris une fonction solve(N,X,Prix,Pages) renvoyant ce maximum

ChatGPT
Ce problème est une variante classique du problème du sac à dos (Knapsack problem) où on doit maximiser la valeur (ici, le nombre total de pages que l’on peut lire) tout en respectant une contrainte de poids (ici, le coût total des livres ne dépassant pas X euros). La solution peut être abordée à l’aide de la programmation dynamique.
La fonction solve(N, X, Prix, Pages) suivra cette logique :

1. Initialisation : Créer un tableau 2D dp de dimensions (N+1) x (X+1) où dp[i][j] représentera le maximum de pages qu’on peut obtenir avec les i premiers livres et un budget de j euros. Initialiser ce tableau avec des zéros, puisque avec 0 livre ou un budget de 0 euro, le nombre maximal de pages est 0.
2. Remplissage du tableau : Remplir ce tableau ligne par ligne. Pour chaque livre i, et chaque budget j, il y a deux possibilités :
◦ Si le livre i coûte plus cher que le budget j, alors il est impossible de l’acheter, donc on garde le maximum de pages qu’on peut obtenir sans ce livre, qui est déjà calculé dans la case dp[i-1][j].
◦ Si le livre i peut être acheté avec le budget j, alors on doit décider si l’acheter ou pas. Le maximum de pages qu’on peut obtenir est le maximum entre ne pas acheter ce livre (dp[i-1][j]) et acheter ce livre (dp[i-1][j-Prix[i]] + Pages[i], c’est-à-dire le maximum de pages qu’on pouvait obtenir avec le budget restant après l’achat plus le nombre de pages de ce livre).
3. Résultat : La valeur dp[N][X] contiendra le maximum de pages qu’on peut obtenir avec tous les livres et le budget initial X

def solve(N, X, Prix, Pages):
   # Tableau de programmation dynamique
   # dp[i][j] représente le maximum de pages qu'on peut obtenir avec les i premiers livres et
   # un budget de j euros
   dp = [[0 for _ in range(X + 1)] for _ in range(N + 1)]

   # Remplir le tableau ligne par ligne
   for i in range(1, N + 1):  # On parcourt chaque livre
       for j in range(1, X + 1):  # On parcourt chaque budget possible de 1 à X
           # Si le livre i-1 n'est pas achetable car trop cher, on garde le meilleur précédent
           dp[i][j] = dp[i-1][j]
           # Si on peut acheter ce livre avec le budget actuel
           if j >= Prix[i-1]:
               # Calculer le maximum de pages en prenant ou non le livre i-1
               dp[i][j] = max(dp[i][j], dp[i-1][j-Prix[i-1]] + Pages[i-1])
               
   # Le résultat se trouve à dp[N][X], qui donne le maximum de pages avec N livres et
   # un budget de X euros
   return dp[N][X]

Dans ce code :
• N est le nombre de livres disponibles.
• X est le budget total en euros.
• Prix est une liste où Prix[i-1] indique le prix du i-ème livre.
• Pages est une liste où Pages[i-1] indique le nombre de pages du i-ème livre.
Le tableau dp est construit de telle sorte que chaque cellule dp[i][j] stocke le maximum de pages que l’on peut obtenir avec les premiers i livres et un budget j. L’objectif est de remplir ce tableau en considérant chaque livre et chaque sous-budget possible, pour finalement obtenir la solution optimale dans dp[N][X].

Le code fonctionne mais il est bien difficile à notre niveau de le comprendre parfaitement. Notons que ChatGPT évoque la variante classique du problème du sac à dos (Knapsack problem), ce qui nous permettrait de faire des recherches ciblées afin d’en savoir plus sur ces problèmes du sac à dos !

Terminons cette première partie par une note négative. On appelle hallucination une réponse de l’IA qui est fausse mais qui est pourtant, fait aggravant, présentée comme certaine. Lors de notre étude, nous avons été confrontés à ce problème plusieurs fois. En voici un exemple éloquent.
Il s’agit de l’exercice 1 de l’épreuve du BAC dont nous avons parlé dans l’introduction.
Voici la première question de cet exercice :

Question 1 de l’exercice 1
BAC NSI : sujet 1 juin Métropole 2022

Si des éléments sont ajoutés dans une liste et retirés dans le même ordre de leur arrivée alors il s’agit, sans qu’il n’y ait aucune discussion possible, d’une FILE.
Or voici la réponse de ChatGPT :

Pour cette première partie, la réponse est que cela décrit le comportement d’une pile, car le dernier élément ajouté (la dernière parenthèse ouvrante) est le premier à être retiré lorsqu’on rencontre sa correspondante parenthèse fermante. C’est le principe LIFO (Last In, First Out).

Les échanges qui vont s’en suivre sont savoureux. On appréciera les excuses récurrentes de ChatGPT, ainsi qu’une espèce d’étrange « mauvaise foi ».

You
avant de continuer, relis bien la question 1 , en particulier ceci : « les éléments sont maintenant retirés (pour être lus) de cette structure de données dans le même ordre qu’ils y ont été ajoutés lors de l’enregistrement »

ChatGPT
Je m’excuse pour toute confusion précédente. La question 1 demande de justifier si les éléments sont retirés de la structure de données dans le même ordre qu’ils y ont été ajoutés lors de l’enregistrement et si cela décrit le comportement d’une file ou d’une pile.
La structure de données qui retire les éléments dans le même ordre qu’ils y ont été ajoutés est une file (First In, First Out - FIFO). Cependant, l’exercice décrit l’utilisation d’une variable « contrôleur » pour valider l’expression, ce qui n’implique pas directement l’utilisation d’une pile ou d’une file.
Cependant, pour vérifier le parenthésage correct, une pile (Last In, First Out - LIFO) est généralement utilisée. Lorsque l’on rencontre une parenthèse ouvrante, on la « pousse » dans la pile, et lorsqu’on rencontre une parenthèse fermante, on « dépile » le dernier élément ajouté (la dernière parenthèse ouvrante correspondante). Si à la fin toutes les parenthèses ouvrantes ont été correctement appariées avec des parenthèses fermantes et que la pile est vide, l’expression est correctement parenthésée.
En résumé, pour l’opération décrite dans l’exercice, on utilise une pile pour stocker les parenthèses ouvrantes et on les retire (on lit et on dépile) dans l’ordre inverse de leur ajout (LIFO) pour correspondre aux parenthèses fermantes. Si le processus se termine correctement, cela signifie que les parenthèses sont bien équilibrées et que l’expression est correctement parenthésée.

You
Je reprends cette phrase : « les éléments sont maintenant retirés (pour être lus) de cette structure de données dans le même ordre qu’ils y ont été ajoutés lors de l’enregistrement » Supposons que j’ajoute 1 , puis 2 , puis 3. Je les retire dans le même ordre Donc je retire 1, puis je retire 2, puis je retire 3. Est-ce une pile ou une file ?

ChatGPT
Je m’excuse pour la confusion. Si vous ajoutez les éléments 1, puis 2, puis 3, et que vous les retirez ensuite dans cet ordre exact, c’est-à-dire que vous retirez d’abord 1, puis 2, puis 3, cela correspond au comportement d’une file.
Dans une file, l’ordre de sortie est le même que l’ordre d’entrée, ce qui est connu sous le nom de FIFO (First In, First Out). Vous « enfilez » les éléments à une extrémité et vous les « défilez » à l’autre extrémité, en respectant l’ordre dans lequel ils ont été ajoutés.
Pour une pile, l’ordre de sortie est l’inverse de l’ordre d’entrée, ce qui est connu sous le nom de LIFO (Last In, First Out). Vous « empilez » les éléments et ensuite vous retirez le dernier élément qui a été ajouté en premier.
Donc, dans le contexte de l’exercice et selon votre dernier exemple, si vous retirez les éléments dans le même ordre que vous les avez ajoutés, vous décrivez le comportement d’une file (FIFO).

La réponse est donc une file et cela n’a rien à voir avec mon dernier exemple. Quant à mentionner le contexte de l’exercice, c’est assez amusant puisqu’il s’agit précisément d’une question de l’exercice.
En réalité, classiquement, quand on traite ce problème on utilise bel et bien une PILE, d’où la confusion de ChatGPT qui ne fait que puiser dans sa gigantesque base de données pour élaborer ses réponses.

 L’IA et le professeur

L’un des points forts des IA génératives étant de générer des listes (de toute nature) , nous nous sommes empressés de tester cette compétence au service de l’enseignant, et avons commencé par demander la constitution de listes d’exercices.
Nous avons testé le prompt suivant sur Mistral-medium :

A mistral-medium
"Prends le rôle d’un enseignant de NSI.
Ecris une liste de 10 exercices de difficulté progressive qui portent sur les listes et les boucles, à destination d’élèves de 1ère qui découvrent la notion.

Mistral-medium
Exercice 1 : Déclaration et initialisation d’une liste
Déclarer une liste nommée « liste_nombre » contenant les nombres entiers de 1 à 5.

Exercice 2 : Affichage des éléments d’une liste
En utilisant une boucle for, afficher tous les éléments de la liste « liste_nombre » définie à l’exercice 1.

Exercice 3 : Ajout d’éléments à une liste
Ajouter les nombres 6, 7 et 8 à la fin de la liste « liste_nombre » et afficher à nouveau tous les éléments de la liste.

Exercice 4 : Suppression d’éléments d’une liste
Supprimer le premier élément de la liste « liste_nombre » (sans connaître sa valeur) et afficher la liste mise à jour.

Exercice 5 : Recherche d’un élément dans une liste
Écrire une fonction nommée « recherche » qui prend en paramètres une liste et un élément. Cette fonction doit renvoyer True si l’élément est présent dans la liste, et False sinon.

Exercice 6 : Compter les occurrences d’un élément dans une liste
Écrire une fonction nommée « compte_occurrences » qui prend en paramètres une liste et un élément. Cette fonction doit renvoyer le nombre de fois que l’élément apparaît dans la liste.

Exercice 7 : Modification d’un élément d’une liste
Écrire une fonction nommée « modifier_element » qui prend en paramètres une liste, un indice et une nouvelle valeur. Cette fonction doit modifier l’élément de la liste situé à l’indice donné avec la nouvelle valeur.

Exercice 8 : Inversion des éléments d’une liste
Écrire une fonction nommée « inverser_liste » qui prend en paramètre une liste et qui modifie cette liste pour obtenir les mêmes éléments mais dans l’ordre inverse.

Exercice 9 : Liste des carrés des nombres impairs
Écrire une fonction nommée « carres_impairs » qui prend en paramètre un entier n et renvoie une liste contenant les carrés des nombres impairs inférieurs ou égaux à n.

Exercice 10 : Tri d’une liste de nombres
Écrire une fonction nommée « trier_liste » qui prend en paramètre une liste de nombres et qui trie cette liste par ordre croissant. Vous pouvez utiliser la méthode « sort » du module « sorted », mais essayez de l’implémenter vous-même à l’aide d’une boucle.

Cette liste s’avère décevante. La moitié des exercices (1,2,3,4,7) nous semblent manquer d’intérêt. Le dernier est hors-sujet : il est trivial si la méthode sort est utilisée, et relève d’un autre chapitre sinon. Seuls les quatre exercices restants nous semblent utilisables, tout en restant peu originaux : nous n’avions certainement pas besoin d’aide pour les imaginer.
Mais peut-être notre prompt était-il trop vague ?
Nous avons donc tenté de guider un peu plus l’IA. Remarquez bien le soin apporté à la rédaction du prompt.

A mistral-medium
« Prends le rôle d’un enseignant de NSI. Ecris une liste de 10 exercice de difficulté progressive qui porte sur les listes et les boucles, à destination d’élèves de 1ère qui découvrent la notion. Tu éviteras les questions de connaissance de la syntaxe, et préféreras des questions qui nécessitent un peu de réflexion. Tu choisiras des exemples variés de listes : listes de nombres, listes de chaînes de caractère, listes de booléens, listes de listes,... Au moins un exercice demandera ou utilisera des listes par compréhension, et au moins un exercice nécessitera d’utiliser un tableau sous la forme d’une liste de listes. Chaque exercice doit avoir un enjeu, soit pragmatique parce qu’il permet d’aboutir à un résultat utile ou parlant, soit pédagogique car il permet question après question de s’approprier une notion. »

Mistral-medium
1. **Exercice 1 : Somme des éléments**
Écrire une fonction `somme` qui prend en paramètre une liste de nombres et qui renvoie la somme de tous les nombres de cette liste.

2. **Exercice 2 : Nombre pair et impair**
Écrire une fonction `pairs_et_impairs` qui prend en paramètre une liste de nombres et qui renvoie deux listes : une liste contenant les nombres pairs et une liste contenant les nombres impairs.

3. **Exercice 3 : Compter les voyelles**
Écrire une fonction `compte_voyelles` qui prend en paramètre une chaîne de caractères et qui renvoie le nombre de voyelles présentes dans cette chaîne.

4. **Exercice 4 : Liste des carrés**
Écrire une fonction `liste_carres` qui prend en paramètre une liste de nombres et qui renvoie une nouvelle liste contenant les carrés de ces nombres. Utiliser une liste par compréhension pour résoudre cet exercice.

5. **Exercice 5 : Maximum local**
Écrire une fonction `maximum_local` qui prend en paramètre une liste de nombres et qui renvoie la liste des indices des éléments qui sont plus grands que leurs voisins (à gauche et à droite). On considère que le premier et le dernier élément n’ont pas de voisins.

6. **Exercice 6 : Matrice de caractères**
On dispose d’une matrice représentée par une liste de listes de caractères, par exemple : matrice = [['X', 'O', 'X'], ['O', 'X', 'O'], ['X', 'O', 'X']]. Écrire une fonction nombre_croix qui renvoie le nombre de ’X’ présents dans la matrice.

7. **Exercice 7 : Transposer une matrice**
Écrire une fonction `transpose` qui prend en paramètre une matrice sous forme d’une liste de listes et qui renvoie la matrice transposée. La matrice transposée d’une matrice A est la matrice obtenue en échangeant les lignes et les colonnes de A.

8. **Exercice 8 : Liste des diviseurs**
Écrire une fonction `diviseurs` qui prend en paramètre un nombre entier positif et qui renvoie la liste de ses diviseurs.

9. **Exercice 9 : Palindrome**
Écrire une fonction `est_palindrome` qui prend en paramètre une chaîne de caractères et qui renvoie True si la chaîne est un palindrome (elle se lit de la même façon de gauche à droite et de droite à gauche) et False sinon.

10. **Exercice 10 : Tableau de multiplication**
Écrire une fonction `tableau_mult` qui prend en paramètre un entier positif n et qui renvoie un tableau de multiplication sous forme d’une liste de listes. Chaque ligne du tableau doit correspondre à la multiplication d’un nombre entre 1 et n par tous les nombres entre 1 et n. Par exemple, pour n = 3, la fonction doit renvoyer : `[[1, 2, 3], [2, 4, 6], [3, 6, 9]

Ces exercices nous paraissent déjà plus intéressants. Cependant, l’IA utilise le terme « matrice », qui est à proscrire dans ce contexte - l’exercice 7 est d’ailleurs hors-sujet ici. L’exercice sur les palindromes est également hors-sujet, n’utilisant pas les listes. L’exercice 10 nous semble artificiel, au contraire de l’exercice 6, que nous apprécions et serons susceptibles d’utiliser. L’exercice 8 est sans doute de nature trop mathématique pour apparaître dans nos liste.
Au final, ce prompt plus précis aura peut-être contribué à générer un exercice exploitable supplémentaire. Mais il nous semble manquer d’âme : nous souhaitons des exercices qui aient davantage de sens, d’enjeu, de contexte. Peut-être y arriverons-nous avec un dernier prompt ?

A mistral-medium
« Prends le rôle d’un enseignant de NSI. Ecris un exercice qui doit clôturer le chapitre sur les listes en classe de 1ère. Cet exercice doit permettre, par des questions de difficulté croissante, de créer un programme en Python qui fasse sens, tout en balayant les notions les plus importantes sur les listes. L’élève doit avoir le sentiment, à la fin de l’exercice, d’avoir réussi à réaliser quelque chose qu’il ne savait sans doute pas faire avant. »

Mistral-medium
Exercice : Gestion d’une bibliothèque de films en Python

Objectif : À la fin de cet exercice, vous serez capable de créer un programme en Python pour gérer une bibliothèque de films, mettant en œuvre les principales notions relatives aux listes.

1. Initialisation
Commençons par créer une liste de films de la façon suivante :
```python
films = [« Le Parrain », « Pulp Fiction », « Inception », « Star Wars », « Le Seigneur des Anneaux »]```

Question 1.1 : Afficher la liste des films
Écrire une fonction nommée `afficher_films()` qui prend en paramètre une liste de films et affiche chacun d’eux avec un numéro d’ordre.

Exemple :
```
1. Le Parrain
2. Pulp Fiction
3. Inception
4. Star Wars
5. Le Seigneur des Anneaux
```

2. Ajouter un film

Question 2.1 : Ajouter un film à la fin de la liste
Écrire une fonction nommée `ajouter_film()` qui prend en paramètre une liste de films, demande à l’utilisateur de saisir un film et l’ajoute à la fin de la liste.
2.2. Ajouter un film à une position donnée
Écrire une fonction nommée `ajouter_film_position()` qui prend en paramètre une liste de films, demande à l’utilisateur de saisir un film et sa position, et insère le film à cette position.

3. Supprimer un film
Question 3.1 : Supprimer un film par son titre
Écrire une fonction nommée `supprimer_film_titre()` qui prend en paramètre une liste de films et supprime un film dont le titre est saisi par l’utilisateur.
3.2. Supprimer un film par sa position

Écrire une fonction nommée `supprimer_film_position()` qui prend en paramètre une liste de films et supprime le film se trouvant à la position saisie par l’utilisateur.

4. Rechercher un film
Question 4.1 : Rechercher un film par son titre
Écrire une fonction nommée `rechercher_film_titre()` qui prend en paramètre une liste de films et affiche la position du film dont le titre est saisi par l’utilisateur. Si le film n’est pas trouvé, afficher un message approprié.
4.2. Rechercher un film par son réalisateur
Pour cette question, modifier la liste de films initiale afin d’inclure le nom du réalisateur à l’aide d’un dictionnaire. Par exemple :
```python
films = [
« titre » : « Le Parrain », « realisateur » : « Francis Ford Coppola »,
« titre » : « Pulp Fiction », « realisateur » : « Quentin Tarantino »,
« titre » : « Inception », « realisateur » : « Christopher Nolan »,
« titre » : « Star Wars », « realisateur » : « George Lucas »,
« titre » : « Le Seigneur des Anneaux », « realisateur » : « Peter Jackson »
]
```
Écrire une fonction nommée `rechercher_film_realisateur()` qui prend en paramètre une liste de films et affiche la position du film dont le réalisateur est saisi par l’utilisateur. Si le film n’est pas trouvé, afficher un message approprié.

5. Trier les films
Question 5.1 : Trier les films par titre
Écrire une fonction nommée `trier_films_titre()` qui prend en paramètre une liste de films et trie les films par leur titre.
5.2. Trier les films par année de sortie
Modifier la liste de films initiale afin d’inclure l’année de sortie de chaque film. Par exemple :
```python
films = [
« titre » : « Le Parrain », « realisateur » : « Francis Ford Coppola », « annee_sortie » : 1972,
« titre » : « Pulp Fiction », « realisateur » : « Quentin Tarantino », « annee_sortie » : 1994,
« titre » : « Inception », « realisateur » : « Christopher Nolan », « annee_sortie » : 2010,
« titre » : « Star Wars », « realisateur » : « George Lucas », « annee_sortie » : 1977,
« titre » : « Le Seigneur des Anneaux », « realisateur » : « Peter Jackson », « annee_sortie » : 2001
]
```
Écrire une fonction nommée `trier_films_annee()` qui prend en paramètre une liste de films et trie les films par leur année de sortie.

6. Mise en page et menus
Question 6.1 : Créer un menu principal
Écrire une fonction nommée `menu_principal()` qui affiche un menu permettant à l’utilisateur de choisir parmi les options suivantes :
 Afficher les films
 Ajouter un film
 Supprimer un film
 Rechercher un film
 Trier les films
 Quitter le programme

Question 6.2 : Gérer le menu
Écrire une fonction nommée `gestion_menu()` qui appelle la fonction `menu_principal()` et gère les choix de l’utilisateur. Cette fonction doit être appelée en fin de programme pour lancer la boucle principale du menu.

7. Améliorations optionnelles
 Ajouter une fonctionnalité permettant de modifier un film existant.
 Ajouter une fonctionnalité permettant de filtrer les films par genre ou par réalisateur.
 Afficher les films sous forme de tableau avec des colonnes pour le titre, le réalisateur, et l’année de sortie.
 Ajouter une fonctionnalité permettant de sauvegarder et de charger la bibliothèque de films à partir d’un fichier.

Voilà qui nous paraît déjà bien plus intéressant !
Certes, il s’agit davantage d’un TP que d’un exercice, mais celui- ci fait sens et propose un réel enjeu. Les premières questions permettent effectivement de réinvestir les notions souhaitées, mais l’exercice dérape déjà à la question 4 en introduisant des dictionnaires, a priori non encore traités… mais aussi à juste titre, car les dictionnaires sont effectivement plus efficaces que les listes pour implémenter une base de données. L’exercice était-il dans ce cas pertinent ? Probablement pas dans un chapitre sur les listes, mais peut-être voudrons-nous le conserver quand arrivera le moment d’introduire les dictionnaires !

En terme de génération d’exercices, mistral-medium offre pour le moment une aide limitée. Des prompts plus raffinés semblent nous permettre de légèrement améliorer son efficacité, mais l’enseignant doit rester vigilant quant à la pertinence des propositions, et tout comme un élève ne doit pas espérer pouvoir n’apporter aucune correction au travail de l’IA.

Voici la proposition de ChatGPT à la question initiale :

Prends le rôle d’un enseignant de NSI. Ecris une liste de 10 exercices de difficulté progressive qui portent sur les listes et les boucles, à destination d’élèves de 1ère qui découvrent la notion.

ChatGPT
Bien sûr, voici une liste d’exercices progressifs sur les listes et les boucles pour les élèves de 1ère en NSI (Numérique et Sciences Informatiques) :
Exercice 1 : Initialisation et accès
Objectif : Créer et accéder à des éléments d’une liste.
1. Créez une liste contenant les jours de la semaine.
2. Affichez le premier et le dernier jour de la semaine.
Exercice 2 : Manipulation simple de listes
Objectif : Ajouter, supprimer et modifier des éléments dans une liste.
1. Ajoutez « dimanche » au début de la liste des jours de la semaine.
2. Supprimez « mercredi » de la liste.
3. Modifiez le dernier jour de la semaine en « dimanche ».
Exercice 3 : Parcours de liste avec boucle for
Objectif : Utiliser une boucle pour parcourir et afficher les éléments d’une liste.
1. Écrivez une boucle for qui affiche tous les jours de la semaine.
Exercice 4 : Compréhensions de liste
Objectif : Créer une nouvelle liste à partir d’une existante avec des critères spécifiques.
1. Utilisez une compréhension de liste pour créer une nouvelle liste des jours qui contiennent la lettre ’e’.
Exercice 5 : Recherche dans une liste
Objectif : Trouver un élément dans une liste.
1. Vérifiez si « vendredi » est dans la liste des jours de la semaine et affichez un message approprié.
Exercice 6 : Fonctions sur les listes
Objectif : Écrire des fonctions qui manipulent des listes.
1. Écrivez une fonction qui prend une liste et renvoie le nombre d’éléments dans cette liste.
2. Écrivez une autre fonction qui renvoie la liste inversée.
Exercice 7 : Boucle while
Objectif : Utiliser une boucle while pour modifier les éléments d’une liste jusqu’à ce qu’une condition soit remplie.
1. À l’aide d’une boucle while, supprimez tous les éléments d’une liste jusqu’à ce qu’elle soit vide.
Exercice 8 : Plusieurs listes
Objectif : Travailler avec plusieurs listes.
1. Créez deux listes, une avec les nombres pairs et une autre avec les nombres impairs de 1 à 10.
2. Fusionnez ces deux listes en une seule qui est triée.
Exercice 9 : Listes de listes
Objectif : Manipuler des listes contenant d’autres listes.
1. Créez une liste de listes où chaque sous-liste représente une semaine du mois, contenant les jours correspondants.
2. Écrivez une fonction qui retourne le jour de la semaine pour une date donnée (par exemple, le 15 du mois).
Exercice 10 : Projet d’application
Objectif : Appliquer toutes les connaissances acquises sur les listes et les boucles pour créer une application simple.
1. Écrivez un petit programme qui permet à l’utilisateur de créer une liste de courses, de supprimer des articles, d’ajouter des articles, et de voir la liste courante.

Ces exercices couvrent une gamme de compétences de base à intermédiaire, en introduisant les élèves à la manipulation pratique des listes en Python, tout en renforçant leur compréhension des boucles et des fonctions.
La réponse nous semble plus pertinente et intéressante que la première proposition de mistral-medium.

Et voici la proposition de ChatGPT pour l’exercice bilan :

Exercice Final : Gestion d’un Répertoire Téléphonique
Objectif : Cet exercice final vise à consolider et mettre en pratique les notions apprises sur les listes, les boucles, les compréhensions de liste, et les fonctions en Python. Vous allez créer un programme qui gère un répertoire téléphonique simple. Cet exercice est découpé en plusieurs sous-parties, augmentant graduellement en complexité.
Partie 1 : Création et affichage du répertoire
1. Définition de la structure de données : Créez une liste pour stocker les entrées du répertoire. Chaque entrée sera elle-même une liste contenant le nom d’une personne et son numéro de téléphone.
2. Ajout d’entrées : Écrivez une fonction ajouter_entree(nom, numero, repertoire) qui prend en paramètres le nom et le numéro de téléphone d’une personne, ainsi que le répertoire, et ajoute cette nouvelle entrée au répertoire.
3. Affichage du répertoire : Écrivez une fonction afficher_repertoire(repertoire) qui affiche toutes les entrées du répertoire, chacune sur une nouvelle ligne.
Partie 2 : Recherche et suppression
4. Recherche dans le répertoire : Écrivez une fonction rechercher_nom(nom, repertoire) qui recherche une personne par son nom dans le répertoire et affiche son numéro de téléphone. Si le nom n’est pas trouvé, affichez un message approprié.
5. Suppression d’une entrée : Écrivez une fonction supprimer_entree(nom, repertoire) qui permet de supprimer une entrée du répertoire à partir du nom de la personne. Si l’entrée est supprimée avec succès, affichez un message de confirmation, sinon un message d’erreur.
Partie 3 : Modification et sauvegarde
6. Modification d’un numéro de téléphone : Créez une fonction modifier_numero(nom, nouveau_numero, repertoire) qui permet de modifier le numéro de téléphone d’une entrée existante. Si le nom est trouvé, le numéro est mis à jour, sinon un message d’erreur est affiché.
7. Sauvegarde du répertoire : Écrivez une fonction sauvegarder_repertoire(repertoire, fichier) qui enregistre le contenu du répertoire dans un fichier texte. Chaque entrée doit être écrite sur une nouvelle ligne sous la forme « nom, numéro ».
Partie 4 : Interface utilisateur
8. Création d’une interface utilisateur en ligne de commande : Mettez en place une boucle qui permet à l’utilisateur de choisir des actions à réaliser (ajouter, rechercher, supprimer, modifier, sauvegarder, afficher le répertoire, quitter). Utilisez les fonctions créées précédemment pour effectuer chaque action.
Instructions supplémentaires :
• Assurez-vous de gérer les cas d’erreurs potentiels, comme les entrées dupliquées ou les formats invalides.
• Encouragez les élèves à ajouter des améliorations personnelles, comme une fonction de tri des entrées ou une recherche insensible à la casse.
Conclusion :
À la fin de cet exercice, les élèves auront créé un programme complet qui met en pratique des concepts clés autour des listes et des opérations courantes en Python. Ils auront non seulement renforcé leur compréhension théorique, mais aussi acquis une compétence pratique significative.

Cette tâche finale nous semble comparable à celle fournie par mistral-medium. Les enjeux, la forme et le fond sont très similaires, de même que le principal défaut : l’utilisation de dictionnaires serait plus appropriée que celle de listes dans ce type de projet.

Pour conclure cette deuxième partie, nous avons demandé à ChatGPT de détailler le fonctionnement du parcours en largeur d’un graphe. L’idée consiste à utiliser la réponse de ChatGPT afin de nous aider à construire la séquence de cours correspondante.

Pour information, voici le parcours en
largeur du graphe suivant :

A – B – C – E – D – F – G

Après quelques échanges permettant d’affiner notre demande (par exemple, ChatGPT utilise la bibliothèque Collections pour travailler sur les graphes, or nous ne le voulons pas), voici une sélection de ce qui reste des échanges étant donnés nos attendus.

ChatGPT
Bien sûr, je vais vous expliquer comment implémenter l’algorithme de parcours en largeur (Breadth-First Search, BFS) sur un graphe en utilisant Python. Cet algorithme est utile pour visiter tous les nœuds d’un graphe de manière systématique en partant d’un nœud source. Il est particulièrement pratique pour trouver le chemin le plus court dans un graphe non pondéré.
Explication du code
Le BFS commence à un nœud source, puis visite tous les voisins de ce nœud à la distance 1, ensuite tous leurs voisins à la distance 2, et ainsi de suite. Pour cela, l’algorithme utilise une file d’attente pour gérer l’ordre de visite des nœuds.
Voici les étapes détaillées de l’algorithme BFS :
1. Initialisation : On crée une file d’attente et on ajoute le nœud source à cette file. On marque ce nœud comme visité.
2. Traitement de la file : Tant que la file n’est pas vide, on traite chaque nœud. On le retire de la file, puis on traite tous ses voisins non visités. Chaque voisin non visité est marqué comme visité et ajouté à la file.
3. Répétition : On continue jusqu’à ce que la file soit vide.
Code Python
Pour illustrer cela, prenons un exemple avec le graphe suivant

    1 -- 2 -- 3
    |    |    |
    4 -- 5 -- 6
    |    |    |
    7 -- 8 -- 9

Structure du graphe
Nous représenterons ce graphe dans notre code Python comme un dictionnaire où chaque clé correspond à un nœud et chaque valeur est la liste de ses voisins directs :

graph = {
   1: [2, 4],
   2: [1, 3, 5],
   3: [2, 6],
   4: [1, 5, 7],
   5: [2, 4, 6, 8],
   6: [3, 5, 9],
   7: [4, 8],
   8: [5, 7, 9],
   9: [6, 8]
}

Code BFS
Voici le code BFS adapté pour utiliser uniquement des listes Python, avec ce graphe comme exemple :

def bfs(graph, start):
   visited = []  # Liste pour stocker les nœuds visités
   queue = [start]  # Liste utilisée comme file d'attente, avec le nœud de départ

   visited.append(start)  # Marquer le nœud de départ comme visité
   print(f"Visite du nœud: {start}")  # Afficher le nœud visité
   
   while queue:
       vertex = queue.pop(0)  # Enlever le premier élément de la liste
       
       for neighbor in graph[vertex]:
           if neighbor not in visited:  # Vérifier si le voisin n'a pas été visité
               visited.append(neighbor)  # Marquer comme visité en ajoutant à la liste
               queue.append(neighbor)  # Ajouter à la fin de la liste
               print(f"Visite du nœud: {neighbor}")  # Afficher le nœud visité

# Exemple d'utilisation
bfs(graph, 1)

Explication des nœuds visités dans l’ordre
Si nous commençons le BFS à partir du nœud 1, l’ordre des visites sera :
1. Nœud 1 : D’abord visité, ses voisins 2 et 4 sont ajoutés à la file.
2. Nœud 2 : Ensuite visité (premier dans la file), ajoute ses voisins non visités 3 et 5.
3. Nœud 4 : Puis visité, ajoute son voisin non visité 7.
4. Nœud 3 : Visité ensuite, ajoute son voisin non visité 6.
5. Nœud 5 : Visité, ajoute son voisin non visité 8.
6. Nœud 7 : Visité, n’a plus de nouveaux voisins à ajouter.
7. Nœud 6 : Visité, ajoute son voisin non visité 9.
8. Nœud 8 : Visité, n’a plus de nouveaux voisins à ajouter.
9. Nœud 9 : Finalement visité, n’a plus de nouveaux voisins à ajouter.
Cet ordre démontre bien le principe du BFS où chaque couche ou niveau du graphe est exploré complètement avant de passer au niveau suivant. Cela assure que nous visitons les nœuds dans le plus court chemin possible à partir du nœud source.

À la différence d’une recherche classique Google, le dialogue permet de se rapprocher assez finement de ce que nous désirons pour notre enseignement. Le résultat obtenu est satisfaisant et constitue une aide sérieuse pour le jeune professeur qui enseigne pour la première fois cette notion délicate.

Dans la même optique que d’utiliser l’IA à la place d’un moteur de recherche, nous avons demandé à mistral-medium de nous résumer le programme de NSI de classe de Terminale.

A mistral-medium
« Donne-moi la liste des chapitres du programme de Terminale en spécialité Numérique et Sciences Informatiques (NSI). Pour chaque chapitre, tu listeras de manière concise quelques points importants »

L’IA nous fait alors la réponse suivante, un parfait exemple d’hallucination :

Mistral-medium
Voici la liste des chapitres du programme de Terminale en spécialité Numérique et Sciences Informatiques (NSI) avec quelques points importants pour chaque chapitre :

1. Algorithmique et programmation
* Notion de fonction et de procédure en Python
* Types de données (entiers, réels, chaînes de caractères, booléens, listes, tuples)
* Structures de contrôle (instructions conditionnelles, boucles)
* Manipulation de tableaux et de listes
2. Langages et machines
* Représentation interne des données (codage des entiers, réels, caractères)
* Notion de langage machine et assembleur
* Architectures des processeurs (RISC, CISC)
* Principes de la compilation et de l’interprétation
3. Bases de données
* Modélisation d’une base de données relationnelle (schéma relationnel, tables, clés)
* Langage SQL (requêtes sélection, insertion, mise à jour, suppression)
* Normalisation et dénormalisation
4. Réseaux et Internet
* Modèles OSI et TCP/IP
* Adressage IP et routage
* Principes de la transmission de données (paquets, encapsulation)
* Protocoles HTTP, HTTPS et DNS
5. Architecture et systèmes d’exploitation
* Architecture des systèmes informatiques (matériel, logiciel)
* Notion de système d’exploitation (OS) et ses fonctionnalités (gestion de processus, mémoire, fichiers)
* Multi-tâches et multi-threading
6. Systèmes d’information et numérique responsable
* Notion de système d’information (SI) et son rôle dans les organisations
* Protection des données personnelles (RGPD)
* Impact environnemental du numérique
* Éthique et déontologie informatique
7. Algorithmique approfondie et programmation avancée
* Algorithmes de tri (tri rapide, tri fusion, tri par tas) et de recherche (recherche dichotomique)
* Complexité algorithmique (temps, espace)
* Notion de paradigme de programmation (impératif, fonctionnel, objets)
8. Structures de données et algorithmes
* Piles, files et listes chaînées
* Arbres binaires de recherche, AVL et hépatés
* Tris par fusion et rapide
* Algorithmique gloutonne et programmation dynamique

Note : Les points mentionnés ne sont pas exhaustifs et peuvent varier légèrement en fonction des établissements scolaires.

Ce résumé pourrait sembler plausible à quelqu’un qui ne connaîtrait pas les programmes – la forme est plutôt convaincante – mais le contenu présenté est essentiellement faux. Un second prompt, rappelant la question et demandant à l’IA de ne se baser que sur le programme officiel, génère une réponse assez différente mais toute aussi fausse, adjointe d’un lien vers sa prétendue source sur Eduscol, lien qui renvoie… une erreur 404…

 L’IA et l’élève

Pour un élève d’un bon niveau, voire d’un niveau moyen, un ChatBot pourra constituer une aide certaine dès lors que l’élève garde toujours un recul suffisant par rapport aux réponses de l’IA. Il réalisera rapidement qu’il est nécessaire de soigner ses prompts, ce qui est évidemment une bonne chose.
En revanche, pour un(e) élève en difficulté, la situation est bien plus délicate. Prenons par exemple le cas d’un élève de Terminale qui ne sait toujours pas, malgré tous les efforts du professeur, résoudre l’exercice suivant :

Exercice : Écrire une fonction max_liste demandant en paramètre une liste L et renvoyant le maximum (première occurrence) et l’indice du maximum.

Le lecteur aura compris qu’une IA donnera immédiatement la réponse. Mais son professeur de Terminale et son professeur de Première lui ont déjà donné dix fois la réponse à des exercices analogues Donc une réponse de plus de la part d’un IA ne changera pas la donne.

En ce qui concerne les projets, ces IA sont également efficaces.
Par exemple, quand on demande à ChatGPT le code d’un labyrinthe utilisant la bibliothèque pygame avec une sortie en bleu et le personnage en rouge, on obtient par exemple le résultat ci-dessous. Le personnage se déplace correctement. On notera que la sortie du labyrinthe est inaccessible mais ce point est facile à corriger. L’élève peut alors se contenter de reprendre le code sans le comprendre. Comme par ailleurs de nouveaux prompts permettent d’affiner le cahier des charges du projet, il est aisé d’avoir un labyrinthe personnalisé. Pour le professeur, il devient alors indispensable de questionner l’élève sur les lignes de code de son projet ! Et quand bien même l’élève comprendrait son programme, on pourra toujours bien entendu regretter qu’il n’a fait que recopier, certes en comprenant, des lignes de code.

Il ne s’est passé qu’une année entre le début de l’engouement du grand public pour les IA génératives et l’écriture de cet article, mais nous pouvons déjà en percevoir les conséquences dans nos classes. Pour l’instant, nous n’avons pu observer essentiellement que deux types d’interactions avec les IA génératives :

type 1 : des élèves faibles voire très faibles qui tentent de faire faire le travail (TP, projet) à l’IA, sans rien comprendre de ce qu’ils recopient. Il est pour l’instant facile de déceler l’imposture, le code de l’IA tranchant de manière flagrante avec les capacités observées chez les élèves, sans compter que ces derniers se retrouvent incapables d’expliquer le sens des lignes recopiées. Nous avons pu de même déceler 3 fraudes ou tentatives de fraudes en DS, à chaque fois à l’aide de ChatGPT installé sur un téléphone, caché dans la trousse ou sur les genoux.

type 2 : des élèves extrêmement compétents, qui ont pu utiliser l’IA à de rares reprises, sans s’en cacher, pour générer la partie ingrate d’un projet, pour davantage se concentrer soi-même sur des problèmes plus stimulants. Dans ce cas, il nous évident que les élèves concernés étaient pleinement capables d’écrire eux-même le code ; nous avons vérifié qu’ils comprenaient le code de l’IA, et nous avons jugé leur démarche honnête et cohérente. Citons également le cas de cet élève (excellent en NSI) qui proposa à ChatGPT 3 pages manuscrites (illisibles) d’un cours de SVT afin de lui demander un résumé clair d’une page résumant les notions essentielles de son document . Le résultat fut bluffant.
Ce constat est quelque peu déprimant. Les interactions de type 1 n’apportent strictement rien aux élèves, si ce n’est l’éphémère illusion de produire un rendu « correct », un cruel retour à la réalité lors de l’évaluation. Les interactions de type 2 ne sont certes pas négatives, ont le mérite de rendre les élèves concernés plus productifs, mais n’apportent au final qu’un léger gain de temps : ne peut-on pas espérer mieux d’un outil aussi prometteur ?
Après tout ne pourrait-on pas utiliser l’IA autrement ?

Testons avec cet élève fictif, en difficulté, qui manifeste soudain une grande volonté de comprendre et de résoudre l’exercice précédent.

You
Je suis eleve de terminale et j’ai des difficultés en NSI
J’ai une exercice à faire :
« Ecrire une fonction max_liste demandant en paramètre une liste L et renvoyant le maximum (première occurrence) et l’indice du maximum. »
J’ai codé ceci mais cela ne marche pas du tout

def max_liste(L):
   max = 0
   for i in range(L):
       if i > max:
           max = i
   return max

peux-tu m’aider SANS me donner la solution
Est-il possible d’avoir une aide ou des indications pour le faire ?

ChatGPT
Bien sûr, je peux te guider pour que tu puisses améliorer ton code sans te donner directement la solution. Voici quelques points et questions pour t’aider à réfléchir sur les problèmes dans ton code actuel :

1. Comprendre la fonction range : Tu utilises range(L) dans ta boucle for, mais range() attend un nombre entier comme argument, alors que L est une liste. Comment pourrais-tu modifier la boucle pour qu’elle itère correctement sur les indices de la liste ?
2. Initialisation de la variable max : Tu as initialisé max à 0. Que se passe-t-il si tous les éléments de la liste sont négatifs ? Est-ce que commencer avec 0 est toujours une bonne idée ?
3. Comparer les éléments de la liste : Dans ton code, tu compares i (qui est en fait l’indice et non la valeur de l’élément de la liste) à max. Comment peux-tu ajuster cela pour comparer les valeurs des éléments de la liste à la valeur maximale actuelle ?
4. Renvoyer l’indice et la valeur maximum : Tu souhaites renvoyer à la fois la valeur maximale et son indice. Ta fonction actuelle ne renvoie que la valeur maximale présumée. Comment pourrais-tu modifier ta fonction pour inclure également l’indice de cet élément maximum ?

Réfléchis à ces points et essaie de voir comment tu pourrais ajuster ton code en conséquence. Si tu as besoin de plus d’aide ou des explications supplémentaires sur un point, n’hésite pas à demander !

You
J’ai fait ceci mais ce n’est pas encore bon

def max_liste(L):
   max = -100000
   for e in L :
       if e >= max:
           max = i
   return max

Est-il possible d’avoir une aide ou des indications dans me donner la solution ?

ChatGPT
C’est bien d’avoir essayé de modifier ton code. Tu t’approches un peu plus de la solution, mais il y a encore quelques ajustements à faire. Voici quelques indices supplémentaires pour t’aider à corriger les erreurs :

1. Initialisation de max : Tu as changé l’initialisation de max pour gérer le cas des nombres négatifs. C’est une bonne idée, mais il y a une manière encore plus sûre de l’initialiser. Peux-tu penser à utiliser une valeur de la liste elle-même comme point de départ, ou une autre méthode qui ne dépend pas d’un nombre arbitraire ?
2. Utilisation de la variable e : Dans la boucle, e est utilisé pour parcourir les éléments de la liste, mais quand tu attribues une nouvelle valeur à max, tu utilises i qui n’est pas défini dans ce bloc de code. Comment peux-tu corriger cela pour que tu mettes à jour max avec la valeur correcte ?
3. Renvoyer l’indice du maximum  : Ton code actuel ne gère pas encore le renvoi de l’indice de l’élément maximal. Comment pourrais-tu suivre à la fois la valeur maximale et son indice à mesure que tu parcours la liste ?
4. Structure de la boucle : Pour pouvoir suivre à la fois la valeur et l’indice, tu pourrais utiliser une autre forme de boucle qui te donne à la fois l’indice et la valeur de chaque élément de la liste. Quelle syntaxe de boucle te permet de faire ça en Python ?

Essaie de penser à ces points et de les appliquer à ton code. Si tu as d’autres questions ou besoin de clarifications, n’hésite pas à demander. Tu es sur la bonne voie !

You
J’ai fait cela mais cela n’est pas encore bon.

def max_liste(L):
   max = L[0]
   for i in range(L) :
       i = i +1
       if L[i] >= max:
           max = i
           indice = i
   return max

Est-il possible d’avoir une aide ou des indications dans me donner la solution ?

ChatGPT
Tu progresses, mais il y a encore quelques erreurs dans ton code. Examinons-les et voyons comment les corriger :

1. Utilisation de range(L)  : Comme mentionné précédemment, range() est utilisé avec des nombres entiers. Pour parcourir les indices de la liste, tu devrais utiliser range(len(L)), car len(L) te donnera le nombre d’éléments dans la liste, ce qui est le bon argument pour range().
2. Utilisation de la variable i dans la boucle : Tu modifies i dans ton code avec i = i + 1, ce qui n’est pas nécessaire et peut causer des erreurs en sautant des éléments ou en allant au-delà de la fin de la liste. La boucle for s’occupe déjà d’incrémenter i.
3. Affectation des variables max et indice : Tu veux garder une trace de la valeur maximale et de son indice. Dans ton code, tu réassignes max à i au lieu de la valeur actuelle de L[i]. Il est important de distinguer entre la valeur maximale trouvée dans la liste (max) et son indice (indice).

Voici des indices pour ajuster ton code sans te donner la solution complète :

* Initialisation et boucle : Commence par initialiser max avec la première valeur de la liste et indice avec 0, puisque le premier élément est ton point de départ.
* Boucle correcte : Utilise for i in range(len(L)) : pour parcourir correctement tous les indices de la liste sans modifier i à l’intérieur de la boucle.
* Mise à jour de max et indice : À l’intérieur de la boucle, compare L[i] (et non i) à max. Si L[i] est plus grand que max, alors mets à jour max avec L[i] et indice avec i.

En suivant ces conseils, tu devrais pouvoir ajuster ton code pour qu’il fonctionne correctement. Bonne chance, et si tu as besoin de plus d’aide, n’hésite pas à demander.

You
je crois que j’y suis presque.

def max_liste(L):
   max = L[0]
   indice =0
   for i in range(len(L)) :
       if L[i] >= max:
           max = L[i]
           indice = i
   return [max,indice]

Mais cela ne marche pas
Par exemple >>> max_liste([4,7,5,7,2]) renvoie [7,3] au lieu de [7 ;1] ???
Est-il possible d’avoir une aide ou des indications dans me donner la solution ?

ChatGPT
Ton code est presque correct, mais le problème que tu rencontres est lié à la condition que tu utilises pour mettre à jour le maximum et son indice. Tu utilises >= pour la comparaison, ce qui fait que si tu trouves une valeur égale au maximum actuel plus tard dans la liste, tu mets à jour l’indice pour cette nouvelle occurrence. Cela explique pourquoi dans ton exemple, la fonction retourne l’indice de la deuxième occurrence du nombre 7 et non la première.

Pour résoudre ce problème, tu dois modifier la condition dans ta boucle de manière à ce que tu ne mettes à jour max et indice que si tu trouves une valeur strictement supérieure à max. Cela garantira que tu conserves l’indice de la première occurrence du maximum et non d’une occurrence ultérieure.

Ainsi, remplace la condition >= par > dans ta boucle. Cela devrait résoudre le problème et faire en sorte que ta fonction renvoie l’indice de la première occurrence du maximum.

Si tu as besoin d’autre chose ou d’une explication supplémentaire, n’hésite pas à demander !

You
J’ai compris
Comment faire l’exercice avec comme boucle
for element in L
C’est une demande du professeur
On a plus l’indice
Est-il possible d’avoir une aide ou des indications dans me donner la solution ?

ChatGPT
Pour utiliser la boucle for element in L, et toujours suivre l’indice du maximum, tu dois introduire une variable supplémentaire pour suivre l’indice manuellement. Tu ne peux pas obtenir l’indice directement avec cette forme de boucle, mais tu peux le compter toi-même.

Voici quelques indices pour t’orienter :

1. Initialisation d’un compteur : Tu peux initialiser une variable, disons i, à 0 avant de commencer la boucle. Cette variable servira à compter l’indice courant de chaque élément que la boucle traite.
2. Incrémentation du compteur : À chaque itération de la boucle, après avoir traité l’élément, tu incrémentes i de 1. Cela te permet de maintenir le compte de l’indice de l’élément actuel.
3. Utilisation de la boucle avec le compteur : Dans la boucle, utilise element pour accéder à l’élément actuel de la liste. Compare cet élément à la valeur maximale actuelle. Si element est plus grand que le maximum actuel, mets à jour le maximum et aussi l’indice en utilisant la variable i.
4. Renvoi des résultats : Comme avant, à la fin de la fonction, tu peux renvoyer à la fois le maximum et l’indice associé.
Avec cette méthode, tu peux efficacement suivre l’indice sans accéder directement à l’indice via la boucle, ce qui respecte la consigne de ton professeur d’utiliser for element in L. Cette approche te permet de garder la simplicité de la boucle for element in L tout en contrôlant l’indice manuellement.

Si tu as besoin d’explications supplémentaires ou de plus d’aide, n’hésite pas à le demander.

Nous pensons qu’il est inutile ni de poursuivre ni de multiplier ce genre d’exemple car cet échange à lui seul montre un potentiel intéressant et constructif. Il demande cependant que l’élève en difficulté « joue le jeu » et soit patient. En outre ce genre d’échanges entre un(e) élève et une IA ne va pas de soi : il nécessite une formation , celle d’apprendre à dialoguer avec l’IA dans le but d’apprendre. Il s’agit également de convaincre l’élève que c’est son intérêt de se plier aux exigences de ce type d’apprentissage. Et, comme chacun sait, ce vœu pieu n’est pas nouveau...

 En guise de conclusion

Le sujet est clivant. L’IA générative est décrite par certains collègues comme une infestation, le mot est éloquent et fort. Quelques-uns sont enthousiastes, mais peu nombreux. Quoi que l’on en pense, il apparaît à tous qu’il va falloir de toute façon apprendre à enseigner avec ces IA. La plupart des collègues sont déjà conscients de la nécessité de repenser la nature du travail donné hors temps scolaire ainsi que ses modalités d’évaluation. Il en est de même pour les élèves pour qui l’enjeu se résume à la question : comment utiliser l’IA pour comprendre et apprendre plus efficacement ? Sur ce point, nous pouvons nous montrer inquiets. Il y a quelques années, nous évoquions la question de la fracture numérique. En ce temps là en effet, se posaient les questions de l’accès aux machines et des compétences TICE. Admettons que dans un futur proche tout individu possède un smartphone dotée d’une IA performante, cette fracture serait-elle alors résorbée ? Nous avons de sérieuses raisons d’en douter. Il y a plusieurs raisons à cela.
En premier lieu, l’importance de la qualité des prompts qui nécessite de sérieuses compétences rédactionnelles, crée une fracture. En outre, la capacité à prendre du recul devant une réponse de l’IA demande de disposer au préalable de connaissances et de savoirs. Enfin et surtout, l’esprit critique, la volonté de réellement comprendre et de ne pas céder à la facilité consistant à recopier rapidement la réponse, sans creuser et questionner à nouveau, nous semble fondamental. Comme tout l’enjeu réside dans une utilisation intelligente de l’IA, afin d’instaurer un cercle vertueux, on mesure le chantier nécessaire pour surmonter les trois obstacles précédents. Cela nous semble fondamental car il est clair qu’une utilisation mécanique et facile de l’IA ne peut que tirer l’élève vers le bas. Finalement, la fracture s’est déplacée, et elle devient plus subtile : il s’agit pour tous d’utiliser ces outils d’une manière critique afin de progresser, de mieux comprendre et d’apprendre.

Mais au fait, que répond ChatGPT à la question simple suivante ?

You
Je suis professeur et mon rôle est d’enseigner. Que penser d’un élève qui questionne une IA générative, en reprenant par exemple une question de son professeur, et qui recopie bêtement la réponse de l’IA ? N’est-ce pas contre-productif ?

ChatGPT
C’est une question pertinente, surtout à l’ère de l’intelligence artificielle dans l’éducation. L’utilisation d’une IA générative comme source d’information peut être à double tranchant.
D’un côté, les élèves ont accès à une quantité impressionnante d’informations rapidement et peuvent utiliser ces outils pour enrichir leur compréhension des sujets abordés en classe. Cela peut être particulièrement utile pour clarifier des points complexes ou pour accéder à des connaissances qui complètent celles du cours.
D’un autre côté, si un élève se contente de recopier les réponses fournies par une IA sans chercher à comprendre ou à analyser l’information, cela peut effectivement être contre-productif. Cela risque de limiter leur capacité à développer un esprit critique et à apprendre efficacement. Le rôle essentiel de l’éducation est d’encourager les élèves à penser par eux-mêmes, à poser des questions, et à développer des compétences analytiques et critiques.
Pour rendre l’utilisation de l’IA bénéfique en classe, voici quelques stratégies :
1. Encadrement : Guidez les élèves sur comment utiliser l’IA de manière constructive, en leur apprenant à poser des questions pertinentes et à critiquer les réponses obtenues.
2. Intégration pédagogique : Intégrez l’utilisation de l’IA dans le curriculum de manière structurée, en la combinant avec des activités qui demandent de la réflexion, comme des débats ou des travaux de recherche.
3. Développement de compétences : Utilisez l’IA pour aider les élèves à développer des compétences numériques et informatiques, tout en les formant à identifier les sources fiables et à vérifier les informations.
4. Évaluation critique : Encouragez les élèves à évaluer la qualité et la pertinence des informations fournies par l’IA, en comparant avec d’autres sources et en discutant de leurs découvertes en classe.

En somme, l’IA peut être un outil puissant pour l’enseignement et l’apprentissage, mais elle doit être utilisée judicieusement pour compléter et non remplacer les méthodes pédagogiques qui encouragent une pensée critique active.

À méditer !