Eintauchen in die KI: Eine dreiteilige Serie
Hallo, ich bin Kevin Séjourné, Doktor der Informatik und Senior R&D Engineer bei Cloud Temple. Wie Sie sich vorstellen können, habe ich in den letzten 20 Jahren viel Code geschrieben. Als leidenschaftlicher Erforscher von LLMs stelle ich fest, dass sie nun Code an meiner Stelle schreiben können. Umso besser! Aber da ich mich gewöhnlich auf wissenschaftliche Beobachtungen stütze, habe ich beschlossen, die Qualität ihrer Arbeit zu testen.
Sehen Sie sich die drei Episoden meiner Studie an :
- Episode 1: Ich automatisiere meine Arbeit mit LLMs
- Episode 2: Lassen Sie uns mithilfe der LLM den Code korrigieren und vergessene Algorithmen rekonstruieren.
- Episode 3: Vervollständigen wir das ursprüngliche Programm, testen wir, testen wir härter
Episode 1: Ich automatisiere meine Arbeit mit LLMs
LLMs können nun Code für mich schreiben. Ich werde Ihnen zeigen, wie das geht. Beginnen wir mit einer einfachen und häufigen Aufgabe: eine Anwendung ganz oder teilweise umzuschreiben.
Oft muss Code neu geschrieben werden, um :
- Obsoleszenz adressieren
- Eine unpassend gewordene Architektur korrigieren
- Die Leistung steigern
- Ein Verhalten ändern
- Zu einer anderen Programmiersprache wechseln
Wo fangen wir an?
Wir wählen ein kleines Programm, nur 31 KB inklusive aller Daten, etwa 1000 Zeilen, in Python. Wir werden Veralterungen adressieren und einen Teil eines Programms löschen, das nicht mehr benötigt wird. Aufgrund veränderter Anforderungen hatte dieses Programm zwei mögliche Aufgaben zu erledigen statt einer. Nach und nach ersetzte die neue Aufgabe die alte vollständig, und es ist wünschenswert, sie zu entfernen, um die Angriffsfläche zu verringern. Wir überarbeiten die Architektur leicht und suchen ganz nebenbei nach einem Leistungsgewinn und Modernität bei den Abhängigkeiten. Die altehrwürdige Bibliothek "request" hat ausgedient.
Rust ist ein guter Kandidat für das Umschreiben eines Programms Python. Die starke Typisierung bei der Kompilierung ist der erste Vorteil für das Überschreiben mit LLM. Sie zwingt die LLM, Probleme bei der Generierung frühzeitig zu erkennen und zwingt sie so zu einer logischeren Generierung. Dadurch wird die Aufmerksamkeit der LLM auf eine zusätzliche Dimension gelenkt. Darüber hinaus ist Rust eine moderne Sprache, die angemessen mit Konkurrenz umgeht, wo Python wird durch seinen globalen Interpreter Lock (GIL) begrenzt.
Wir verfügen über einen No-Limit-Zugang zu GPT 4o über das von Cloud Temple entwickelte KI-Portal. Wenn wir uns bei einer Antwort nicht sicher sind, können wir mit groq.com mit Llama3 70b und Mixtral 8x7b. Ein lokales Llama3-8b_q4, das auf jan.ai und ein RTX ist für vertrauliche Teile verfügbar.
Die Fähigkeiten der verwendeten Vorlagen leiten die Größe des zu konvertierenden Programms. Mixtral verarbeitet Kontexte bis zu einer Größe von 32 KB, und auch wenn GPT/Gemmini sich mit größeren Kontexten befassen, sind sie dem "lost in the middle" ausgesetzt, d. h. sie können nicht unbedingt auf die Informationen achten, die in der Mitte ihres Kontextes vorhanden sind. Derzeit hindert ein größeres Programm den LLM daran, seine Aufmerksamkeit auf die Gesamtheit der Teile des Codes zu richten.
Wir verwenden VSCode, um den erzeugten Code zu kopieren und einzufügen. Dort agglutinieren wir alle Teile des Codes.
Wie geht es jetzt weiter?
Wie sage ich dem LLM, dass er meinen Code konvertieren soll? Wie gebe ich ihm den Code, den er umwandeln soll?
Einen Prompt zu bauen heißt, es einfach zu machen. Und einfach zu machen ist kompliziert. Hier ist der Prompt: Achten wir auf die Kommentare und Datentypen sowie auf Cargo.toml, wandeln wir das folgende Python-Programm in Rust um:
[Hier kommt die Verkettung des gesamten Anwendungscodes] Und ja, man muss sich schon trauen, 31 KB per Copy & Paste in die Texteingabebox einzufügen. Aber das ist das Einfachste, was es gibt.
Wir haben bereits frühere Experimente durchgeführt, bei denen der Code stückweise kopiert wurde. Aber es gibt ein paar knifflige Fragen:
- Wie groß sind die Stücke? Wie groß ist die Datei? Funktion ? Klasse ? Wie viele KB? Wie viele Zeilen?
- In welcher Reihenfolge sollen die Stücke integriert werden? In alphabetischer Reihenfolge? Topologische Sortierung ? Funktionale Sortierung ? Wie sieht es mit Querabhängigkeiten aus?
Einfacher: alles auf einen Schlag. Dazu sind wir alle Dateien des Programms durchgegangen und haben sie zu einer großen Datei verkettet. In dieser großen Datei werden sie durch einen Befehl der folgenden Form getrennt FILE main.py :
[gefolgt vom Dateibody].
Die Angabe der Originaldateien ist in Python unerlässlich, da der Dateiname in dieser Sprache zur Auflösung von Abhängigkeiten verwendet wird. Dies bildet auch nützliche Markierungen für später, um die Aufmerksamkeit des Modells auf einen bestimmten Teil zu lenken.
Die Prompt hat dann diesen Aspekt :
Und wann beginnt dann diese Codegenerierung?
Sehr gut, hier ist, was passiert, wenn wir [Eingabe] drücken:
Wir können feststellen, dass GPT4o nicht in der Lage ist, die vollständige Ausgabe zu erzeugen. Die maximale Länge der Ausgabe ist erreicht. Wir haben zwar einige Funktionen aus den ersten Dateien erhalten, aber es fehlt noch viel Code. Außerdem ist die Codegenerierung, die von GPT4o vorgenommen wird, oft wortreicher als der ursprüngliche Code, in einem Verhältnis von 3 zu 2. Dies hängt nicht spezifisch von der Paarung Python / Rust ab, sondern ist eher ein Artifakt der Codegenerierung durch LLM. Wie bei menschlichen Antworten scheinen LLMs Schwierigkeiten zu haben, kurze Antworten zu geben.
Es ist möglich, den LLM einfach zu bitten, weiterzumachen :
Das Problem ist, dass er sich schließlich in dem verliert, was er bereits bearbeitet hat und noch nicht bearbeitet hat... 31 KB Code + 31 KB * 1,5 erwartete Codegenerierung + Markdown-Dekoratoren, wir kommen im besten Fall bereits auf 64 KB Kontext. Leider endet die Aufforderung, ohne echten Anhaltspunkt weiterzumachen, damit, dass er bereits verarbeitete Dateien wieder umwandelt. Die 64 KB rutschen ab und überschreiten schließlich das 128 KB-Fenster von GPT4o, was zu einem Verlust des Kontexts führt.
Fangen wir noch einmal von vorne an. Diesmal geben wir jedoch im Prompt an, dass nur die erste Datei konvertiert werden soll. Wenn wir das Ergebnis erhalten haben, fragen wir nach der zweiten Datei und so weiter. Der LLM hält also das gesamte Programm im Kontext, um die Referenzen zu verarbeiten, konzentriert sich aber nur auf jeweils eine Umwandlung.
Nach und nach können wir unser gesamtes neues Programm per Kopieren und Einfügen in VSCode einfügen. Wenn die LLM wortreich ist, muss der Mensch kurz und bündig sein.
Durch nettes Nachfragen erhalte ich auch die Cargo.toml, das ist die Datei, die die Abhängigkeiten und die Kompilierung in Rust verwaltet. Es ist keine sehr komplizierte Datei, aber ihr Hauptmerkmal ist, dass sie im ursprünglichen Programm in Python überhaupt nicht existiert. Es handelt sich um eine kleine Ergänzung, die eine Zusammenfassung des vorherigen Programms erfordert, ähnlich wie die Zusammenfassungen, die oft von LLMs erstellt werden. Es ist wichtig, die Generierung der Datei Cargo.toml erst nach der Generierung der Rust-Code-Dateien anzufordern, da die LLM sonst möglicherweise Bibliotheken auslässt. Zu Beginn hat der LLM noch nicht darauf geachtet, was er alles brauchen wird.
O Wunder, das Copy-and-Paste-Programm scheint bereit zu sein, mit dem traditionellen LLM-Vertrauen zu arbeiten, das uns versichert, die Wahrheit zu haben. Das ist aber nicht ganz der Fall, denn unter anderem kompiliert das Programm nicht. Um das zu korrigieren, werden wir mit dem Lernen beginnen ... in einem späteren Artikel.
Bilanz des ersten Schritts
Wie Sie vielleicht bemerkt haben, haben wir mit der LLM mehr Zeit damit verbracht, zu planen, was wir tun werden, warum wir es tun werden, und weniger damit, tatsächlich Code zu generieren. Zu diesem Zeitpunkt betrug die Zeit, die wir für das Projekt aufgewendet haben, etwa 8 Stunden, von denen zwei auf die Generierung entfielen.