Le magazine > « Les LLM savent coder mieux que toi » : vrai ou faux ? | Episode 1
Publié le 04/07/2024 par Kevin Séjourné, ingénieur R&D senior chez Cloud Temple

Plongée dans l’IA : Une série de 3 épisodes

Bonjour, je suis Kevin Séjourné, docteur en informatique et ingénieur R&D senior chez Cloud Temple. Comme vous pouvez l’imaginer, depuis 20 ans, j’ai beaucoup écrit de code. Explorateur passionné des LLM, je constate qu’ils peuvent maintenant écrire du code à ma place. Tant mieux ! Mais comme j’ai l’habitude de m’appuyer sur des observations scientifiques, j’ai décidé de tester la qualité de leur travail.

Kevin Séjourné


Retrouvez les 3 épisodes de mon étude :

Épisode 1 : J’automatise mon travail avec les LLM

Les LLM peuvent désormais écrire du code à ma place. Je vais vous montrer comment. Commençons par une tâche simple et fréquente : réécrire tout ou partie d’une application.

Il faut souvent réécrire du code pour :

  • Adresser les obsolescences
  • Corriger une architecture devenue inadaptée
  • Augmenter les performances
  • Changer un comportement
  • Passer à un autre langage de programmation

Par où on commence ?

Nous choisissons un petit programme, seulement 31 Ko tout compris, environ 1000 lignes, en Python. Nous allons adresser des obsolescences, et supprimer une portion d’un programme devenu inutile. Suite à une évolution des besoins, ce programme a eu deux tâches possibles à réaliser au lieu d’une. Progressivement, la nouvelle tâche a remplacé entièrement l’ancienne, qu’il est souhaitable de retirer pour réduire la surface d’attaque. Nous revoyons légèrement l’architecture et recherchons accessoirement un gain de performances et de la modernité sur les dépendances. La vénérable bibliothèque “request” a fait son temps.

Rust est un bon candidat pour réécrire un programme Python. Le typage fort à la compilation est le premier avantage pour une réécriture par LLM. Il va forcer une détection précoce des problèmes de génération du LLM, l’obligeant à une génération plus logique. Cela permet d’attirer l’attention du LLM sur une dimension supplémentaire. Par ailleurs, Rust est un langage moderne traitant convenablement la concurrence, là où Python est limité par son global interpreter lock (GIL).

Nous disposons d’un accès no-limit à GPT 4o via le portail d’IA développé par Cloud Temple. En cas de doute sur une réponse, nous pouvons utiliser groq.com avec Llama3 70b et Mixtral 8x7b. Un Llama3-8b_q4 en local fonctionnant sur jan.ai et un RTX est disponible pour les parties confidentielles.

Les capacités des modèles utilisés guident la taille de programme à convertir. Mixtral traite des contextes jusqu’à 32 Ko, et même si GPT/Gemmini traite des contextes plus grands, ils sont exposés au “lost in the middle”, ils n’arrivent pas forcément à faire attention aux informations présentes au milieu de leur contexte. À l’heure actuelle, un programme plus lourd empêche le LLM de focaliser son attention sur la totalité des parties du code.

Nous utilisons VSCode pour copier-coller le code généré. C’est là que nous agglutinons toutes les parties du code.

Et maintenant, on fait quoi ?

Comment dire au LLM de convertir mon code ? Comment lui donner le code à convertir ?

Construire un prompt, c’est faire simple. Et faire simple, c’est compliqué. Voici le prompt : En faisant attention aux commentaires et aux types de données, et au Cargo.toml, convertissons en Rust le programme Python suivant :

[Ici vient la concaténation de tout le code de l’application] Et oui, faut oser faire un copier-coller de 31 Ko dans la boîte de saisie de texte. Mais c’est ce qu’il y a de plus simple.

Nous avons réalisé des expériences précédentes dans lesquelles on copie le code par morceaux. Mais il y a quelques questions épineuses :

  • Quelle taille des morceaux ? Fichier ? Fonction ? Classe ? Combien de Ko ? Combien de lignes ?
  • Dans quel ordre intégrer les morceaux ? Ordre alphabétique ? Tri topologique ? Tri fonctionnel ? Quid des dépendances croisées ?

Plus simple : tout dans un seul coup. Pour cela, nous avons parcouru tous les fichiers du programme et les avons concaténés en un seul gros fichier. Dans ce gros fichier, ils sont séparés par une commande de la forme FILE main.py :

[suivi du corps du fichier]

Indiquer les fichiers d’origine est indispensable en Python car le nom de fichier est utilisé pour la résolution des dépendances dans ce langage. Ceci forme également des marqueurs utiles pour plus tard afin d’attirer l’attention du modèle sur une partie précise.

Le prompt a alors cet aspect :

Et alors, cette génération de code, elle commence quand ?

Très bien, voici ce qui se passe quand nous appuyons sur [entrée] :

Nous pouvons constater que GPT4o est incapable de générer le résultat complet. La longueur maximale de l’output est atteinte. Nous avons obtenu quelques fonctions des premiers fichiers, mais il manque encore beaucoup de code. Par ailleurs, la génération de code qui est faite par GPT4o est souvent plus verbeuse que le code initial, dans un rapport de 3 pour 2. Ceci ne dépend pas spécifiquement du couple Python / Rust, mais c’est plus un artifact de la génération de code par LLM. Comme pour les réponses humaines, les LLM semblent avoir du mal à donner des réponses courtes.

Il est possible de demander simplement au LLM de continuer :

Le problème est qu’il finit par se perdre dans ce qu’il a déjà traité et n’a pas encore traité… 31 Ko de code + 31 Ko * 1,5 attendu de code à générer + les décorateurs Markdown, nous atteignons déjà à 64 Ko de contexte dans le meilleur des cas. Malheureusement, en lui demandant de continuer sans vrai point de repère, il finit par reconvertir des fichiers déjà traités. Les 64 Ko dérapent et finissent par dépasser la fenêtre des 128 Ko de GPT4o, ce qui entraîne une perte de contexte.

Recommençons depuis le début. Mais cette fois, indiquons dans le prompt de ne convertir que le premier fichier. Puis, une fois le résultat obtenu, nous demandons ensuite le second fichier, ainsi de suite. Le LLM garde ainsi bien en contexte la totalité du programme pour traiter les références, mais ne focalise son attention que sur une transformation à la fois.

Petit à petit, nous pouvons copier-coller l’intégralité de notre nouveau programme dans VSCode. Si le LLM est verbeux, l’humain se doit d’être concis.

En demandant gentiment, j’obtiens également le Cargo.toml qui est le fichier qui gère les dépendances et la compilation en Rust. Ce n’est pas un fichier très compliqué, mais sa principale caractéristique est de ne pas du tout exister dans le programme d’origine en Python. C’est un petit ajout nécessitant une synthèse du programme précédent, à l’image des résumés souvent faits par les LLM. Il est important de demander la génération de ce fichier Cargo.toml après que la génération des fichiers de code Rust est réalisée, sinon le LLM risque d’omettre des bibliothèques. Au début, le LLM n’a pas encore fait attention à tout ce dont il aura besoin.

Ô miracle, le programme copier-coller semble prêt à travailler avec la confiance traditionnelle des LLM qui nous assure avoir la vérité. Ce n’est pas tout à fait le cas, car, entre autres, le programme ne compile pas. Pour corriger cela, nous allons commencer à apprendre… dans un prochain article.

Bilan de première étape

Vous l’aurez remarqué, avec le LLM, nous avons passé plus de temps à planifier ce que nous allons faire, pourquoi nous allons le faire et moins à effectivement générer du code. À ce stade, le temps passé sur le projet est d’environ 8h, dont deux pour la génération.

Le magazine
Politique en matière de cookies

Nous utilisons des cookies pour vous offrir la meilleure expérience possible sur notre site mais nous ne prélevons aucune donnée à caractère personnel.

Les services de mesure d’audience, nécessaires au fonctionnement et à l’amélioration de notre site, ne permettent pas de vous identifier personnellement. Vous avez cependant la possibilité de vous opposer à leur usage.

Pour plus d’informations, consultez notre politique de confidentialité.