La complétion de code optimisée par ML améliore la productivité des développeurs


La complexité croissante du code pose un défi majeur à la productivité en génie logiciel. Complétion de code a été un outil essentiel qui a contribué à atténuer cette complexité dans environnements de développement intégrés (IDE). Classiquement, les suggestions de complétion de code sont implémentées avec des règles basées sur moteurs sémantiques (SE), qui ont généralement accès au référentiel complet et comprennent sa structure sémantique. Des recherches récentes ont démontré que les grands modèles de langage (par exemple, Manuscrit et Palmier) permettent des suggestions de code plus longues et plus complexes, et par conséquent, des produits utiles ont vu le jour (par exemple, Copilote). Cependant, la question de savoir comment la complétion de code alimentée par l’apprentissage automatique (ML) affecte la productivité des développeurs, au-delà productivité perçue et suggestions acceptées, reste ouvert.

Aujourd’hui, nous décrivons comment nous avons combiné ML et SE pour développer un roman TransformateurLa saisie semi-automatique de code ML sémantique hybride, désormais disponible pour les développeurs internes de Google. Nous discutons de la manière dont ML et SE peuvent être combinés en (1) reclassant les suggestions de jeton unique SE à l’aide de ML, (2) en appliquant des complétions à une et plusieurs lignes à l’aide de ML et en vérifiant l’exactitude avec le SE, ou (3) en utilisant un seul et continuation multiligne par ML de suggestions sémantiques à jeton unique. Nous comparons l’achèvement du code ML sémantique hybride de plus de 10 000 Googleurs (sur trois mois dans huit langages de programmation) à un groupe témoin et constatons une réduction de 6 % du temps d’itération de codage (temps entre les versions et les tests) et une réduction de 7 % des changements de contexte ( c’est-à-dire en quittant l’IDE) lorsqu’il est exposé à l’achèvement ML sur une seule ligne. Ces résultats démontrent que la combinaison de ML et de SE peut améliorer la productivité des développeurs. Actuellement, 3 % du nouveau code (mesuré en caractères) est désormais généré à partir de l’acceptation des suggestions d’achèvement ML.

Transformateurs pour l’achèvement

Une approche courante de la complétion de code consiste à former des modèles de transformateurs, qui utilisent un attention à soi mécanisme de compréhension du langage, pour permettre la compréhension du code et les prédictions d’achèvement. Nous traitons un code similaire au langage, représenté par des jetons de sous-mots et un PhraseMorceau vocabulaire et utiliser des modèles de transformateurs codeur-décodeur fonctionnant sur TPU pour faire des prédictions d’achèvement. L’entrée est le code qui entoure le curseur (~ 1000-2000 jetons) et la sortie est un ensemble de suggestions pour compléter la ligne actuelle ou plusieurs lignes. Les séquences sont générées avec un recherche de faisceau (ou exploration arborescente) sur le décodeur.

Pendant la formation sur Google monorepo, nous masquons le reste d’une ligne et certaines lignes de suivi, pour imiter le code qui est activement développé. Nous formons un modèle unique sur huit langages (C++, Java, Python, Go, Typescript, Proto, Kotlin et Dart) et observons des performances améliorées ou égales dans tous les langages, éliminant ainsi le besoin de modèles dédiés. De plus, nous constatons qu’une taille de modèle d’environ 0,5 milliard de paramètres offre un bon compromis pour une précision de prédiction élevée avec une faible latence et un faible coût des ressources. Le modèle bénéficie fortement de la qualité du monorepo, qui est renforcée par des lignes directrices et des examens. Pour les suggestions multi-lignes, nous appliquons de manière itérative le modèle à une seule ligne avec des seuils appris pour décider s’il faut commencer à prédire les achèvements pour la ligne suivante.

Des modèles de transformateur codeur-décodeur sont utilisés pour prédire le reste de la ligne ou des lignes de code.

Reclasser les suggestions de jeton unique avec ML

Pendant qu’un utilisateur tape dans l’IDE, les complétions de code sont demandées de manière interactive à partir du modèle ML et du SE simultanément dans le backend. Le SE ne prédit généralement qu’un seul jeton. Les modèles ML que nous utilisons prédisent plusieurs jetons jusqu’à la fin de la ligne, mais nous ne considérons que le premier jeton pour correspondre aux prédictions du SE. Nous identifions les trois principales suggestions ML qui sont également contenues dans les suggestions SE et renforçons leur classement au sommet. Les résultats reclassés sont ensuite affichés sous forme de suggestions pour l’utilisateur dans l’IDE.

En pratique, nos SE s’exécutent dans le cloud, fournissant des services linguistiques (par exemple, complétion sémantique, diagnostics, etc.) avec lesquels les développeurs sont familiers, et nous avons donc colocalisé les SE pour qu’ils s’exécutent aux mêmes emplacements que les TPU effectuant l’inférence ML. Les SE sont basés sur une bibliothèque interne qui offre des fonctionnalités de type compilateur avec de faibles latences. En raison de la configuration de conception, où les requêtes sont effectuées en parallèle et où le ML est généralement plus rapide à servir (médiane d’environ 40 ms), nous n’ajoutons aucune latence aux achèvements. Nous observons une amélioration significative de la qualité en utilisation réelle. Pour 28 % des réussites acceptées, le classement de la réussite est plus élevé en raison du renforcement, et dans 0,4 % des cas, il est pire. De plus, nous constatons que les utilisateurs saisissent > 10 % de caractères en moins avant d’accepter une suggestion de complétion.

Vérifier l’exactitude sémantique des complétions ML sur une ou plusieurs lignes

Au moment de l’inférence, les modèles ML ne sont généralement pas conscients du code en dehors de leur fenêtre d’entrée, et le code vu pendant la formation peut manquer les ajouts récents nécessaires pour les achèvements dans les référentiels en évolution active. Cela conduit à un inconvénient commun de l’achèvement de code alimenté par ML, dans lequel le modèle peut suggérer un code qui semble correct, mais qui ne se compile pas. D’après des recherches internes sur l’expérience utilisateur, ce problème peut entraîner une érosion de la confiance des utilisateurs au fil du temps tout en réduisant les gains de productivité.

Nous utilisons des SE pour effectuer des contrôles d’exactitude sémantique rapides dans un budget de latence donné (<100 ms pour l'achèvement de bout en bout) et utilisons la mise en cache arbres de syntaxe abstraite pour permettre une compréhension structurelle « complète ». Les vérifications sémantiques typiques incluent la résolution de référence (c’est-à-dire, cet objet existe-t-il), les vérifications d’invocation de méthode (par exemple, confirmer que la méthode a été appelée avec un nombre correct de paramètres) et les vérifications d’assignabilité (pour confirmer que le type est comme prévu).

Par exemple, pour le langage de codage Aller, ~8 % des suggestions contiennent des erreurs de compilation avant les vérifications sémantiques. Cependant, l’application de vérifications sémantiques a filtré 80 % des suggestions non compilables. Le taux d’acceptation des complétions d’une seule ligne s’est amélioré de 1,9 fois au cours des six premières semaines d’intégration de la fonctionnalité, probablement en raison de la confiance accrue des utilisateurs. À titre de comparaison, pour les langues où nous n’avons pas ajouté de vérification sémantique, nous n’avons constaté qu’une augmentation de 1,3 fois de l’acceptation.

Les serveurs de langage ayant accès au code source et au backend ML sont colocalisés sur le cloud. Ils effectuent tous deux une vérification sémantique des suggestions d’achèvement ML.

Résultats

Avec plus de 10 000 développeurs internes à Google utilisant la configuration de complétion dans leur IDE, nous avons mesuré un taux d’acceptation des utilisateurs de 25 à 34 %. Nous avons déterminé que la complétion de code ML sémantique hybride basée sur un transformateur complète plus de 3 % du code, tout en réduisant de 6 % le temps d’itération de codage pour les Googleurs (à un niveau de confiance de 90 %). La taille du changement correspond aux effets typiques observés pour les caractéristiques transformationnelles (par exemple, le cadre clé) qui n’affectent généralement qu’une sous-population, alors que ML a le potentiel de se généraliser pour la plupart des principaux langages et ingénieurs.

Fraction de tout le code ajouté par ML2,6 %
Réduction de la durée des itérations de codage6%
Réduction du nombre de changements de contextesept%
Taux d’acceptation (pour les suggestions visibles pendant plus de 750 ms)25%
Nombre moyen de caractères par acceptation21
Indicateurs clés pour l’achèvement du code sur une seule ligne mesurés en production pour plus de 10 000 développeurs internes à Google qui l’utilisent dans leur développement quotidien dans huit langues.
Fraction de tout le code ajouté par ML (avec > 1 ligne en suggestion)0,6 %
Nombre moyen de caractères par acceptation73
Taux d’acceptation (pour les suggestions visibles pendant plus de 750 ms)34%
Indicateurs clés pour l’achèvement de code multiligne mesurés en production pour plus de 5 000 développeurs internes à Google qui l’utilisent dans leur développement quotidien dans huit langues.

Fournir de longs achèvements tout en explorant les API

Nous avons également étroitement intégré la complétion sémantique avec la complétion complète de la ligne. Lorsque la liste déroulante avec les complétions sémantiques à jeton unique apparaît, nous affichons en ligne les complétions à une seule ligne renvoyées par le modèle ML. Ces derniers représentent une continuation de l’élément qui est au centre de la liste déroulante. Par exemple, si un utilisateur examine les méthodes possibles d’une API, les complétions de ligne complètes en ligne affichent l’invocation complète de la méthode contenant également tous les paramètres de l’invocation.

Complétions de lignes complètes intégrées par ML poursuivant la complétion de liste déroulante sémantique qui est mise au point.
Suggestions de complétions de plusieurs lignes par ML.

Conclusion et travaux futurs

Nous démontrons comment la combinaison de moteurs sémantiques basés sur des règles et de grands modèles de langage peut être utilisée pour améliorer considérablement la productivité des développeurs avec une meilleure complétion du code. Dans une prochaine étape, nous souhaitons utiliser davantage les SE, en fournissant des informations supplémentaires aux modèles ML au moment de l’inférence. Un exemple peut être que de longues prédictions vont et viennent entre le ML et le SE, où le SE vérifie de manière itérative l’exactitude et offre toutes les suites possibles au modèle ML. Lors de l’ajout de nouvelles fonctionnalités optimisées par ML, nous voulons être conscients d’aller au-delà des résultats « intelligents », mais garantir un impact positif sur la productivité.

Remerciements

Cette recherche est le fruit d’une collaboration de deux ans entre Google Core et Google Research, Brain Team. Remerciements particuliers à Marc Rasi, Yurun Shen, Vlad Pchelin, Charles Sutton, Varun Godbole, Jacob Austin, Danny Tarlow, Benjamin Lee, Satish Chandra, Ksenia Korovina, Stanislav Pyatykh, Cristopher Claeys, Petros Maniatis, Evgeny Gryaznov, Pavel Sychev, Chris Gorgolewski , Kristof Molnar, Alberto Elizondo, Ambar Murillo, Dominik Schulz, David Tattersall, Rishabh Singh, Manzil Zaheer, Ted Ying, Juanjo Carin, Alexander Froemmgen, Maxim Kachurovskiy et Marcus Revaj pour leurs contributions.