Den langsamen Schritt finden
Einen Modellaufruf nachzuverfolgen heißt, aufzuzeichnen, was jeder Schritt einer Anfrage getan hat und wie lange er dauerte. Das ist wichtig, weil eine Funktion mit Modell mitten in einer Kette scheitert. Je eine Logzeile am Anfang und am Ende sagt nicht, wo.
Eine Nutzerin meldet, Antworten dauerten zehn Sekunden. Lag es am Prompt, am Modell, an einer Wiederholung oder an der Prüfung danach? Ein Trace beantwortet das auf einen Blick.
Am Ende dieser Lektion
Notiz
Ich kann aufzeichnen, was jeder Aufruf getan hat, um die Quelle eines Fehlers oder einer Verzögerung zu finden.
Schlüsselwörter
| Begriff | Was er bedeutet |
|---|---|
| Trace | die Aufzeichnung einer Anfrage von Anfang bis Ende |
| Span | ein zeitlich gemessener Schritt in einem Trace |
| Elternteil | der Span, der einen anderen Span enthält |
| Attribut | eine benannte Angabe, die an einem Span hängt |
| Trace-ID | die Kennung, die alle Spans einer Anfrage teilen |
| Schwärzen | Geheimnisse entfernen, bevor ein Eintrag gespeichert wird |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Ein Trace ist ein Baum aus Spans
Ein Trace ist eine Anfrage. Er besteht aus Spans. Jeder Span hat einen Namen, einen Start, ein Ende und ein Elternteil: den Span, der ihn enthält. Nur ein Span hat kein Elternteil. Er ist die Wurzel.
Alle Spans einer Anfrage tragen dieselbe Trace-ID. So fügt ein Speicher sie wieder zusammen. Ein Span hält auch Attribute, etwa die Route oder das Ergebnis.
Durchgerechnetes Beispiel: eine Anfrage
| Span | Elternteil | Start | Ende | Dauer |
|---|---|---|---|---|
| Anfrage | keines | 0 | 856 | 856 ms |
| Prompt bauen | Anfrage | 0 | 4 | 4 ms |
| Modellaufruf | Anfrage | 4 | 854 | 850 ms |
| Antwort prüfen | Anfrage | 854 | 856 | 2 ms |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Was ein Trace nie enthalten darf
Ein Trace-Speicher wird von vielen gelesen und wochenlang aufbewahrt. Darum enthält ein Span nie ein Geheimnis: keinen API-Schlüssel, kein Token, kein Passwort. Er enthält nie personenbezogene Daten: keine E-Mail-Adresse, keinen Namen, keine Telefonnummer.
In der Regel sollte er auch weder den Prompt noch die Antwort speichern. Speichern Sie Größen, Zahlen und Ergebnisse. Entfernen Sie die gefährlichen Schlüssel an einer einzigen Stelle, bevor der Span gespeichert wird. Dieser Schritt heißt Schwärzen.
Ein häufiger Fehler
Warnung
Viele glauben, den ganzen Prompt zu loggen sei harmlos, weil das Log intern ist. Doch Prompts enthalten, was Nutzer getippt haben, und sie tippen Namen und Geheimnisse. Loggen Sie die Länge und das Ergebnis, nicht den Text.
Die Modell-Hilfe schreiben, Teil 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const basis = process.env.AI_URL || \"http://ai:4000\";' '// Die Token einer Antwort oder null, wenn sie keine nennt.' 'function zaehlen(daten, name) {' ' return daten.usage && typeof daten.usage[name] === \"number\" ? daten.usage[name] : null;' '}' > 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 Modell-Hilfe schreiben, Teil 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' '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 || 100 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"Status \" + res.status);' ' const d = await res.json();' ' return { text: d.choices[0].message.content, eingabe: zaehlen(d, \"prompt_tokens\"), ausgabe: zaehlen(d, \"completion_tokens\"), aufgezeichnet: false };' ' } catch (fehler) {' ' console.log(\"Aufgezeichnete Probe: Kein Modell hat geantwortet (\" + fehler.message + \").\");' ' return { text: probe, eingabe: null, ausgabe: null, aufgezeichnet: true };' ' }' '}' '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.
Den Tracer schreiben, Teil 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { fragen } = require(\"./model\");' '' 'let jetzt = 0; // eine Uhr, die wir selbst weiterstellen: alle sehen dieselben Zeiten' 'const spans = [];' 'function weiter(ms) { jetzt = jetzt + ms; }' 'function starten(name, eltern) {' ' const span = { id: spans.length + 1, name, eltern, start: jetzt, ende: jetzt, attribute: {} };' ' spans.push(span);' ' return span;' '}' 'function beenden(span) { span.ende = jetzt; }' > trace1.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 Tracer schreiben, Teil 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' '// Schlüssel, die nie in einen Trace gelangen: Geheimnisse und personenbezogene Daten.' 'const NIE = [\"email\", \"api_schluessel\", \"prompt\", \"name\"];' 'function vermerken(span, schluessel, wert) {' ' span.attribute[schluessel] = NIE.includes(schluessel) ? \"[entfernt]\" : wert;' '}' >> trace1.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 Tracer schreiben, Teil 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function anzeigen(eltern, tiefe) {' ' for (const s of spans) {' ' if (s.eltern === eltern) {' ' console.log(\" \".repeat(tiefe) + s.name + \" \" + (s.ende - s.start) + \" ms \" + JSON.stringify(s.attribute));' ' anzeigen(s.id, tiefe + 1);' ' }' ' }' '}' >> trace1.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 Tracer schreiben, Teil 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function modellSchritt(wurzel) {' ' const aufruf = starten(\"Modellaufruf\", wurzel.id);' ' const nachrichten = [{ role: \"user\", content: \"Nenne eine Verwendung eines Traces in einem Satz.\" }];' ' const antwort = await fragen(nachrichten, \"Ein Trace zeigt, welcher Schritt einer Anfrage langsam war.\", 40);' ' weiter(850); // 850 ms fest auf unserer Uhr, egal wie lange der echte Aufruf dauerte' ' vermerken(aufruf, \"ergebnis\", antwort.text.length > 0 ? \"ok\" : \"leer\");' ' vermerken(aufruf, \"prompt\", nachrichten[0].content);' ' beenden(aufruf);' '}' >> trace1.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 Tracer schreiben, Teil 5
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' const wurzel = starten(\"Anfrage\", 0);' ' vermerken(wurzel, \"route\", \"/frage\");' ' vermerken(wurzel, \"email\", \"[email protected]\");' ' const bauen = starten(\"Prompt bauen\", wurzel.id);' ' weiter(4); beenden(bauen);' ' await modellSchritt(wurzel);' ' const pruefen = starten(\"Antwort prüfen\", wurzel.id);' ' weiter(2); beenden(pruefen); beenden(wurzel);' ' console.log(\"Trace t-0001\");' ' anzeigen(0, 0);' '}' 'main();' >> trace1.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.
Ausführen und den Trace ausgeben
docker exec -w /home/node/project agent node trace1.jsHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Ein Übungs-Trace und wie man ihn liest
Das Labor hat keinen Trace-Dienst. Darum liegen die Spans in einer Liste, und die Uhr ist eine Zahl, die das Skript weiterstellt. Ein echtes System schickt seine Spans an einen Trace-Dienst und liest die echte Uhr. Die Form bleibt gleich.
Den langsamen Schritt finden Sie mit der eigenen Zeit: die Dauer eines Spans minus die Dauern seiner Kinder. Ein Elternteil wirkt immer langsam, denn es enthält seine Kinder.
Eine mögliche Ausgabe
| Zeile | Was sie zeigt |
|---|---|
| Trace t-0001 | Die Trace-ID |
| Anfrage 856 ms | Die Wurzel, mit der Route und der entfernten E-Mail |
| Prompt bauen 4 ms | Ein Kind, zwei Leerzeichen eingerückt |
| Modellaufruf 850 ms | Der langsame Schritt, mit entferntem Prompt |
| Antwort prüfen 2 ms | Das letzte Kind |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.