AI Development · Level 1 · Grundlagen

Eine kleine KI-Web-App veröffentlichen

Eine kleine KI-App sicher online bringen: statische Seite plus Serverless-Funktion, API-Schlüssel als Umgebungsvariable, Rate Limits, HTTPS, Logs, Kosten.

Von 9 Min. Lesezeit
Eine kleine KI-App sicher online bringen: statische Seite plus Serverless-Funktion, API-Schlüssel als Umgebungsvariable, Rate Limits, HTTPS, Logs, Kosten.

Ihr Skript aus Teil 1 läuft auf Ihrem Laptop. Damit andere es nutzen können, muss es im Internet laufen — ohne dass Ihr API-Schlüssel offenliegt, ohne Einladung zum Missbrauch und ohne böse Überraschung auf der Rechnung. Software so auf einen Server zu bringen, dass Menschen sie erreichen, nennt man Deployment.

Dies ist Teil 5 und damit der letzte Teil von Level 1 unseres Lernpfads AI Development. Sie richten die einfachste solide Architektur für eine kleine KI-Web-App ein: eine statische Seite und eine Serverless-Funktion. Sie erfahren, wo der API-Schlüssel liegt, wie Sie Anfragen und Kosten begrenzen, wie Sie Ihre eigene Domain mit HTTPS nutzen und was Sie nach dem Start beobachten. Die Anleitung baut auf Ihrem ersten LLM-API-Aufruf auf und auf den Teilen einer KI-App aus Level 0.

Die Architektur: eine statische Seite und eine Funktion

Eine kleine KI-Web-App braucht nur zwei eigene Teile:

  • Das statische Frontend: HTML-, CSS- und JavaScript-Dateien, die der Server unverändert ausliefert — Ihre Seite mit dem Chatfenster. Hosting-Plattformen liefern solche Dateien meist über ein CDN (Content Delivery Network) aus: Server an vielen Orten, die Kopien Ihrer Dateien nah bei Ihren Besuchern bereithalten.
  • Eine Serverless-Funktion: ein kleines Stück Backend-Code, das die Plattform nur dann ausführt, wenn eine Anfrage eintrifft. Einen Server verwalten Sie nicht. Die Plattform startet die Funktion, betreibt so viele Kopien wie nötig und beendet sie wieder. Nur diese Funktion kennt den API-Schlüssel und spricht mit dem Modell.

Architekturdiagramm: Der Browser lädt statische Dateien von der Hosting-Plattform und schickt Fragen an die Funktion /api/ask; die Funktion liest den Schlüssel aus einer Umgebungsvariable, ruft die Modell-API beim Anbieter auf, erhält Antwort und Token-Verbrauch, schreibt Logs und antwortet dem Browser
Eine kleine KI-Web-App: Der Browser spricht nur mit Ihrer Funktion, und nur die Funktion kennt den Schlüssel.

Der Browser spricht nie direkt mit dem Modellanbieter. Alles, was im Browser läuft, kann jeder Besucher lesen — ein Schlüssel in der Seite wäre schnell gefunden. Beide Teile können auch an anderen Orten laufen. Das sind die drei üblichen Wege:

Eine kleine KI-Web-App veröffentlichen
WegWas Sie selbst betreuenPasst, wenn
Hosting-Plattform mit FunktionenIhren Code und die EinstellungenKleine Apps und Prototypen mit wenig bis mittlerem Verkehr
Eigener Server mit KontrollpanelServer, Updates, Sicherheit und ZertifikateSie betreiben schon Server oder brauchen volle Kontrolle
GPU-Cloud für ein eigenes ModellZusätzlich den ModellserverSie betreiben ein Modell mit offenen Gewichten statt der API eines Anbieters

Laut den Anbietern ist Netlify eine Plattform zum Bauen, Ausliefern und Hosten von Websites und Web-Apps. Plesk ist ein Kontrollpanel für Websites, DNS und Datenbanken auf dem eigenen Server. Runpod ist eine GPU-Cloud zum Betreiben von KI-Modellen, abgerechnet nach Nutzung. Weitere Optionen führt unser Tool-Vergleich. Wir haben diese Tools nicht getestet.

Kurzbeschreibungen aus unserem Tool-Vergleich, nach Angaben der Anbieter — nicht von ABXK getestet.

Schritt 1: Die Funktion schreiben

Die Funktion nimmt die Frage entgegen, prüft sie, ruft das Modell auf und schickt nur die Antwort zurück. Das Beispiel folgt dem Format von Netlify Functions, die mit den standardisierten Web-Objekten Request und Response arbeiten. Andere Plattformen nutzen sehr ähnlichen Code, nur der Speicherort der Datei und einige Einstellungen unterscheiden sich.

// netlify/functions/ask.mjs
const SYSTEM_PROMPT = "Sie beantworten Fragen zu unserem Coworking-Space. ...";
const reply = (body, status = 200) => Response.json(body, { status });

export default async (req) => {
  if (req.method !== "POST") return reply({ error: "Bitte POST verwenden." }, 405);

  // 1. Eingabe prüfen, bevor etwas Geld kostet
  const body = await req.json().catch(() => null);
  const question = typeof body?.question === "string" ? body.question.trim() : "";
  if (!question || question.length > 1000) {
    return reply({ error: "Bitte stellen Sie eine Frage mit höchstens 1.000 Zeichen." }, 400);
  }

  // 2. Anfragen pro Besucher begrenzen (siehe Schritt 3)

  // 3. Modell aufrufen: Schlüssel und Modell aus der Umgebung, Token-Grenze, Timeout
  const started = Date.now();
  let status = 0;
  let data = null;
  try {
    const res = await fetch("https://api.example.com/v1/chat", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${process.env.LLM_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        model: process.env.LLM_MODEL,
        messages: [
          { role: "system", content: SYSTEM_PROMPT },
          { role: "user", content: question },
        ],
        max_tokens: 300,
      }),
      signal: AbortSignal.timeout(20000),   // nach 20 Sekunden aufgeben
    });
    status = res.status;
    data = await res.json();
  } catch {
    // Timeout, Netzfehler oder eine Antwort, die kein JSON ist
  }

  // 4. Antwort prüfen (Feldnamen wie in Teil 1; sie unterscheiden sich je nach Anbieter)
  const answer = data?.output?.[0]?.text;
  const ok = status === 200 && typeof answer === "string" && answer !== "";

  // 5. Protokollieren, was für Fehler und Kosten nötig ist, aber nicht die Frage; dann antworten
  console.log(JSON.stringify({ status, ok, ms: Date.now() - started, usage: data?.usage }));
  if (!ok) return reply({ error: "Der Assistent ist gerade nicht erreichbar." }, 502);
  return reply({ answer });
};

export const config = { path: "/api/ask" };

Die Seite ruft nur diese Funktion auf, nie den Anbieter:

const res = await fetch("/api/ask", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ question }),
});
const { answer, error } = await res.json();

Fünf Schritte der Funktion von links nach rechts: Eingabe prüfen, Anfragen begrenzen, Modell aufrufen mit Schlüssel, Token-Grenze und Timeout, Antwort prüfen, loggen und antworten; darunter die Regel, dass alles, was Geld kostet, erst nach den Prüfungen passiert
Was die Funktion bei jeder Anfrage tut. Eine abgelehnte Anfrage kostet keine Tokens.

Zwei Details zählen in der Praxis. Erstens bleiben Fehlermeldungen an den Browser allgemein. Details wie der Fehlertext des Anbieters gehören in Ihre Logs, nicht auf den Bildschirm. Zweitens begrenzen Plattformen, wie lange eine Funktion laufen darf. Bei Netlify darf eine normale Funktion laut Dokumentation 60 Sekunden laufen. Ihr eigenes Timeout sollte deutlich kürzer sein, damit Sie noch eine freundliche Meldung schicken können.

Schritt 2: Den Schlüssel in einer Umgebungsvariable ablegen

Legen Sie in den Einstellungen Ihrer Hosting-Plattform die Umgebungsvariablen LLM_API_KEY und LLM_MODEL an. Die Funktion liest sie zur Laufzeit, sodass keiner der beiden Werte in Ihrem Code steht. Bei Netlify zum Beispiel setzen Sie sie im Dashboard oder über die Kommandozeile, und ein geänderter Wert gilt ab dem nächsten Deploy.

  • Nie gehört der Schlüssel ins Repository, in den Frontend-Code, in Logs oder in Fehlermeldungen.
  • Nutzen Sie einen eigenen Schlüssel für diese App und getrennte Schlüssel für Test und Betrieb. Dann können Sie einen Schlüssel widerrufen, ohne alles andere anzuhalten.
  • Widerrufen Sie einen öffentlich gewordenen Schlüssel sofort, erstellen Sie einen neuen und veröffentlichen Sie erneut.

Schritt 3: Kosten und Missbrauch bremsen

Ihre Funktion hat eine öffentliche Adresse. Jeder kann sie aufrufen — nicht nur Ihre Seite, sondern auch Skripte und Bots —, und jeder Aufruf kostet Sie Tokens. Die OWASP Top 10 für LLM-Anwendungen 2025 führen dieses Risiko als „Unbounded Consumption“, also unbegrenzten Verbrauch. Dazu gehören Angriffe, die gezielt Ihre Rechnung in die Höhe treiben sollen, manchmal „Denial of Wallet“ genannt (Quelle: OWASP Gen AI Security Project, genai.owasp.org). Mehrere Bremsen hintereinander halten das Risiko klein:

Sechs Bremsen als gestapelte Zeilen: Eingabelänge, Rate Limit, maximale Tokens, Timeout, ein eigener Schlüssel und eine Ausgabengrenze beim Anbieter; die Zahlen sind Beispiele
Sechs Bremsen gegen hohe Rechnungen. Jede fängt ab, was die vorige durchlässt. Die Zahlen sind Beispiele.

Ein Rate Limit begrenzt, wie viele Anfragen ein Besucher in einer bestimmten Zeit schicken darf, zum Beispiel zehn pro Minute. Eine Serverless-Funktion kann in mehreren getrennten Kopien laufen, die keinen gemeinsamen Speicher haben. Ein einfacher Zähler im Code funktioniert deshalb nicht. Nutzen Sie eine Rate-Limit-Einstellung Ihrer Plattform, falls es eine gibt, oder zählen Sie Anfragen in einer kleinen gemeinsamen Datenbank, etwa einem Key-Value-Speicher. Über dem Limit antwortet die Funktion mit Status 429, wie Sie ihn aus Teil 1 kennen. Nutzen viele Menschen Ihre App, hilft zusätzlich ein Login oder eine Bot-Prüfung vor der Funktion. Unser Bereich AI Security behandelt Missbrauch und Abwehr ausführlicher.

Die letzte Bremse sitzt beim Anbieter. Viele Modellanbieter erlauben in ihrer Konsole eine Ausgabengrenze oder Warnungen. Richten Sie beides ein, bevor Sie den Link teilen.

Schritt 4: Die eigene Domain mit HTTPS nutzen

HTTPS verschlüsselt die Verbindung zwischen Browser und App. Browser warnen vor Seiten ohne HTTPS. Die meisten Hosting-Plattformen geben jedem Projekt von Anfang an eine Adresse mit HTTPS, etwa eine Subdomain der Plattform.

Ihre eigene Domain tragen Sie in den Einstellungen der Plattform ein. Die Plattform zeigt Ihnen dann die DNS-Einträge, die Sie bei Ihrem Domain-Anbieter anlegen, oft einen CNAME- oder einen A-Eintrag. DNS ist das Adressbuch des Internets: Es übersetzt einen Domainnamen in die Adresse eines Servers. Änderungen können eine Weile brauchen, bis sie überall ankommen. Sobald die Domain auf die Plattform zeigt, beantragt die Plattform ein Zertifikat für HTTPS, oft bei der gemeinnützigen Zertifizierungsstelle Let’s Encrypt, und erneuert es automatisch. Zertifikate laufen nach einer festen Zeit ab, deshalb ist die automatische Erneuerung wichtig. Betreiben Sie einen eigenen Server, prüfen Sie, dass auch Ihr Kontrollpanel Zertifikate automatisch erneuert.

Schritt 5: Logs und Kosten nach dem Start beobachten

Jede console.log-Zeile Ihrer Funktion erscheint in den Funktions-Logs der Plattform. Protokollieren Sie, was Sie brauchen, um Fehler zu finden und Kosten zu steuern: Zeit, Status, Dauer, Token-Verbrauch sowie Modell- und Prompt-Version. Protokollieren Sie nicht standardmäßig vollständige Fragen und Antworten, denn sie können personenbezogene Daten enthalten. Brauchen Sie Beispiele für Qualitätsprüfungen, informieren Sie Ihre Nutzer, behalten Sie nur wenige und löschen Sie sie nach einer festen Frist.

Sechs Dinge, die Sie nach dem Start beobachten: Fehlerquote, Antwortzeit, Tokens und Kosten, Anfragen pro Absender, Feedback der Nutzer sowie Modell- und Prompt-Versionen
Was Sie nach dem Start beobachten. Die Zahlen stammen aus Ihren eigenen Logs.

Sehen Sie sich in den ersten Wochen täglich Fehler und Kosten an. Richten Sie danach Warnungen ein, etwa wenn die Fehlerquote springt oder die Tageskosten eine selbst gewählte Grenze überschreiten. Level 3 erklärt Observability für LLM-Apps — Logs, Traces, Dashboards und Qualitätsprüfungen — ausführlich.

Checkliste für den Start

Gehen Sie diese Liste durch, bevor Sie den Link teilen, und erneut, wenn Sie Modell, Prompt oder Hosting ändern:

Eine kleine KI-Web-App veröffentlichen (2)
BereichPrüfen
SchlüsselNur in Umgebungsvariablen; ein eigener Schlüssel für diese App; nicht im Repository, in der Seite oder in den Logs
EingabeLeere und zu lange Fragen werden vor dem Modellaufruf abgelehnt
GrenzenRate Limit pro Besucher, maximale Tokens und ein Timeout unter dem Limit der Plattform
KostenAusgabengrenze und Warnungen beim Anbieter; Token-Verbrauch pro Tag in Ihren Logs sichtbar
FehlerFreundliche Meldungen für Nutzer; keine internen Details in Antworten
DatenschutzNutzer wissen, dass sie mit einer KI sprechen; Ihre Datenschutzerklärung nennt den Modellanbieter; keine vollständigen Texte in den Logs ohne Grund
DomainHTTPS funktioniert unter jeder Adresse; das Zertifikat wird automatisch erneuert
ZurückrollenSie wissen, wie Sie zum vorherigen Deploy zurückkehren; viele Plattformen bewahren frühere Versionen dafür auf
VerantwortungEine Person liest die Warnungen und entscheidet, was bei einem Problem passiert