KI und Ich

Ein Blog über KI, Auswirkungen und Experimente von Karlheinz Agsteiner

Tokens verbrennen

Es wird immer schwieriger, die Grenzen der neusten LLMs zu ermitteln. Darum hier mein neuster Test: was ist die beste "One Prompt Chess Engine", die ich hinbekomme. Vielleicht kann ich ja andere zu einem Contest anstiften, könnte lustig sein. Und natürlich schließt sich die Frage an: was ist die beste Engine, die ich pur mit Vibe-Coding entwickeln kann? Und was lerne ich dabei?

Aller Anfang ist schwer

Ich geb's zu, ich bin zu faul, mir GCC oder ein JDK zu installieren, um eine wirklch schnelle Engine zu bekommen. Es soll ja nur ein Experiment sein. Unschlüssig ob Javascript oder Python die bessere Alternative ist, habe ich die schlechte Idee, die Wahl der AI zu lassen. Ich bitte sie also im Prompt, sich die Aufgabe, eine Schach-Engine zu schreiben, gründlich anzusehen, dann zu entscheiden, welche der beiden Sprachen geeigneter ist, und dann loszulegen.

Und ich schreibe den Satz "I will publish the results. Be your best".

War es der Stress der Publikation? Die Überforderung der Sprachwahl? Man weiß es nicht, jedenfalls ist Cursor + Opus 4.6 überfordert, verbrennt eine Stunde lang Tokens im Wert von $8, bis ich abbreche. Ausser teils inkohärentem Denkprozess kein Ergebnis.

Screenshot: Cursor + Opus überfordert

Aller einfacher Anfang ist einfach

Diesmal lege ich mit der Kombination von VS Code, Github Copilot und Cline los, darunter läuft Claude Opus 4.5. Ich fange an mit einem einfachen Prompt für eine einfache Engine. Und ich lege Python als Sprache vorab fest.

Screenshot: einfacher Prompt für eine Schach-Engine

Und nach gar nicht langer Zeit habe ich eine einfache Engine, die Alpha-Beta mit iterativer Vertiefung beherrscht und ganz ordentlich Schach spielt. Ja, in 5-10 Sekunden Bedenkzeit denkt sie nur 4 Halbzüge voraus, aber immerhin. Bin zufrieden mit dem Ergebnis.

Parallel baut mir die Engine ein einfaches Schach-UI, um als Mensch gegen Engines zu spielen oder Engine-Matches zu machen. Nachdem meine Engine mit "python engine.py" gestartet werden muss, kann ich keine echten Schach-UIs dafür verwenden. Einige Iterationen später (ein ASCII-Board ist wirklich unlesbar) habe ich das:

Screenshot: Schach-UI mit Brettdarstellung

Wie weit kann man gehen?

Der nächste Prompt ist mein erster Versuch, eine gut spielende Engine schreiben zu lassen:

Screenshot: großer Prompt für eine stärkere Engine

Das Ergebnis kann sich sehen lassen. Kommt in normalen Stellungen auf 10.000 analysierten Positionen pro Sekunde, erreicht normalerweise 8-ply + 15 Selektiv, und spielt insgesamt ganz anständiges Schach. Allerdings hat sie keine Ahnung von Eröffnungen und zieht gerne dumm die Springer übers Brett, statt Figuren zu entwickeln oder ums Zentrum zu kämpfen. Ähnlich hat sie keine Ahnung von Endspielen - und wenn ein Bauer auf der 3. Reihe ist, mindestens 10 Halbzüge von einer Umwandlung entfernt, dann kommt die Engine nicht auf die Idee, diesen Bauern zu ziehen.

Verbesserung durch weitere Prompts

Also der Engine sagen, sie möge in der Eröffnung Analysen für Zentrumskontrolle, Figurenbeweglichkeit, Entwicklung hinzufügen, im Endspiel Königszentralisierung und vorgerückte Bauern.

Ich komme mir vor wie Arthur Dent in "Per Anhalter durch die Galaxis", der der Getränke-AI, die erst etwas "almost, but not quite, entirely unlike tea" produzierte, die Berge Indiens erklärte, die Milch der Kühe. Worauf dann die Maschine mit gewaltigem Rechenaufwand Tee produzierte.

Denn nach meinen Erklärungen und den Verbesserungen der AI spielt die Engine Schach. Ich habe die ELO-Werte nicht gemessen, aber würde sie so auf 1800 ELO schätzen. Keine dummen Fehler, manchmal strategisch ungeschickt, manchmal sehr druckvoll.

Und dann kam das, was mich umgehauen hat. Warum ich auch diesen länglichen Text für dich, lieber Leser, schreibe.

Performance-Tuning

Ich wollte wissen: kann ein LLM etwas nicht-triviales wie eine Schach-Engine selbständig Performance-Optimieren?

Also geprompted:

Screenshot: Prompt zum Performance-Tuning

Worauf die AI nach ein paar Minuten grübeln antwortete:

Screenshot: Plan für Performance-Optimierungen

Das sind ziemlich beeindruckende Erkenntnisse. Punkt 1 würde ich mir nicht zutrauen, hat auch das Potential, für wenig Performance den Code komplizierter zu machen, doch die anderen Punkte sind äusserst valide Einsichten in die Funktionsweise der Engine.

Das LLM werkelte daraufhin etwa 15 Minuten herum und erklärte die Performanceprobleme für gelöst.

Laufen lassen. Nach einer Zeile Info-Ausgabe hing die Engine. Also dem LLM davon erzählt, meine Theorie, dass das Problem vermutlich am Wechsel auf eine neue Iteration liegt (die sich als komplett falsch heraus stellte), vermittelt. Das LLM legt los, schreibt eine Reihe von Test-Skripten um den Fehler einzugrenzen. Meine Aufgabe: Testscripte überfliegen, OK klicken.

Das Erstaunliche: mit diesem Ansatz, kein Debugging, nur Skripte schreiben, Verhalten beobachten, Code ansehen, kam das LLM nach 10 Minuten darauf, dass der Fehler im Rücknehmen von En-Passant Zügen liegt. Fixte den Fehler. Ich (ungläubig) starte die Engine und alles funktioniert. Und in einer Partie gegen die Vorgängerversion:

Screenshot: Vergleich vorher – 5000 Positionen pro Sekunde

Vorher: Die Engine analysiert etwa 5000 Positionen pro Sekunde. Nicht schlecht.

Screenshot: Vergleich nachher – 20000 Positionen pro Sekunde

Nachher: Die Engine analysiert etwa 20000 Positionen pro Sekunde. Insgesamt liegt die Verbesserung irgendwo zwischen Faktor 2 und 4, abhängig von der Position.

Schockzustand

Ich hatte da eine bequeme Weltsicht: AIs können gut neuen Code erzeugen, aber ein Refactoring, gerade von etwas Nichttrivialem, das ist etwas für Menschen, das kann die AI noch nicht. Entsprechend beeindruckt bin ich, dass ein zwar von der Anzahl von Codezeilen her eher kleines Stück Software (etwa 3000 Zeilen), dafür aber eines von algorithmisch hoher Komplexität von der AI sauber auf Schwächen analysiert wurde, und durch große Umbauten selbständig signifikant verbessert.

Da kann's einem schon ein wenig Angst um die Zukunft der eigenen Profession werden.

Doch das war nicht die erstaunlichste Erkenntnis des Tages.

Der Umzug

Das Arbeiten an einer Schach-Engine kann etwas Süchtigmachendes haben - man verbessert iterativ die Stellungsbewertung, versucht aggressivere Varianten, lässt die ältere gegen die neuere spielen usw. Irgendwann habe ich meine selbstgeschriebene Testumgebung verlassen und (dank eines kleinen Skripts) in HIARCS Chess Explorer als Engine eingezogen, gegen - ELO-beschränkte - echte Engines angetreten. Mit der Zeit lernte ich, dass die AI-geschriebene Engine so um die 1600 ELO hat. Gar nicht schlecht. Mein Niveau, an einem guten Tag.

Nun ist Python interpretiert, und nicht rasend schnell, nicht ideal für Number Crunching einer Schach-Engine. Also musste die nächste Aufgabe für diesmal Cursor + ChatGPT 5.3 codex ran:

Screenshot: Prompt für C-Portierung der Engine

Hat das geklappt? Auf Anhieb eher mäßig - die erste Engine hat die Hälfte der Funktionalität weggelassen - weniger komplexe Suche, weniger komplexe Analyse, Fehler in der UCI-Umsetzung. Aber nach etwa 5 weiteren Prompts hatte ich eine Umsetzung der Engine in nativem C.

Und wow ist Python schneckenlahm.

Screenshot: Performancevergleich Python vs. C

Ich hatte einen Faktor von irgendwo zwischen 10 und 20 erwartet. Aber 200? Wo die Python-Engine 6 Halbzüge vorausdenkt, schafft sie in C 14, und statt 5.000 Stellungen pro Sekunde eine Million.

ELO-mäßig dürfte sich die Engine bei ca. 2200-2400 bewegen. Das ist weit davon entfernt, was gute Engines schaffen, aber für eine mit ca. 4h Arbeit selbst zusammengevibte Engine ganz ordentlich. Und ich kann eine weitere Engine unter "zu stark für mich" verbuchen.

Die Moral von der Geschicht

Zum Einen: Eine Schach-Engine ist nicht der Test, mit dem man heutige LLMs an ihre Grenzen bringen kann. Klar, 3000 Zeilen passen heute 30-mal in den Kontext eines LLMs. Was für einen Mensch mit 40 Seiten Quelltext schon viel ist, und was damals den 16K Kontext von ChatGPT 3.5 überfüllt hätte, ist bei einer Million Tokens schlicht klein.

Zum Anderen: Moderne Agenten-Umgebungen mit modernen LLMs drunter haben bei solchen Projekten auch keine Probleme mit großem Refactoring, mit Konvertigerung in eine sehr andere Programmiersprache.

Und zum Dritten: ich habe lang darüber nachgedacht, was es bedeutet, wenn ein LLM einen recht komplizierten Suchalgorithmus einfach hinschreibt. Ist sie so clever? Hat sie einfach 100 Schachprogramme auf Github gesehen und kopiert runter? Aber gibt es denn sonst jemanden, der so dämlich ist wie ich und ein Schach in python schreibt? Ich bin kein Anhänger der Plagiatstheorie - ich habe all mein Informatik-Wissen aus dem Wissensschatz der Menschheit, und dafür keinen Cent gezahlt (Universitäten in Deutschland ja fast umsonst). Ich habe vom Wissen in stackoverflow profitiert, mir daraus Wissen angeeignet. Warum sollte das verwerflich sein, wenn nicht ich, sondern eine künstliche Intelligenz das Gleiche macht?

Mir geht es um die Messung echter Programmierkompetenz. Einen Algorithmus auswendig kennen und leicht angepasst runterschreiben, erfordert keine Intelligenz. Andererseits wurden meine Wünsche für eine Verbesserung der Stellungsanalyse korrekt und sauber umgesetzt. Würde die Maschine nur kopieren und nicht das verstehen, was sie geschrieben hat, wäre ihr das unmöglich.

Es bleibt schwierig. Was ist das nächste Problem, um LLMs zu testen? Eines, das groß genug für sie ist?

(Teaser: es ist GECODE (mit dem ich beruflich zu tun habe)).