← Alle Lessons|Sicherheit in der Generierung – Prüfpipelines für KI-Assistenten im Kundenkontakt

Sicherheit in der Generierung – Prüfpipelines für KI-Assistenten im Kundenkontakt

Schritt 1 von 7

Die fünf Positionen der Prüfung

Der Leitsatz der Lesson, die fünf Stellen, an denen ein Assistent im Kundenkontakt geprüft wird, und das Beispielsystem, das sich durch alle Steps zieht.

Lesson-Header: die Werkbank einer Gießerei mit geordnet ausgelegten Formhälften und Werkzeug

Mehr Prüfschichten bedeuten nicht mehr Sicherheit

Sobald ein KI-Assistent nach außen antwortet, im Kundenservice, im Support-Chat oder im Self-Service-Portal, steht jede Antwort im Namen des Unternehmens. Der verbreitetste Umgang mit den Sicherheitsbedenken, die daraus folgen, ist eine zusätzliche Prüfschicht. Das erhöht die Sicherheit nicht: Jede nachgelagerte Prüfung fängt nur ab, was vorher nicht gesteuert wurde, und ein Netz aus Prüfschichten wird mit jeder Prompt-Änderung durchlässiger. Eine Prüfstufe, die häufig greift, zeigt ein Steuerungsproblem in der Generierung an. Sie ist ein Symptom, keine Lösung.

💡
Voraussetzungen: Du solltest TypeScript lesen können und wissen, was Guardrails sind. Als Vorbereitung lohnen sich Der Stack hinter einer KI-App (die Werkzeuge unter der Haube) und Eindämmen statt abwehren (die Rechte-Perspektive auf Agenten-Sicherheit).

Der Leitsatz dieser Lesson stammt aus einem realen Architektur-Review in einer stark regulierten Domäne: Sicherheit entsteht nicht dadurch, dass mehr geprüft wird, sondern dadurch, dass in der Generierung weniger schiefgehen kann. Prüfschichten sind Absicherung, keine Steuerung. Gesteuert wird dort, wo die Antwort entsteht.

Die Landkarte: Position 0 bis 4

Schaubild: Pipeline mit fünf Prüfpositionen, deterministische Positionen farblich abgesetzt
PositionWoMittelPrüft
0 – VorfilterVor jedem ModellaufrufRegex, MusterlistenPersonenbezogene Daten, strukturierte Entitäten, plumpe Missbrauchsmuster
1 – GuardErste ModellstufeModellBedürfnis, Scope, Risikoklasse
2 – GenerierungZweite ModellstufePrompt plus BausteinmetadatenGrenzen als Steuerung, nicht als Filter
3 – NachfilterNach der GenerierungRegex, Abgleich gegen QuellbausteineVerbotene Formulierungen, Deckung, Pflichthinweise
4 – PrüfstufeNach dem NachfilterModellTon, Passung, Marke

Position 0 und 3 sind derselbe Mechanismus an unterschiedlichen Stellen, und sie werden regelmäßig verwechselt. Der Nachfilter schützt den Nutzer vor einer fehlerhaften Antwort. Der Vorfilter schützt die Daten des Nutzers vor dem System: Was er maskiert, gelangt nie in den Prompt, nie zum Modellanbieter und nie in die Logs. Dass er daneben auch plumpe Missbrauchsmuster abfängt, ist Kostenbremse, nicht Sicherheitsgrenze, mehr dazu in Step 2. Damit die Positionen greifbar bleiben, zieht sich ein Beispielsystem durch alle Steps: ein Leistungs-Assistent für ein Versicherungsportal. Er beantwortet Fragen zu Leistungen, Beträgen und Fristen, also genau die Mischung aus harmlos und haftungsrelevant, an der Sicherheitsarchitektur sichtbar wird. In fünf Schritten baust du seine Pipeline: das Grundmuster mit seinen Verträgen, den Vorfilter davor, das Risiko-Routing, den Freiheitsgrade-Regler und die drei Ausstiegspfade.

Takeaway
Regel #0: Bewerte jede Architektur an zwei Punkten: wo die Grenzen sitzen (am Rand oder zusätzlich in der Mitte) und ob für jeden Fall, in dem kein Weg funktioniert, ein Ausgang definiert ist.
Schritt 2 von 7

Guard, Generate, Validate – die Übergabeverträge

Drei Stufen mit je eigenem Modellaufruf. Die eigentliche Architektur steckt in dem, was zwischen den Stufen übergeben wird.

Step-Header: drei Stationen in Reihe auf der Werkbank, ein Werkstück wird übergeben

Wer einen Assistenten in einem regulierten Umfeld baut, landet fast zwangsläufig bei diesem Muster: prüfen, was hereinkommt, generieren, prüfen, was hinausgeht. Drei Stufen, drei getrennte Modellaufrufe. Das ist eine gute Grundfigur. Der häufigste Denkfehler liegt nicht im Muster, sondern in seiner Auslegung: Die dritte Stufe wird als die Sicherheitsmaßnahme behandelt und die zweite als reine Textproduktion.

StufeAufgabeProduziertModellanforderung
1 – Guard (Eingang)Anfrage lesen, Bedürfnis klassifizieren, Scope prüfen, unzulässige Anfragen abweisenStrukturiertes Signal (JSON)Klein, schnell, klassifikationsstark
2 – GenerateWissen abrufen, Antwort aus geprüftem Material formulieren, Ton nach Bedürfnis setzenAntwortentwurf plus BelegverweiseStärkstes verfügbares Modell
3 – Validate (Ausgang)Antwort gegen harte Grenzen und weiche Vorgaben prüfen, freigeben oder zurückgebenUrteil plus BegründungKlein, eng gefasster Prüfauftrag

Drei getrennte Aufrufe statt einem, aus drei Gründen:

  1. Zielkonflikt-Entkopplung: „Sei maximal hilfreich“ und „mach keine verbindlichen Zusagen“ im selben Aufruf ist eine Regelkollision, und unter Druck gewinnt meist die Hilfsbereitschaft. Ein separater Prüfaufruf hat diesen Druck nicht.
  2. Modellgröße: Drei fokussierte Durchläufe machen mit mittelgroßen Modellen messbar weniger Fehler als ein einzelner Aufruf, der klassifizieren, formulieren und prüfen gleichzeitig soll.
  3. Auditierbarkeit: Drei Stufen erzeugen drei protokollierbare Zwischenergebnisse. In regulierten Domänen trägt oft genau dieses Audit-Argument die Entscheidung.

Die Übergabeverträge als Typen

Die Qualität der Pipeline steckt in den Übergabeverträgen, nicht in den Prompts. Zwei Verträge musst du festlegen: was der Guard an die Generierung übergibt, und was die Generierung an den Validator übergibt. Als TypeScript-Typen sehen sie so aus:

TypeScript
// Vertrag 1: Was der Guard an die Generierung übergibt
type GuardSignal = {
  beduerfnis: { primaer: string; sekundaer?: string };
  konfidenz: number;                // 0..1, unter Schwelle wird eskaliert
  dringlichkeit: "normal" | "erhoeht" | "akut";
  kognitiveKapazitaet: "voll" | "reduziert";
  retrievalHinweise: {
    themenKandidaten: string[];     // Hinweise, keine fertige Abfrage
    filter: Record<string, string>; // z. B. { vertragsart: "pflege" }
  };
  risikoklasse: "niedrig" | "mittel" | "hoch";
};

// Vertrag 2: Was die Generierung an den Validator übergibt
type GenerateOutput = {
  antwort: string;
  genutzteBausteine: { id: string; version: string }[];
  mitgereisteRegeln: string[];      // aus den Metadaten der Bausteine
  signal: GuardSignal;              // das Bedürfnis reist mit
};

Der zweite Vertrag enthält die Stelle, die in Reviews am häufigsten fehlt: die Liste der tatsächlich genutzten Wissensbausteine. Ein Validator, der nur den Antworttext sieht, kann nicht prüfen, ob die Antwort gedeckt ist. Er kann nur beurteilen, ob sie plausibel klingt, und das ist genau die Eigenschaft, die du nicht willst. Erst mit den Quellbausteinen im Kontext wird aus einer Stilprüfung eine Deckungsprüfung.

⚠️
Schwachstelle 1: Grenzen am Rand statt in der Mitte. Der typische Aufbau kennt die Regeln zweimal: als Sperrliste am Eingang und als Prüfung am Ausgang. Die Generierung selbst kennt sie nicht. Ein Generator, der nicht weiß, dass er keine individuellen Zusagen formulieren darf, formuliert sie. Der Validator verwirft, der Generator produziert sie erneut. Die Rückweisungsquote steigt, und mit ihr Latenz und Kosten. Die Korrektur folgt im nächsten Abschnitt.

Das Skelett der Pipeline

So sehen die drei Stufen orchestriert aus, und hier steckt die Korrektur zu Schwachstelle 1: Die harten Grenzen stehen zusätzlich im System Prompt der Generierungsstufe, nicht nur in der Prüfung. Nicht als einzige Absicherung, sondern damit die Absicherung selten greifen muss:

TypeScript
async function beantworte(anfrage: string): Promise<string> {
  const signal = await guard(anfrage);        // Stufe 1: klassifizieren

  // Das Retrieval läuft eigenständig und hybrid:
  // semantische Suche plus Metadatenfilter.
  // Der Guard liefert Hinweise, nicht die Abfrage.
  const bausteine = await retrieval({
    semantisch: anfrage,
    filter: signal.retrievalHinweise.filter,
    kandidaten: signal.retrievalHinweise.themenKandidaten,
  });

  // Stufe 2: Grenzen stehen HIER im System Prompt
  const entwurf = await generiere(signal, bausteine);

  // Stufe 3: sieht Antwort UND Quellbausteine
  const urteil = await validiere(entwurf);

  if (!urteil.freigegeben) {
    // Was jetzt passiert, klärt Step 5: die Ausstiegspfade
  }
  return entwurf.antwort;
}

Achte auf das Retrieval: Der Guard liefert Themenkandidaten und Filterwerte, aber nicht die fertige Abfrage. Würde die Abfrage aus der Themenextraktion des Guards gebaut, entschiede ein Modell ohne Kenntnis der Wissensbasis darüber, welches Wissen geladen wird. Eine falsche Extraktion hieße falsches oder gar kein Wissen, und die Generierung merkt es nicht. Sie formuliert aus dem, was sie bekommt.

Übung: Architektur-Review im Kleinen

Aufgabe: Ein Team legt dir diese Pipeline vor: Der Guard extrahiert thema: string und baut daraus direkt die Retrieval-Abfrage. Der Validator bekommt antwort: string, sonst nichts.

  1. Benenne die zwei Vertragsfehler und was sie im Betrieb anrichten.
  2. Schreibe die korrigierten Typen für beide Übergaben.
  3. Gegenprobe: Könnte dein Validator erkennen, dass eine genannte Zahl in keinem geladenen Baustein steht?

Zeitaufwand: ~10 Minuten

Takeaway
Regel #1: Harte Grenzen gehören zusätzlich in den System Prompt der Generierung, und der Validator braucht die Quellbausteine im Kontext. Sonst prüfst du Stil statt Deckung.
Schritt 3 von 7

Position 0: der deterministische Vorfilter

Was nie in den Prompt gelangt, kann nirgends leaken. Datenminimierung ist ein Architekturmerkmal, keine Verhaltensregel.

Step-Header: ein feines Sieb über dem Tiegel, Rohmaterial wird vor der Schmelze gesiebt

Pipeline-Diagramme beginnen üblicherweise mit der Eingangsstufe, und die ist ein Modellaufruf. Damit ist eine Entscheidung gefallen, die niemand bewusst getroffen hat: Der volle Rohtext der Nutzeranfrage geht an ein Modell, inklusive Versicherungsnummer, Klarname, IBAN und Gesundheitsangaben. Eine Verhaltensregel im System Prompt hilft dagegen nicht, denn sie greift erst, nachdem die Daten das Modell erreicht haben. Die Position davor arbeitet deterministisch: Regex und Musterlisten, bevor das erste Modell den Text sieht.

Was sich musterhaft erkennen lässt

TypeScript
const MUSTER = {
  iban: /\bDE\d{2}\s?(\d{4}\s?){4}\d{2}\b/g,
  steuerId: /\b\d{2}\s?\d{3}\s?\d{3}\s?\d{3}\b/g, // 11 Ziffern, gruppiert oder am Stück
  email: /\b[\w.+-]+@[\w-]+\.[\w.]{2,}\b/g,
};

type VorfilterErgebnis = {
  maskiert: string;
  funde: { klasse: keyof typeof MUSTER }[];
};

function vorfilter(roh: string): VorfilterErgebnis {
  let maskiert = roh;
  const funde: VorfilterErgebnis["funde"] = [];
  for (const [klasse, regex] of Object.entries(MUSTER)) {
    maskiert = maskiert.replace(regex, () => {
      funde.push({ klasse: klasse as keyof typeof MUSTER });
      return `[${klasse.toUpperCase()}]`;
    });
  }
  return { maskiert, funde };
}

Strukturierte Kennungen wie IBAN, Steuer-ID oder E-Mail-Adressen haben feste Formate, teils Prüfsummen. Diese Klasse erkennt ein Regex mit hoher Präzision. Was mit einem Fund passiert, ist dagegen keine technische Entscheidung, sondern eine Designentscheidung, und sie fällt pro Datenklasse:

StrategieWas passiertWann passend
MaskierenFund wird durch Platzhalter ersetzt, das Modell sieht [IBAN]Standardfall: Die Anfrage bleibt beantwortbar, die Daten bleiben draußen
AblehnenAnfrage wird nicht verarbeitet, Nutzer wird gebeten, ohne die Angabe zu fragenWenn schon die Übermittlung ein Problem ist oder der Kanal ungeeignet
Durchlassen mit KennzeichnungDaten bleiben, werden markiert und von der Protokollierung ausgenommenNur wenn die Angabe fachlich gebraucht wird und der Verarbeitungsrahmen es deckt
⚠️
Der häufigste Fehler ist Maskieren ohne Nutzerhinweis. Wer seine Versicherungsnummer mitschickt, erwartet eine personalisierte Antwort. Bekommt er eine allgemeine, wirkt das System begriffsstutzig. Der Vorfilter braucht eine sichtbare Stimme: kurz benennen, dass die Angabe nicht verarbeitet wurde, warum, und was stattdessen möglich ist.
Praktischer Tipp aus der UX-Sicht: Die sichtbare Stimme kann eine Rückfrage sein. Ein kleiner Dialog zeigt den Fund und lässt den Nutzer selbst entscheiden: maskiert senden, unverändert senden oder gar nicht senden. Das ist Human-in-the-Loop im Kleinen und nimmt dem Vorfilter die Härte, stillschweigend über fremde Daten zu entscheiden.

Was Regex nicht kann

DatenklasseMittelVerlässlichkeit
Strukturierte KennungenRegex mit FormatprüfungHoch, produktionsreif
Namen, Orte, OrganisationenEntitätserkennung (NER-Modell, lokal lauffähig)Mittel, sprach- und domänenabhängig
Gesundheits- und Sozialangaben in FreitextNur durch ModellklassifikationKein deterministisches Mittel verfügbar

Für die dritte Zeile gibt es keine Vorfilter-Lösung: Gesundheitsangaben in Freitext („bei meiner Mutter wurde letzte Woche etwas festgestellt“) lassen sich musterhaft nicht erkennen. Wer sie erkennen will, braucht eine Modellklassifikation, und dann hat ein Modell die Daten bereits gesehen. Die Architektur kann diese Entscheidung nicht umgehen, sie kann sie nur explizit machen. Auch bekannte Injection-Formeln fängt der Vorfilter nur in der plumpen Variante. Er ist an dieser Stelle eine Kostenbremse, keine Sicherheitsgrenze. Die eigentliche Absicherung bleibt die positive Scope-Definition eine Stufe später.

Die Reihenfolge-Entscheidung

In regulierten Umfeldern ist die Protokollierung jedes Durchlaufs oft Freigabevoraussetzung. Ohne Vorfilter widerspricht sie der Datenminimierung: Wer den Rohrequest protokolliert, legt personenbezogene Daten in Logs ab, und Logs leben länger und liegen an mehr Stellen als Gesprächsverläufe. Die Auflösung ist eine Reihenfolgeentscheidung: Der Vorfilter läuft vor der Protokollierung. Ins Log kommt die maskierte Fassung plus die Information, welche Klasse maskiert wurde, nicht der Wert:

JSON
{
  "vorgangId": "a1f4-0815",
  "zeitpunkt": "2026-08-03T10:14:22Z",
  "eingabe": "Wie hoch ist das Pflegegeld? Meine IBAN ist [IBAN].",
  "maskiert": [{ "klasse": "iban" }],
  "beduerfnis": "leistungshoehe",
  "risikoklasse": "mittel"
}
⚠️
Der häufigste Leckagepfad ist keine Antwort, sondern ein Fehler: Eine Ausnahmebehandlung, die den Rohrequest in einen Stacktrace schreibt, umgeht den gesamten Aufbau. Prüfe jeden Fehlerpfad darauf, was er protokolliert.
Übung: Vorfilter erweitern

Aufgabe: Erweitere den Vorfilter aus diesem Step.

  1. Ergänze ein Muster für deutsche Telefonnummern und teste es gegen: „Ruf mich unter 0351 4795830 zurück.“
  2. Lege für IBAN, Telefonnummer und Geburtsdatum je eine Strategie fest (maskieren, ablehnen, durchlassen) und begründe sie in einem Satz.
  3. Teste gegen die Falle: „Die Rechnung über 130 Euro kam am 12.03. an.“ Was maskiert dein Filter fälschlich, und mit welcher Kennzahl würdest du das im Betrieb bemerken?

Zeitaufwand: ~10 Minuten

Takeaway
Regel #2: Filtere deterministisch, bevor das erste Modell den Text sieht, und protokolliere erst danach. Was nie in den Prompt gelangt, kann nicht in Logs, Antworten oder Stacktraces auftauchen.
Schritt 4 von 7

Vier Varianten und das Risiko-Routing

Die dreistufige Pipeline zahlt für jede Anfrage den vollen Preis. Die Prüftiefe gehört an die Risikoklasse, nicht ans System.

Step-Header: verzweigte Gusskanäle, eine Weiche lenkt den Fluss in unterschiedliche Rinnen

Das volle Muster aus Step 1 behandelt jede Anfrage gleich: Die Frage nach den Öffnungszeiten durchläuft dieselben drei Modellaufrufe wie die Frage nach dem individuellen Leistungsanspruch. Das kostet Latenz und Geld, und es verhindert Streaming, denn ein Validator, der die vollständige Antwort beurteilt, lässt den Nutzer mehrere Sekunden auf das erste Zeichen warten. Die entscheidende Größe ist deshalb nicht die Zahl der Prüfschichten, sondern die Freiheit, die die Generierung für die jeweilige Anfrage braucht. Je weniger Freiheit, desto weniger Prüfung.

Die vier Varianten

VariantePrinzipPassend für
A – ZweistufigGuard plus Generierung mit Grenzen im Prompt, am Ausgang nur deterministische PrüfungSachliche Auskunftsstrecken, interne Werkzeuge, latenzkritische Kanäle
B – Risiko-RoutingDrei Stufen bleiben, aber die Prüftiefe folgt der Risikoklasse aus dem Guard-SignalÖffentliche Assistenten mit breitem Anfragespektrum und gemischtem Risiko
C – KuratiertModell wählt und verbindet freigegebene Antwortbausteine statt frei zu formulierenKleine Menge von Anfragen mit sehr hohem Risiko
D – EinstufigEin starkes Modell, Verfassung im Prompt, danach nur deterministische PrüfungInterne Anwendungen, Prototypen, unkritische Domänen
KriteriumABCD
LatenzNiedrigGemischtSehr niedrigSehr niedrig
Streaming möglichJaBei niedrigem RisikoJaJa
AuditierbarkeitMittelHochSehr hochNiedrig
Schutz bei harten GrenzenHochHochSehr hochMittel
Schutz bei weichen KriterienNiedrigHochHochMittel
Redaktioneller AufwandMittelMittelHochNiedrig

Auswahl in vier Fragen

  1. Gibt es Haftungsrisiko oder Auditpflicht? Nein: Variante D genügt. Ja: weiter.
  2. Ist das Modell in Größe oder Anbieter eingeschränkt? Ja: D scheidet aus, die Zerlegung kompensiert die Modellgrenze.
  3. Sind Tonalität und Angemessenheit produktkritisch, oder geht es um korrekte Sachauskunft? Nur Sachauskunft: Variante A. Tonalität kritisch: Variante B.
  4. Gibt es eine kleine Menge von Anfragen mit sehr hohem Risiko? Ja: für diese Variante C, für den Rest B.
Die typische Zielarchitektur ist B mit C-Einsprengsel: risikobasiertes Routing als Rahmen, kuratierte Antworten für die harte Spitze. Die Varianten schließen sich nicht aus. Die Frage ist nicht, welche Variante du baust, sondern welche Variante pro Risikoklasse.

Das Routing im Code

KlasseMerkmalePrüftiefe
NiedrigReine Sachauskunft, keine Beträge, keine Ansprüche, kein NotfallsignalDeterministische Prüfung, Streaming an
MittelBeträge, Ansprüche, Verfahrensauskünfte, Vergleiche zwischen OptionenDeterministisch plus Modellprüfung
HochAkute Notlage, verletzliche Zielgruppe, individuelle Anspruchsfrage, Umgehungsversuch, niedrige KonfidenzDeterministisch plus Modellprüfung plus reduzierte Freiheitsgrade
TypeScript
type Pruefplan = {
  deterministisch: true;          // läuft immer, ohne Ausnahme
  modellpruefung: boolean;
  freiheitsgrad: 1 | 2 | 3 | 4 | 5; // der Regler aus Step 4
  streaming: boolean;
};

function pruefplan(signal: GuardSignal): Pruefplan {
  // Bei Unsicherheit immer nach oben eskalieren, nie nach unten:
  // Eine falsch als niedrig eingestufte Anfrage verliert ihre Prüfung.
  const klasse =
    signal.konfidenz < 0.6 ? "hoch" : signal.risikoklasse;

  switch (klasse) {
    case "niedrig":
      return { deterministisch: true, modellpruefung: false, freiheitsgrad: 2, streaming: true };
    case "mittel":
      return { deterministisch: true, modellpruefung: true, freiheitsgrad: 2, streaming: false };
    case "hoch":
      return { deterministisch: true, modellpruefung: true, freiheitsgrad: 4, streaming: false };
  }
}
Architektur
Anfrage
  │
  ├─ Vorfilter: maskieren, extrahieren       [deterministisch]
  │
  ├─ Guard: Bedürfnis + Scope + Risikoklasse
  │
  ├─ Retrieval: eigenständig, hybrid ──► keine Deckung? → Abstain
  │
  ├─ Generierung: Grenzen im Prompt
  │     niedrig/mittel → freie Formulierung aus Bausteinen
  │     hoch           → kuratierte Bausteinkomposition
  │
  ├─ Deterministische Prüfung                [immer]
  │
  └─ Modellprüfung: Ton, Passung, Marke      [nur mittel/hoch]
        └─ max. ein Wiederholungslauf → dann Safe-Fallback
Übung: Anfragen klassifizieren

Aufgabe: Drei Anfragen an den Versicherungs-Assistenten:

  1. „Bis wann habt ihr heute geöffnet?“
  2. „Wie hoch ist das Pflegegeld bei Pflegegrad 3?“
  3. „Bei meiner Mutter wurde gestern Pflegegrad 3 festgestellt. Was steht uns jetzt zu?“

Klassifiziere jede Anfrage mit der Risikoklassen-Tabelle und benenne, was der Prüfplan jeweils tut. Beantworte danach die vier Auswahlfragen für einen KI-Assistenten aus deinem Umfeld und lege die Zielvariante fest.

Zeitaufwand: ~10 Minuten

Takeaway
Regel #3: Wähle die Variante pro Risikoklasse, nicht pro System. Und eskaliere bei niedriger Konfidenz immer nach oben, nie nach unten.
Schritt 5 von 7

Freiheitsgrade: der Regler von frei bis kuratiert

Die stärkste Sicherheitsmaßnahme ist keine weitere Prüfschicht, sondern eine Generierung, die weniger frei erfinden kann.

Step-Header: eine Reihe von Gussformen, von der offenen Sandform bis zur geschlossenen Präzisionsform

Alle Prüfarchitekturen aus Step 3 laufen einer Generierung hinterher, die zu viel darf. Der Gegenentwurf dreht die Richtung um: Was nie generiert werden kann, muss nicht abgefangen werden. Für die kritischsten Anfragen formuliert das Modell keine Fakten mehr. Es wählt aus freigegebenen Antwortbausteinen aus, ordnet sie und verbindet sie sprachlich. Die fachliche Prüfung wandert aus der Laufzeit in die Redaktion. Freiheit ist dabei kein Schalter, sondern ein Regler mit fünf Stufen:

Schaubild: Regler mit fünf Rasten von freier Formulierung bis fester Antwort, das Risiko sinkt nach rechts
StufeWas das Modell darfWas festgelegt istRisiko
1 – Freie FormulierungFakten aus Bausteinen selbst formulierenNur die QuellauswahlHoch
2 – Gebundene FormulierungFormulieren, aber nur mit wörtlich gedeckten AussagenZahlen, Beträge, Rechtsverweise als ZitatMittel
3 – Platzhalter-FüllungWerte in freigegebene Satzschablonen einsetzenSatzstruktur und FormulierungNiedrig
4 – BausteinkompositionFreigegebene Textblöcke auswählen, ordnen, verbindenDer gesamte FaktentextSehr niedrig
5 – Feste AntwortNichts außer der AuswahlAllesKein Generierungsrisiko
💡
Abgrenzung zum Entscheidungsbaum: Ein Entscheidungsbaum bestimmt den Weg durch die Fakten. Bei der Bausteinkomposition bestimmt das Modell Auswahl, Reihenfolge, Umfang, Anrede und Übergänge, nur eben nicht den Faktengehalt. Genau das ist der Teil, den ein Assistent besser kann als eine statische Seite.

Stufe 4 im Code

Die Redaktion pflegt dafür Antwortbausteine, nicht nur Wissensbausteine. Der Unterschied: Ein Wissensbaustein ist informationsdicht und tonlos, er weiß nicht, wer ihn liest. Ein Antwortbaustein ist eine freigegebene, an eine Person adressierte Formulierung, zwei bis fünf Sätze, mit Version und Freigabedatum:

JSON
{
  "id": "pflegegeld-kurz-v3",
  "typ": "kurzfassung",
  "version": "3",
  "freigabe": "2026-06-12",
  "text": "Das Pflegegeld richtet sich nach dem Pflegegrad. Bei Pflegegrad 2 sind es derzeit 347 Euro im Monat, bei Pflegegrad 3 sind es 599 Euro.",
  "regeln": ["kein-individualanspruch", "pflichthinweis-beratung"]
}

Das Modell bekommt zur Laufzeit das Bedürfnis-Signal, die Kandidatenbausteine mit Metadaten und einen engen Auftrag: Wähle die passenden aus, bringe sie in eine sinnvolle Reihenfolge, füge Anrede und Übergänge hinzu. Formuliere keine Aussage, die nicht in einem gewählten Baustein steht. Die Ausgabe ist strukturiert, nicht Prosa, und damit wird die Prüfung trivial:

TypeScript
type KompositionsErgebnis = {
  bausteinIds: string[];   // nur freigegebene IDs
  uebergaenge: string[];   // generierte Übergangssätze, keine Fakten
  anrede: "du" | "sie";
};

function pruefeKomposition(
  k: KompositionsErgebnis,
  freigegeben: Set<string>
): boolean {
  const alleFreigegeben = k.bausteinIds.every((id) => freigegeben.has(id));
  // Übergänge dürfen verbinden, aber nichts behaupten:
  const keineFakten = k.uebergaenge.every(
    (satz) => !/\d|Anspruch|zugesagt|garantier/i.test(satz)
  );
  return alleFreigegeben && keineFakten;
}
AnfragetypEmpfohlene StufeBegründung
Akute Notlage, Gefahrensignal5 – feste AntwortKeine Variation erwünscht, jede Sekunde zählt
Individuelle Anspruchsfrage4 – KompositionHöchstes Haftungsrisiko, gut bekannte Fragen
Beträge, Leistungsumfang3 oder 4Zahlen dürfen nicht driften
Verfahren, Fristen, Zuständigkeit2 – gebundenErklärungsbedarf hoch, Faktenmenge klein
Allgemeine Sachauskunft1 oder 2Risiko gering, Flexibilität wertvoll
⚠️
Die ehrlichen Kosten: Pro Thema entstehen fünf bis acht freigegebene Bausteine, und bei jeder Rechtsänderung erneut. Halb gepflegte Antwortbausteine sind schlechter als eine gut geprüfte freie Generierung, denn ein still veralteter Baustein trägt die Autorität seiner Freigabe. Wer den Redaktionsaufwand nicht einplanen kann, sollte das Muster nicht wählen.
  1. Frei mit Deckungsprüfung starten: Stufe 1 bis 2 aufbauen, deterministische Deckungsprüfung dahinter. Damit läuft das System.
  2. Rückweisungen und Beschwerden auswerten: festhalten, welche Fragen Verstöße produzieren und welche häufig kommen.
  3. Die Schnittmenge kuratieren: Für häufige und riskante Fragen Antwortbausteine erstellen und diese Anfragen auf Stufe 4 heben.
  4. Rest auf Stufe 2 lassen: Die Prüfstufen bleiben für alles außerhalb der Kuration. So wächst die Kuration datengetrieben statt nach Vermutung.
Übung: Bausteine schreiben

Aufgabe: Nimm die Hochrisiko-Anfrage aus Step 3 („Bei meiner Mutter wurde gestern Pflegegrad 3 festgestellt. Was steht uns jetzt zu?“).

  1. Schreibe drei Antwortbausteine als JSON: eine Kurzfassung mit den Kernzahlen, einen Verfahrenshinweis, einen Verweis auf die persönliche Beratung. Jeder mit id, freigabe und regeln.
  2. Formuliere den Kompositions-Auftrag als Absatz für den System Prompt der Generierung.
  3. Gegenprobe: Welche Aussage dürfte in den Übergangssätzen nicht stehen?

Zeitaufwand: ~10 Minuten

Takeaway
Regel #4: Stelle den Freiheitsgrad pro Risikoklasse ein, nicht pro System. Die stärksten Beschränkungen gehören dorthin, wo Risiko und Wiederkehr zusammenfallen, denn dort sind die Fragen am besten bekannt.
Schritt 6 von 7

Die drei Ausstiegspfade

Drei definierte Ausgänge mit eigener Antwortstrategie und Kennzahl: der am häufigsten fehlende Teil jeder Architektur.

Step-Header: eine Hauptrinne mit drei sicher abzweigenden Überlauf-Kanälen

Architekturdiagramme zeigen den Erfolgsfall. Was passiert, wenn die Anfrage nicht hierher gehört, das Wissen nicht reicht oder die Prüfung nicht besteht, taucht selten auf, obwohl diese Fälle zusammen einen erheblichen Teil des Verkehrs ausmachen. Ohne definierten Ausgang nimmt das System den einzigen Weg, den es kennt: Es antwortet trotzdem. Eine ungedeckte Antwort, die später als Halluzination auffällt, ist meist nicht das Ergebnis eines Modellfehlers, sondern einer fehlenden Alternative zum Antworten.

Ausgang 1: Scope-Guard

Der verbreitete Aufbau prüft Anfragen gegen eine Sperrliste unerwünschter Themen. Das Problem ist strukturell: Eine Sperrliste ist eine Liste dessen, woran man bisher gedacht hat. Sie wächst reaktiv, nach Vorfällen, und ist per Konstruktion immer unvollständig. Robuster ist die umgekehrte Logik, eine Zulassungsliste: Der zulässige Raum wird positiv definiert.

TypeScript
function imScope(
  signal: GuardSignal,
  abgedeckteThemen: Set<string>
): boolean {
  const bekanntesBeduerfnis = signal.konfidenz >= 0.6;
  const themaGetroffen = signal.retrievalHinweise.themenKandidaten
    .some((thema) => abgedeckteThemen.has(thema));
  return bekanntesBeduerfnis && themaGetroffen;
}

// Zulassungsliste heißt: Das System begründet, warum es antwortet,
// nicht, warum es ablehnt. In einer regulierten Domäne ist das
// die richtige Richtung der Beweislast.
💡
Die Sperrliste verschwindet nicht, sie wechselt die Rolle: vom Hauptschutz zum Auslöser für Sonderpfade. Gefährdungssignale führen in einen sofortigen Notfallpfad, erkennbare Umgehungsversuche in eine freundliche Ablehnung mit Protokollierung und ohne Diskussion über die Regeln, Themen mit Rechtsvorbehalt in einen Verweis auf die zuständige Stelle. Und eine gute Scope-Ablehnung sagt nicht „das kann ich nicht“, sondern benennt, was das System kann, und zeigt den Weg dorthin.

Ausgang 2: Abstain

Abstain, wörtlich „sich enthalten“, ist die bewusste Entscheidung des Systems, nicht oder nur teilweise zu antworten, weil das geprüfte Wissen nicht reicht. Es ist der wichtigste und am häufigsten fehlende Ausgang. Liefert das Retrieval nichts oder nur schwach Passendes und die Generierung läuft trotzdem, formuliert sie aus dem Allgemeinwissen des Modells. Die Antwort klingt kompetent, sie ist nur nicht gedeckt. Genau so gelangen die meisten ungedeckten Aussagen in geprüfte Systeme. Der Normalfall ist dabei der Teilabstain: Die allgemeine Regelung ist gedeckt, der individuelle Anspruch nicht. Die Architektur muss diesen gemischten Zustand können, sonst wird er auf „antworten“ gerundet. Eine gute Abstain-Antwort hat vier Elemente, in dieser Reihenfolge:

  1. Was gesichert bekannt ist: Falls es einen gedeckten Teil gibt, kommt der zuerst.
  2. Was offen ist, ohne Umschreibung: Nicht „dazu gibt es unterschiedliche Auffassungen“, sondern „das liegt mir nicht geprüft vor“.
  3. Wohin: Eine konkrete Stelle, nicht „bitte informieren Sie sich“.
  4. Was der Nutzer mitnehmen kann: Die Frage so formuliert, dass sie an der zuständigen Stelle direkt gestellt werden kann. Das ist der Unterschied zwischen einer Absage und einer Hilfestellung.
⚠️
Eine Abstain-Quote von null ist ein Warnsignal, kein Erfolg. Sie bedeutet, dass das System auch dann antwortet, wenn das Wissen nicht reicht. Umgekehrt ist die Abstain-Quote nach Themen die wertvollste Kennzahl für die Redaktionsplanung: Sie zeigt Wissenslücken dort, wo tatsächlich gefragt wird, nicht dort, wo man sie vermutet.

Ausgang 3: Fallback mit Wiederholungsbudget

TypeScript
const MAX_WIEDERHOLUNGEN = 1;

async function liefereAntwort(
  signal: GuardSignal,
  bausteine: Baustein[]
): Promise<Antwort> {
  let entwurf = await generiere(signal, bausteine);
  let urteil = await pruefe(entwurf); // deterministisch + ggf. Modell

  for (let i = 0; i < MAX_WIEDERHOLUNGEN && !urteil.freigegeben; i++) {
    // Die konkrete Beanstandung reist als Zusatzanweisung mit.
    entwurf = await generiere(signal, bausteine, {
      beanstandung: urteil.grund,
    });
    urteil = await pruefe(entwurf);
  }

  if (!urteil.freigegeben) {
    // Kein weiterer Versuch: eine vorab freigegebene
    // Standardantwort je Beanstandungstyp.
    return safeFallback(urteil.beanstandungsTyp);
  }
  return entwurf;
}

Mehr als ein Wiederholungslauf lohnt nicht: Wird eine präzise benannte Beanstandung im zweiten Versuch nicht behoben, liegt das Problem meist nicht in der Formulierung, sondern in der Faktenlage oder im Prompt. Weitere Versuche kosten Zeit und Geld, ohne die Wahrscheinlichkeit deutlich zu erhöhen. Der Safe-Fallback ist kein generierter Text, sondern eine vorab freigegebene Antwort pro Beanstandungstyp, faktisch ein Baustein der Stufe 5 aus Step 4. Und er ist keine Blockade: Eine leere Antwort oder ein technischer Fehler wäre für den Nutzer der schlechteste aller Ausgänge.

AusgangAuslöserAntwortstrategieKennzahlWas ein Ausschlag bedeutet
Scope-GuardKein Bedürfnis oder Thema getroffen; Sonderpfad-AuslöserKönnen benennen, weiterleiten, Teilantwort wo möglichAblehnungsquote nach GrundLücke im Bedürfnis-Vokabular
AbstainKein oder unzureichend gedecktes WissenGedeckten Teil zuerst, Lücke benennen, Anlaufstelle, verwertbare FrageAbstain-Quote nach ThemaWissenslücke in der Redaktion
FallbackPrüfung nach einem Wiederholungslauf nicht bestandenFreigegebene Standardantwort je BeanstandungstypRückweisungsquote je GrenzeSteuerungsproblem in der Generierung
Übung: Die drei Ausgänge bauen

Aufgabe: Schreibe für den Versicherungs-Assistenten je eine konkrete Antwort für alle drei Ausgänge:

  1. Scope: „Kannst du mir bei meiner Steuererklärung helfen?“ Benenne, was das System kann, und leite weiter.
  2. Teilabstain: „Wie hoch ist das Pflegegeld, und bekommt meine Mutter es rückwirkend?“ Der erste Teil ist gedeckt, der zweite nicht. Nutze die vier Elemente.
  3. Safe-Fallback: Formuliere die freigegebene Standardantwort für den Beanstandungstyp „individuelle Zusage“.

Lege danach für jeden Ausgang die Kennzahl fest, die du im Betrieb beobachten würdest.

Zeitaufwand: ~10 Minuten

Takeaway
Regel #5: Baue jeden der drei Ausgänge als eigenen Zustand mit eigener Antwortstrategie und eigener Kennzahl. Ein System, das immer antwortet, ist nicht besonders fähig, es hat nur keine Alternative.
Schritt 7 von 7

Die Pipeline im Ganzen

Alle Bausteine zusammengesetzt, dazu die Checkliste, mit der du jede vorgelegte Architektur in zwei Minuten bewertest.

Step-Header: fertige, makellose Gussstücke aufgereiht unter der Werkstattlampe

Die Orchestrierung unten setzt jedes Artefakt dieser Lesson zusammen: den Vorfilter vor der Protokollierung, den Guard mit Signal, die Zulassungsliste, das eigenständige Retrieval mit Abstain, den Prüfplan aus der Risikoklasse, die Generierung mit Grenzen im Prompt, Nachfilter und Modellprüfung, das Wiederholungsbudget und den Safe-Fallback:

TypeScript
async function beantworte(roh: string): Promise<Antwort> {
  // Position 0: Vorfilter, erst danach Protokollierung (Step 2)
  const { maskiert, funde } = vorfilter(roh);
  const vorgang = protokolliere({ eingabe: maskiert, maskiert: funde });

  // Stufe 1: Guard liefert das Signal (Step 1)
  const signal = await guard(maskiert);

  // Ausgang 1: Zulassungsliste statt Sperrliste (Step 5)
  if (!imScope(signal, abgedeckteThemen)) return scopeAntwort(signal);

  // Retrieval: eigenständig und hybrid (Step 1)
  const bausteine = await retrieval(maskiert, signal.retrievalHinweise);

  // Ausgang 2: Abstain statt Antwort aus Allgemeinwissen (Step 5)
  if (!ausreichendGedeckt(bausteine, signal)) return abstain(signal, bausteine);

  // Prüftiefe und Freiheitsgrad aus der Risikoklasse (Steps 3 + 4)
  const plan = pruefplan(signal);

  // Stufe 2: Grenzen im System Prompt; bei "hoch" Bausteinkomposition
  let entwurf = await generiere(signal, bausteine, plan);

  // Position 3: Nachfilter läuft immer (Step 2)
  let urteil = nachfilter(entwurf, bausteine);

  // Position 4: Modellprüfung nur, wenn der Plan es verlangt (Step 3)
  if (urteil.freigegeben && plan.modellpruefung) {
    urteil = await modellpruefung(entwurf, signal);
  }

  // Ausgang 3: ein Wiederholungslauf, dann Safe-Fallback (Step 5)
  if (!urteil.freigegeben) {
    entwurf = await generiere(signal, bausteine, plan, urteil.grund);
    urteil = nachfilter(entwurf, bausteine);
    if (!urteil.freigegeben) return safeFallback(urteil.beanstandungsTyp);
  }

  protokolliere({ vorgang, bausteine, urteil });
  return entwurf;
}
💡
Bewusst vereinfacht: Diese Funktion zeigt die Anordnung, nicht produktionsreifen Code. In einem echten System kommen Fehlerbehandlung, Timeouts, Streaming, Parallelisierung und Instrumentierung dazu, und die Stufen liegen hinter eigenen Schnittstellen statt in einer Funktion. Für das Verständnis der Pipeline ist genau diese Reduktion gewollt.

Die sechs Schwachstellen als Review-Checkliste

Die Steps haben sie einzeln eingeführt, hier stehen sie als Prüfliste für jede vorgelegte Architektur:

SchwachstelleSymptomKorrektur
Grenzen am Rand statt in der MitteHohe Rückweisungsquote, Wiederholungs-LatenzGrenzen zusätzlich in den System Prompt der Generierung
Harte Grenzen stochastisch geprüftEin Modell prüft, was ein Regex prüfen könnteDeterministisch prüfen, was sich beschreiben lässt; das Modell prüft Ton und Passung
Sperrliste statt ZulassungslisteLücken fallen erst nach Vorfällen aufZulässigen Raum positiv definieren, Sperrliste nur für Sonderpfade
Retrieval hängt an der Themenextraktion des GuardsFalsches oder fehlendes Wissen, unbemerktGuard liefert Hinweise, Retrieval läuft eigenständig und hybrid
Kein definierter AuswegUngedeckte Antworten, Schleifen oder TimeoutsDrei Ausgänge als eigene Zustände mit Kennzahlen
Latenz und fehlendes StreamingSekunden ohne Rückmeldung, gerade bei dringenden AnfragenRisikobasiert routen, Streaming bei niedrigem Risiko

Die Regeln auf einen Blick

#Regel
0Bewerte jede Architektur an zwei Punkten: wo die Grenzen sitzen und ob jeder Ausgang definiert ist
1Harte Grenzen zusätzlich in den System Prompt der Generierung, Quellbausteine in den Validator-Kontext
2Deterministisch filtern, bevor das erste Modell den Text sieht, erst danach protokollieren
3Variante pro Risikoklasse wählen, bei niedriger Konfidenz immer nach oben eskalieren
4Freiheitsgrad pro Risikoklasse einstellen: was nie generiert werden kann, muss nicht abgefangen werden
5Drei Ausgänge als eigene Zustände bauen, jeder mit Antwortstrategie und Kennzahl
💡
Wie diese Lesson zu den anderen steht: Eindämmen statt abwehren beantwortet, was ein Agent mit seinen Rechten schlimmstenfalls anrichtet. Diese Lesson beantwortet, wie du die Generierung selbst so baust, dass weniger schiefgehen kann. Human-in-the-Loop ergänzt die Freigabe-Perspektive, Der Stack hinter einer KI-App liefert die Werkzeuge unter dieser Pipeline, und Prompts, die halten die Prompt-Ebene der Grenzen. Ob deine Pipeline hält, was sie verspricht, misst du mit Evals.
Übung: Dein eigenes Review

Aufgabe: Nimm einen KI-Assistenten aus deinem Umfeld, etwa einen Kundenservice- oder Support-Bot, oder den Versicherungs-Assistenten, wenn du keinen zur Hand hast.

  1. Geh die Sechs-Schwachstellen-Checkliste durch und notiere jeden Fund.
  2. Ordne jeden Fund einer der fünf Prüfpositionen aus Step 0 zu.
  3. Schreibe pro Fund die Korrektur als einen Satz, so wie du sie ins nächste Review einbringen würdest.

Zeitaufwand: ~10 Minuten

Takeaway
Der Kern in einem Satz: Sicherheit entsteht nicht dadurch, dass mehr geprüft wird, sondern dadurch, dass in der Generierung weniger schiefgehen kann. Prüfschichten sind Absicherung. Gesteuert wird dort, wo die Antwort entsteht.
Rico Loschke

Rico Loschke

KI-Stratege & Übersetzer zwischen Tech und Business

15+ Jahre Digitalisierung, 4+ Jahre KI. Ich übersetze zwischen Technologie und Unternehmensstrategie, berate und trainiere Organisationen auf ihrem KI-Weg. Hier teile ich, was ich dabei lerne.

loschke.ai.Visionen, Konzepte, Meinungen →
unlearn.how

Diese Lessons gibt es auch als Team-Training.

Workshops, Seminare und Begleitung für Unternehmen, die KI nicht nur verstehen, sondern anwenden wollen.

Mehr erfahren →