Lässt es sich mit cremefarbenem Papier, einer Tönung, mehr Kontrast oder größerer Schrift besser lesen? Wählen Sie Ihre Farben und Ihre Schrift, einmalig für alle Seiten.

Kostenlose Lektion

Eine Chatbot-Antwort als Datenstrom in eine Webseite

Nach dieser Lektion: Ich kann eine gestreamte Antwort in einer Webseite anzeigen, während sie ankommt.

Lektion, 60 Min.9 BefehleLab für KI-Coding-Agenten: mit opencode Code erklären und reparieren lassen und die Arbeit prüfen

Die Antwort zeigen, während sie ankommt

Eine Chat-Seite mit Datenstrom zeigt die Antwort eines Chatbots Stück für Stück, wenige Worte auf einmal, noch während sie entsteht. Der Server schickt jedes Stück, sobald er es hat. Das ist wichtig, weil eine lange Antwort viele Sekunden dauern kann und eine leere Seite wirkt, als sei sie kaputt.

Der Server schickt kleine Stücke. Die Seite hängt jedes Stück an den Bildschirm an. Das Labor-Terminal hat keinen Browser, deshalb bauen Sie hier die Seite und den Datenstrom als Text. Auf Ihrem eigenen Rechner würden Sie sie in einem Browser öffnen.

Am Ende dieser Lektion

Notiz

Ich kann eine gestreamte Antwort in einer Webseite anzeigen, während sie ankommt.

Schlüsselwörter

BegriffWas er bedeutet
Datenstromeine Antwort, die in kleinen Stücken gesendet wird
Server-Sent Eventsein Weg, wie ein Server Zeilen an eine Seite schiebt
Handlerdie Funktion, die eine Anfrage beantwortet
MaskierenZeichen so ändern, dass sie als Text erscheinen
Stückein kleiner Teil einer gestreamten Antwort

Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.

Ein Server kann eine Antwort in Stücken senden

Bei Server-Sent Events hält der Server die Verbindung offen und schreibt Zeilen. Jedes Ereignis beginnt mit data: , trägt ein Stück als JSON und endet mit einer Leerzeile. Der Typ der Antwort ist text/event-stream.

Ein letztes Ereignis namens ende sagt der Seite, dass die Antwort fertig ist.

Beispiel: die Zeilen eines Datenstroms

Gesendete ZeileWas die Seite tut
data: {"stueck": "Hallo"} und eine LeerzeileHängt Hallo an den Bildschirm an
data: {"stueck": " und willkommen"} und eine LeerzeileHängt die nächsten Worte dahinter
event: ende, dann data: ende und eine LeerzeileSchließt die Verbindung

Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.

Die Seite hängt an und kann stoppen

Die Seite enthält ein kleines Skript. Es öffnet den Datenstrom und hängt bei jedem Ereignis das Stück an einen Absatz an. Eine Stopp-Taste schließt den Datenstrom, danach kommen keine Stücke mehr.

Ein Stück mit append und einem String anzuhängen fügt einfachen Text ein. Es fügt nie Markup ein.

Modelltext maskieren

Ein Modell kann wiederholen, was man ihm gab, auch <script>. Gelangt dieser Text als HTML in eine Seite, kann der Browser ihn ausführen.

Maskieren macht aus < ein &lt; und aus den anderen Sonderzeichen sichere Codes. Maskieren Sie jeden Modelltext, der in HTML geht. Machen Sie & zuerst, sonst maskieren Sie Ihre eigenen Codes.

Ein häufiger Fehler

Warnung

Viele glauben, Modelltext sei sicher, weil sie den Prompt geschrieben haben. Das stimmt nicht. Das Modell kann die Worte einer Nutzerin oder einer Quelle wiederholen. Behandeln Sie jede Antwort als nicht vertrauenswürdig: Hängen Sie sie als Text an oder maskieren Sie sie vorher.

Die Modellhilfe schreiben, Teil 1

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const basis = process.env.AI_URL || \"http://ai:4000\";' 'async function fragen(nachrichten, probe, max) {' '  try {' '    const res = await fetch(basis + \"/v1/chat/completions\", {' '      method: \"POST\",' '      headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' '      body: JSON.stringify({ model: \"lab\", messages: nachrichten, max_tokens: max || 200 }),' '      signal: AbortSignal.timeout(30000),' '    });' '    if (res.ok === false) throw new Error(\"Status \" + res.status);' '    return (await res.json()).choices[0].message.content;' > model.js"

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Die Modellhilfe schreiben, Teil 2

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' '  } catch (fehler) {' '    console.log(\"Aufgezeichnete Probe: Kein Modell hat geantwortet (\" + fehler.message + \").\");' '    const liste = [].concat(probe);' '    const runde = nachrichten.filter(function (m) { return m.role === \"assistant\"; }).length;' '    return liste[Math.min(runde, liste.length - 1)];' '  }' '}' 'module.exports = { fragen };' >> model.js"

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Seite und Datenstrom schreiben, Teil 1

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { fragen } = require(\"./model\");' '' 'function zitieren(text) { return JSON.stringify(text); }' 'function htmlMaskieren(text) {' '  return text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\")' '    .replace(/\"/g, \"&quot;\").replace(/\x27/g, \"&#39;\");' '}' > oberflaeche4.js"

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Seite und Datenstrom schreiben, Teil 2

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function seitenHtml() {' '  const skript = [' '    \"const ausgabe = document.getElementById(\" + zitieren(\"antwort\") + \");\",' '    \"const strom = new EventSource(\" + zitieren(\"/strom\") + \");\",' '    \"strom.onmessage = function (e) { ausgabe.append(JSON.parse(e.data).stueck); };\",' '    \"strom.addEventListener(\" + zitieren(\"ende\") + \", function () { strom.close(); });\",' '    \"document.getElementById(\" + zitieren(\"stopp\") + \").onclick = function () { strom.close(); };\",' '  ].join(\"\n\");' '  return \"<html><body><p id=antwort></p><button id=stopp>Stopp</button><script>\" + skript + \"</script></body></html>\";' '}' >> oberflaeche4.js"

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Seite und Datenstrom schreiben, Teil 3

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function sseZeile(stueck) { return \"data: \" + JSON.stringify({ stueck: stueck }) + \"\n\n\"; }' 'function stromKoerper(stuecke, stoppNach) {' '  let koerper = \"\";' '  stuecke.slice(0, stoppNach).forEach(function (stueck) { koerper = koerper + sseZeile(stueck); });' '  return stoppNach >= stuecke.length ? koerper + \"event: ende\ndata: ende\n\n\" : koerper;' '}' >> oberflaeche4.js"

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Seite und Datenstrom schreiben, Teil 4

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function bearbeiten(anfrage, stuecke) {' '  if (anfrage.url === \"/\") return { status: 200, typ: \"text/html\", koerper: seitenHtml() };' '  if (anfrage.url === \"/strom\") {' '    return { status: 200, typ: \"text/event-stream\", koerper: stromKoerper(stuecke, anfrage.stoppNach || 99) };' '  }' '  return { status: 404, typ: \"text/plain\", koerper: \"Nicht gefunden\" };' '}' >> oberflaeche4.js"

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Seite und Datenstrom schreiben, Teil 5

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function zeigen(stuecke) {' '  const start = bearbeiten({ url: \"/\" }, stuecke);' '  console.log(\"GET / ->\", start.status, start.typ, start.koerper.length + \" Zeichen\");' '  const live = bearbeiten({ url: \"/strom\" }, stuecke);' '  console.log(\"GET /strom ->\", live.status, live.typ);' '  console.log(live.koerper.split(\"\n\n\").join(\" | \"));' '  const gestoppt = bearbeiten({ url: \"/strom\", stoppNach: 2 }, stuecke);' '  console.log(\"Stopp nach 2 Stücken:\", gestoppt.koerper.split(\"\n\n\").length - 1, \"Stücke gesendet, keine Zeile ende\");' '  console.log(\"Maskiert:\", htmlMaskieren(\"<b>hallo</b> & danke\"));' '}' >> oberflaeche4.js"

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Seite und Datenstrom schreiben, Teil 6

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  // Aufgezeichnete Probe, nur benutzt, wenn kein Modell antwortet.' '  const probe = \"Hallo und willkommen an Bord, wohin möchten Sie fahren?\";' '  const antwort = await fragen([{ role: \"user\", content: \"Begrüßen Sie einen Busfahrgast in einem kurzen Satz.\" }], probe, 40);' '  zeigen(antwort.split(\" \").map(function (wort, stelle) { return stelle === 0 ? wort : \" \" + wort; }));' '}' 'main();' >> oberflaeche4.js"

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Den Handler aufrufen

Befehl
docker exec -w /home/node/project agent node oberflaeche4.js

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Eine mögliche Ausgabe

ZeileWas sie zeigen kann
GET /200 text/html und die Größe der Seite
GET /strom200 text/event-stream, dann die Stücke einer Antwort, getrennt durch |
Stopp2 Stücke gesendet, keine Zeile ende
Maskiert&lt;b&gt;hallo&lt;/b&gt; &amp; danke, immer gleich

Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.

Über dieses Lab und seinen Quellcode: Lab für KI-Coding-Agenten: mit opencode Code erklären und reparieren lassen und die Arbeit prüfen

Sie unterrichten eine Gruppe? Weisen Sie dieses Modul Ihren Studierenden zu, mit Handbuch für Lehrende, automatisch geprüften Aufgaben und einem Lab für jede Person.