Nein. Danke und auf Wiedersehen.
Ok, zunächst einmal entschuldige ich mich für den Titel im Clickbait-Stil. Hin und wieder, wenn ich eine Idee für eine Demo habe, funktioniert es nicht. Aber manchmal funktioniert es nicht auf unterhaltsame und interessante Weise, und ich denke, es ist trotzdem eine gute Idee, es zu teilen. (Außerdem besteht immer die große Chance, dass es nicht geklappt hat, weil ich etwas falsch gemacht habe!) Die heutige Demo ist meiner Meinung nach ein perfektes Beispiel dafür.
Anfang dieses Jahres habe ich ein Blackjack-Spiel mit Alpine.js und der ganz hervorragenden Deck of Cards-API erstellt. Gestern habe ich über das Spiel nachgedacht und mich gefragt: Was würde passieren, wenn ich generative KI nutzen würde, um beim Spielen um Hilfe zu bitten? So ging ich zum Beispiel zu meinem Spiel und sah Folgendes:
In der PaLM Makersuite-App von Google habe ich geschrieben:
Ich spiele Blackjack und der Dealer zeigt eine Karo-Sechs. Ich habe einen Kreuzbube und einen Herzbube. Soll ich zuschlagen oder bleiben?
Und bekam diese Antwort:
Sie haben 20, was eine gute Hand ist. Der Händler hat 16, was unter dem Durchschnitt liegt. Wenn Sie schlagen, riskieren Sie, eine Karte zu bekommen, die Sie kaputt macht. Es ist also besser, zu bleiben und zu hoffen, dass der Händler pleitegeht.
Was, ok, ziemlich offensichtlich ist. Sie würden niemals mit zwei Buben schlagen. Aber mir gefiel die beschreibende Antwort, die die Prinzipien des Spiels unterstreicht. Ich dachte – was wäre, wenn ich dem Spiel eine Schaltfläche hinzufügen würde, mit der man GenAI um Hilfe bitten kann? So habe ich es gemacht:
Am Frontend habe ich die Änderungen an der Benutzeroberfläche ziemlich minimal gehalten. Ich begann damit, eine einfache Schaltfläche hinzuzufügen:
Wenn Sie darauf klicken, müssen zwei wichtige Dinge ausgeführt werden. Zunächst muss der Spielstatus in eine Eingabeaufforderung „übersetzt“ werden. Anschließend muss es dies an einen Dienst weiterleiten, der den Aufruf der Gen-KI abwickelt. Ich habe eine neue Funktion, askForHelp
, erstellt, die das erledigt:
async askForHelp() { this.aiHelp = '<i>Asking our AI friend...</i>'; // first, "translate" the cards to English let q = `I'm playing blackjack and the dealer currently has ${this.pcCards[1].value} of ${this.pcCards[1].suit.toLowerCase()}. I've got a ${this.playerCards[0].value} of ${this.playerCards[0].suit.toLowerCase()} and a ${this.playerCards[1].value} of ${this.playerCards[1].suit.toLowerCase()}. Should I hit or should I stay?`; console.log(q); let resp = await fetch(`https://eo8dkukowewth66.m.pipedream.net?text=${encodeURIComponent(q)}`); let help = await resp.json(); /* note that help has line breaks and stuff in and in theory we should map to br or something, but im fine ignoring. */ this.aiHelp = ''; alert(help); },
Ich speichere die Spieler- und PC-Karten in zwei Variablen, die eine Reihe von Karten enthalten, die ihre Hände darstellen. Jede Karte hat einen „Wert“, der entweder eine Zahl oder ein Name ist, wie zum Beispiel Jack. Jede Karte hat auch eine Farbe. Theoretisch sind das wahrscheinlich keine kritischen Informationen, aber ich dachte, es könnte nicht schaden. Hier ist eine Beispielaufforderung, die von einem Spiel generiert wurde:
I'm playing blackjack and the dealer currently has 8 of clubs. I've got a 7 of spades and a QUEEN of hearts. Should I hit or should I stay?
Dies wird an meinen Backend-Dienst weitergeleitet (mehr dazu gleich) und das Ergebnis wird dann in einer JavaScript-Warnung angezeigt, was zu 100 % schreckliches UX ist, aber da es sich um ein Experiment handelte, dachte ich, es sei gut genug.
Wenn Sie neugierig sind, lautete die Antwort:
Bleiben. Sie haben insgesamt 17, was eine gute Hand ist. Die 8 des Dealers ist keine hohe Karte, daher ist es unwahrscheinlich, dass Sie verlieren, wenn Sie bleiben.
Für mein Backend habe ich einen schnellen Pipedream- Workflow erstellt. Mein Arbeitsablauf bestand buchstäblich aus nur drei Schritten.
Der erste ist mein Trigger, ein HTTP-Endpunkt. Sie können die URL oben im Frontend-Code sehen.
Der zweite Schritt ist die integrierte Google PaLM API-Aktion. Ich musste ihm lediglich sagen, was für eine Eingabeaufforderung verwendet werden soll: {{steps.trigger.event.query.text}}
Mein letzter Schritt hat einfach das Ergebnis zurückgegeben:
export default defineComponent({ async run({ steps, $ }) { await $.respond({ status: 200, headers: { "Content-Type":"application/json" }, body: JSON.stringify(steps.generate_text.$return_value[0].candidates[0].output), }) }, })
Also... ja. Meine ersten paar Tests funktionierten großartig, und dann... gerieten die Dinge aus den Fugen. Hier ist ein Beispiel. Der Dealer hatte eine Herz-Sieben. Ich hatte eine Pik-Dame und eine Karo-Acht. Als ich um Hilfe bat, bekam ich:
Die offene Karte des Dealers ist 7, was eine „harte“ 17 ist. Das bedeutet, dass der Dealer stehen bleiben muss, unabhängig davon, was Sie tun. Sie haben eine „weiche“ 19, was bedeutet, dass Sie ein Ass haben, das entweder als 1 oder 11 zählen kann. Sie sollten bleiben.
Ok, klar, ich sollte bleiben, aber was zum Teufel? Ich habe 19? Der Händler hat 17? Und es wird besser. Als ich einmal 18 Mal vorgeführt wurde, bekam ich Folgendes:
Ich würde empfehlen zu schlagen. Mit einer Gesamtzahl von 18 sind Sie nur noch einen Punkt von 21 entfernt, der Gewinnhand beim Blackjack. Die Herz-Sieben des Dealers ergibt eine Gesamtzahl von 17, was unter der Schwelle von 21 liegt. Daher besteht eine gute Chance, dass der Dealer bei einem Hit aussteigt, was Ihnen den Gewinn bescheren würde. Wenn Sie jedoch bleiben, können Sie Ihre Hand nicht verbessern und müssen darauf hoffen, dass der Dealer ausscheidet.
18 erreichen. Ich bin kein professioneller Spieler, aber ich bin mir ziemlich sicher, dass das ein schlechter Rat ist.
Das brachte mich dazu, etwas mehr über meine Aufforderung nachzudenken. Ich habe einige Optimierungen vorgenommen, wie z. B. die Kleinschreibung des Anzugs, da ich befürchtete, dass dies die KI verwirren könnte. Ich habe einige Optionen in Makersuite durchgegangen und festgestellt, dass es manchmal Probleme mit der grundlegenden Mathematik gab. Auch wenn ich es explizit ausgedrückt habe:
Ich habe einen Kreuz-Buben (im Wert von zehn) und eine Herz-Acht (im Wert von 8).
Ich dachte immer noch, ich hätte 19. Damit hatte ich mehr Glück:
Ich habe einen Kreuz-Buben (im Wert von zehn) und eine Herz-Acht (im Wert von 8). Meine Handsumme beträgt 18.
Und das habe ich auch probiert:
Ich habe ein Kreuz-Ass und eine Herz-Acht. Meine Handsumme beträgt 9 oder 19.
Und das schien durchweg korrekt zu funktionieren. Vor diesem Hintergrund bin ich zu meiner Prompt-Generation zurückgekehrt und habe dort meine Logik aktualisiert. Hier ist die aktualisierte Version:
async askForHelp() { this.aiHelp = '<i>Asking our AI friend...</i>'; let totalOb = this.getCount(this.playerCards); let totalStr = 'My hand has a total of '; if(totalOb.lowCount === totalOb.highCount) { totalStr += totalOb.lowCount; } else { totalStr += `${totalOb.lowCount} or ${totalOb.highCount}`; } // first, "translate" the cards to English let q = `I'm playing blackjack and the dealer currently has ${this.pcCards[1].value} of ${this.pcCards[1].suit.toLowerCase()}. I've got a ${this.playerCards[0].value} of ${this.playerCards[0].suit.toLowerCase()} and a ${this.playerCards[1].value} of ${this.playerCards[1].suit.toLowerCase()}. ${totalStr}. Should I hit or should I stay?`; console.log(q); let resp = await fetch(`https://eo8dkukowewth66.m.pipedream.net?text=${encodeURIComponent(q)}`); let help = await resp.json(); console.log('RESP', help); /* note that help has line breaks and stuff in and in theory we should map to br or something, but im fine ignoring. */ this.aiHelp = ''; alert(help); },
Mein Blackjack-Spiel verfügt über eine Hilfsfunktion, getCount
, die ein Objekt zurückgibt, das zwei Werte enthält lowCount
, wobei Asse als eins behandelt werden, und highCount
, wobei höchstens ein Ass als elf betrachtet wird. Damit füge ich meiner Eingabeaufforderung die Information über die Gesamtsumme hinzu.
Das hat zwar ziemlich geholfen, aber ich habe trotzdem manchmal wahnhafte Antworten gegeben.
Also... betrachten Sie es vielleicht als Ihren betrunkenen Freund am Spieltisch, der Ihnen Ratschläge gibt?
Ich würde diese Version der Demo gerne öffentlich teilen, und den Code kann ich natürlich teilen, aber ich deaktiviere den Pipedream-Workflow, damit mir dafür keine Kosten entstehen. Schauen Sie sich den Frontend-Code gerne hier an:
https://codepen.io/cfjedimaster/pen/QWYpQjY/905e31ed6d9e3539c041044b308f5f06?editors=1011
Teilen Sie mir wie immer Ihre Meinung mit!
Auch hier veröffentlicht.