L' IA BING GPT-4 passe le BAC informatique!

Data / IA

Nous avons fait passer le BAC « informatique » à l’IA BING (GPT-4)! [Partie 2/2]

Par Laurent Delattre, publié le 23 mars 2023

Cette semaine se tenaient certaines épreuves de spécialités du BAC 2023. Nous avons confronté l’IA Bing au sujet de l’épreuve « Numérique et sciences informatiques 2023 ». Une expérience pleine d’enseignements… (suite et fin).

Pour satisfaire à la fois notre curiosité et notre besoin de mieux cerner le potentiel et les limites des nouvelles IA génératives qui sont en passe d’envahir notre quotidien, aussi bien dans la sphère professionnelle que personnelle, nous avons essayé de faire passer à l’IA Bing (basée sur GPT-4) l’épreuve de BAC 2023 de la spécialité « Numérique et sciences informatiques ».

Après une première partie consacrée à l’univers des bases de données, aux interrogations SQL et à la conception des réseaux, cette seconde partie se focalise sur l’exercice de la programmation en python.

On le sait, le modèle GPT-4 sous-jacent à l’IA de Bing Chat a été entraîné non seulement sur les langages humains mais aussi sur les langages informatiques. Dès lors, cette IA peut – en théorie – convertir en code informatique des énoncés exprimés en langage naturel. Un potentiel déjà exploité par exemple par l’outil d’aide à la génération et complétion de code GitHub Copilot.


À LIRE AUSSI :


La théorie, c’est bien. La pratique, c’est plus utile. Aussi étions-nous curieux de voir comment Bing allait se comportait sur le troisième exercice du BAC 2023 avec ses défis de programmation en Python.

Une épreuve passée par Bing « les doigts dans le nez »… Explications, constatations et enseignements…

EXERCICE 3 : PROGRAMMATION OBJET EN PYTHON & ALGORITHMIE

Question 1 : Associer, en vous appuyant sur l’extrait de code, les noms nom, tab_voisines, tab_couleurs_disponibles et couleur_attribuee au terme qui leur correspond parmi : objet, attribut, méthode ou classe.

La réponse de Bing :
Voici les termes qui correspondent aux noms donnés :

  • nom : attribut
  • tab_voisines : attribut
  • tab_couleurs_disponibles : attribut
  • couleur_attribuee : attribut

Ces noms sont tous des attributs de la classe Region, car ils sont définis dans la méthode init et précédés du mot-clé self. Ils représentent les caractéristiques d’une région sur une carte.

Une classe est un modèle qui définit les attributs et les méthodes communs à un ensemble d’objets. Une méthode est une fonction qui s’applique à un objet et qui utilise souvent ses attributs. Un objet est une instance d’une classe, c’est-à-dire un exemplaire concret qui possède des valeurs spécifiques pour ses attributs.

Notre correction : la réponse est juste. Outre la faculté à comprendre la question, ce qui est intéressant ici c’est de voir comment l’IA Bing découpe la réponse et présente chaque attribut sous forme de liste. Comme déjà noté dans la première partie, l’IA Bing aime expliquer le pourquoi de ses réponses et se montrent non seulement informatif mais aussi didactique. Nous avons ici mis en gras les points forts de la réponse de Bing.


Question 2 : Indiquer le type du paramètre nom_region de la méthode __init__ de la classe Region

La réponse de Bing :
Le type du paramètre nom_region de la méthode init de la classe Region est str, c’est-à-dire une chaîne de caractères. 

Notre correction : la réponse est juste. A l’occasion de la rédaction de cet article, l’examen a été repassé deux fois ou plus par Bing. Nous ne donnons ici que la réponse lors du premier passage. Il est intéressant de noter que l’IA ne formule pas toujours la réponse de la même façon. La réponse est toujours juste mais elle est parfois plus détaillée. Ainsi lors d’un autre passage, alors que nos formulations étaient identiques, l’IA a tenu à compléter sa réponse en la justifiant… Voici cette seconde formulation :

Le type du paramètre nom_region de la méthode init de la classe Region est str (chaîne de caractères). C’est le type attendu pour le nom d’une région. On peut le déduire du code fourni ou le préciser explicitement en utilisant les annotations de type. Par exemple :

class Region:
    '''Modélise une région d'un pays sur une carte.'''
    def __init__(self, nom_region: str):
        ''' initialise une région :
        param nom_region (str) le nom de la région '''
        self.nom = nom_region
        # tableau des régions voisines, vide au départ
        self.tab_voisines = []
        # tableau des couleurs disponibles pour colorier la région
        self.tab_couleurs_disponibles = ['rouge', 'vert', 'bleu', 'jaune', 'orange', 'marron']
        # couleur attribuée à la région et non encore choisie au départ
        self.couleur_attribuee = None

Les annotations de type ne sont pas obligatoires en Python, mais elles peuvent aider à documenter et vérifier le code.


Il est fort quand même ce Bing!


Question 3 : Donner une instruction permettant de créer une instance nommée ge de la classe Region correspondant à la région dont le nom est « Grand Est »

La réponse de Bing :
Pour créer une instance nommée ge de la classe Region correspondant à la région dont le nom est « Grand Est », il suffit d’appeler le nom de la classe en tant que fonction et de lui passer le nom de la région en argument. Par exemple :

ge = Region("Grand Est")

Cette instruction va créer un objet de type Region et l’assigner à la variable ge. On pourra ensuite accéder aux attributs et aux méthodes de cet objet en utilisant le point (.) comme séparateur. Par exemple :

print(ge.nom) # affiche Grand Est

Notre correction : Réponse verbeuse, c’est sûr, mais juste. On note une nouvelle fois cette tendance à la pédagogie de l’IA Bing lorsqu’elle est en mode “Créatif”.


Question 4 : Complète la ligne 6 de la méthode de la classe Region ci-dessous :

1  def renvoie_premiere_couleur_disponible(self):
2     '''
3     Renvoie la première couleur du tableau des couleurs disponibles supposé non vide.
4     : return (str)
5     '''
6     return ...

La réponse de Bing :
Pour compléter la ligne 6 de la méthode de la classe Region ci-dessous, il faut utiliser l’attribut self.tab_couleurs_disponibles qui représente le tableau des couleurs disponibles pour une région. Pour accéder à la première couleur de ce tableau, il faut utiliser l’indice 0 entre crochets. Voici la ligne complétée :

return self.tab_couleurs_disponibles[0]

Cette instruction va renvoyer la chaîne de caractères correspondant à la première couleur du tableau des couleurs disponibles de l’instance qui appelle la méthode. Par exemple, si le tableau contient [‘rouge’, ‘vert’, ‘bleu’, ‘jaune’, ‘orange’, ‘marron’], la méthode va renvoyer ‘rouge’.

Notre correction : Réponse juste et très claire. On notera la capacité de Bing à interpréter le code dans la question. C’est même un peu surprenant, vu que nous avons copié/collé sauvagement le texte du PDF de l’examen sans la présentation ni les indentations de la mise en page.


Question 5 : Complèter la ligne 6 de la méthode de la classe Region ci-dessous :

1  def renvoie_nb_voisines(self) :
2      '''
3      Renvoie le nombre de régions voisines.
4      : return (int)
5      '''
6      return ...

La réponse de Bing :
Pour compléter la ligne 6 de la méthode de la classe Region ci-dessous, il faut utiliser l’attribut self.tab_voisines qui représente le tableau des régions voisines d’une région. Pour obtenir le nombre de régions voisines, il faut utiliser la fonction len qui renvoie la longueur d’un tableau. Voici la ligne complétée :

return len(self.tab_voisines)

Cette instruction renvoie le nombre d’éléments du tableau self.tab_voisines, c’est-à-dire le nombre de régions voisines d’une région. Par exemple, si le tableau contient [‘Bourgogne-Franche-Comté’, ‘Île-de-France’, ‘Hauts-de-France’], la méthode va renvoyer 3.

Notre correction : Réponse juste et très claire. Ce qui est assez fascinant, c’est la capacité de l’IA à comprendre ce qu’on lui demande : remplacer une ligne de code, interpréter le commentaire descriptif pour générer le code correspondant, écrire du code Python… Etonnant non ?


Question 6 : Compléter la méthode de la classe Region ci-dessous à partir de la ligne 6 :

1  def est_coloriee(self):
2      '''
3      Renvoie True si une couleur a été attribuée à cette région et False sinon.
4      : return (bool)
5      '''
6      …

La réponse de Bing :
Pour compléter la méthode de la classe Region ci-dessous à partir de la ligne 6, il faut vérifier si l’attribut couleur_attribuee est différent de None. On peut utiliser l’opérateur != pour comparer deux valeurs. Par exemple :

return self.couleur_attribuee != None

Cette instruction va renvoyer True si une couleur a été attribuée à cette région et False sinon. Par exemple, si l’attribut couleur_attribuee vaut ‘rouge’, la méthode va renvoyer True. Sinon, la méthode va renvoyer False.

Notre correction : La réponse est juste. C’est même la formulation la plus efficace pour répondre à la question mais pas la plus lisible pour des néophytes. Nous imaginons que la plupart des étudiants et la plupart des corrections publiées vont plutôt utiliser une formulation avec un “if…else…”.
Du coup, nous avons demandé à Bing, “Peux tu reformuler la réponse en utilisation une instruction ‘if . else ‘ ?”. Et voici sa réponse :

Oui, je peux reformuler la réponse en utilisant une instruction if . else. Par exemple :

if self.couleur_attribuee != None:
    return True
else:
    return False

Cette instruction va faire la même chose que la précédente, mais en utilisant une structure conditionnelle. Si l’attribut couleur_attribuee est différent de None, la méthode va renvoyer True. Sinon, elle va renvoyer False.


Question 7 : Compléter la méthode de la classe Region ci-dessous à partir de la ligne 8 :

1 def retire_couleur(self, couleur):
2       '''
3       Retire couleur du tableau de couleurs disponibles de la région si elle est dans ce tableau. Ne fait rien sinon.
4       : param couleur (str)
5       : ne renvoie rien
6       : effet de bord sur le tableau des couleurs disponibles
7       '''
8       ...

La réponse de Bing :
Pour compléter la méthode de la classe Region ci-dessous à partir de la ligne 8, il faut utiliser l’attribut self.tab_couleurs_disponibles qui représente le tableau des couleurs disponibles pour une région. Pour retirer une couleur de ce tableau si elle est présente, il faut utiliser la méthode remove qui prend en paramètre la valeur à supprimer. Voici la méthode complétée :

def retire_couleur(self, couleur):
    '''
    Retire couleur du tableau de couleurs disponibles de la région si elle est dans
    ce tableau. Ne fait rien sinon.
    : param couleur (str)
    : ne renvoie rien
    : effet de bord sur le tableau des couleurs disponibles
    '''
    if couleur in self.tab_couleurs_disponibles: # vérifie si la couleur est dans le tableau
        self.tab_couleurs_disponibles.remove(couleur) # retire la couleur du tableau

Cette méthode retire la couleur donnée en paramètre du tableau des couleurs disponibles de la région si elle est dans ce tableau. Elle ne fait rien sinon.

Notre correction : La réponse est juste. On notera le soin apporté par l’IA Bing à la mise en forme colorée de la réponse mais aussi la volonté de commenter chaque ligne générée.


Question 8 : Compléter la méthode de la classe Region ci-dessous, à partir de la ligne 7, en utilisant une boucle :

1   def est_voisine(self, region):
2         '''
3         Renvoie True si la region passée en paramètre est une voisine et False sinon.
4         : param region (Region)
5         : return (bool)
6         '''
7         ...

La réponse de Bing :
Pour compléter la méthode de la classe Region ci-dessous, à partir de la ligne 7, en utilisant une boucle, il faut parcourir le tableau des régions voisines et comparer chaque élément avec la région passée en paramètre. On peut utiliser une boucle for pour itérer sur le tableau et l’opérateur == pour vérifier l’égalité entre deux objets. Par exemple :

for voisine in self.tab_voisines:
    if voisine == region:
        return True
return False

Cette instruction va renvoyer True si la région passée en paramètre est une voisine et False sinon.
Par exemple, si le tableau des régions voisines contient [‘Bourgogne-Franche-Comté’, ‘Île-de-France’, ‘Hauts-de-France’] et que la région passée en paramètre est ‘Île-de-France’, la méthode va renvoyer True. Si la région passée en paramètre est ‘Occitanie’, la méthode va renvoyer False.

Notre correction : Bing a raison! La réponse est tellement optimale et tellement peu dans l’esprit attendue de correcteurs pas toujours experts en Python qu’on a demandé à Bing de reformuler le code en utilisant une variable i pour la boucle (typiquement le genre de réponse donnée par les corrections BAC 2023 publiées sur Internet). On lui a demandé “Peux-tu reformuler ta réponse en utilisant une variable i”, et sa réponse est limpide :

Le code ci-dessus est correct. Il utilise une boucle for qui parcourt directement les éléments d’un tableau sans avoir besoin d’une variable i. C’est une façon plus simple et plus lisible d’écrire une boucle for en Python.

Si vous voulez écrire une boucle for plus classique avec une variable i, vous pouvez utiliser la fonction range qui génère une suite de nombres entiers. Il faut alors utiliser la variable i comme indice pour accéder aux éléments du tableau self.tab_voisines. Voici le code équivalent :

def est_voisine(self, region):
    '''
    Renvoie True si la region passée en paramètre est une voisine et False sinon.
    : param region (Region)
    : return (bool)
    '''
    n = len(self.tab_voisines) # nombre de régions voisines
    for i in range(n): # parcourt les indices de 0 à n-1
        voisine = self.tab_voisines[i] # récupère l'élément à l'indice i
        if voisine == region: # compare l'élément avec la région passée en paramètre
            return True # renvoie True si les régions sont identiques
    return False # renvoie False si aucune région n'a été trouvée

Suite de l’épreuve

Question 9 : Complète la méthode de la classe Pays ci-dessous à partir de la ligne 7 :

1  def renvoie_tab_regions_non_coloriees(self):
2        '''
3        Renvoie un tableau dont les éléments sont les régions du pays sans couleur attribuée.
4        : return (list) tableau d’instances de la classe 
5  Region
6        '''
7        ...

La réponse de Bing :
Pour compléter la méthode de la classe Pays ci-dessous à partir de la ligne 7, il faut créer un tableau vide et y ajouter les régions du pays sans couleur attribuée. On peut utiliser une boucle for pour parcourir le tableau des régions du pays et la méthode append() pour ajouter un élément à un tableau. On peut aussi utiliser la méthode est_coloriee() de la classe Region pour vérifier si une région a une couleur attribuée ou pas. Par exemple :

tab_regions_non_coloriees = [] # création d'un tableau vide
for region in self.tab_regions: # parcours du tableau des régions du pays
    if not region.est_coloriee(): # si la région n'a pas de couleur attribuée
        tab_regions_non_coloriees.append(region) # ajout de la région au tableau
return tab_regions_non_coloriees # renvoi du tableau

Cette instruction va renvoyer un tableau dont les éléments sont les régions du pays sans couleur attribuée. Par exemple, si le pays contient les régions [‘Grand Est’, ‘Occitanie’, ‘Bretagne’] et que seule la région ‘Bretagne’ a une couleur attribuée, la méthode va renvoyer [‘Grand Est’, ‘Occitanie’].

Notre correction : Excellente réponse! Encore une fois, on appréciera la capacité de l’IA à intégrer les contextes et à analyser non seulement ce qui lui est demandé mais aussi le code . Par ailleurs, elle complète le code en prenant le soin de commenter chacune des lignes générées. On parie que 90% des étudiants n’ont pas pris cette peine !

Question 10 : On considère la méthode de la classe Pays ci-dessous.

1  def renvoie_max(self):
2        nb_voisines_max = -1
3        region_max = None
4        for reg in self.renvoie_tab_regions_non_coloriees():
5              if reg.renvoie_nb_voisines() > nb_voisines_max:
6                  nb_voisines_max = reg.renvoie_nb_voisines()
7                  region_max = reg
8  return region_max

a. Explique dans quel cas cette méthode renvoie None.

b. Indique, dans le cas où cette méthode ne renvoie pas None, les deux particularités de la région renvoyée.

La réponse de Bing :

a. Cette méthode renvoie None dans le cas où le pays ne contient aucune région sans couleur attribuée. En effet, dans ce cas, la méthode renvoie_tab_regions_non_coloriees() renvoie un tableau vide et la boucle for de la ligne 4 n’est jamais exécutée. La variable region_max reste donc à None et est renvoyée à la ligne 8.

b. Dans le cas où cette méthode ne renvoie pas None, les deux particularités de la région renvoyée sont :

Elle n’a pas de couleur attribuée, car elle fait partie du tableau renvoyé par la méthode renvoie_tab_regions_non_coloriees().

– Elle a le plus grand nombre de régions voisines parmi les régions sans couleur attribuée du pays, car elle est choisie en fonction de la valeur de l’attribut nb_voisines_max qui est mis à jour à chaque itération de la boucle for.

Notre correction : Bonne réponse! Pourtant nous avions glissé un petit piège. Au lieu de lui poser deux questions séparées, nous avons conservé la formulation d’origine avec (a) et (b). Et l’IA a bien interprété ce qu’on lui demandait et a formulé sa réponse avec un petit (a) et un petit (b).
On notera également la structuration de sa réponse (b). On lui demande “deux particularités”, elle décompose donc sa réponse pour bien les mettre en évidence. Joli, non?

Ceci dit, nous trouvions la réponse empoulée et trop compliquée. Alors on a demandé à Bing de “reformuler sa réponse plus simplement”. Et sa réponse a été:
a. Cette méthode renvoie None quand toutes les régions du pays ont déjà une couleur.
b. La région renvoyée par cette méthode a deux caractéristiques :
– Elle n’a pas encore de couleur.
– Elle a plus de voisins que les autres régions sans couleur.

Question 10 : Coder la méthode colorie(self) de la classe Pays qui choisit une couleur pour chaque région du pays de la façon suivante :

– On récupère la région non coloriée qui possède le plus de voisines.
– Tant que cette région existe :
> La couleur attribuée à cette région est la première couleur disponible dans son tableau de couleurs disponibles.
> Pour chaque région voisine de la région : si la couleur choisie est présente dans le tableau des couleurs disponibles de la région voisine alors on la retire de ce tableau.
– On récupère à nouveau la région non coloriée qui possède le plus de voisines.

La réponse de Bing :

def colorie(self):
   # On récupère la région non coloriée qui possède le plus de voisines
   region = self.renvoie_max()
   # Tant que cette région existe
   while region != None:
      # La couleur attribuée à cette région est la première couleur disponible
        dans son tableau de couleurs disponibles
      couleur = region.renvoie_premiere_couleur_disponible()
      region.couleur_attribuee = couleur
      # Pour chaque région voisine de la région
      for voisine in region.tab_voisines:
          # Si la couleur choisie est présente dans le tableau des couleurs
            disponibles de la région voisine alors on la retire de ce tableau
          voisine.retire_couleur(couleur)
       # On récupère à nouveau la région non coloriée 
         qui possède le plus de voisines
       region = self.renvoie_max()

Cette méthode parcourt les régions non coloriées du pays et leur attribue une couleur en respectant les contraintes données. Elle utilise les méthodes renvoie_max(), renvoie_premiere_couleur_disponible() et retire_couleur() définies précédemment.

Notre correction : Le code est correct et lisible ! Mais il n’est pas forcément optimal et plusieurs optimisations d’écriture sont envisageables. On n’en voudra pas trop à Bing qui par ailleurs fait ici un très bel effort de suivi de discussion et de contexte. On notera qu’il a effectivement bien utilisé toutes les méthodes préalablement étudiées une à une. Il n’a pas perdu le fil de la discussion (alors que l’on arrive à une quinzaine d’échanges) et se souvient des différentes méthodes vues précédemment dans la discussion. Il les réutilise donc à bon escient. On sait que les longues discussions posent problème à ses IA génératives et qu’elles peuvent finir par perdre le contexte et ne plus se souvenir du début de la discussion. C’est d’ailleurs pourquoi Microsoft avait dans un premier temps bridé Bing à 5 échanges par discussion avant de monter progressivement ce seuil, actuellement fixé à 15 éxchanges.


Ce que les DSI peuvent apprendre de ce qui précède…

Outre le fait que Bing est reçu à ce BAC avec la mention Très Bien, ce qui reste anecdotique, cette expérience est un bon moyen d’évaluer les progrès – il faut bien le dire impressionnant – des IA ces deux dernières années.

On saluera la faculté à comprendre le français, la faculté à s’exprimer clairement en français, des capacités de raisonnement et de suivi de discussions en très net progrès depuis GPT-3, et dans le cadre de cette seconde partie, d’indéniables capacités à transformer en code informatique des demandes exprimées en langage naturelle.

Ces IA se révèlent non seulement de puissants outils pour les développeurs quand il s’agit de gagner du temps mais aussi de fantastiques outils d’apprentissage des langages informatiques et de l’algorithmie. Notamment parce que Bing IA tend à systématiquement commenter la moindre ligne de codes produites mais aussi parce qu’elle cherche le plus souvent à expliciter ce qu’elle a fait. Ces qualités directement héritées de son modèle LLM “GPT-4” d’OpenAI.

Nul doute que ces IA vont de plus en plus se démocratiser non seulement au sein des environnements de développement mais aussi au sein des plateformes Low-Code/No-Code et au sein d’outils d’automatisation de tâches. Ces IA arrivent notamment dans les outils CRM, ERP et bureautiques (cf nos articles sur Microsoft 365 Copilot, Google Workspace, Dynamics 365 Copilot et Salesforce Einstein GPT), et on attend avec une certaine impatience de voir leur potentiel en action. Reste à vérifier si – dans le contexte de l’entreprise – les défauts et dérivent de ces IA seront finalement plutôt restreints et donc leur utilité accrue… Affaire à suivre…

À LIRE AUSSI :

Dans l'actualité