Zum Inhalt springen
Acecore
Inhaltsverzeichnis
Technisches Design für einen KI-Kontaktchat in einer Astro-Website

Einen KI-Chat auf eine Website zu setzen, ist einfach. Entscheidend ist der Betrieb: Was darf die KI beantworten, wohin soll sie Besucher führen, welche URLs dürfen erscheinen und wie bleiben API-Kosten kontrollierbar?

Acecore hat einen KI-Kontaktchat in eine statische Astro + Cloudflare Pages Website integriert. Die Hauptimplementierung steht im PR für Kontakt-KI und CMS-begrenzten Übersetzungsfluss. Das sichere Rendering von Markdown-Links wurde anschließend in einem weiteren PR verbessert. Die Details dazu sind in Markdown-Links in KI-Chat-Antworten sicher rendern separat beschrieben.

Dieser Artikel beschreibt das Design als wiederverwendbares Muster für andere statische Websites. Auch außerhalb von Astro gilt: Client-Widget, API-Grenze, Prompt und Renderer sollten getrennte Verantwortlichkeiten haben.

Gesamtstruktur

SchichtVerantwortung
Chat widgetUI, Eingabe, aktueller locale, minimaler Verlauf, Markdown-Rendering
/api/ai-contactValidierung, Origin-Prüfung, Rate Limit, Prompt, OpenAI-Aufruf
OpenAI Responses APIAntwort aus öffentlichem Kontext und Gesprächszustand erzeugen

Der Browser sollte OpenAI nicht direkt aufrufen. Ein serverseitiger Endpoint verhindert Schlüssel-Leaks, erlaubt Anpassungen von Prompt und Kontext und bündelt Limits sowie Fehlerbehandlung.

Bei Astro + Cloudflare Pages kann die Grenze eine Pages Function unter /api/ai-contact sein. In Next.js wäre es ein Route Handler, in Hono oder Express eine normale API-Route.

Den Endpoint-Vertrag klein halten

type ContactAiRequest = {
  message: string
  locale: 'ja' | 'en' | 'zh-cn' | 'es' | 'pt' | 'fr' | 'ko' | 'de' | 'ru'
  history?: Array<{
    role: 'user' | 'assistant'
    content: string
  }>
}

type ContactAiResponse = {
  answer: string
}

Name, E-Mail, Telefonnummer, Firma und detaillierte Formularfelder müssen nicht durch den Chat laufen. Der Chat hilft bei der Wahl von Service und Kontaktweg, er sammelt keine personenbezogenen Daten.

Auch der Verlauf wird auf wenige aktuelle Nachrichten und eine maximale Länge begrenzt. Das reduziert Prompt-Größe und Kosten.

Validierung und Modellaufruf auf dem Server steuern

export async function onRequestPost({ request, env }: PagesFunction<Env>) {
  assertSameOrigin(request)
  assertRateLimit(request)

  const body = await request.json()
  const message = validateMessage(body.message)
  const locale = validateLocale(body.locale)
  const history = trimHistory(body.history)

  const prompt = buildContactPrompt({
    locale,
    message,
    history,
    siteContext: buildPublicSiteContext(locale),
  })

  const answer = await callOpenAIResponsesApi({
    apiKey: env.OPENAI_API_KEY,
    model: env.OPENAI_MODEL,
    prompt,
  })

  return Response.json({ answer })
}

Wichtig ist, Eingaben vor dem KI-Aufruf zu verkleinern und zu validieren. Lange Texte, unbegrenzter Verlauf und fremde wiederholte Aufrufe destabilisieren den Betrieb.

OPENAI_MODEL sollte eine Umgebungsvariable sein, OPENAI_API_KEY bleibt ausschließlich serverseitig. Für Auslieferung und CSP siehe Cloudflare Pages Sicherheit.

Website-Informationen als expliziten Kontext pflegen

Für eine Website dieser Größe ist eine Vektordatenbank nicht der erste Schritt. Strukturierter Kontext aus öffentlichen Seiten ist oft ausreichend.

Dazu gehören Unternehmens- und Service-Übersichten, Zielgruppen, Beispielanfragen, URLs, FAQ, Regeln für Formular/LINE/E-Mail/Telefon, nicht zu behauptende Bereiche wie Preise oder Verträge, und interne URLs pro locale.

function buildPublicSiteContext(locale: Locale) {
  return {
    services: [
      {
        name: 'Web production',
        summary: 'Corporate sites, recruiting sites, and landing pages',
        url: localizePath('/services/web-production/', locale),
      },
      {
        name: 'Business systems',
        summary: 'Reservation, inventory, and customer management systems',
        url: localizePath('/services/business-system/', locale),
      },
    ],
    contact: {
      form: localizePath('/contact/', locale),
      line: 'https://lin.ee/...',
      emailPolicy:
        'Show email only when the form cannot be used or follow-up is needed',
      phonePolicy: 'Show phone only for urgent confirmation',
    },
  }
}

Das Modell soll nicht aus allgemeinem Wissen antworten, sondern aus dem, was diese Website sagen darf. Bei Wachstum kann diese Schicht zu Pagefind, CMS JSON, D1, Vectorize oder anderer Suche erweitert werden.

Im Prompt Regeln schreiben

You are the contact guidance AI for this website.
Answer only from public site information.

Rules:
- Do not make firm statements about pricing, contracts, schedules, or guarantees
- Send formal consultations and estimates to the contact form
- Also suggest LINE for short questions and school-related inquiries
- Show email and phone only when the user asks for direct contact
- Use URLs that match the current locale
- If unsure, do not guess; guide the user to the form

Ein typischer Fehler ist eine zu hilfsbereite KI, die zu viel zusichert. Preise, Termine und Garantien sollten allgemein erklärt und dann ans Formular verwiesen werden.

Kontaktwege trennen

WegRolle
FAQHäufige Fragen direkt auf der Seite klären
KI-ChatServices, Kontaktwege und verwandte Seiten sortieren
LINEKurze Fragen, Schul-Themen und leichte Rückfragen
FormularAngebote, Produktion, Partnerschaften und Recruiting
DirektkontaktErgänzungen nach Formular oder dringende Bestätigung

Die KI verbindet Inhalte wie die Service-Übersicht mit konkreten Wegen auf der Kontaktseite. Das Muster passt zu B2B-Websites, Agenturen, Schulen und SaaS-Support.

Locale-URLs bewahren

Bei mehrsprachigen Websites reicht die richtige Antwortsprache nicht. Auch URLs müssen zum locale passen.

function localizePath(path: string, locale: Locale) {
  if (locale === 'ja') return path
  return `/${locale}${path}`
}

Serverseitige URL-Erzeugung ist stabiler als nur eine Prompt-Anweisung. Der Übersetzungsbetrieb wird in Mehrsprachige Blogs mit Sveltia CMS betreiben beschrieben.

Origin-Prüfung und Rate Limit

function assertSameOrigin(request: Request) {
  const origin = request.headers.get('Origin')
  if (!origin) return

  const requestUrl = new URL(request.url)
  const originUrl = new URL(origin)

  if (originUrl.host !== requestUrl.host) {
    throw new Response('Forbidden', { status: 403 })
  }
}

IP-basiertes Rate Limiting ist eine erste Bremse. In Cloudflare können CF-Connecting-IP, X-Forwarded-For oder CF-Ray genutzt werden. Bei höherem Traffic sind Cloudflare WAF, Turnstile, KV, D1 oder Durable Objects stabiler. Den CMS-Betrieb für Content-Updates beschreibt der Sveltia CMS Einrichtungsleitfaden; Bot-Schutz für Formulare und Kommentare ist eine eigene Ebene.

Erlauben Sie nur Absätze, Listen, Fettdruck, Inline-Code und Markdown-Links. Linkziele werden auf interne Pfade, aktuellen Origin, https://acecore.net, offizielle LINE-URLs und notwendige mailto: oder tel: beschränkt.

function sanitizeHref(rawHref: string, currentOrigin: string) {
  const href = rawHref.trim()

  if (href.startsWith('/')) return href
  if (href.startsWith(`${currentOrigin}/`)) return href
  if (href.startsWith('https://acecore.net/')) return href
  if (href.startsWith('https://lin.ee/')) return href
  if (href === 'mailto:[email protected]') return href
  if (href === 'tel:05088902788') return href

  return null
}

trim() ist wichtig, weil KI-Ausgaben wie [Services]( /services/ ) vorkommen können. Ein kleiner, strenger Renderer ist leichter zu pflegen als vollständiges Markdown.

Local, Preview und Produktion testen

Astro dev oder preview entspricht nicht vollständig Cloudflare Pages Functions. Ohne OPENAI_API_KEY sollten lokal Fallback und Fehleranzeige geprüft werden.

In Preview oder Produktion prüfen Sie POST auf /api/ai-contact, OPENAI_API_KEY und OPENAI_MODEL, Ablehnung fremder Origins, Eingabelimits, Antworten im richtigen locale, lokalisierte URLs, keine Zusagen zu Angebot oder Vertrag, keine Standardanzeige von E-Mail und Telefon, sowie Markdown-Links nur bei erlaubter URL.

Testen Sie außerdem lange Eingaben, unerwartete Fragen, englische Seiten, Direktkontakt-Wünsche und Preisfragen.

Betriebsmetriken

Beobachten Sie API-Fehlerquote, Rate-Limit-Treffer, durchschnittliche Nachrichten pro Anfrage, Übergänge zu Formular und LINE, Weiterleitungen zum Formular bei fehlender Antwort und Nutzung pro locale.

Wenn Gesprächsinhalte gespeichert werden, müssen Datenschutzregeln zuerst feststehen. Ein sicherer Start ist, nur Ereignisse und Fehler ohne Nachrichtentext zu speichern.

Abgegrenzter Umfang

Dieser Artikel behandelt nur das technische Design des KI-Chats. Die Strecke, die den Beratungsgegenstand von der Service-Seite ins Formular übergibt, ist ebenfalls implementiert und in Technisches Design zur Kontextübergabe vom Service-CTA zum Kontaktformular beschrieben.

  • KI-Chat: Unsicherheit im Gespräch ordnen und sicher führen
  • Service-CTA: Den gelesenen Service-Kontext ins Formular übergeben

Getrennt bleiben beide Artikel lesbarer und lassen sich später besser verlinken.

Zusammenfassung

Bei einem KI-Kontaktchat für eine statische Website sollten API-Grenze und Antwortkontrolle vor der UI gestaltet werden.

Die wichtigsten Entscheidungen: OpenAI über Cloudflare Pages Function aufrufen, Eingabe und Verlauf klein halten, Kontext und locale-URLs serverseitig bauen, Grenzen im Prompt formulieren, Formular/LINE/Direktkontakt trennen, Origin-Prüfung und Rate Limit einbauen, Markdown-Links nach trim() per Allow-List rendern.

Statische Websites können sinnvolle KI-Kontaktchats haben. Entscheidend ist nicht, die KI sichtbar zu machen, sondern Besucher sicher zur nächsten Aktion zu führen.

Referenzarchitektur

Widget

Das Astro-Chat-UI sendet nur Frage, aktuellen locale und minimalen Verlauf.

Function

Die Cloudflare Pages Function validiert Eingaben, prüft Origin, begrenzt Anfragen und baut den Prompt.

Model

Die OpenAI Responses API erhält öffentlichen Website-Kontext und Gesprächszustand.

Renderer

Der Client rendert nur erlaubtes Markdown und führt zu internen Links oder freigegebenen Kontaktwegen.

Verantwortlichkeiten trennen

Alles vermischt

  • Die KI-API wird direkt aus dem Browser aufgerufen
  • Website-Kontext, API-Schlüssel, UI und Link-Rendering sind gekoppelt
  • Die KI kann Preise, Verträge oder Termine zu bestimmt formulieren
  • Markdown und URLs können direkt als HTML gerendert werden

Getrennte Verantwortlichkeiten

  • API-Schlüssel und Modellaufrufe bleiben serverseitig
  • Öffentliche Website-Informationen werden als expliziter Kontext gepflegt
  • Der Prompt steuert Antwortumfang und Kontaktwege
  • Markdown und URLs werden über Allow-Lists gerendert
Design-Checkliste für andere Websites
  • Erledigt: Den Chat als Orientierungshilfe definieren, nicht als vollständigen Formularersatz
  • Erledigt: Eine serverseitige API-Grenze schaffen und den API-Schlüssel nicht im Browser ausgeben
  • Erledigt: Antworten auf öffentliche Website-Informationen beschränken
  • Erledigt: Festlegen, was die KI nicht behaupten darf, etwa Preise, Verträge, Fristen und Garantien
  • Erledigt: Rollen von Formular, LINE, E-Mail und Telefon definieren
  • Erledigt: URLs nach locale erzeugen, damit mehrsprachige Navigation intakt bleibt
  • Erledigt: Origin-Prüfung, Längenlimits, Verlaufslimits und Rate Limiting einbauen
  • Erledigt: Markdown-Link-URLs vor der Allow-List-Prüfung trimmen
Häufige Fragen
Braucht man RAG oder eine Vektordatenbank für einen KI-Kontaktchat?
Für eine kleine Unternehmenswebsite reicht oft strukturierter Kontext aus öffentlichen Seiten im Prompt. Suche oder Vektordatenbank kann man später ergänzen, wenn Umfang oder Aktualisierungsfrequenz wachsen.
Wird der OpenAI API-Schlüssel im Browser sichtbar?
Nein. Der Browser sendet nur die Frage an /api/ai-contact. Die Cloudflare Pages Function ruft die OpenAI Responses API auf und verwaltet den Schlüssel.
Darf die KI beliebige Links ausgeben?
Nein. Links sind auf interne Pfade, den aktuellen Origin, acecore.net, die offizielle LINE-URL sowie notwendige mailto- und tel-Links beschränkt. Markdown-URLs werden vor der Prüfung getrimmt.

Kommentare

Kommentare werden geladen...

Links, E-Mail-Adressen und Werbetexte können nicht veröffentlicht werden.

G

Gui

CEO von Acecore. Steuert Geschäftssysteme, Web, Datenbanken und Infrastruktur, Qualität und KI-Einsatz von der Analyse geschäftlicher Probleme über Design und Einführung bis zur Verbesserung nach dem Launch. Baut auf praktischer C#/.NET-Kompetenz auf und berücksichtigt zugleich PHP/JavaScript, SQL Server/PostgreSQL/MySQL und Linux/Windows Server, um Anforderungen, Technologieauswahl, Qualitätsstandards und GitHub-basierte Entwicklungsabläufe als kohärenten Prozess zu gestalten. Integriert generative KI in Entwicklungs-, Prüfungs- und Informationsorganisationsprozesse, als praktische Grundlage, damit kleine Teams schneller und verlässlicher liefern können.

Geschäftsproblem-AnalyseTechnologieauswahlSystemdesignC#/.NETDatenbank-/InfrastrukturdesignGitHub-EntwicklungsbetriebGenerative KIKI-Workflow-DesignQualitätsdesignVor-Ort-Integration

Möchten Sie mehr über unsere Dienste erfahren?

Wir bieten umfassende Unterstützung, einschließlich Systementwicklung, Webdesign, Grafikdesign und IT-Bildung.

Verwandte Artikel

Artikel suchen