Einen Ticket-Zusammenfassungs-Endpunkt hinzufügen

ShellBeginner
Jetzt üben

Einführung

Eine Anwendung folgt normalerweise Regeln, die direkt in ihrem Code stehen. Inferenz mit künstlicher Intelligenz (KI) fügt eine andere Art von Vorgang hinzu: Ihre Anwendung sendet Eingaben an ein trainiertes Modell, und das Modell erzeugt ein Ergebnis. Die Anweisung und der Kontext, die an das Modell gesendet werden, heißen Prompt. Der erzeugte Text kann sich zwischen Anfragen unterscheiden. Deshalb steuert eine zuverlässige Anwendung die Eingaben und prüft das Ergebnis, statt einen ganz bestimmten Satz zu erwarten.

Cloudflare Workers AI ermöglicht es einem Worker, unterstützte KI-Modelle über die Cloudflare-Plattform auszuführen. Ein Worker ist Anwendungscode, der auf dem Cloudflare-Netzwerk auf Anfragen reagiert. Ein AI-Binding ist die konfigurierte Verbindung, über die Workers AI dem Code als env.AI zur Verfügung steht. Dadurch müssen Sie keinen separaten API-Schlüssel eines anderen Anbieters im Projekt hinterlegen.

In diesem Lab benötigt eine Supportanwendung eine kurze Zusammenfassung eines Tickets, bevor ein Agent die vollständige Beschreibung öffnet. Sie konfigurieren ein AI-Binding, implementieren einen POST /summaries-Endpunkt, lehnen ungeeignete Eingaben ab, bevor sie Inferenz verbrauchen, testen denselben Worker lokal, stellen ihn bereit und untersuchen die tatsächlichen Worker- und AI-Aktivitäten im Cloudflare Dashboard. Das Lab verwendet @cf/meta/llama-3.3-70b-instruct-fp8-fast, ein von Cloudflare gehostetes Modell, das über die standardmäßige kostenlose Workers-AI-Zuteilung verfügbar ist. Der genaue Wortlaut der Antwort wird nicht bewertet, sondern der Anwendungsvertrag.

Schließen Sie vor Beginn dieses Kurses Connect LabEx to Your Cloudflare Account ab. Dort lernen Sie das LabEx-VM-Terminal, die Geräteautorisierung, die Bestätigung des Kontos und das Speichern der tatsächlichen Konto-ID kennen. Sie sollten außerdem wissen, wie ein kleiner JavaScript-Worker eine HTTP-Anfrage verarbeitet. Kenntnisse im maschinellen Lernen sind nicht erforderlich.

Workers AI stellt kostenlosen Worker-Konten derzeit täglich eine gemeinsame Zuteilung von 10.000 Neurons bereit. Neurons sind die von Cloudflare verwendete Einheit für den Rechenaufwand von Modellen. Dieses Lab hält Prompts und Ausgaben klein und erfordert keinen kostenpflichtigen Tarif. Andere Aktivitäten in demselben Konto verwenden jedoch dieselbe Zuteilung. Lesen Sie vor Beginn die aktuelle Llama-3.3-Modellseite und die Workers-AI-Preise. Wenn die tägliche Zuteilung bereits aufgebraucht ist, schlägt die Inferenz fehl, bis das Limit zurückgesetzt wird. Erzeugen Sie keine wiederholten Aufrufe, um das Limit zu umgehen. Auch die lokale Entwicklung mit Workers AI verwendet das Cloud-Modell und zählt zur Zuteilung. Sie ist keine Offline-Simulation.

Das Setup installiert Node.js 22.22.0 und Wrangler 4.132.0 lokal im Projektverzeichnis /home/labex/project/ticket-summary. Außerdem stellt es deterministische Tests bereit, die die AI-Antwort nachahmen, ohne Modellaufrufe auszuführen. Während des Setups erfolgen keine Anmeldung, Tarifänderung, Bereitstellung oder Inferenz. Lassen Sie diese VM geöffnet, bis der temporäre Worker gelöscht und die Abmeldung überprüft wurde.

Die VM autorisieren und ein Konto auswählen

In diesem Schritt verbinden Sie diese neue LabEx-VM mit Ihrem Cloudflare-Lernkonto und erstellen eine eindeutige Worker-Konfiguration. Eine Browsersitzung im Dashboard autorisiert Terminalbefehle in der VM nicht automatisch.

Wechseln Sie in das vorbereitete Projekt und prüfen Sie die festgelegte Wrangler-Version:

cd /home/labex/project/ticket-summary
npx wrangler --version

Erwartet wird 4.132.0. Starten Sie die Geräteautorisierung mit genau den Berechtigungen, die dieses Lab benötigt. workers_scripts:write ermöglicht das Bereitstellen, Lesen und Löschen des temporären Workers. ai:write erlaubt dem Worker, Workers AI aufzurufen. Wrangler 4.132.0 prüft beim Löschen eines Workers außerdem Referenzen auf KV-Bindings. workers_kv:write ermöglicht, dass diese Bereinigungsprüfung abgeschlossen wird, obwohl dieses Lab keinen KV-Namespace erstellt. Lesezugriff auf Konto und Benutzer ermöglicht Ihnen, das gewünschte Konto zu bestätigen.

npx wrangler login --device --browser=false --scopes account:read user:read workers_scripts:write workers_kv:write ai:write

Öffnen Sie den angezeigten Link im Browser, geben Sie den aktuellen Gerätecode ein, prüfen Sie die Berechtigungen und wählen Sie Ihr Lernkonto aus. Möglicherweise wird auch Background Access angezeigt, da Wrangler nach dem Browserablauf weiterarbeiten muss. Autorisieren Sie erst, wenn Konto und Berechtigungsliste zu diesem Lab passen. Kehren Sie anschließend zum Terminal zurück und warten Sie auf die Erfolgsmeldung.

npx wrangler whoami --json

Bestätigen Sie loggedIn: true. Lesen Sie anschließend name und id des Kontos, das Sie verwenden möchten, auch wenn nur ein Konto aufgeführt ist. Der Name hilft Ihnen, die Verwendung des falschen Kontos zu vermeiden. Die ID ist der stabile Wert, den Wrangler in der Konfiguration speichert.

Erzeugen Sie einen eindeutigen Worker-Namen. openssl rand -hex 6 erstellt 12 zufällige Hexadezimalzeichen, und $(...) fügt sie in die Shell-Variable ein.

RUN="labex-c07-a01-$(openssl rand -hex 6)"
printf '%s\n' "$RUN"

Kopieren Sie die ausgewählte Konto-ID in die folgende Konfiguration, indem Sie YOUR_ACCOUNT_ID ersetzen. Ein Here-Dokument schreibt die Zeilen zwischen den beiden Markierungen JSON in wrangler.jsonc. Die nicht quotierte Markierung ermöglicht die Expansion von $RUN; der Backslash sorgt dafür, dass der Schlüssel $schema wörtlich bleibt.

cat > wrangler.jsonc <<JSON
{
  "\$schema": "./node_modules/wrangler/config-schema.json",
  "name": "$RUN",
  "account_id": "YOUR_ACCOUNT_ID",
  "main": "src/index.js",
  "compatibility_date": "2026-09-16",
  "compatibility_flags": ["nodejs_compat"],
  "workers_dev": true,
  "preview_urls": false,
  "observability": {
    "enabled": true,
    "head_sampling_rate": 1
  },
  "ai": {
    "binding": "AI",
    "remote": true
  }
}
JSON

compatibility_date legt das Laufzeitverhalten fest, das in diesem Lab getestet wird. observability bewahrt Aufrufe und Anwendungsprotokolle für den späteren Dashboard-Checkpoint auf. Durch das Schreiben der Datei wird kein Worker bereitgestellt und kein Modell aufgerufen.

Das Workers-AI-Binding untersuchen

In diesem Schritt wandeln Sie die Konfiguration in eine typisierte Beschreibung der Worker-Umgebung um und verknüpfen den Namen des Bindings mit dem Code, den Sie als Nächstes schreiben.

Ein Binding ist eine benannte Funktion, die von der Workers-Laufzeit bereitgestellt wird. Der Name AI in wrangler.jsonc bedeutet, dass der Worker Modelle über env.AI ausführt. Im Quellcode gibt es kein API-Token: Cloudflare verbindet den bereitgestellten Worker mit dem ausgewählten Konto. Die Einstellung remote: true ist bei wrangler dev wichtig, weil die Modellinferenz immer auf Cloudflare stattfindet, auch wenn der Request-Handler selbst auf dieser VM läuft.

Erzeugen Sie anhand der Projektkonfiguration die Beschreibung der Umgebungs-Typen:

npx wrangler types

Wrangler erstellt worker-configuration.d.ts. Suchen Sie nach dem generierten Env-Eintrag, statt die gesamte Datei zu lesen:

grep -A4 'interface __BaseEnv_Env' worker-configuration.d.ts

Die Ausgabe enthält ein AI-Binding ähnlich wie dieses:

interface __BaseEnv_Env {
    AI: Ai;
}

Wrangler legt generierte Bindings in einem Basis-Interface ab und erweitert dieses anschließend mit Env. Die Zeile AI: Ai ist die wichtige Konsistenzprüfung: Wenn Sie den Binding-Namen in der Konfiguration ändern, aber den Code nicht aktualisieren, würde die Bereitstellung sonst erfolgreich beginnen und der Worker erst zur Laufzeit fehlschlagen. Erzeugen Sie die Typen immer neu, wenn sich Bindings ändern. Ein vollständiger Bereitstellungs-Testlauf validiert später sowohl diese Konfiguration als auch das Worker-Bundle gemeinsam.

Einen begrenzten Zusammenfassungs-Endpunkt erstellen

In diesem Schritt implementieren Sie die Anfragegrenze und den Modellaufruf. Ein Sprachmodell kann gut eine kompakte Erklärung erzeugen. Es sollte jedoch nicht selbst entscheiden, ob eine beliebige Anfrage sicher verarbeitet werden kann. Gewöhnlicher Anwendungscode muss den falschen Inhaltstyp, ungültiges JSON, fehlende Details und zu große Eingaben ablehnen, bevor eine Inferenz ausgeführt wird.

Der Endpunkt sendet zwei Nachrichten an das Modell. Eine Systemnachricht definiert die Rolle des Modells und die Einschränkung für die Antwort. Eine Benutzernachricht enthält das synthetische Ticket. Modelle lesen und erzeugen Tokens. Das sind kleine Textteile, die ein Wort, ein Wortteil oder ein Satzzeichen sein können. max_tokens begrenzt die erzeugte Ausgabe, während die Anwendung die eingehenden Zeichen separat begrenzt. Das sind zwei unterschiedliche Kontrollen: Die eine begrenzt, was Sie senden, die andere, was das Modell erzeugen kann. temperature steuert die mögliche Variation. Der niedrige Wert hier begünstigt eine gleichmäßige Zusammenfassung, garantiert aber keinen identischen Wortlaut.

Erstellen Sie den Einstiegspunkt des Workers:

cat > src/index.js <<'JS'
const MODEL = "@cf/meta/llama-3.3-70b-instruct-fp8-fast";
const MAX_DETAILS = 2000;

function json(data, status = 200) {
  return Response.json(data, { status });
}

async function readTicket(request) {
  const contentType = request.headers.get("content-type") || "";
  if (!contentType.toLowerCase().includes("application/json")) {
    return { error: json({ error: "json_required" }, 415) };
  }

  const raw = await request.text();
  if (raw.length > 4096) {
    return { error: json({ error: "ticket_too_large" }, 413) };
  }

  let body;
  try {
    body = JSON.parse(raw);
  } catch {
    return { error: json({ error: "invalid_json" }, 400) };
  }

  const subject = typeof body?.subject === "string" ? body.subject.trim() : "";
  const details = typeof body?.details === "string" ? body.details.trim() : "";
  if (!details) {
    return { error: json({ error: "invalid_ticket" }, 400) };
  }
  if (subject.length > 120 || details.length > MAX_DETAILS) {
    return { error: json({ error: "ticket_too_large" }, 413) };
  }
  return { ticket: { subject, details } };
}

async function summarize(request, env) {
  const requestId = crypto.randomUUID();
  const parsed = await readTicket(request);
  if (parsed.error) return parsed.error;

  try {
    const result = await env.AI.run(MODEL, {
      messages: [
        {
          role: "system",
          content: "Summarize this support ticket in one plain sentence. Do not invent facts."
        },
        {
          role: "user",
          content: `Subject: ${parsed.ticket.subject || "(none)"}\nDetails: ${parsed.ticket.details}`
        }
      ],
      max_tokens: 120,
      temperature: 0.2
    });

    const summary = result.response?.trim();
    if (!summary) throw new Error("empty model response");

    console.log(JSON.stringify({
      event: "ticket_summarized",
      requestId,
      model: MODEL,
      inputCharacters: parsed.ticket.details.length,
      totalTokens: result.usage?.total_tokens ?? null
    }));

    return json({ summary, model: MODEL, requestId });
  } catch (error) {
    console.error(JSON.stringify({
      event: "ticket_summary_failed",
      requestId,
      model: MODEL,
      reason: error instanceof Error ? error.message : "unknown"
    }));
    return json({ error: "model_unavailable", requestId }, 502);
  }
}

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    if (request.method === "GET" && url.pathname === "/health") {
      return json({ status: "ok" });
    }
    if (request.method === "POST" && url.pathname === "/summaries") {
      return summarize(request, env);
    }
    return json({ error: "not_found" }, 404);
  }
};
JS

Jede Anfrage erhält eine zufällige Anfrage-ID, die sowohl in der Antwort als auch im Protokoll erscheint. So lässt sich eine einzelne Anfrage verfolgen, ohne ihr Ticket zu protokollieren. Der Code protokolliert diese ID, die Modellauswahl und Zähler, aber nicht den Tickettext. Dadurch wird die spätere Observability—also die Aufzeichnung von Informationen über das Verhalten des Workers—nützlich, ohne Kundendaten in Überwachungsdaten zu kopieren. Außerdem überprüft der Code die vom konkreten Modell zurückgegebene Zeichenkette response, statt davon auszugehen, dass jedes Workers-AI-Modell dasselbe Objekt zurückgibt.

Führen Sie die bereitgestellten deterministischen Tests aus. Sie ersetzen env.AI durch ein kleines Fixture. Daher verbrauchen diese Tests keine Modellnutzung:

node --test test/worker.test.mjs

Erwartet werden vier erfolgreiche Tests. Bitten Sie Wrangler anschließend, den Worker zu erstellen, ohne ihn bereitzustellen:

npx wrangler deploy --dry-run

Die Tests belegen die Ein- und Ausgabe-Verträge mit kontrollierten Modelldaten. Der Testlauf belegt, dass Wrangler den tatsächlichen Worker bündeln kann. Keiner der beiden Schritte beweist, dass das Modell derzeit verfügbar ist oder dass dieses Konto noch über eine tägliche kostenlose Zuteilung verfügt. Das prüfen Sie als Nächstes mit einer echten Anfrage.

Eine lokale Inferenz ausführen

In diesem Schritt führen Sie den Request-Handler auf der VM aus, während sein AI-Binding das echte, von Cloudflare gehostete Modell aufruft. Dies wird lokale Entwicklung genannt. Lokal läuft jedoch nur der Worker-Prozess; die Inferenz erfolgt remote und wird abgerechnet.

Starten Sie Wrangler im Hintergrund auf Port 8787. > speichert Protokolle in einer Datei, 2>&1 leitet Fehler in dieselbe Datei um, und & gibt die Terminal-Eingabeaufforderung zurück, während der Server weiterläuft. Durch das Speichern von $! sichern Sie die Prozess-ID für die Bereinigung.

npx wrangler dev --port 8787 > .labex/dev.log 2>&1 &
echo $! > .labex/dev.pid

Warten Sie, bis die Health-Route antwortet:

for attempt in $(seq 1 30); do
  if curl --silent --fail http://127.0.0.1:8787/health; then
    break
  fi
  sleep 1
done

Die Health-Antwort sollte {"status":"ok"} lauten und ruft das Modell nicht auf. Senden Sie nun ein kleines synthetisches Ticket. --data macht daraus eine POST-Anfrage, während der Header dem Worker mitteilt, JSON zu verarbeiten.

curl --silent --show-error http://127.0.0.1:8787/summaries \
  --header 'Content-Type: application/json' \
  --data '{"subject":"Invoice upload fails","details":"After signing in, the customer selects a PDF invoice. The upload stops before completion and no confirmation appears."}' | jq

Erwartet werden ein nichtleeres summary, die exakte Modell-ID und eine anwendungsspezifische requestId. Ihr Satz kann vom folgenden Beispiel abweichen:

{
  "summary": "The customer cannot complete a PDF invoice upload after signing in.",
  "model": "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
  "requestId": "..."
}

Beweisen Sie, dass ungültige Eingaben vom gewöhnlichen Code vor der Inferenz abgelehnt werden:

curl --silent --show-error --write-out '\nHTTP %{http_code}\n' \
  http://127.0.0.1:8787/summaries \
  --header 'Content-Type: application/json' \
  --data '{"details":""}'

Erwartet werden {"error":"invalid_ticket"} und HTTP 400. Die Anwendung sendet diese Anfrage nicht an das Modell. Wenn die gültige Anfrage model_unavailable meldet, untersuchen Sie .labex/dev.log. Eine erschöpfte kostenlose Zuteilung, fehlende Modellkapazität oder ein Autorisierungsfehler belegt nicht, dass der Endpunktvertrag erfüllt wurde.

Den AI-Worker bereitstellen und untersuchen

In diesem Schritt stoppen Sie den lokalen Prozess, stellen denselben Code bei Cloudflare bereit und verknüpfen Belege aus der Befehlszeile mit dem sichtbaren Dashboard-Zustand.

Stoppen Sie nur den gespeicherten Entwicklungsprozess und warten Sie, bis er beendet ist:

kill "$(cat .labex/dev.pid)"
wait "$(cat .labex/dev.pid)" 2>/dev/null || true

Stellen Sie den Worker bereit:

npx wrangler deploy

Wrangler gibt die öffentliche workers.dev-URL aus. Speichern Sie genau diese URL und ersetzen Sie den Beispielwert:

WORKER_URL="https://YOUR_WORKER_URL"

Senden Sie ein neues synthetisches Ticket an den bereitgestellten Endpunkt:

curl --silent --show-error "$WORKER_URL/summaries" \
  --header 'Content-Type: application/json' \
  --data '{"subject":"Password reset loop","details":"The customer opens the reset email, chooses a new password, and returns to the sign-in page, but the old password remains active."}' | jq

Der erzeugte Satz kann abweichen. model muss jedoch Llama 3.3 erkennen lassen, und requestId muss vorhanden sein. Damit ist nachgewiesen, dass der öffentliche Worker sein konfiguriertes AI-Binding erreicht hat.

Öffnen Sie das Cloudflare Dashboard und gehen Sie zu Workers & Pages → Overview → Ihrem labex-c07-a01-...-Worker → Settings → Bindings. Suchen Sie das Workers-AI-Binding AI. Dies ist die sichtbare Verbindung zwischen wrangler.jsonc und env.AI im Code.

Worker mit dem Workers-AI-Binding namens AI verbunden

Das Beispiel zeigt den Binding-Namen AI, der mit dem in env.AI verwendeten Namen übereinstimmt. Der Name Ihres temporären Workers wird anders sein.

Öffnen Sie anschließend Observability → Logs für denselben Worker. Suchen Sie einen aktuellen erfolgreichen Aufruf und erweitern Sie das strukturierte ticket_summarized-Protokoll. Vergleichen Sie seine Request-ID mit der Antwort des bereitgestellten Workers. Das Protokoll sollte das Modell und die Zähler anzeigen, nicht jedoch den Tickettext. Wenn gespeicherte Protokolle noch nicht angekommen sind, verwenden Sie Real-time logs, senden Sie eine weitere kleine synthetische Anfrage und untersuchen Sie diesen Aufruf.

Workers-Observability mit erfolgreichen Anfragen im Free-Tarif

Die Übersicht bestätigt zunächst, dass Anfragen den Worker ohne Fehler erreicht haben. Wenn Sie eine Anfrage öffnen, wird das strukturierte Anwendungsereignis angezeigt:

Strukturiertes ticket_summarized-Protokoll mit Modell, Tokenanzahl und Request-ID ohne Tickettext

Beachten Sie, dass das Protokoll technische Informationen wie Modell, Tokenanzahl und Request-ID enthält, nicht jedoch Betreff oder Details des Supporttickets. Diese Grenze für den Datenschutz entsteht durch den von Ihnen geschriebenen Protokollierungscode.

Öffnen Sie schließlich Workers AI in der Navigation der Developer Platform und untersuchen Sie die Nutzungsansicht. Suchen Sie nach aktuellen Modellaktivitäten oder Neuron-Nutzung, die mit diesem begrenzten Test verbunden sind. Nutzungsdaten können später als die Anfrage eintreffen. Ein unmittelbar leeres Diagramm ist daher nicht aussagekräftig und sollte nicht durch wiederholte Inferenzaufrufe „behoben“ werden.

Workers-AI-Neuron-Nutzung für das Llama-3.3-Modell innerhalb der täglichen Free-Zuteilung

Hier bedeutet 20.32/10k, dass dieser Abnahmelauf nur einen kleinen Teil der täglichen Free-Zuteilung dieses Kontos verbraucht hat. Ihre Gesamtsumme umfasst alle anderen Workers-AI-Aktivitäten in Ihrem Lernkonto und wird daher nicht mit dem Screenshot übereinstimmen.

Die Dashboard-Screenshots in diesem Lab zeigen Beispielwerte aus einem einmaligen Abnahmelauf. Worker-Name, Request-ID, Zeitstempel, Tokenanzahl und Nutzungswerte werden bei Ihnen anders sein.

Den Worker löschen und sich abmelden

In diesem Schritt entfernen Sie die temporäre Cloud-Anwendung und widerrufen anschließend die Wrangler-Sitzung dieser VM. Durch das Löschen des Workers wird sein öffentlicher Endpunkt deaktiviert. Ihr Workers-Tarif und kontoweite Nutzungsdaten werden dadurch nicht geändert oder gelöscht.

Löschen Sie den in wrangler.jsonc angegebenen Worker:

npx wrangler delete

Bestätigen Sie die Löschung, wenn Wrangler den eindeutigen Namen dieses Labs anzeigt. Löschen Sie keine andere Anwendung. Kehren Sie im Dashboard zu Workers & Pages → Overview zurück und bestätigen Sie, dass der genaue labex-c07-a01-...-Worker nicht mehr vorhanden ist. Historische Protokolle oder Nutzungsdaten können nach dem Löschen des Scripts weiterhin vorhanden sein.

Wrangler prüft vor dem Abschluss, ob ein anderer Worker von diesem abhängt. Deshalb enthielt die frühere Anmeldung Zugriff für die KV-Bereinigung, obwohl Ihre Anwendung KV nicht verwendet hat. Nach einer erfolgreichen Löschung sollte die Eingabeaufforderung ohne Authentifizierungsfehler erscheinen.

Führen Sie die Löschprüfung aus, solange die VM noch autorisiert ist:

python3 .labex/verify.py deleted

Entfernen Sie erst, nachdem PASS: deleted gemeldet wurde, die gespeicherte Autorisierung:

npx wrangler logout
npx wrangler whoami --json

Die letzte Ausgabe muss loggedIn: false melden. Ein Netzwerkfehler ist kein Nachweis für eine erfolgreiche Abmeldung.

Zusammenfassung

Sie haben einen Worker über ein AI-Binding mit einem von Cloudflare gehosteten Modell verbunden, Eingaben und erzeugte Ausgaben begrenzt, deterministisches Verhalten vor dem Verbrauch von Modellnutzung getestet, echte Inferenz lokal und nach der Bereitstellung ausgeführt und die Antwort mit Binding-, Protokoll- und Nutzungsnachweisen im Dashboard verknüpft. Außerdem haben Sie den temporären Worker gelöscht und die neue VM sicher abgemeldet.