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

KI-Aufrufe mit Spans nachverfolgen

Nach dieser Lektion: Ich kann eine Anfrage durch eine KI-Funktion nachverfolgen und im Trace finden, was langsam, teuer oder fehlerhaft war.

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

Warum hat diese Antwort fünf Sekunden gedauert?

Eine KI-Funktion nachzuverfolgen heißt, jeden Modell- und Werkzeugaufruf einer Anfrage zu messen. Ein Support-Assistent plant, ruft zwei Werkzeuge auf, fragt erneut ein Modell und prüft seine Antwort. Eine Nutzerin wartet fünf Sekunden, und die Rechnung ist höher als geplant. Welcher Schritt war langsam, und welcher hat das Geld gekostet?

Modul 69 verfolgte einen einzelnen Aufruf. Diese Lektion geht weiter: ein ganzer Lauf eines Agenten, mit Token, Kosten und Fehlern an jedem Schritt.

Am Ende dieser Lektion

Notiz

Ich kann eine Anfrage durch eine KI-Funktion nachverfolgen und im Trace finden, was langsam, teuer oder fehlerhaft war.

Schlüsselwörter

BegriffWas er bedeutetBeispiel
Span-IDdie Kennung eines einzelnen Spansspan_id
Eltern-IDdie Kennung des Spans, der diesen enthältparent_span_id
Statusob ein Span gut oder mit einem Fehler endetefehler
Werkzeug-Spanein Span für ein Werkzeug, das ein Agent aufrief
Token-Zahlwie viele Token hinein- oder herausgingen
Offener Standardein gemeinsamer Entwurf, den alle nutzen dürfen

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

Ein Span hält Kennungen, Zeiten und Angaben

Jeder Span hat eine Span-ID und die Trace-ID seiner Anfrage. Sein Elternteil nennt er mit einer Eltern-ID, die bei der Wurzel leer ist.

Er hat einen Namen, einen Start, ein Ende und einen Status: ok oder fehler. Angaben stehen in seinen Attributen. OpenTelemetry zählt die Zeit in Nanosekunden seit 1970. Dieses Labor zählt Millisekunden ab dem Start, damit die Zahlen kurz bleiben.

Durchgerechnetes Beispiel: der Span eines Modellaufrufs

FeldWert
trace_id7a3f0c1d00000000000000000000aa01
span_id0000000000000005
parent_span_id0000000000000001
nameModell: Antwort
start und ende3100 und 4900
statusok
attributemodell m-small-2026-08, token_ein 2100, token_aus 300, ausgewichen true

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

Was der Span eines Modellaufrufs aufzeichnet

Zeichnen Sie das Modell und seine Version auf, denn eine neue Version kann Tempo und Kosten ändern. Zeichnen Sie die Token für Eingabe und Ausgabe und die Dauer auf. Halten Sie fest, ob der Aufruf wiederholt wurde oder auf ein anderes Modell auswich.

Legen Sie nie personenbezogene Daten im Klartext an einen Span. Modul 86 zeigt in der Lektion „Sicher protokollieren in einer KI-App“, wie Sie sie fernhalten.

Ein Agent erhält einen Span für jedes Werkzeug

Ein Agent tut mehr, als ein Modell aufzurufen. Er plant, ruft Werkzeuge auf und fragt dann wieder das Modell. Geben Sie jedem Werkzeugaufruf einen eigenen Werkzeug-Span, ein Kind des Spans der Anfrage.

Ein Werkzeug-Span zeichnet den Namen des Werkzeugs, seine Dauer und seinen Status auf. Ein Werkzeug, das scheitert, erscheint als Fehler in einer Anfrage, die trotzdem gut enden kann.

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\";' '// 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 Modellhilfe schreiben, Teil 2

Befehl
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 Trace des Agenten schreiben, Teil 1

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { fragen } = require(\"./model\");' 'const TRACE = \"7a3f0c1d00000000000000000000aa01\";' 'const PREISE = { \"m-large-2026-09\": [3, 15], \"m-small-2026-08\": [1, 4] };' 'const spans = [];' 'function sid(n) { return String(n).padStart(16, \"0\"); }' 'function span(n, eltern, name, start, ende, status, attribute) {' '  spans.push({ trace_id: TRACE, span_id: sid(n), parent_span_id: eltern ? sid(eltern) : \"\",' '    name, start, ende, status, attribute });' '}' > trace2.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 Trace des Agenten schreiben, Teil 2

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'span(1, 0, \"Anfrage des Agenten\", 0, 5000, \"ok\", {});' 'span(2, 1, \"Modell: Plan\", 0, 800, \"ok\", { modell: \"m-large-2026-09\", token_ein: 900, token_aus: 60 });' 'span(3, 1, \"Werkzeug: Bestellung finden\", 800, 1100, \"ok\", { werkzeug: \"bestellung_finden\" });' 'span(4, 1, \"Werkzeug: Liefertermin\", 1100, 3100, \"fehler\", { werkzeug: \"liefertermin\" });' 'span(5, 1, \"Modell: Antwort\", 3100, 4900, \"ok\", { modell: \"m-small-2026-08\", token_ein: 2100, token_aus: 300, ausgewichen: true });' 'span(6, 1, \"Antwort prüfen\", 4900, 5000, \"ok\", {});' 'function kinder(id) { return spans.filter(function (s) { return s.parent_span_id === id; }); }' 'function dauer(s) { return s.ende - s.start; }' >> trace2.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 Trace des Agenten schreiben, Teil 3

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function kosten(a) {' '  const p = PREISE[a.modell];' '  return p ? a.token_ein * p[0] + a.token_aus * p[1] : 0;' '}' 'function zeigen(id, tiefe) {' '  for (const s of kinder(id)) {' '    const marke = s.attribute.ausgewichen ? \", ausgewichen\" : \"\";' '    console.log(\"  \".repeat(tiefe) + s.name + \" \" + dauer(s) + \" ms \" + s.status + marke);' '    zeigen(s.span_id, tiefe + 1);' '  }' '}' >> trace2.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 Trace des Agenten schreiben, Teil 4

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  console.log(\"Trace \" + TRACE);' '  zeigen(\"\", 0);' '  const blaetter = spans.filter(function (s) { return kinder(s.span_id).length === 0; });' '  blaetter.sort(function (a, b) { return dauer(b) - dauer(a); });' '  console.log(\"langsamster Schritt: \" + blaetter[0].name + \", \" + dauer(blaetter[0]) + \" ms\");' '  const bezahlt = spans.filter(function (s) { return kosten(s.attribute) > 0; });' '  bezahlt.sort(function (a, b) { return kosten(b.attribute) - kosten(a.attribute); });' '  console.log(\"teuerster Schritt: \" + bezahlt[0].name + \", \" + kosten(bezahlt[0].attribute) + \" Einheiten\");' '  for (const s of spans.filter(function (x) { return x.status === \"fehler\"; })) {' '    const oben = spans.find(function (x) { return x.span_id === s.parent_span_id; });' '    console.log(\"fehlgeschlagen: \" + s.name + \", in \" + (oben ? oben.name : \"nichts\"));' '  }' >> trace2.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 Trace des Agenten schreiben, Teil 5

Befehl
docker exec -w /home/node/project agent sh -c "printf '%s\n' '  const live = { trace_id: \"7a3f0c1d00000000000000000000aa02\", span_id: sid(7), parent_span_id: \"\",' '    name: \"Modell: Live-Prüfung\", start: 0, ende: 600, status: \"ok\", attribute: {} };' '  const nachrichten = [{ role: \"user\", content: \"Was zeichnet ein Span auf? Antworten Sie in einem kurzen Satz.\" }];' '  const a = await fragen(nachrichten, \"Ein Span zeichnet einen gemessenen Schritt einer Anfrage auf.\", 40);' '  live.attribute = { modell: \"lab\", token_ein: a.eingabe, token_aus: a.ausgabe, aufgezeichnet: a.aufgezeichnet };' '  console.log(\"Live-Span: \" + JSON.stringify(live));' '  console.log(\"Das Modell sagte: \" + a.text);' '}' 'main();' >> trace2.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 Trace ausführen und lesen

Befehl
docker exec -w /home/node/project agent node trace2.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.

Was der Run ausgibt

ZeileWas sie zeigt
Trace 7a3f0c1d00000000000000000000aa01Die Trace-ID, die alle Spans teilen
Werkzeug: Liefertermin 2000 ms fehlerEin Werkzeug-Span, der fehlschlug
Modell: Antwort 1800 ms ok, ausgewichenEin Modell-Span, der ein anderes Modell nutzte
langsamster Schritt: Werkzeug: Liefertermin, 2000 msDer längste Schritt ohne Kinder
teuerster Schritt: Modell: Plan, 3600 EinheitenToken mal Preis seines Modells
Live-Span: {...}Ein echter Aufruf als Span. Seine Token sind null, wenn eine Aufgezeichnete Probe antwortet

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

Einen Trace auf drei Arten lesen

Für das Tempo suchen Sie den Schritt ohne Kinder, der am längsten dauerte. Für die Kosten multiplizieren Sie die Token jedes Modell-Spans mit den Preisen seines Modells.

Für die Fehler listen Sie jeden Span mit dem Status fehler und den Span, in dem er steckt. Ein fehlgeschlagenes Kind in einem Span, der gut endet, heißt: Der Agent hat sich erholt.

Ein häufiger Fehler

Warnung

Viele denken, der langsamste Schritt sei auch der teuerste. Hier ist das Werkzeug für den Liefertermin am langsamsten, aber der Plan-Aufruf kostet am meisten. Warten macht die Zeit, Token machen die Kosten. Prüfen Sie also beides, bevor Sie etwas ändern.

OpenTelemetry ist ein offener Standard für Traces

OpenTelemetry ist ein offener Standard für Traces, Metriken und Logs. Viele Werkzeuge lesen seine Form eines Spans, sodass eine Aufzeichnung mit mehr als einem Speicher funktioniert.

Er hat auch vorläufige Namen für die Attribute von KI-Aufrufen. Diese Entwürfe ändern sich noch, nehmen Sie die Namen unten also als Beispiel. Prüfen Sie die aktuelle Dokumentation, bevor Sie einen verwenden.

Vorläufige Namen, in der aktuellen Dokumentation prüfen

Unser SchlüsselEin vorläufiger NameWas er enthält
modellgen_ai.request.modelDas angefragte Modell
token_eingen_ai.usage.input_tokensDie gesendeten Token
token_ausgen_ai.usage.output_tokensDie erhaltenen Token
werkzeuggen_ai.tool.nameDas aufgerufene Werkzeug
hier keinergen_ai.operation.nameDie Art des Aufrufs, etwa chat

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.