Wie bringt man einer KI das Jassen bei?

Was ist die Technik hinter der KI, die Trumpf ansagen kann?

Jassen mit Sprachmodellen, Algorithmen und künstlicher Intelligenz

Wir hatten den Ehrgeiz, ein KI-Sprachmodell allein durch Prompten dazu zu bringen, gute Entscheidungen für das Ansagen oder Schieben beim Jassen zu treffen. Das tönt nach einer einfachen Aufgabe. Bis wir Euch jedoch auf unserer Website eine fertige Demo zum Ausprobieren anbieten konnten, mussten wir einige technische Probleme lösen. Eine solche Applikation muss nämlich das Sprachmodell, die Prompt-Erzeugung, das Weiterverarbeiten und Darstellen der Ergebnisse zu einem Gesamtkunstwerk integrieren. In diesem Blogbeitrag wollen wir Euch zeigen, wie wir das gemacht haben.

Mit Schere und Klebstoff an die Prompts?

Als erstes mussten wir herausfinden, wie wir effizient komplexe Prompts generieren und diese Prompts während der Entwicklungszeit schnell und zuverlässig optimieren und abändern können. Wie in Nathalie's Blogpost beschrieben ist, waren die Ergebnisse des Sprachmodells mit unseren ersten Prompts noch nicht sehr gut - es hatte manchmal Halluzinationen und verstieg sich bei den Erklärungen. Wir mussten also die Prompts optimieren und lernen, wo im Prompt wir die nötigen Informationen zum aktuellen Problem (nämlich: welche Karten hast du auf der Hand?) einfügen müssen, und welche Instruktionen wir geben müssen, um Halluzinationen und Denkfehler zu minimieren. Mit Schere und Kleber kann man das aber nicht machen - und copy/paste ist ja fast dasselbe.

Es musste eine Möglichkeit her, um längere Prompt-Texte zu verwalten, die dann an verschiedenen Stellen Lücken enthalten, so dass man sie zur Laufzeit, passend für die Situation, befüllen kann.

Bei der Jass-Demo haben wir das pragmatisch und einfach mit Python Bordmitteln gelöst. Python kann mit der format Methode Variablen in einen String einfügen. Das geht so:

prompt = "Du hast folgende Karten in der Hand: {karten}. Sortiere sie nach Farbe und Wert."

karten = "Schilten Banner, Rosen Under, Schilten As, Rosen Ober"
print(prompt.format(karten=karten))

# Resultierender Prompt: Du hast folgende Karten in der Hand: Schilten Banner, Rosen Under, Schilten As, Rosen Ober. Sortiere sie nach Farbe und Wert.

karten = "Eichle Under, Rosen Banner"
print(prompt.format(karten=karten))

# Resultierender Prompt: Du hast folgende Karten in der Hand: Eichle Under, Rosen Banner. Sortiere sie nach Farbe und Wert.

Das funktioniert zwar gut, in neueren Projekten verwenden wir aber das LangChain Framework, denn es bietet noch ausgefeiltere Möglichkeiten, um komplexe Prompts zusammenzustellen.

Ein bisschen mehr Struktur, bitte!

Nach einigen Prompt-Optimierungsrunden waren wir so weit, dass das Sprachmodell gute Ergebnisse geliefert hat. Bei der Optimierung stellte sich sehr schnell heraus, dass das ChatCPT Standardmodell (GPT-3.5) mit der Aufgabe überfordert war. Das GPT4-Modell ist viel stärker im Bereich "Reasoning", d.h. beim Schlussfolgern und Begründen, und wir haben uns bald entschieden, für diese Aufgabe ausschliesslich das GPT4-Modell zu verwenden. Allerdings musste Nathalie, um die guten Ergebnisse mit GPT-4 zu erreichen, in den Instruktionen das Modell dazu anleiten "laut zu denken" und die Zwischenschritte in der Antwort auszugeben. Wenn man das Modell nämlich nicht so instruiert, neigt auch GPT-4 dazu, denkfaul zu sein und oberflächlich eine Antwort zu generieren. Dabei übersieht es Informationen oder erfindet nicht zutreffende Aussagen (Halluzinationen). Mit der Instruktion zur Ausgabe der Zwischenschritte klappt das deutlich besser. Diese Technik hat aber den Nachteil, dass das Modell sehr ausführliche Antworten generiert, wobei die Form der Antwort oft variiert, denn das Modell bemüht sich, keine eintönigen Texte zu erzeugen. Das macht es schwierig, die Antworten anschliessend weiterzuverarbeiten. Zu versuchen, im Prompt immer genauere Anweisungen zu geben, in welcher Reihenfolge, Form und Länge das Modell die Teile der Antwort ausgeben soll, führt zu keinen besseren Ergebnissen. Wir haben stattdessen eine elegante Lösung aus dem LangChain Framework nachgebaut. In LangChains gibt es die Möglichkeit eine Instruktion erstellen zu lassen welche das Sprachmodell anweist, die Antwort gemäss einem JSON-Schema zu generieren. Diese Instruktion fügt man dann gegen Ende des Prompts als zusätzliche Anweisung ein. Unser Nachbau dieser Technik sieht als Skizze etwa so aus:

FORMAT_INSTRUCTIONS = """Deine Antwort muss als JSON Instanz formatiert sein, welche dem untenstehenden JSON Schema entspricht.

Beispiele: Für das Schema {{"properties": {{"foo": {{"title": "Foo", "description": "a list of strings", "type": "array", "items": {{"type": "string"}}}}}}, "required": ["foo"]}}}}
ist das Objekt {{"foo": ["bar", "baz"]}} eine wohlgeformte Instanz des Schemas. Das Objekt {{"properties": {{"foo": ["bar", "baz"]}}}} is nicht wohlgeformt.

Hier ist das Schema:
{schema}
"""

Dieses Prompt-Fragment ist übrigens selbst ein Besipiel für eine mächtige Prompting-Technik: Man gibt eine kleine Anzahl von Beispielen im Prompt an, das Modell lernt daraus gleich, was von ihm erwartet wird. Dieses Lernen aus wenigen Beispielen nennt man "few-shot learning".

Das benötigte Schema kann man nun bequem mit Pydantic erzeugen, oder, wem das Spass macht, von Hand. Im Original von LangChain war diese Instruktion in Englisch, aber da der Rest des Prompts in Deutsch gehalten ist, haben wir das übersetzt. Das funktioniert gut so, offenbar werden im Modell Konzepte von einer Sprache in die andere übertragen, denn ich gehe nicht davon aus, dass das Modell mit vielen Deutschsprachigen JSON-Schemata und Python-Files trainiert wurde. Schlussendlich bekommen wir mit dieser Technik eine Antwort, welche dem gegebenen Schema entspricht. Das Schema wählen wir so, dass wir die Daten gut weiterverarbeiten können. In der Live-Demo könnt Ihr den resultierenden Prompt unter "Prompt Gesamtanalyse" sehen. In der Anzeige des Resultats verwenden wir dann nur die Texte in den Feldern Ansage (als Titel) und Begründung (als Fliesstext).

Umlernen ist schwierig: Die Grenzen des Sprachmodells mit Algorithmen austricksen

Als wir schon fast am Ziel waren, kamen wir an eine Grenze des Sprachmodells: Trotz einiger Versuche ist es uns nicht gelungen, das Sprachmodell zum Kopfstand zu bringen und die Welt mal als Undenufe zu betrachten. Die Macht des As war stärker als unsere Prompts. Was tun? Sollen wir es mit einem extra-Prompt nur für Undenufe probieren? Sollen wir die Funktionalität der Demo einschränken und auf Undenufe verzichten? Oder gibt es eine Möglichkeit, das Problem zu umgehen? Wir haben den Weg gewählt, einen klassischen Algorithmus einzubauen, der das Sprachmodell bei dieser Schwäche unterstützt. Wir haben eine kleine Python-Funktion gebaut, welche für das gegebene Kartenblatt die Basis für das Anwenden von Faustregeln berechnet. Die Funktion berechnet die Anzahl sicherer Stiche (d.h. alle Stiche, die man am Anfang beim Undenufe-Spiel ohne Unterbruch ausspielen kann) und ebenso "fast sichere Stiche", also solche, die man mit etwas partnerseitigem Kartenglück auch noch machen kann (z.B. eine 8 zu einer 6 oder ein Banner zu einer 6,7,8er Folge). Diese Information geben wir dem Sprachmodell im Prompt für die Schlussanalyse mit, und dann kann es die Faustregeln, welche auf solchen Stichen beruhen, wieder selbst anwenden. Der Nutzen des Sprachmodells bleibt dabei erhalten: Es kann in der Begründung erklären, auf der Basis von welchen Faustregeln es die Ansage macht, auch wenn es selbst mit dem Erstellen der Basisinformationen überfordert ist. Wenn Ihr in der Demo die Prompts anschaut findet ihr die berechneten Informationen in Form der "Obenabeliste" und "Undenufeliste" .

Das Beste aus zwei Welten

Bei der Entwicklung unserer Jass-Demo sind wir bis an die Grenzen der Sprachmodelle gestossen. Unsere Lösungen reichten von der kreativen Optimierung der Prompts, über die Einbindung von JSON-Schemas zur Strukturierung der Antworten, bis hin zur Kombination von klassischem Algorithmus und dem Sprachmodell. Dabei hat es sich bewährt, Stärken des KI-Sprachmodells und der "klassischen IT" miteinander zu kombinieren. Das Sprachmodell hat es ermöglicht, Entscheidungen auf der Basis von Regeln zu treffen und zu erklären, während die klassischen IT-Techniken die Berechnungen ausführen, die für das Sprachmodell zu komplex waren.

In unserem Projekt hat sich gezeigt, dass ähnlich wie beim Jassen die beste Strategie oft darin besteht, flexibel auf die jeweilige Situation zu reagieren - sei es beim Entscheiden, ob du 'schieben' oder 'ansagen' solltest, oder beim Wählen, ob du Python f-Strings, LangChain oder einen klassischen Algorithmus verwendest. Wie im Jassen sind die beste Entscheidungen oft diejenigen, die sich am flexibelsten an die Herausforderungen anpassen, die dir das Spiel - oder das Projekt - stellt.

Am Ende des Tages ist es nicht nur wichtig, die richtigen Werkzeuge zu haben, sondern auch zu wissen, wie und wann man sie einsetzt. Wir teilen unsere Erfahrungen gern, und Ihr könnt die Tipps in eigenen Projekten anwenden, oder uns kontaktieren, wenn Ihr Unterstützung braucht.

Und falls Ihr immer noch an der Frage hängt, ob Ihr eine Schere zur Bearbeitung der Prompts braucht – die Antwort ist immer noch nein. Aber mit der richtigen Mischung aus KI, klassischer IT und ein bisschen Kreativität kann man die Applikationen auf ein neues Level heben, ganz ohne Papier und Klebstoff.

Markus Emmenegger
Markus Emmenegger

Lust auf mehr Blogs?

Warum bringt man einer KI das Jassen bei?

Nathalie Portmann macht darauf aufmerksam, dass KI bei Entscheidungsfindungsprozessen eingesetzt werden kann, ohne dass am nächsten Tag die Menschheit untergeht.

Wie haben wir poemAI.ch gebaut? Mit KI!

Markus Emmenegger verrät, wie wir künstliche Intelligenz bei der Erstellung der Website von poemAI.ch eingesetzt haben. In diesem Blog gibt es anschauliche Tipps, wie man KI im Arbeitsalltag einsetzen kann.

Warum bringt man einer KI das Jassen bei?

Nathalie Portmann macht darauf aufmerksam, dass KI bei Entscheidungsfindungsprozessen eingesetzt werden kann, ohne dass am nächsten Tag die Menschheit untergeht.

Wie haben wir poemAI.ch gebaut? Mit KI!

Markus Emmenegger verrät, wie wir künstliche Intelligenz bei der Erstellung der Website von poemAI.ch eingesetzt haben. In diesem Blog gibt es anschauliche Tipps, wie man KI im Arbeitsalltag einsetzen kann.

Kontaktieren Sie uns!

poemAI GmbH
Rämsiweg 8
6048 Horw
;