Ein Chatbot ist eine Schleife um einen Aufruf
Ein Kommandozeilen-Assistent ist ein Programm, das eine Zeile liest, die Sie tippen, und sie an ein Sprachmodell sendet. Es gibt die Antwort aus und wiederholt das, bis Sie beenden. Es ist das kleinste nützliche Programm auf Basis eines Modells.
Es ist wichtig, weil es alles Bisherige vereint. Es hat Nachrichten, einen Verlauf, einen Strom und einen gescheiterten Aufruf, der den Chat nicht zerstören darf.
Am Ende dieser Lektion
Notiz
Ich kann Modellaufrufe zu einem Programm zusammenfügen, das eine Person benutzen kann.
Schlüsselwörter
| Begriff | Was er bedeutet | Beispiel |
|---|---|---|
| Schleife | Code, der sich wiederholt, bis ihm gesagt wird, dass er aufhören soll | |
| Befehl | eine getippte Zeile, die das Programm steuert, nicht das Modell | /ende |
| Verlauf | die früheren Nachrichten, die jeder Aufruf erneut sendet | |
| Kürzen | die ältesten Nachrichten entfernen, damit der Verlauf kurz bleibt | |
| Sauberes Beenden | absichtlich gehen, ohne Fehler und ohne etwas zu verlieren |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Das Programm ist eine Schleife mit einer Liste
Jede Runde macht dieselben Schritte. Eine Zeile lesen. Sie dem Verlauf als user-Nachricht hinzufügen. Die Nachrichten senden. Die Antwort ausgeben. Die Antwort dem Verlauf als assistant-Nachricht hinzufügen.
Die Liste ist das ganze Gedächtnis des Programms. Ist sie falsch, sind es alle späteren Antworten auch.
Teil 1 schreiben: Verlauf und Grenze
docker exec -w /home/node/project agent node -e 'require("fs").writeFileSync("assistent.js", ["// assistent.js, Teil 1: der Verlauf und eine Grenze für seine Länge.", "const labor = require(\"./labor.js\");", "const readline = require(\"readline\");", "const anweisung = { role: \"system\", content: \"Sie sind ein hilfreicher Assistent. Antworten Sie in ein oder zwei kurzen Sätzen.\" };", "const verlauf = [];", "const GRENZE = 6;", "", "// Nur die neuesten Nachrichten behalten, nie mit einer Assistant-Nachricht beginnen.", "function kuerzen() {", " while (verlauf.length > GRENZE) verlauf.shift();", " while (verlauf.length > 0 && verlauf[0].role === \"assistant\") verlauf.shift();", "}"].join("\n") + "\n")'Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Kürzen Sie den Verlauf, damit er kurz bleibt
Jeder Aufruf sendet den ganzen Verlauf. Ein langer Chat kostet daher in jeder Runde mehr und kann die Größe überschreiten, die das Modell lesen kann. Kürzen Sie ihn: Behalten Sie nur die neuesten Nachrichten.
Nach dem Kürzen darf die Liste nicht mit einer assistant-Nachricht beginnen. Ein Chat beginnt mit dem Benutzer, wie Sie in der ersten Lektion gesehen haben.
Teil 2 ergänzen: der Strom
docker exec -w /home/node/project agent node -e 'require("fs").appendFileSync("assistent.js", ["", "// Teil 2: den Verlauf senden und den Strom ausgeben, sobald er ankommt.", "const { stueckeVon } = require(\"./strom.js\");", "async function stromAntwort() {", " let antwort = \"\";", " for await (const stueck of stueckeVon({ max_tokens: 120, messages: [anweisung, ...verlauf] })) {", " antwort += stueck;", " process.stdout.write(stueck);", " }", " if (antwort === \"\") throw new Error(\"kein Wort kam an\");", " return antwort;", "}"].join("\n") + "\n")'Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Teil 3 ergänzen: der Verlauf in Ordnung
docker exec -w /home/node/project agent node -e 'require("fs").appendFileSync("assistent.js", ["", "// Teil 3: den Verlauf in Ordnung halten. Schlägt der Aufruf fehl, wird die Frage entfernt.", "async function antworten(text) {", " verlauf.push({ role: \"user\", content: text });", " try {", " const antwort = await stromAntwort();", " process.stdout.write(\"\\n\");", " verlauf.push({ role: \"assistant\", content: antwort });", " kuerzen();", " } catch (fehler) {", " verlauf.pop();", " console.log(\"\\nAufgezeichnetes Beispiel: Ich erreiche das Modell gerade nicht, dies ist eine aufgezeichnete Antwort. (\" + fehler.message + \")\");", " }", "}"].join("\n") + "\n")'Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Ein häufiger Fehler
Warnung
Viele lassen die Frage im Verlauf, wenn ein Aufruf scheitert. In der nächsten Runde gehen dann zwei user-Nachrichten hintereinander hinaus, und die Reihenfolge bricht. Scheitert ein Aufruf, entfernen Sie die Frage, sagen Sie es und lassen Sie die Person es erneut versuchen.
Befehle und ein sauberes Beenden
Manche Zeilen sind für das Programm, nicht für das Modell. Eine Zeile, die mit / beginnt, ist ein Befehl: /ende geht, /loeschen leert den Verlauf und /verlauf zählt ihn.
Prüfen Sie auf Befehle, bevor Sie das Modell aufrufen. So kann eine Person immer gehen, was auch das Modell tut.
Teil 4 ergänzen: die Schleife
docker exec -w /home/node/project agent node -e 'require("fs").appendFileSync("assistent.js", ["", "// Teil 4: die Schleife. Eine Zeile, die mit / beginnt, ist ein Befehl.", "const zeilen = readline.createInterface({ input: process.stdin });", "const eingabe = () => process.stdout.write(\"Sie> \");", "(async () => {", " console.log(\"Assistent bereit. Befehle: /ende, /loeschen, /verlauf.\");", " eingabe();", " for await (const zeile of zeilen) {", " const text = zeile.trim();", " if (!process.stdin.isTTY) console.log(text);", " if (text === \"/ende\") break;", " if (text === \"/loeschen\") { verlauf.length = 0; console.log(\"Verlauf gelöscht.\"); }", " else if (text === \"/verlauf\") console.log(verlauf.length + \" Nachrichten gespeichert.\");", " else if (text !== \"\") { process.stdout.write(\"Assistent> \"); await antworten(text); }", " eingabe();", " }", " console.log(\"Auf Wiedersehen.\");", " process.exit(0);", "})();"].join("\n") + "\n")'Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Mit einem getippten Skript chatten
printf "Ich heiße Jonas.\nWie heiße ich?\n/verlauf\n/loeschen\n/verlauf\n/ende\n" | docker exec -i -w /home/node/project agent node assistent.jsHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Beispiel: was das Skript getan hat
| Getippt | Was das Programm getan hat |
|---|---|
| Ich heiße Jonas. | Hat 2 Nachrichten gesendet (System und Frage), eine Antwort ausgegeben, 2 behalten |
| Wie heiße ich? | Hat 4 Nachrichten gesendet (System, Frage, Antwort, Frage), eine Antwort ausgegeben, 4 behalten |
| /verlauf | Hat 4 gespeicherte Nachrichten ausgegeben |
| /loeschen | Hat den Verlauf geleert |
| /ende | Hat Auf Wiedersehen ausgegeben und ist gegangen |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Chatten Sie selbst damit
Das Skript oben wurde für Sie getippt. Um von Hand zu chatten, öffnen Sie im Labor ein Terminal und tippen diese Zeile: docker exec -it -w /home/node/project agent node assistent.js. Tippen Sie dann Fragen und beenden Sie mit /ende.
Es wartet auf Ihre Eingabe, ist also kein Knopf. Tippen Sie kein Passwort und nichts Persönliches: Was Sie tippen, wird an ein Modell gesendet.
Zum Weiterdenken: den Assistenten ändern
Ändern Sie die Anweisung in Teil 1, um dem Assistenten eine Persönlichkeit zu geben, und setzen Sie GRENZE auf 4. Chatten Sie sechs Runden lang.
Notieren Sie, was der Assistent vergessen hat und wann. Sagen Sie, was ein langer Verlauf kostet und was Sie dagegen täten.