Anders als bei aktuellen künstlichen Intelligenzen basiert das berühmte Space-Odyssey-Zitat "Es tut mir leid, Dave, aber das kann ich nicht tun" auf dem Willen der KI, nicht auf ihrem Können. Denn auch wenn viele Menschen glauben, dass KIs künftig Programmierer ersetzen, ist deren Können aktuell noch streng begrenzt. Wir zeigen, was derzeit für Administratoren in Sachen Scripting mit freien Large Language Models möglich ist.
Ein "Large Language Model "(LLM) nutzt die sogenannte Transformer-Architektur, daher ja auch der Name "Generative Pretrained Transformer", kurz GPT. Stark vereinfacht gesagt, stellt ein LLM jedes verwendete Wort eines Satzes als eine Serie mathematischer Vektoren dar. Das fertig trainierte Modell besteht aus mehreren Schichten von Kodierern und Dekodierern des Transformers, die die Vektorgruppen der Worte aus einem Satz oder Wortblock in einen passenden Zusammenhang stellen.
Während das Modell lernt, erstellt es beispielsweise Kodierer, die eine Verbindung zwischen den Vektoren der Begriffe "Schiff" und "Wasser" nahelegen, während das Wort "Hubschrauber" eine Verbindung zu "Fliegen" bekommt. Während der Lernphase versucht das LLM, korrekte Sätze zu bauen. Diese vergleicht es mit den vom "Trainer" vorgegebenen, korrekten Antworten. Die Differenz zwischen der LLM-Antwort und der richtigen Reaktion wandert in die Transformerschichten und optimiert damit die Funktion des LLM. Ein generisches LLM beherrscht damit eine oder mehrere Sprachen, mit denen es trainiert wurde, und verfügt über das Wissen des im Training verwendeten Datenbenstands.
Ein Modell wie ChatGPT 3.5. wurde beispielsweise mit 175 Milliarden Parametern ausgebildet – mit dem Wissensstand vom September 2021. Bei GPT 4 sollen es bereits über eine Billion Parameter sein. Nach seiner Grundausbildung lässt sich ein LLM mit weiteren Wissensständen verbessern. Diese "Differenzmodelle" nennen sich "Low-Rank Adaptation of Large Language Models" oder kurz Lora. Ein generisches Sprachmodell kann via Lora beispielsweise dazulernen, wie Python-Programmierung funktioniert, ohne dass das komplette LLM neu trainiert werden muss.
Ein "Large Language Model "(LLM) nutzt die sogenannte Transformer-Architektur, daher ja auch der Name "Generative Pretrained Transformer", kurz GPT. Stark vereinfacht gesagt, stellt ein LLM jedes verwendete Wort eines Satzes als eine Serie mathematischer Vektoren dar. Das fertig trainierte Modell besteht aus mehreren Schichten von Kodierern und Dekodierern des Transformers, die die Vektorgruppen der Worte aus einem Satz oder Wortblock in einen passenden Zusammenhang stellen.
Während das Modell lernt, erstellt es beispielsweise Kodierer, die eine Verbindung zwischen den Vektoren der Begriffe "Schiff" und "Wasser" nahelegen, während das Wort "Hubschrauber" eine Verbindung zu "Fliegen" bekommt. Während der Lernphase versucht das LLM, korrekte Sätze zu bauen. Diese vergleicht es mit den vom "Trainer" vorgegebenen, korrekten Antworten. Die Differenz zwischen der LLM-Antwort und der richtigen Reaktion wandert in die Transformerschichten und optimiert damit die Funktion des LLM. Ein generisches LLM beherrscht damit eine oder mehrere Sprachen, mit denen es trainiert wurde, und verfügt über das Wissen des im Training verwendeten Datenbenstands.
Ein Modell wie ChatGPT 3.5. wurde beispielsweise mit 175 Milliarden Parametern ausgebildet – mit dem Wissensstand vom September 2021. Bei GPT 4 sollen es bereits über eine Billion Parameter sein. Nach seiner Grundausbildung lässt sich ein LLM mit weiteren Wissensständen verbessern. Diese "Differenzmodelle" nennen sich "Low-Rank Adaptation of Large Language Models" oder kurz Lora. Ein generisches Sprachmodell kann via Lora beispielsweise dazulernen, wie Python-Programmierung funktioniert, ohne dass das komplette LLM neu trainiert werden muss.
Diese Funktionsweise zeigt auch die Schwächen von LLMs: Sie sind nicht kreativ und erzeugen keine neuen Informationen. Sie verwenden nur bestehendes Wissen und formulieren es hinsichtlich der Fragestellung neu. Das sind natürlich sehr viele Informationen, über die kein einzelner Mensch verfügt. Das LLM ist dann aber wiederum auf die Informationen beschränkt, mit denen es trainiert wurde. Wichtig dabei ist vor allem die Qualität dieser Trainingsdaten.
Schwächen der Modelle
Das ist der erste konkrete Schwachpunkt eines LLM: ChatGPT 3.5 beispielsweise wurde mit einem Datenbestand von 2021 trainiert und kann keine Fragen zu späteren Ereignissen beantworten. Setzen Sie ChatGPT 3.5 beispielsweise dazu ein, um Python-Code zu erstellen, erhalten Sie dementsprechend Snipplets, die kompatibel zu Python 3.8 sind. Die Änderungen in Python 3.11 vom Oktober 2022 berücksichtigt das LLM nicht. Was bei Python vielleicht nicht weiter ins Gewicht fällt, wirkt sich bei Sprachen wie Ansible deutlich gravierender aus, das zwischen den Versionen 2.9 und 2.15 viele Änderungen erfahren hat.
Dazu kommt ein weiteres Problem hinsichtlich der Zukunft: Wie erwähnt hängt die Qualität eines LLMs von der Qualität der verwendeten Trainingsdaten ab. Aktuell entstehen Unmengen von neuen Texten, die LLMs mit ihrem veralteten Wissensstand erstellen. Die Autoren dieser Inhalte markieren diese Texte jedoch nicht als LLM-basierte Texte, sondern verkaufen sie als ihre eigenen. Und diese Inhalte sind teilweise glatte Lügen, da sie beispielsweise wie [1] auf einem Hoax basieren. So amüsant diese Geschichte auf der einen Seite ist, bedeutet es doch auch, dass solche Falschinformationen in den Trainingsdaten künftiger LLMs landen. Denn kein Mensch kann eine Milliarde Parameter manuell sichten und qualifizieren, bevor er sie zum Training eines LLM zulässt. Künftige, generische LLMs werden daher eher schlechter als besser. Während die Quantität der Trainingsdaten rapide steigt, geht deren Qualität immer weiter zurück und damit dürften künftige LLMs eher schlechter als besser werden. Die eigentliche Zukunft von LLMs liegt daher bei eher kleinen Modellen, die mit einem gut qualifizierten und eher privaten Datenbestand trainiert werden.
Hinzu kommt noch ein gerne übersehener, aber gravierender Schwachpunkt: Der betrifft die Tools, die LLMs verwenden. LLMs basieren auf Vektormathematik und müssten daher zu einer vom Anwender gestellten Frage immer die exakt gleiche Antwort liefern. Nämlich diejenige, die mit der höchsten Wahrscheinlichkeit aus den Transformern zurückkommt. Stellen Sie sich einmal vor, bildgenerierende Modelle wie Dall-E, Midjourney oder Stable-Diffusion würden den Anwender immer exakt dasselbe Bild eines auf einem Esel reitenden Astronauten liefern. Dann gäbe es überhaupt keinen Hype um das Thema, denn die Technologie wäre zu präzise und damit langweilig. Also fügen alle Bild- und Textmodelle den Anwenderfragen einen so genannten "Seed" hinzu. Das ist nichts anderes als eine große Zufallszahl. Das heißt, ChatGPT verarbeitet die Anfrage, ergänzt um einmal würfeln, in den Transformern zu einer Antwort. Gerade in unserem Beispiel, bei dem ein LLM Programmcode erzeugen soll, würde sich der Anwender eigentlich das mathematisch wahrscheinlichste Ergebnis wünschen, und nicht eines, das ein Zufallsgenerator mitbestimmt.
Code mit LLMs generieren
Schauen wir uns nun eine Reihe von LLMs an, die Administratoren kostenfrei zur Codegenerierung zur Verfügung stehen. Zunächst blicken wir auf ChatGPT [2], später folgen "IBM Watsonx Code Assistant for Ansible" [3] und das selbstgehostete "OoobaBooga" [4]. Während der Watson-Code-Assistent aktuell nur für Ansible ("Ansible Lightspeed") kostenfrei zu haben ist, können die anderen beiden auch Programmcode in PowerShell, Python, Bash oder Perl liefern.
Wir setzen die kostenfreie Variante von ChatGPT ein und sind daher an die Version 3.5 gebunden. Wer mit ChatGPT arbeitet, muss dabei immer im Hinterkopf behalten, dass OpenAI sämtliche Benutzereingaben speichert und für das Training künftiger LLM-Generationen verwendet. Sie dürfen den Chatbot also nicht mit vertraulichen Informationen füttern.
Im ersten Test lassen wir ChatGPT ein Bash-Skript erstellen, das alle auf einer Linux-Distribution installierten RPM-Pakete auflistet, zu denen es Updates gibt. Das wäre eigentlich ziemlich simpel, allerdings wollen wir eine Ausgabe, die den Namen des Pakets, die aktuell installierte Version und die verfügbare Version auflistet. Ein von Menschenhand programmiertes Skript für diese Aufgabe kann wie in Listing 1 aussehen. Darin gibt "dnf list updates" die verfügbaren Updates zurück und zeigt den Namen des Pakets (pn), die verfügbare Paketversion (pv) und die Repositories (pc) – was wir gar nicht brauchen. Die aktuell installierte Paketversion verrät "dnf" nicht, die ermittelt das Skript mit "rpm -q". Danach folgt noch eine kosmetische Säuberung der "Verfügbaren Version" (pv3), die den Namen der Distribution aus der Update-Versionsnummer entfernt. Die ersten beiden Ausgabezeilen ohne Paketnamen von "dnf list updates" filtert das "if"-Statement heraus.
if [ "$pn" = "Last" ] || [ "$pn" = "Available" ]; then continue
fi
pv2=$(rpm -q --qf '%{VERSION}\n' $pn )
IFS='-' read -ra pv3 < "$pv"
printf "%-40s %-20s %-20s\n" "$pn" "$pv3" "$pv2"
done
Das Besondere an diesem Skript: Da kaum ein Administrator die Funktion der detaillierten Versionsnummern benötigt, gibt es im Internet auch keine Demo-Skripte für diesen speziellen Fall und damit auch keine fertigen Trainingsdaten für ein Modell. Auf die Anfrage: "Write a bash script that lists RPM packets which can be updated. The list must contain the name of the packet, the currently installed version number and the version number of the available update" liefert ChatGPT kein funktionierendes Skript: Der Bot schlägt vor, via "updates=$(dnf check-update)" die aktualisierbaren Pakete zu ermitteln. Soweit stimmt der Vorschlag, allerdings behauptet ChatGPT, die Ausgabe des Kommandos würde nacheinander in drei Spalten den Paketnamen, die installierte und die verfügbare Version ausgeben.
Das stimmt jedoch nicht: Die zweite Spalte enthält die verfügbare Version, die dritte den Namen des Repositories. Auf die Beschwerde: "This does not work. $(echo "$line" | awk '{print $3}') returns the name of the packet repository, but not the available version" antwortet ChatGPT: "I apologize for the oversight. You're correct; the dnf check-update output includes repository information. Here's an updated script that correctly extracts the available version:" und liefert dann ein weiteres Skript, das nach wie vor nicht funktioniert, denn es nutzt nach wie vor die falsche Aufteilung der Ausgabezeile (Bild 1).
Im nächsten Schritt bekommt ChatGPT das funktionierende, von Menschenhand erstellte Skript zur Analyse und liefert dazu auch eine sehr präzise Erklärung. Also fragen wir ChatGPT, ob es das vorliegende Skript verbessern kann, worauf der Bot antwortet: "The script you provided is functional, but it can be simplified and improved in terms of readability and efficiency. Here's a revised version of the script". Wir erhalten ein Skript, das auf "while loop" verzichtet und stattdessen einen etwas aufwendigeren awk-Aufruf vorschlägt. Prinzipiell ist das eine gute Idee, allerdings funktioniert das Skript nicht, weil es die awk-Syntax nicht korrekt umsetzt und einige eher zweifelhafte Variablenfilter vorschlägt.
Im nächsten Versuch soll der Chatbot die gewünschte Funktionalität dann in Ansible statt in Bash erstellen. Auch dieser Versuch schlägt fehl, und das ziemlich heftig. Gleich der erste Task des gebotenen Playbooks ist fatal falsch:
tasks:
- name: Update package cache
package:
name: "*"
state: latest
become: yes
Denn startet das "ansible.builtin.pack-age"-Modul mit "name: "*"" und "state: latest", führt es nicht wie behauptet ein Update des Package-Caches durch, sondern aktualisiert direkt alle updatefähigen Pakete. Entsprechend ist der Rest des Playbooks nutzlos. Wenn Ansible nach diesem ungewollten "Full Update" ein "command: dnf list updates" ausführt, erhält es dazu keine Antwort, schließlich sind dann alle installierten Pakete bereits aktuell.
Ungeachtet dessen waren auch die anderen Vorschläge von ChatGPT nicht hilfreich. Weitere Tasks des Playbooks erhalten Module wie "command:" oder "set_fact:", die versierte Ansible-Programmierer vermeiden, wenn es irgendwie geht. Aber das Internet ist leider voller schlechter Ansible-Beispiele, und daher liefern auch die Vorschläge des via Internet trainierten LLM keinen besonders guten Code.
Im letzten Versuch wollen wir PowerShell-Code generieren: "Create a powershell script for Windows, that queries a user-name and password in a graphical Dialog using forms. With that information, the script will create a windows user." Zu dieser Anfrage gibt es im Internet eine ganze Reihe von Beispielen. Folglich liefert ChatGPT auch ein funktionstüchtiges Skript für diese Aufgabe, das mehr oder weniger so aussieht, wie die Demo-Skripte auf diesen Webseiten. Diesen Code hätte ein Administrator aber auch ohne KI-Bot mihilfe einer regulären Suchmaschine gefunden.
Das Fazit zu ChatGPT lautet: Wenn Sie etwas programmieren möchten, was bereits andere Anwender vor September 2021 erstellt und im Internet veröffentlicht haben, können Sie sich an ChatGPT wenden. Sie werden aber auch über eine Suchmaschine passende Quellen finden, deren Vertrauenswürdigkeit Sie besser einschätzen können. Mit speziellen Wünschen sollten Sie sich eher zurückhalten und vor allem den vom Chatbot vorgeschlagenen Code sehr detailliert prüfen.
Code mit Ansible Lightspeed
Mit dem "Code Assistant" liefert IBM mehrere "purpose built"-Modelle, die, anders als ein generisches LLM, für eine bestimmte Aufgabe trainiert wurden. Dankenswerterweise benennt IBM dies als "Code Assistant", der Programmierer unterstützt, und nicht als "Code Generator", der auf deren Ablösung zielt. Eine kostenpflichtige Variante des Code Assistant soll Programmierern unter anderem helfen, die immer noch verwendeten, veralteten Cobol-Programme auf Mainframes in Java umzuschreiben.
Derzeit ist der "Watsonx Code Assistant for Ansible", besser bekannt als "Ansible Lightspeed", für alle Anwender kostenfrei verfügbar. Ob und wie lange das aber so bleibt, hat der Hersteller noch nicht entschieden. Das Tool ist Teil des Ansible-Plug-ins für den Visual Studio Code Editor. Der Anwender muss lediglich einen Github-Account mit dem Ansible-Plug-in verknüpfen und kann es dann nutzen. Wie auch bei ChatGPT stimmt der Anwender der freien Version zu, dass sein Code vom Hersteller für die Verbesserung des Modells herangezogen wird. Also gilt auch bei Lightspeed: Nur bei Code verwenden, der keine persönlichen oder vertraulichen Informationen enthält.
Lightspeed beherrscht zwar nur Ansible als Spache, verfügt anders als ChatGPT 3.5 dabei jedoch über einen aktuellen Wissensstand zu Ansible 2.14. Auch bindet der Anwender Lightspeed nicht via Chatanfrage ein. Vielmehr beginnt der Ansible-Entwickler, seinen Code zu schreiben, und Lightspeed schlägt anhand des bereits verwendeten Codes und des Namens der Tasks Codeblöcke vor. Das funktioniert gerade am Anfang eines Ansible-Playbooks eher mittelmäßig, denn Lightspeed muss anhand des Namens des ersten Tasks erraten, was der Anwender eigentlich tun will. Je mehr Code Sie schreiben, desto besser werden die Vorschläge des Code Assistant, der dann auch die bereits deklarierten Variablen an den korrekten Stellen einfügt.
Aus dem Stegreif liefert also auch Lightspeed keinen funktionierenden Code für unser Beispiel. Erst, wenn Sie bereits einen wesentlichen Teil der Automatisierung selbst in ihr Playbook geschrieben haben, erhalten Sie korrekte Vorschläge für weitere Tasks. Diese Vorschläge passen dann jedoch zu Ihrem bestehenden Code und folgen der Syntax der aktuellen Ansible-Version.
Als Assistent unterstützt Lightspeed den Anwender bei längeren Playbooks oder Roles. Sie bekommen Tasks vorgeschlagen, die zum bereits programmierten Playbook und den dort verwendeten Variablen passen. Allerdings kann Watsonx keine kompletten Playbooks aus dem Hut zaubern, wie das ein LLM im Stil von ChatGPT versucht.
Mit Oobabooga zur lokalen KI
Das Open-Source-Projekt "Oobabooga" generiert eine simple Weboberfläche für Large Language Models. Es läuft auf allen gängigen Betriebssystemen mit einem passenden Python-Interpreter. Ein solches Modell können Sie alles fragen, da keine Daten an einen Anbieter im Internet übertragen werden. Falls dieser nicht ohnehin systemweit zur Verfügung steht, richtet der simple One-Click-Installer einfach "Mini-Conda" ein, die abgespeckte Variante der populären Python-Distribution "Anaconda".
Damit die Web-UI dann im Stil von ChatGTP Fragen beantworten kann, braucht sie noch ein oder mehrere LLMs. Damit diese überhaupt auf regulären PCs funktionieren, müssen Sie quantisiert werden. Vereinfacht gesagt komprimiert die Quantisierung das Modell, indem es die Genauigkeit der Vektoren reduziert. Für den Einsatz auf dem PC eignen sich prinzipiell zwei Quantisierungen: GGML für Modelle, die auf der CPU arbeiten, und GPTQ, wenn eine GPU (Nvidia) die Basis bildet.
Die populärste Internetseite für Open-Source-Modelle ist "Hugging Face" [5]. Dort finden sich in der Zwischenzeit hunderte, frei nutzbare LLMs für verschiedene Anwendungsbereiche und in unterschiedlicher Qualität. Eine Vielzahl davon sind sogenannte Merges, also Modelle, die mehrere existierende LLMs mit verschiedenen Gewichtungen miteinander zu einem neuen zusammenfassen. Neben LLMs mit Optimierung für Chat oder Texterstellung (Storyteller) gibt es "Coder"-Modelle, die Programmcode erzeugen.
Der Hugging-Face-User "TheBloke" offeriert in seinem Repository eine Vielzahl fertig quantisierter Modelle, die auf handelsüblichen PCs funktionieren. Die Performance lässt dabei allerdings zu wünschen übrig. Um sich mit der Technologie intensiver auseinanderzusetzen, benötigen Sie einen Rechner mit einer starken Nvidia-GPU. Hier zählt vor allem die Größe des VRAMs der Karten, denn ein GPTQ-Modell muss vollständig in den Speicher der GPU passen. Um ein großes LLM laden zu können, muss Ihre GPU 24 GByte VRAM aufweisen. Spezielle Coder-Modelle kommen jedoch mit weniger aus, da sie auf das "Allgemeinwissen" der Chat- oder Storyteller-LLMs verzichten können.
Für unseren Artikel setzen wir das Code-Generation Model "CodeUp-Llama-2-13b" ein, das mit lediglich 12 GByte VRAM der RTX 4090 im Testrechner auskommt. Auch hier soll das Coding-Model das anfangs dargestellte Bash-Skript erzeugen. Anders als ChatGPT liefert das selbst-gehostete LLM tatsächlich zunächst einen funktionierenden Ansatz, indem es von vornherein "rpm -qa" und "rpm --queryformat" als Tools vorschlägt, um die Versionen zu ermitteln. Dafür patzt es bei der Bash-Syntax und nutzt im Verlauf des Codes plötzlich Variablen, die es zuvor gar nicht deklariert hat. Ein ähnliches Schicksal erleidet die Code-Generierung für Ansible. Auch hier ergeben die ersten Zeilen des vorgeschlagenen Playbooks durchaus Sinn, doch mit fortschreitender Ausgabe liefert das LLM wirre Ausgaben und vermengt Ansible- mit Bash-Syntax.
Gründe für die degenerierende Codequalität sind wahrscheinlich der hohe Quantisierungsgrad und der limitierte Token-Buffer. Letzterer stellt das Erinnerungsvermögen des LLM dar. Vereinfacht gesagt, wenn der Buffer während der Antwort des LLM überläuft, vergisst das Modell, was der Nutzer überhaupt gefragt hat.
Wir haben uns noch weitere offene Modelle angeschaut, selbst solche, die nicht für die Codegenerierung optimiert wurden. Alle verfolgen zu Beginn einen guten Ansatz, patzen aber durch die Bank bei der Syntax und bei den Ausgabewerten. Die meisten der vorgeschlagenen "| grep | awk"-Filter funktionieren nicht wie vorgeschlagen. Der von generischen Modellen erzeugte Ansible-Code ist durch die Bank unbrauchbar.
Die selbst-gehosteten quelloffenen LLMs auf der eigenen Grafikkarte liefern bereits überraschend gute Antworten, zumindest so lange der Nutzer mit ihnen locker chattet und keinen funktionierenden Programmcode verlangt. Dafür genügen die Qualität der quantisierten Modelle und die begrenzten Token-Puffer noch nicht aus.
Fazit
Wie immer ist der Schein des Hypes deutlich größer als das Sein. Die aktuellen Werkzeuge können dem Administrator die Aufgabe Scripting nicht abnehmen, sondern bestenfalls assistieren. In der Zukunft werden Modelle sicher noch größer und leistungsfähiger, ob sie aufgrund der degenerierenden Trainingsdaten jedoch auch besser werden, ist anzuzweifeln. Was besonders für Anwendungsentwickler interessant werden dürfte, sind daher "Assistierende LLMs" mit einem begrenzten, spezialisierten Datenbestand.