Evaluation

Évaluation des LLM : Au-delà du Pass@1, vers la maintenabilité

Depuis deux ans, l'industrie se concentre sur une seule métrique pour évaluer les grands modèles de langage (LLM) en programmation : Pass@1. Bien que le Pass@1 indique si un modèle peut générer une fonction qui passe les tests du premier coup, il échoue à répondre à une question plus cruciale pour le développement d'entreprise : Le code est-il maintenable ?

À mesure que nous passons des prototypes expérimentaux aux systèmes de production, nous avons besoin de cadres d'évaluation qui tiennent compte de la santé du code, de sa lisibilité et de sa capacité à évoluer. Cet article explore comment nous pouvons évaluer les LLM non seulement sur leur exactitude, mais aussi sur la qualité du code qu'ils produisent.

Les limites du Pass@1

Le Pass@1 est une métrique binaire. Une fonction générée passe la suite de tests cachée ou non. Cette approche présente plusieurs angles morts :

  • Ignore le style : Un LLM peut générer un code efficace mais illisible en utilisant des one-liners obscurs ou des techniques d'optimisation agressives que les humains trouvent difficiles à examiner.
  • Manque de contexte : Il ne mesure pas à quel point le code s'intègre dans une base de code existante. Respecte-t-il les conventions de nommage du projet ? Utilise-t-il la bibliothèque standard ou introduit-il des dépendances inutiles ?
  • Aucun signal de refactoring : Il ne teste pas la capacité du modèle à comprendre et à modifier du code existant, ce qui constitue une plus grande partie du travail quotidien d'un développeur que l'écriture à partir de zéro.

Introduction des métriques de qualité composites

Pour combler ces lacunes, nous proposons un système de notation composite qui pondère l'exactitude fonctionnelle avec des métriques d'analyse statique. Voici un aperçu des composants :

1. Complexité du code (Complexité cyclomatique)

Nous utilisons des outils comme radiate ou pylint pour mesurer la complexité cyclomatique. Des scores de complexité élevés indiquent un code difficile à tester et à maintenir. Un benchmark devrait pénaliser les solutions qui obtiennent des résultats corrects via un imbriquement profond ou une logique conditionnelle complexe.

2. Stabilité du diff et modifications minimales

Dans les tâches de refactoring, nous mesurons la « stabilité du diff ». Un modèle de haute qualité doit effectuer des modifications minimales et chirurgicales sur le code existant. Si un LLM est demandé d'ajouter un paramètre à une fonction mais réécrit à la place toute la classe, il devrait être pénalisé. Nous pouvons quantifier cela en utilisant la distance de Levenshtein sur le diff ou simplement en comptant le nombre de lignes modifiées par rapport aux lignes nécessaires.

3. Couverture des tests de la solution

Le code généré est-il accompagné de tests robustes ? Nous pouvons évaluer la qualité des tests unitaires auto-générés en mesurant leur couverture des cas limites. Un LLM qui génère du code mais ne teste que le « chemin heureux » (happy path) devrait obtenir un score inférieur à celui qui identifie les modes de défaillance potentiels.

Exemple pratique : Évaluation d'un refactoring

Considérons une tâche où le prompt est : « Refactorisez la fonction suivante pour améliorer la lisibilité et ajouter la gestion des erreurs. »


# Code original
def process_data(data):
    if data:
        return [x for x in data if x > 0]
    return []

Un modèle qui répond avec le code suivant obtiendrait un score élevé au Pass@1 (si les tests passent) mais un score faible en termes de maintenabilité :


# Réponse A : Faible qualité
def process_data(d):
    if d is not None:
        try:
            return [i for i in d if i > 0]
        except Exception as e:
            return []
    return []

La Réponse A utilise des noms de variables obscurs (d, i) et capture toutes les exceptions, ce qui est un anti-pattern. Une réponse de haute qualité ressemblerait à ceci :


# Réponse B : Haute qualité
def process_data(data):
    """
    Filtre les valeurs non positives des données d'entrée.
    
    Args:
        data: Une liste de nombres.
        
    Returns:
        Une liste de nombres positifs, ou une liste vide si l'entrée est None.
    """
    if not data:
        return []
    
    positive_values = []
    for value in data:
        if isinstance(value, (int, float)) and value > 0:
            positive_values.append(value)
            
    return positive_values

La Réponse B est verbale, mais elle est auto-documentée, gère explicitement la vérification des types et respecte les normes PEP8. Un benchmark axé sur la maintenabilité attribuerait à la Réponse B un score significativement plus élevé qu'à la Réponse A, même si les deux passent les tests fonctionnels de base.

Mise en œuvre du benchmark

Pour mettre en œuvre cela, nous pouvons créer un pipeline qui s'intègre au flux CI/CD du harnais d'évaluation :

  1. Génération de code : Demander au LLM d'exécuter la tâche.
  2. Analyse statique : Exécuter flake8, bandit et mypy sur la sortie. Analyser la sortie pour les avertissements.
  3. Tests fonctionnels : Exécuter le code généré contre une suite de tests unitaires.
  4. Validation du refactoring : Si la tâche implique de modifier du code existant, exécuter une « vérification du diff » pour s'assurer que les modifications sont localisées.
  5. Agrégation des scores : Combiner ces signaux en un score final pondéré. Par exemple : Score = 0.5 * Exactitude_Fonctionnelle + 0.3 * Score_Analyse_Statique + 0.2 * Efficacite_Refactoring

Conclusion

À mesure que les LLM deviennent intégraux à nos flux de développement, se fier uniquement au Pass@1 revient à embaucher un développeur basé uniquement sur sa capacité à passer un seul entretien de codage, en ignorant son adéquation culturelle à long terme et la qualité de son code. En introduisant des métriques de maintenabilité et de refactoring dans nos benchmarks, nous pouvons mieux prédire comment ces modèles se comporteront dans des contextes d'ingénierie logicielle réels. L'avenir de l'évaluation des LLM ne concerne pas seulement ce qui fonctionne aujourd'hui, mais ce qui fonctionnera encore dans six mois.

Share: