Ratespiel mit der Prompt API erstellen

Veröffentlicht: 10. Oktober 2025

Schulkinder spielen 2014 das Spiel „Wer bin ich?“.

Das klassische Brettspiel Wer bin ich? ist ein Meisterwerk des deduktiven Denkens. Jeder Spieler beginnt mit einem Brett mit Gesichtern und schränkt durch eine Reihe von Ja- oder Nein-Fragen die Möglichkeiten ein, bis er den geheimen Charakter seines Gegners sicher identifizieren kann.

Nachdem ich auf der Google I/O Connect eine Demo von integrierter KI gesehen hatte, fragte ich mich, was wäre, wenn ich ein „Wer bin ich?“-Spiel gegen eine KI spielen könnte, die im Browser läuft. Mit clientseitiger KI würden die Fotos lokal interpretiert. Ein individuelles „Wer bin ich?“ mit Freunden und Familie bliebe also privat und sicher auf meinem Gerät.

Ich habe hauptsächlich Erfahrung in der UI- und UX-Entwicklung und bin es gewohnt, pixelgenaue Designs zu erstellen. Genau das wollte ich mit meiner Interpretation erreichen.

Meine Anwendung AI Guess Who? basiert auf React und verwendet die Prompt API und ein im Browser integriertes Modell, um einen überraschend leistungsfähigen Gegner zu erstellen. Dabei habe ich festgestellt, dass es gar nicht so einfach ist, „pixelgenaue“ Ergebnisse zu erzielen. Diese Anwendung zeigt jedoch, wie KI verwendet werden kann, um eine durchdachte Spiellogik zu erstellen, und wie wichtig Prompt Engineering ist, um diese Logik zu optimieren und die erwarteten Ergebnisse zu erzielen.

Lesen Sie weiter, um mehr über die integrierte KI-Integration, die Herausforderungen, denen ich gegenüberstand, und die Lösungen zu erfahren, die ich gefunden habe. Sie können das Spiel spielen und den Quellcode auf GitHub finden.

Grundlage des Spiels: Eine React-App

Bevor wir uns die KI-Implementierung ansehen, betrachten wir die Struktur der Anwendung. Ich habe eine Standard-React-Anwendung mit TypeScript erstellt, mit einer zentralen App.tsx-Datei, die als Dirigent des Spiels fungiert. Diese Datei enthält:

  • Spielstatus: Ein Enum, das die aktuelle Phase des Spiels verfolgt (z. B. PLAYER_TURN_ASKING, AI_TURN, GAME_OVER). Dies ist der wichtigste Status, da er bestimmt, was auf der Benutzeroberfläche angezeigt wird und welche Aktionen dem Spieler zur Verfügung stehen.
  • Figurenlisten: Es gibt mehrere Listen, in denen die aktiven Figuren, die geheime Figur jedes Spielers und die Figuren, die vom Brett entfernt wurden, angegeben sind.
  • Spielchat: Ein fortlaufendes Protokoll von Fragen, Antworten und Systemnachrichten.

Die Benutzeroberfläche ist in logische Komponenten unterteilt:

GameSetup ist der erste Bildschirm.
Auf dem GameBoard werden das Raster mit den Zeichen und die Chat-Steuerelemente für alle Nutzereingaben angezeigt.

Mit den Funktionen des Spiels wuchs auch seine Komplexität. Anfangs wurde die gesamte Spiellogik in einem einzigen, großen benutzerdefinierten React-Hook (useGameLogic) verwaltet. Dieser wurde jedoch schnell zu groß, um darin zu navigieren und Fehler zu beheben. Um die Wartbarkeit zu verbessern, habe ich diesen Hook in mehrere Hooks mit jeweils einer einzigen Aufgabe umgestaltet. Beispiel:

  • useGameState verwaltet den Hauptstatus
  • usePlayerActions ist für den Spielerzug
  • useAIActions ist für die Logik der KI

Der Haupt-useGameLogic-Hook fungiert jetzt als sauberer Composer, der diese kleineren Hooks zusammenfasst. Diese architektonische Änderung hat die Funktionalität des Spiels nicht beeinträchtigt, aber die Codebasis erheblich übersichtlicher gemacht.

Spiellogik mit der Prompt API

Das Herzstück dieses Projekts ist die Verwendung der Prompt API.

Ich habe die KI-Spiellogik zu builtInAIService.ts hinzugefügt. Das sind die wichtigsten Aufgaben:

  1. Restriktive, binäre Antworten zulassen.
  2. Dem Modell eine Spielstrategie beibringen
  3. Modellanalyse trainieren
  4. Geben Sie dem Modell Amnesie.

Restriktive, binäre Antworten zulassen

Wie interagiert der Spieler mit der KI? Wenn ein Spieler fragt: „Hat dein Charakter einen Hut?“, muss die KI sich das Bild des geheimen Charakters ansehen und eine klare Antwort geben.

Meine ersten Versuche waren ein Chaos. Die Antwort war konversationell: „Nein, die Figur, an die ich denke, Isabella, trägt anscheinend keinen Hut“, anstatt mit einem einfachen „Ja“ oder „Nein“ zu antworten. Zuerst habe ich das mit einem sehr strengen Prompt gelöst, der dem Modell im Grunde vorschrieb, nur mit „Ja“ oder „Nein“ zu antworten.

Das hat zwar funktioniert, aber ich habe eine noch bessere Methode mit strukturierter Ausgabe kennengelernt. Durch die Bereitstellung des JSON-Schemas für das Modell konnte ich eine Antwort mit „Wahr“ oder „Falsch“ garantieren.

const schema = { type: "boolean" };
const result = session.prompt(prompt, { responseConstraint: schema });

So konnte ich den Prompt vereinfachen und meinen Code die Antwort zuverlässig verarbeiten lassen:

JSON.parse(result) ? "Yes" : "No"

Dem Modell eine Spielstrategie beibringen

Es ist viel einfacher, dem Modell zu sagen, dass es eine Frage beantworten soll, als es selbst Fragen stellen zu lassen. Ein guter „Wer bin ich?“-Spieler stellt keine zufälligen Fragen. Sie stellen Fragen, mit denen möglichst viele Buchstaben gleichzeitig ausgeschlossen werden. Eine ideale Frage halbiert die Anzahl der möglichen verbleibenden Zeichen durch binäre Fragen.

Wie bringen Sie einem Modell diese Strategie bei? Auch hier ist Prompt Engineering gefragt. Der Prompt für generateAIQuestion() ist eigentlich eine kurze Lektion in der Spieltheorie von „Wer bin ich?“.

Zuerst habe ich das Modell gebeten, „eine gute Frage zu stellen“. Die Ergebnisse waren unvorhersehbar. Um die Ergebnisse zu verbessern, habe ich negative Einschränkungen hinzugefügt. Der Prompt enthält jetzt Anweisungen wie:

  • „WICHTIG: NUR nach vorhandenen Funktionen fragen“
  • „KRITISCH: Erstelle originelle Inhalte. Wiederhole KEINE Frage.“

Diese Einschränkungen schränken den Fokus des Modells ein und verhindern, dass es irrelevante Fragen stellt. Dadurch wird es zu einem viel angenehmeren Gegner. Sie können die vollständige Prompt-Datei auf GitHub ansehen.

Modellanalyse beibringen

Das war mit Abstand die schwierigste und wichtigste Herausforderung. Wenn das Modell eine Frage stellt, z. B. „Hat deine Figur einen Hut?“, und der Spieler mit „Nein“ antwortet, wie weiß das Modell dann, welche Figuren auf seinem Brett ausgeschlossen werden?

Das Modell sollte alle Personen mit Hut entfernen. Meine ersten Versuche waren von Logikfehlern geprägt. Manchmal hat das Modell die falschen Zeichen oder gar keine Zeichen entfernt. Was ist ein „Hut“? Zählt eine „Mütze“ als „Hut“? Das kann, seien wir ehrlich, auch in einer Diskussion zwischen Menschen passieren. Natürlich können auch allgemeine Fehler auftreten. Aus Sicht der KI kann es so aussehen, als würde die Person einen Hut tragen.

Ich habe die Architektur so umgestaltet, dass die Wahrnehmung vom Code-Deduction getrennt ist:

  1. KI ist für die visuelle Analyse verantwortlich: Modelle eignen sich hervorragend für die visuelle Analyse. Ich habe das Modell angewiesen, seine Frage und eine detaillierte Analyse in einem strengen JSON-Schema zurückzugeben. Das Modell analysiert jedes Zeichen auf dem Board und beantwortet die Frage: „Hat dieses Zeichen dieses Merkmal?“ Das Modell gibt ein strukturiertes JSON-Objekt zurück:

    { "character_id": "...", "has_feature": true }
    

    Auch hier sind strukturierte Daten der Schlüssel zum Erfolg.

  2. Der Spielcode verwendet die Analyse, um die endgültige Entscheidung zu treffen. Der Anwendungscode prüft die Antwort des Spielers („Ja“ oder „Nein“) und durchläuft die Analyse der KI. Wenn der Spieler „Nein“ gesagt hat, werden alle Zeichen entfernt, bei denen has_feature gleich true ist.

Diese Aufteilung der Aufgaben ist entscheidend für die Entwicklung zuverlässiger KI-Anwendungen. Nutzen Sie KI für ihre Analysefunktionen und überlassen Sie binäre Entscheidungen Ihrem Anwendungscode.

Um die Wahrnehmung des Modells zu überprüfen, habe ich eine Visualisierung dieser Analyse erstellt. So ließ sich leichter bestätigen, ob die Wahrnehmung des Modells korrekt war.

Prompt Engineering

Trotz dieser Trennung habe ich jedoch festgestellt, dass die Wahrnehmung des Modells immer noch fehlerhaft sein kann. Es kann vorkommen, dass fälschlicherweise angenommen wird, dass eine Person eine Brille trägt, was zu einer frustrierenden, falschen Eliminierung führt. Um dem entgegenzuwirken, habe ich einen zweistufigen Prozess ausprobiert: Die KI stellt ihre Frage. Nachdem die Antwort des Spielers eingegangen ist, würde eine zweite, neue Analyse mit der Antwort als Kontext durchgeführt. Die Theorie war, dass bei einer zweiten Überprüfung Fehler aus der ersten gefunden werden könnten.

So hätte der Ablauf funktioniert:

  1. KI-Antwort (API-Aufruf 1): Die KI fragt: „Hat deine Figur einen Bart?“
  2. Spieler ist an der Reihe: Der Spieler sieht sich seinen geheimen Charakter an, der glatt rasiert ist, und antwortet mit „Nein“.
  3. KI-Zug (API-Aufruf 2): Die KI fordert sich selbst auf, alle verbleibenden Zeichen noch einmal zu betrachten und anhand der Antwort des Spielers zu entscheiden, welche eliminiert werden sollen.

Im zweiten Schritt kann es passieren, dass das Modell eine Person mit leichten Stoppeln fälschlicherweise als „ohne Bart“ einstuft und sie nicht entfernt, obwohl der Nutzer das erwartet hat. Der grundlegende Wahrnehmungsfehler wurde nicht behoben und der zusätzliche Schritt hat die Ergebnisse nur verzögert. Bei einem menschlichen Gegner können wir eine Vereinbarung oder Klarstellung dazu treffen. In der aktuellen Konfiguration mit unserem KI-Gegner ist das nicht der Fall.

Dieser Prozess führte zu einer zusätzlichen Latenz durch einen zweiten API-Aufruf, ohne dass die Genauigkeit dadurch wesentlich gesteigert wurde. Wenn das Modell beim ersten Mal falsch lag, lag es oft auch beim zweiten Mal falsch. Ich habe den Prompt so geändert, dass er nur einmal überprüft wird.

Analysen verbessern, anstatt weitere hinzuzufügen

Ich habe mich auf ein UX-Prinzip verlassen: Die Lösung war nicht mehr Analyse, sondern bessere Analyse.

Ich habe viel Zeit in die Optimierung des Prompts investiert und explizite Anweisungen hinzugefügt, damit das Modell seine Arbeit noch einmal überprüft und sich auf bestimmte Funktionen konzentriert. Das hat sich als effektivere Strategie zur Verbesserung der Genauigkeit erwiesen. So funktioniert der aktuelle, zuverlässigere Ablauf:

  1. KI-Turn (API-Aufruf): Das Modell wird aufgefordert, sowohl seine Frage als auch seine interne Analyse gleichzeitig zu generieren und ein einzelnes JSON-Objekt zurückzugeben.

    1. Frage: „Trägt deine Figur eine Brille?“
    2. Analyse (Daten):
    [
      {character_id: 'brad', has_feature: true},
      {character_id: 'alex', has_feature: false},
      {character_id: 'gina', has_feature: true},
      ...
    ]
    
  2. Spieler ist an der Reihe: Die geheime Figur des Spielers ist Alex (ohne Brille). Er antwortet also mit „Nein“.

  3. Runde endet: Der JavaScript-Code der Anwendung wird ausgeführt. Die KI muss nichts weiter fragen. Es durchläuft die Analysedaten aus Schritt 1.

    1. Der Spieler hat „Nein“ gesagt.
    2. Der Code sucht nach jedem Zeichen, für das has_feature zutrifft.
    3. Es klappt Brad und Gina nach unten. Die Logik ist deterministisch und sofortig.

Diese Experimente waren entscheidend, erforderten aber viel Ausprobieren. Ich hatte keine Ahnung, ob es besser werden würde. Manchmal wurde es sogar noch schlimmer. Es ist nicht ganz einfach, herauszufinden, wie Sie die konsistentesten Ergebnisse erzielen.

Nach einigen Runden mit meinem neuen KI-Gegner trat jedoch ein fantastisches neues Problem auf: ein Patt.

Deadlock beenden

Wenn nur noch zwei oder drei sehr ähnliche Zeichen übrig waren, blieb das Modell in einer Schleife hängen. Es wurde eine Frage zu einem gemeinsamen Merkmal gestellt, z. B. „Trägt deine Figur einen Hut?“

Mein Code würde dies korrekt als verschwendeten Zug erkennen und die KI würde eine andere, ebenso allgemeine Funktion ausprobieren, die die Zeichen auch alle gemeinsam haben, z. B. „Trägt deine Figur eine Brille?“

Ich habe den Prompt um eine neue Regel erweitert: Wenn ein Versuch, eine Frage zu generieren, fehlschlägt und noch drei oder weniger Zeichen übrig sind, ändert sich die Strategie.

Die neue Anleitung ist explizit: „Anstatt nach einer allgemeinen Funktion zu fragen, müssen Sie nach einer spezifischeren, einzigartigen oder kombinierten visuellen Funktion fragen, um einen Unterschied zu finden.“ Anstatt zu fragen, ob die Figur einen Hut trägt, wird sie aufgefordert, zu fragen, ob sie eine Baseballkappe trägt.

Dadurch wird das Modell gezwungen, sich die Bilder genauer anzusehen, um das eine kleine Detail zu finden, das schließlich zum Durchbruch führen kann. So funktioniert die Late-Game-Strategie in den meisten Fällen etwas besser.

Dem Modell Amnesie geben

Die größte Stärke eines Language Models ist sein Gedächtnis. In diesem Spiel wurde seine größte Stärke jedoch zu einer Schwäche. Als ich ein zweites Spiel startete, wurden verwirrende oder irrelevante Fragen gestellt. Mein KI-Gegner behielt natürlich den gesamten Chatverlauf aus dem vorherigen Spiel bei. Es hat versucht, zwei (oder sogar mehr) Spiele gleichzeitig zu analysieren.

Anstatt dieselbe KI-Sitzung wiederzuverwenden, zerstöre ich sie jetzt explizit am Ende jedes Spiels, wodurch die KI im Grunde Amnesie erleidet.

Wenn Sie auf Nochmal spielen klicken, wird das Brett durch die Funktion startNewGameSession() zurückgesetzt und eine neue KI-Sitzung erstellt. Das war eine interessante Lektion im Verwalten des Sitzungsstatus nicht nur in der App, sondern auch im KI-Modell selbst.

Zusätzliche Funktionen: Benutzerdefinierte Spiele und Spracheingabe

Um die Nutzung ansprechender zu gestalten, habe ich zwei zusätzliche Funktionen hinzugefügt:

  1. Benutzerdefinierte Charaktere: Mit getUserMedia() können Spieler mit ihrer Kamera einen eigenen Satz aus fünf Zeichen erstellen. Ich habe IndexedDB verwendet, um die Zeichen zu speichern. Das ist eine Browserdatenbank, die sich perfekt zum Speichern von Binärdaten wie Image-Blobs eignet. Wenn Sie ein benutzerdefiniertes Set erstellen, wird es in Ihrem Browser gespeichert und im Hauptmenü wird eine Option zum Wiederholen angezeigt.

  2. Spracheingabe: Das clientseitige Modell ist multimodal. Es kann Text, Bilder und Audio verarbeiten. Mit der MediaRecorder API konnte ich Mikrofoneingaben erfassen und den resultierenden Audio-Blob mit einem Prompt an das Modell senden: „Transkribiere das folgende Audio…“. So macht das Spielen noch mehr Spaß – und es ist auch lustig zu sehen, wie die KI meinen flämischen Akzent interpretiert. Ich habe diese Funktion hauptsächlich entwickelt, um die Vielseitigkeit dieser neuen Webfunktion zu demonstrieren. Aber ehrlich gesagt hatte ich es auch satt, Fragen immer wieder neu einzugeben.

Schlussgedanken

Die Entwicklung von „KI Wer bin ich?“ war definitiv eine Herausforderung. Aber mit ein wenig Hilfe aus der Dokumentation und etwas KI zur Fehlersuche bei KI (ja, das ist Ich habe das gemacht und es hat sich als lustiges Experiment herausgestellt. Es hat das immense Potenzial eines Modells im Browser für eine private, schnelle und internetunabhängige Nutzung aufgezeigt. Es handelt sich noch um ein Experiment und manchmal spielt der Gegner einfach nicht perfekt. Es ist nicht pixel- oder logikperfekt. Bei generativer KI sind die Ergebnisse modellabhängig.

Anstatt nach Perfektion zu streben, konzentriere ich mich darauf, das Ergebnis zu verbessern.

Dieses Projekt hat auch die ständigen Herausforderungen des Prompt-Engineerings unterstrichen. Das Prompting wurde zu einem wichtigen, aber nicht immer angenehmen Teil des Prozesses. Die wichtigste Lektion, die ich gelernt habe, war jedoch, die Anwendung so zu konzipieren, dass die Wahrnehmung von der Deduktion getrennt wird und die Funktionen von KI und Code aufgeteilt werden. Trotz dieser Trennung habe ich festgestellt, dass die KI immer noch (für einen Menschen) offensichtliche Fehler machen kann, z. B. Tattoos mit Make-up verwechseln oder den Überblick darüber verlieren, wessen geheimer Charakter gerade besprochen wird.

Jedes Mal bestand die Lösung darin, die Prompts noch expliziter zu formulieren und Anweisungen hinzuzufügen, die für einen Menschen offensichtlich sind, aber für das Modell unerlässlich sind.

Manchmal fühlte sich das Spiel unfair an. Manchmal hatte ich das Gefühl, dass die KI die geheime Figur schon kannte, obwohl diese Information im Code nie explizit weitergegeben wurde. Hier sehen Sie einen wichtigen Unterschied zwischen Mensch und Maschine:

Das Verhalten einer KI muss nicht nur korrekt sein, sondern sich auch fair anfühlen.

Deshalb habe ich die Prompts mit direkten Anweisungen wie „Du weißt NICHT, welche Figur ich ausgewählt habe“ und „Kein Betrügen“ aktualisiert. Ich habe gelernt, dass man beim Erstellen von KI-Agents mehr Zeit für die Definition von Einschränkungen als für Anweisungen aufwenden sollte.

Die Interaktion mit dem Modell könnte weiter verbessert werden. Wenn Sie mit einem integrierten Modell arbeiten, verlieren Sie zwar etwas von der Leistungsfähigkeit und Zuverlässigkeit eines großen serverseitigen Modells, gewinnen aber an Datenschutz, Geschwindigkeit und Offline-Funktionen. Für ein Spiel wie dieses war es wirklich wert, damit zu experimentieren. Die Zukunft der clientseitigen KI wird jeden Tag besser, die Modelle werden auch immer kleiner und ich bin gespannt, was wir als Nächstes entwickeln können.