Agentic Coding: Ein großes Lehr-Projekt

Gero Scholz

Hier geht es um das AIDE Quiz, also ein Web-System mit Vanilla UI ohne großartiges Framework, mit NodeJS und einer Datenbank auf dem Server. Das System ist nach professionellen Maßstäben klein, im Rahmen der Ausbildung dürfte es allerdings eher groß wirken mit seinen ca. 20.000 Lines of Code. Es gibt drei Tabellen (Quizzes, QuizSessions, Submissions) und vier Dialoge. Technisch kann das System auf einem durchschnittlichen Laptop mit Windows und WSL/Ubuntu laufen. Wir skizzieren einige Aufgaben, die geeignet sind, die Struktur eines solchen Systems zu erschließen, um dann auch kleinere Änderungen daran vorzunehmen.

Aufgabe 0: Erklärungen fordern

Nachdem die Studis das System als Lehrer und als Teilnehmer ausprobiert haben, fordern sie die AI auf, allgemein anhand des Schichtenmodells und danach auch speziell mit Code-Ausschnitten zu erklären, wie bestimmte Use-Cases abgehandelt werden. Beispiel: Der User hat die letzte Frage beantwortet und soll nun erfahren, wie er abgeschnitten hat. Er bekommt neben der Punktezahl auch einen Link auf eine genaue Auswertung seiner Antworten. Dieser Link ist allerdings erst nach Beendigung der Quiz-Session zugänglich.

Aufgabe 1: CSS

Die Studis probieren CSS Änderungen im Browser aus und sehen, wie speziellere Definitionen allgemeinere überschreiben und verdecken. Nützliches handwerkliches Wissen. Sie können auch Fontsizes verändern und über Style-Guides nachdenken. Die Anwendung auf dem Handy testen usw.

Man weist sie darauf hin, dass fortgeschrittene UIs "Themes" verwenden, um User-Präferenzen zu unterstützen und dass Barrierefreiheit in bestimmten Anwendungen wichtig sein kann. Aber es bleibt bei der Diskussion. Mehr nicht. Selbständiges Nachlesen über UI Design hochgradig erwünscht!

Aufgabe 2: Einzelfeld-Plausi

Dann folgt das Einbauen einer Plausiprüfung für ein bestimmtes Eingabefeld. Wir könnten z.B. bestimmte Sonderzeichen in der Bezeichnung eines Quiz verbieten und verlangen, dass es mit einem Großbuchstaben beginnt.

Auf der Mikroebene lernen die Studis dabei, was reguläre Ausdrücke sind. Aber sie müssen nicht das ganze Konzept incl. der Identifikation referenzierbarer Subpatterns erklärt bekommen, wie man es in einer Vorlesung klassisch wohl machen würde. Sie müssen ja nur ^[A-ZAÖÜ][-a-zA-Z0-9, ]+ kapieren! Sie sollen ein kleines Problem lösen und erwerben kontextbezogenes partielles Grundlagenwissen.

Dabei werden sie die erste Überraschung erleben, denn die Architektur in unserem Beispiel sieht vor, dass der Server regelbasierte Plausis festlegt, die er einerseits selbst durchführt, andererseits aber als JSON-Regeln auch dem Client zur Verfügung stellt, der sie dann lokal in einem Interpreter abarbeitet. Entweder lässt man die Studis diesen Mechanismus selbst im Code oder in der Doku entdecken oder man erklärt es ihnen. Wie auch immer: Das Denken in Strukturen beginnt sofort: Warum macht das denn der Server? Muss das so kompliziert sein? Was wäre, wenn er es nicht machen würde? Wie viel Vertrauen darf zwischen Server und Client herrschen? Was ist, wenn Nachbarsysteme das API des Servers nutzen und sich nicht an die Plausi-Regeln halten? Was ist, wenn wir jetzt Plausi-Regeln nachträglich verschärfen, obwohl es ja schon Daten in der Datenbank gibt?

Wir behaupten: Diese Diskussion könnte man sogar mit Jura-Studenten führen 😉
Dazu muss man noch nicht programmieren können.

Die Durchführung der Änderung ist so klein, dass sie manuell zu bewältigen sein wird.

Dann kommt ein AI Agent ins Spiel. Man stellt ihm die Aufgabe, genau diese Änderung durchzuführen, vergleicht seinen Eingriff mit der eigenen Änderung und prüft, ob ihm die Problematik mit den existierenden Einträgen in der Datenbank auffällt. Ist er ignorant? Was tut er, wenn man ihn darauf hinweist? Schlägt er vor, den existierenden Quiz-Editor zu verwenden, um die Einträge VORHER zu bereinigen? Geht das auch nachher, denn der Server liefert falsche Einträge ja durchaus noch aus, akzeptiert sie aber bei einem Update nicht mehr wegen der geänderten Regel? Wie erfährt der User in diesem Fall, was er tun muss — schließlich hat er ja nichts an diesem Feld geändert!? Wird er überhaupt die fachliche Kompetenz dafür haben? Bietet die AI ein Script an, das konfliktierende Einträge zumindest ermittelt? Bietet sie evtl. sogar eine Transition-Rule und einen Batch-Lauf für deren Anwendung an? Was machen wir mit Nachbarsystemen, die vielleicht innerhalb ihrer Domäne die Werte gespeichert haben, die wir jetzt nachträglich für ungültig erklären. Klarer Fall für Juristen: Im Strafrecht gibt es das Rückwirkungsverbot 😉 Aber in der IT? Den Fluch der Abwärtskompatibilität …

Schon mit der zweiten Anfängeraufgabe landen wir bei Architekturüberlegungen. So soll es sein!

Aufgabe 3: Feld-übergreifende Plausibilität

Der Editor kann festlegen, dass bei einer Frage eine oder mehrere Antworten gültig sein sollen. Wir wollen verhindern, dass ein Lehrer Fragen entwirft, bei denen er alle Antworten als gültig erklärt. Wie finden wir die Stelle im Code, wo das geprüft werden kann? Wie setzen wir das um?

Aufgabe 4: Bewertungsverfahren ändern

Aktuell ist die Bewertung bei Aufgaben mit mehreren richtigen Lösungen sehr streng: Jede Abweichung vom exakten Ergebnis führt zu 0 Punkten. Außerdem erfährt der Nutzer nur, dass mehrere Antworten richtig sind, aber nicht, wie viele. Das muss anders werden!

Jetzt geht es um Fachlichkeit: Wollen wir dem User sagen, wie viele richtige Antworten es gibt? Wollen wir ihn zwingen, genau diese Zahl von Antworten als richtig zu markieren? Bekommt er einen halben Punkt, wenn er eine von zwei richtigen Antworten gewählt hat? Kann unser System überhaupt mit nicht-ganzzahligen Punkten umgehen? Was ist, wenn drei Antworten richtig sind? Haben wir dann 0.33 und 0.66 Punkte? Wenn es mehrere solche Fragen gibt, können als Summe auch wieder ganze Zahlen herauskommen, oder? Aber der Computer rechnet ja nicht mit echten Brüchen, sondern er muss die Kommazahlen ja abschneiden. Sieht der User dann ein Ergebnis wie: "Du hast 14.00000001 Punkt erzielt"?

Wenn drei von vier Antworten richtig sind, könnte der User einfach alle vier ankreuzen. Dann soll er wohl nicht 3 x 0.25 Punkte bekommen. Wie ermitteln wir den Abzug für eine falsche Antwort? Tilgt sie quasi eine richtige, indem sie negatives Gewicht hat? Aber wenn bei einer Aufgabe zwei von vier Antworten richtig sind, könnte der User auch -1 Punkte bekommen, wenn er ausgerechnet die beiden falschen Antworten auswählt.

Neben dem Führen einer hitzigen fachlichen Diskussion und der korrekten Umsetzung der beschlossenen Änderung hat die Aufgabe noch einen ganz anderen Aspekt, den wir aber nicht zu erkennen geben: Viele Institutionen benutzen Prüfungen auf der Basis von Multiple Choice Tests. Wir sollten vielleicht auch mal sehen, ob es da eine Mehrheitsmeinung gibt. Wir haben auch die Möglichkeit, unserem Auftraggeber zu widersprechen, wenn er etwas fordert, was nicht mit dem Konsens der Fachöffentlichkeit zusammenpasst!

Und dann gibt es noch eine nachgeschobene Anforderung: Es soll eben doch durchaus zulässig sein, dass Lehrer eine Frage stellen, bei der alle Antworten richtig sind. Das sei weder unfair noch eine Art Irreführung des Users. Wie verhalten wir uns? Wir haben gerade erst vorhin erzwungen, dass mindestens eine Antwort falsch sein muss! Haben wir dabei an existierende Fragen gedacht, die lauter korrekte Antworten besitzen? Wir verstehen plötzlich, warum man in der Wartung eines Systems so vorsichtig agiert. Hätten wir damals daran gedacht, dass es eine Quiz Property allowQuestionsWithoutFalseOptions geben sollte, würden wir jetzt ein feines Lächeln aufsetzen.

Aufgabe 5: Ein neues Datenfeld

Jedes Quiz bekommt ein neues Attribut, z.B. eine Domäne wie "Physik, Architektur, Biologie". Es gibt keine inhaltlichen Restriktionen für das Feld. Es soll in der Datenbank ergänzt werden und im UI des Lehrers erscheinen. Es bleibt leer bei vorhandenen Quizzes. Diesmal lassen wir die AI einfach machen und schauen uns hinterher jede geänderte Code-Zeile an. Wir erteilen den Auftrag an sie übrigens per Spracheingabe.

Aufgabe 6: Gewichtung von Fragen ändern

Nochmal ein wenig Fachlichkeit: Jede Frage hat ja bereits ein Gewicht. Einem Lehrer fällt anhand der Auswertung mehrerer Sessions mit einem bestimmten Quiz auf, dass er die Gewichtung einzelner Fragen ändern möchte. Das kann er doch einfach tun, oder?

Wir sollten dem Lehrer dankbar sein für seine umsichtige Anfrage und fallen fast in Ohnmacht! Eine Änderung dieses Felds ist aktuell problemlos möglich, würde aber sämtliche Ergebnisse und Statistiken rückwirkend verfälschen. Wir wüssten nicht mehr, welches Ergebnis wir den Teilnehmern früher gezeigt haben — kurz: Ein entsetzlicher Design-Mangel!

Wenn die erste Panik vorbei ist, kommt jemand hoffentlich auf die Idee zu empfehlen, das veränderte Quiz unter neuem Namen abzuspeichern. Wir haben zwar keine SAVE_AS Funktion, aber wir können einen "brillanten" Workaround anbieten: (1) altes Quiz öffnen, in der JSON-Ansicht den ganzen Text kopieren, (2) neues Quiz unter passendem Namen anlegen, (3) JSON Fenster öffnen, den Code hineinkopieren und (4) speichern.

Der nächste Schritt der Erkenntnis sollte dann sein, dass es offenbar eine Entwurfsphase für ein Quiz gibt, in der Änderungen am Quiz (neue Fragen, andere Antworten, geänderte Gewichtungen) zulässig sind, auch wenn schon probeweise Sessions und Submissions erzeugt werden. Danach muss es offenbar eine Art "Freigabe" geben, nach der ein Quiz für jegliche weitere Veränderung gesperrt ist.

Nächstes Problem: Die Sessions und Submissions, die während der Erstellung eines Quiz entstanden sind, wollen wir vermutlich wieder loswerden. Aktuell haben wir aber nur ein Cascading Delete, das ausgelöst wird, wenn das ganze Quiz gelöscht wird.

Noch ein genialer Workaround gefällig? Vor der ersten echten Session soll der Lehrer den JSON Code kopieren, dann das Quiz löschen, dann unter demselben Namen wieder neu anlegen und den JSON Code per Pasting wieder hineinschreiben.

In der internen Liste für Bugfixes landet ein Requirement für das Löschen einzelner Sessions (Cascading zu den Submissions) bedauerlicherweise weit hinten, weil so viele andere Wünsche auf Halde liegen…

Der Freigabemechanismus wird (eventuell) eingebaut, diesmal in Interaktion zwischen Human und AI, am besten in mehreren Schritten, auf Basis eines Plans, der zu Beginn mit der AI vereinbart wird.

Diesmal ist die Gelegenheit da, für einen weit ausholenden Vortrag über die Problematik vor- und rückdatierter Änderungen, über die Festlegung lückenloser zeitlicher Gültigkeitszeiträume für fachliche Objekte, über die Unterscheidung von Änderungsdatum und Gültigkeitsdatum. Das Ganze gipfelt in der Frage, was passiert, wenn eine künftige Änderung vor Beginn ihrer Gültigkeit erneut geändert wird? Und vor allem (viel schwieriger): Wie kann ich herausfinden, was vor zwei Wochen über den Inhalt und die Gültigkeit einer aus damaliger Sicht zukünftigen Änderung bekannt war, die danach noch mehrfach geändert wurde, bevor sie eintrat? Allein die Fragestellung dieses Satzes zu verstehen, ist nicht ganz einfach. Wenn ich aber als Bank damals jemandem eine Kreditzusage gegeben habe und aus heutiger Sicht bei dem Blick auf die aktuellen Daten nicht mehr nachvollziehbar ist, "wieso wir als Bank damals ein solches Risiko eingehen konnten?", dann können auch Studis im ersten Semester begreifen, dass wir über durchaus relevante Probleme betrieblicher Informationssysteme sprechen.

Wir lehren, dass es sich um eine Standard-Fragestellung handelt, für die es kluge Standardlösungen gibt. Ob die Studis es schaffen, sie technisch zusammen mit der AI umzusetzen, ist allerdings zweifelhaft. Wir belassen diese Unterrichtseinheit vielleicht besser im Bereich der NON-CODE Dokumentation. Das Artefakt ist diesmal also eine Beschreibung des Problems, der Workaround sowie eine Skizze der möglichen professionellen Umsetzung einer wirklich sauberen Lösung. Mehr nicht. Ein wenig SQL darf die Lösungsskizze aber durchaus enthalten. Die AI wird sie uns vermutlich liefern, wenn wir genau genug fragen.

Aufgabe 7: Mehrsprachigkeit

Der Lehrer berichtet darüber, wie das aktuelle Konzept für Mehrsprachigkeit entstand:

  • Am Anfang war alles in deutsch, die Kommentare im Code, die Dokumentation, die Ausgaben an den Benutzer und die JSON-Inhalte eines Quiz. So wie es einem naiven ersten Entwurf entspricht. Die Idee war, dass die Mehrzahl der User Deutsch als Muttersprache hat und alle anderen den Google Translator nutzen können.
  • Dann kam als Komfort ein Widget in der Kopfleiste hinzu, das den Google Translator aktiviert
  • Dann wurde beschlossen, das Projekt auf Englisch umzustellen; zuerst die Texte im Frontend, also HTML, Hilfetexte und Architektur-Dokumentation
  • Dann auch das Backend (Fehlermeldungen und andere Texte, die der Server erzeugt)
  • Da das Projekt Ausbildungscharakter haben soll, wurde beschlossen (und die AI beauftragt) auch die Inline-Kommentare im Code auf Englisch umzustellen
  • Das hat im Wesentlichen funktioniert, aber es bleiben ein paar Ungereimtheiten übrig, weil z.B. jetzt GT (Google Translate) entscheidet, ob "formality"="DU oder Sie" verwendet wird. GT entscheidet das, abhängig vom jeweiligen Textschnipsel, aber nicht konsistent für eine HTML Seite.
  • Eine Lösung mit DeepL wurde erwogen, aber wegen der Kosten verworfen
  • Die Quiz-Dokumente sind nach wie vor in der Sprache des Lehrers, also in Deutsch in unserem Beispiel.
  • Es zeigte sich, dass GT dynamisch nachgeladene Texte nicht übersetzt, also sah man weiterhin deutsche Frage- und Antwort-Texte, auch wenn das UI insgesamt z.B. in Spanisch war.
  • Die AI schlug vor, GT zu einem "refresh" zu nötigen, nachdem die Texte geladen worden sind. Das hat nicht funktioniert und wurde wieder zurückgebaut.
  • Dann schlug die AI vor, die JSON Files auf dem Server in mehreren Sprachen vorzuhalten, was natürlich einen vom Menschen gesteuerten Übersetzungsprozess verlangt hätte. Das wollte der Autor nicht.
  • Dann schlug die AI vor, DeepL (nur für die JSON-Inhalte) auf dem Client einzubinden; bei dem zu erwartenden Volumen kann man hoffen, innerhalb des kostenlosen Budgets an Übersetzungen zu bleiben.
  • Der Autor schlug vor, über Caching der übersetzten Texte nachzudenken.
  • Die AI entwarf ein Konzept dazu.
  • Der Autor dachte nach und schlug dann vor, die Übersetzung auf dem Server zu initiieren und auch dort das Caching zu machen.
  • Die AI erkannte, dass diese Lösung architektonisch vorteilhafter und effizienter ist.
  • Gemeinsam wurde beschlossen, den Cache nur dann zu invalidieren, wenn der Lehrer das Quiz verändert hat.
  • Die AI hat das Konzept umgesetzt durch eine neue Klasse, die mit DeepL interagiert.
  • Es ergab sich die Notwendigkeit, ein Token bei DeepL zu beschaffen und dieses ins Environment zu integrieren. Es entstand u.a. die Frage, ob dieses Token im git repository landen darf oder nicht.
  • Dann wurde erkannt, dass die Übersetzungsqualität für die programm-eigenen Bedienelemente unzureichend ist und einen deterministischen Ansatz erfordert, den wir vollständig selbst kontrollieren können.
  • Es gab eine sorgfältige Evaluierung möglicher Frameworks und Bibliotheken; eine der Anforderungen war, dass in den übersetzten Texten Parameter-Ersetzung möglich sein sollte. Parameter, die auf einer festen Reihenfolge basieren, wurden als unzureichend eingeschätzt, weil die Satzstellung von der Zielsprache abhängen kann.
  • Die Library wurde eingebunden und die AI hat freundlicherweise alle Literale im Code identifiziert und je Sprache ein Translation-File erstellt — eine Aufgabe, für die ein Mensch Schmerzensgeld verlangen würde.

Aufgabe 8: Warum so spät?

Der Lehrer verlangt ein umfassendes Testkonzept. Diskussion, ob nur der Server oder auch der Client einbezogen wird. Beispielhafte Implementierung eines Zyklus, bei dem über API Calls ein Quiz erstellt und verändert wird, eine Session dazu erzeugt wird, ein User teilnimmt und sein Resultat erhält. Danach werden Quiz, Sessions und Submissions wieder gelöscht. Erstellung eines Scripts dafür. Einbinden des Scripts in alle git commits, die den Server betreffen.

Aufgabe 9: Wünsch dir was!

Die Studis denken sich eigene CRs aus und schätzen den Umsetzungsaufwand auf einer Skala von 1–10. Dann prüfen sie im Planning Mode der AI, ob sie ihr Ranking korrigieren sollten.


← Übersicht: Disruption in der IT-Ausbildung | Weiter: Agentic Coding — Eine Unterrichts-Einheit →