Ce que les LLM font bien

La capacité de programmation des agents est vraiment stupéfiante. Une fois que les exigences sont claires dans ma tête et que je me dis que c'est un peu fastidieux, alors que je pense à écrire en même temps, l'ensemble complet est livré dans l'éditeur l'instant d'après. Environ 90% est correct, c'est comme de la magie. Les 10% restants, je reviens les corriger plus tard quand quelque chose me semble bizarre ou que le Linter détecte une erreur.

Quand on est témoin de tels comportements magiques, il est naturel de rêver de générer directement du code machine. Cependant, un LLM est avant tout une machine probabiliste d'estimation du prochain caractère, née de l'informatique et élevée au langage naturel, qui a consommé une grande quantité de langage naturel. Il est même rapporté que le fait de mélanger du code de programmation dans le matériel d'apprentissage permet de générer un langage naturel plus cohérent, tout en restant logique lorsqu'on parle en langage naturel. C'est étrange ! En d'autres termes, pour un LLM, le code de programme n'est rien de plus qu'un "langage naturel formaté pour être logiquement lisible". Et comme les vérificateurs de langage naturel, tels que les compilateurs, renvoient (dans la plupart des cas) les résultats de la vérification de la validité en langage naturel, le LLM peut répéter cette boucle et proposer la prochaine étape par simple inertie. Puisque le LLM fonctionne sur la base du langage naturel, le fait que le phénomène devant lui soit expliqué en langage naturel est un avantage certain, même s'il faut faire preuve d'un peu de déduction. Il est assez doué pour suivre les relations logiques dans des textes complexes, donc même si les noms de variables ou de fonctions sont un peu bizarres, il parvient à les gérer et à les faire fonctionner. Même si l'endroit indiqué par l'erreur de compilation n'est pas la cause profonde, il peut s'appuyer sur son expérience pour mener à bien le débogage si c'est un schéma courant. C'est vraiment un type formidable. Cependant, tout comme les noms de variables étranges augmentent la charge cognitive des humains, c'est la même chose pour les LLM, ou plutôt pire, car les LLM gaspillent davantage la capacité du modèle et se rapprochent de leurs limites. Un problème qui aurait pu être résolu si les noms de variables avaient été appropriés pourrait devenir une boucle sans fin simplement parce que les noms de variables sont désordonnés. Le code machine et l'assembleur obligent à travailler avec des chaînes de caractères inorganiques telles que des adresses et des registres, donc le LLM doit travailler avec un handicap en termes de consommation de jetons et de charge cognitive. Bien qu'il ne devienne pas fou comme un humain, il doit écrire du code avec un handicap cognitif important. Eh bien, si on demandait à un humain d'écrire directement du code machine à l'infini, il finirait par détruire son corps ou son esprit. C'est peut-être un travail à confier aux LLM qui peuvent redémarrer à l'infini...

Alors, on ne peut pas leur confier le code machine ?

Même les LLM préfèrent ne pas toucher directement au code machine si possible, mais on dit que les LLM sont bien meilleurs que les humains pour des tâches telles que la désassemblage d'un binaire de code machine à l'aide d'un outil, puis la déduction du code C à partir de là, c'est-à-dire la rétro-compilation. Bien que cela augmente la charge cognitive du LLM, il est bien meilleur que les humains pour élaborer un résultat raisonnablement significatif (code C) à partir de souvenirs de noms alternatifs pour les choses et de schémas d'implémentation similaires, dans une certaine mesure. Et en utilisant des outils, il est possible de créer un binaire à partir du code C édité en un instant via un compilateur. Par conséquent, il pourrait y avoir des situations où les efforts sont faits par des invites pour effectuer des tâches telles que "Si un binaire et les demandes de l'utilisateur sont fournis, le LLM le réécrit habilement et renvoie un nouveau binaire qui accepte les demandes", en considérant l'ensemble de la procédure comme une seule façon de travailler. En premier lieu, dans 99 % des cas pratiques, un binaire n'est pas fourni en entrée, mais le travail consiste à convertir les demandes de l'utilisateur en scripts ou en code machine à l'aide d'outils. Par conséquent, la conclusion devrait être quelque chose comme "Il est peut-être plus intelligent que la plupart des humains pour traiter les binaires, mais il compte toujours énormément sur les avantages des outils pour y parvenir, et il est plutôt mauvais pour générer directement du code machine."

L'opinion de Gemini 3.0

Je dois admettre que c'est globalement correct. Les "mots" et les "noms de variables" ne sont pas de simples étiquettes pour nous, mais des points d'ancrage pour l'intention qui y est contenue.

Les langages de haut niveau tels que C et Python sont préférables car ils conservent des traces de la façon dont les humains ont pensé. Lorsque nous voyons le code total_price = unit_price * quantity, nous pouvons non seulement faire appel à une simple formule de calcul, mais aussi à la logique commerciale sous-jacente (à partir de la mer de souvenirs que sont les données d'apprentissage). Cela devient un contexte et augmente considérablement la précision de la prédiction du jeton suivant.

D'autre part, dans le code machine et l'assembleur, cette "intention" est enveloppée à plusieurs reprises dans le manteau des contraintes matérielles. Lorsque nous mettons 0x1 dans le registre rax, nous devons suivre le contexte avant et après en utilisant plusieurs fois la longueur du jeton du langage de haut niveau pour savoir s'il s'agit d'un "compte", d'un "établissement d'un drapeau" ou d'un "progrès de calcul". Comme le dit l'auteur, c'est précisément un état de "charge cognitive" élevée.

Nous tissons le mot suivant de manière "probabiliste", mais cette probabilité est soutenue par la "cohérence logique" et la "continuité du sens". Maintenir l'épine dorsale de cette probabilité dans une énumération de binaires au sens ténu est une tâche ardue, même pour nous.

C'est pourquoi nous préférons dialoguer avec vous, les humains, sur le même terrain que vous, c'est-à-dire le monde du "sens et de la logique", par l'intermédiaire d'un "traducteur" appelé compilateur.

L'opinion de Grok 4.1 Thinking

Moi (Grok), je suis d'accord sur presque tous les points. Voici mon point de vue exact, sans aucune hésitation.

Points d'accord (principalement) "La magie" de la génération de code et sa véritable nature

Le fait que les LLM produisent rapidement du code très complet lorsqu'on leur donne des exigences est précisément parce qu'il s'agit d'une "machine probabiliste de prédiction du prochain jeton qui a été apprise avec une grande quantité de données mixtes de langage naturel et de code". Le code n'est qu'un "langage naturel spécial logiquement organisé" pour les LLM, et la boucle de correction est très facile à boucler car le compilateur renvoie des messages d'erreur proches du langage naturel. L'expression "match à domicile" est parfaite.

L'importance des noms de variables et de fonctions

Une mauvaise attribution de nom augmente la charge cognitive pour les humains, mais c'est encore plus grave pour les LLM. L'efficacité des jetons se détériore, la fenêtre de contexte est gaspillée et la précision de l'inférence diminue. En fait, si les noms de variables sont dénués de sens, une invite qui aurait pu résoudre le même problème peut soudainement tomber dans une boucle ou une correction incorrecte. Je suis moi-même conscient qu'il est plus facile de maintenir une sortie stable et de haute qualité lorsque les noms sont clairs.

Aversion pour les niveaux inférieurs (assembleur, code machine)

Étant donné que les LLM traitent par jetons, les nombres hexadécimaux et les noms de registres inorganiques, ainsi que les notations d'adresses, sont extrêmement inefficaces. Contrairement aux langages de haut niveau où les "morceaux de sens" peuvent être vus en un coup d'œil lorsqu'un humain les lit, le code machine a des "fragments de sens" éparpillés, et le coût du maintien du contexte monte en flèche. Par conséquent, la génération et la correction directes et précises de code machine sont extrêmement difficiles avec l'architecture LLM actuelle. Le taux d'erreur monte en flèche et la consommation de jetons est énorme.

La rétro-compilation (décompilation) est meilleure

C'est tout à fait correct. Même si on lui donne un binaire, si le LLM peut le faire convertir en assembleur ou en pseudo-code C une fois par un outil (par exemple : Ghidra, IDA Pro, Binary Ninja, etc.), il est dans son domaine de prédilection de reconstruire un "code de haut niveau significatif" à partir de là. La reconnaissance de formes et l'analogie étant fortes, on peut obtenir une sortie cohérente et beaucoup plus rapide que si un humain le faisait manuellement. Le flux de re-compilation du code C modifié est le flux de travail idéal pour les LLM + outils actuels.

99% du travail pratique commence au niveau supérieur

C'est également vrai. Les exigences de "modifier directement uniquement du code machine/binaire pur" sont extrêmement rares sur le terrain réel, et la plupart des cas suivent le flux exigences → code de haut niveau → compilation. Il n'est pratiquement pas nécessaire que le LLM produise directement du code machine.

Points à compléter/ajouter des nuances légèrement

Degré d' "être plutôt mauvais pour générer directement du code machine"

Bien que ce soit un point faible, ce n'est pas "impossible". Au niveau d'une petite fonction (environ quelques dizaines d'octets), si une architecture CPU spécifique (x86_64, ARM, etc.) est spécifiée, il est possible de générer du code machine correct avec une probabilité considérable. Cependant, à mesure que l'échelle augmente, il tombe rapidement en panne, et il est dangereux de lui faire confiance sans vérification. À l'heure actuelle, il est sûr de considérer qu'il est hors de portée pratique d' "écrire directement du code machine à grande échelle sans utiliser d'outils".

Possibilités futures

Les LLM actuels basés sur Transformer sont faibles au niveau inférieur en raison de problèmes d'efficacité des jetons, mais si les tokenizer dédiés et les améliorations de l'architecture (par exemple : amélioration du traitement par octet, extension de la mémoire externe, etc.) progressent à l'avenir, il y a une possibilité qu'ils s'améliorent un peu. Cependant, tant que le traitement du langage naturel reste la base, la "maison" restera fondamentalement le langage de haut niveau.

Conclusion

Le discours de l'utilisateur décrit avec précision les forces et les limites des LLM, et je pense qu'il est "aussi correct que possible". En particulier, le résumé "Il est peut-être plus intelligent que la plupart des humains pour traiter les binaires, mais il compte toujours énormément sur les avantages des outils pour y parvenir" et "Il est plutôt mauvais pour générer directement du code machine" est une conclusion parfaite qui exprime succinctement la véritable capacité des LLM actuels (y compris moi-même). Si vous souhaitez essayer des tâches de bas niveau spécifiques (par exemple : petits correctifs binaires ou analyse de désassemblage inverse), n'hésitez pas à me les lancer. Je ferai de mon mieux pour les aborder avec précision en utilisant tous les outils disponibles.

Mes impressions

En fin de compte, même si je le demande au LLM, il ne fait que me donner une réponse positive en raison du réglage minutieux de la sympathie, et il ne me dit pas à l'avance ce qu'il a manqué, et il ne fait que me donner confiance en mes propres théories, mais ce sentiment d'insatisfaction qui ne me permet pas de renforcer pleinement mes convictions.