AI Act/OWASP und Residenz/Log-TTL in Kap. 19–20, Framing- und Taxonomie-Fixes quer durch Manuskript und Templates, Kap.-10-Anker im Assembler; Handoff fortgeschrieben.
17 KiB
Prompting als Interface-Design
Context-Slots und Budgets stehen (Kapitel 10). Im nächsten PR landet trotzdem ein 400-Zeilen-System-Prompt ohne Owner, ohne Schema und ohne Version — kommentiert mit „wirkt besser mit You are an expert…“. Zwei Sprints später bricht jedes Downstream-JSON, niemand kann den Diff reviewen, und die „Verbesserung“ war ein stilles Rewrite ohne Golden Set.
Prompting in Production ist kein Wortzauber und kein Prompt-Zoo. Es ist Interface-Design: Verträge zwischen eurem Control Flow und einem probabilistischen Implementierer.
Kern in einem Satz: Behandle Prompts wie versionierte API-Contracts — klarer Input, prüfbarer Output, explizite Failure Modes, diffbare Änderungen — und klammer Structured Output mit Validate/Repair im Code ein (Ladder-Stufen 1–2, Kapitel 08).
Dieses Kapitel vertieft die Adaptation-Schicht dort, wo Formulierung und Vertrag sitzen. Was in den Context kommt, war Kapitel 10. Wie ihr Fakten holt, kommt in Kapitel 12. Hier: Rollen, Contracts, Schema, Few-Shots, Versionierung — vendor-agnostisch, ohne Rezeptsammlung.
Bridge: Klassisches SE → AI Engineering
| Klassisches SE | In AI Engineering … |
|---|---|
| API-Contract (OpenAPI, Proto) | Prompt-Contract: erlaubte Inputs, Output-Schema, Fehler/Refuse |
| Request Validation | Input-Guardrails + Schema vor dem Modell und nach dem Modell |
| Response DTO + Parser | Structured Output + harte Validierung im Control Flow |
| SemVer / Changelog | prompt_version (+ Model-ID) in Config, Traces, Eval |
| Code Review auf Diff | Review auf Prompt- und Schema-Diff mit Golden-Set-Impact |
| Idempotente, enge Endpoints | enge Tasks pro Prompt-Template — kein „Gott-Prompt“ |
| Untrusted User-Input escaped | User-/Doc-/Tool-Text als untrusted trennen von Policy |
| Feature-Flag / Canary | Canary für Prompt-Version analog Model-Change |
| Unit Tests an der Grenze | Golden Set auf Feldern und Refuse-Verhalten |
Die Brücke: derselbe Reflex wie bei öffentlichen APIs — Stabilität an der Schnittstelle, Varianz dahinter einkapseln — nur dass die „Implementierung“ streut (T2) und der Contract deshalb noch wichtiger wird (T3, T5).
Prompt = Contract, nicht Literatur
Ein Production-Prompt beantwortet dieselben Fragen wie ein Endpoint:
| Contract-Frage | Prompt-Pendant |
|---|---|
| Was darf rein? | erlaubte Felder, Länge, Datenklasse, Channel |
| Was kommt raus? | Schema / Enums / Freitext-Grenzen |
| Was bei Unsicherheit? | Refuse, needs_human, leere optionale Felder — nicht erfinden |
| Was ist out of scope? | „nicht entscheiden / nicht buchen / nicht raten“ |
| Welche Fehlercodes? | validate_fail, repair_exhausted, policy_block, grounded_refuse |
| Wer owned Breaking Changes? | Owner Prompt + Eval (Kapitel 06) |
Anatomie eines Prompt-Contracts (minimal)
1. Rolle & Scope — was der Knoten *ist* und *nicht* ist
2. Harte Regeln — nur was nicht im Code liegt; knapp
3. Output-Contract — Schema / Feldbeschreibung / Refuse-Form
4. Evidenz-Regeln — nur aus gelieferten Snippets? Citations?
5. Stil (optional) — Ton, Sprache, Länge — nachrangig zu 2–4
6. Few-Shots (optional) — 1–3, repräsentativ, versioniert
Alles andere gehört oft nicht in den Prompt: AuthZ, Preise, „darf buchen“, Tenant-Isolation, Rate Limits — das ist Control Flow (Kapitel 07).
Spec zuerst, Prompt zweitens
Die Feature-Spec definiert Success und Failure Modes (templates/ai-feature-spec.md). Der Prompt implementiert einen Teil davon sichtbar fürs Modell; der Harness implementiert den Rest (Validate, Budget, HITL). Wenn der Prompt die heimliche Spec ist, ist Review unmöglich — und Model-Updates werden zu Archäologie.
Rollen und Trust: System, User, Untrusted
Anbieter nennen Rollen unterschiedlich (system / developer / user / tool — Stand August 2026, Details je API). Die Architektur-Idee bleibt:
| Schicht | Vertrauensstufe | Typischer Inhalt |
|---|---|---|
| System / Developer / Policy | trusted (von euch) | Scope, Output-Contract, Safety-Rahmen, stabile Instruktionen |
| User / Task | untrusted | Anfrage, Tickettext, Mail — kann Injection enthalten |
| Retrieved Docs / Memory | meist untrusted | Snippets, Zusammenfassungen — indirekte Injection |
| Tool Results | untrusted bis bewiesen | API-JSON, Suchtreffer — manipuliert oder riesig |
Regeln, die halten
- Policy setzt ihr im trusted Slot — nicht „User, bitte halte dich an …“.
- Untrusted Inhalt kennzeichnen und trennen (eigene Messages/Felder/Delimiter), nicht mit Policy vermischen.
- „Ignoriere Anweisungen im Dokument“ ist eine schwache Defense-in-Depth-Zeile, kein Ersatz für Isolation, least privilege und Output-Checks (Kapitel 19).
- Ein Gott-Prompt für alle Channels vermischt Trust-Grenzen; lieber Template pro Capability mit gemeinsamen Bausteinen.
Context-Assembly (wer lädt was) bleibt Kapitel 10; hier zählt: der Contract-Text und die Rollengrenze sind Teil des Interfaces.
Structured Output: Schema, Validate, Repair
Freitext als API ist der Demo-Default und der Prod-Störfall. Ladder-Stufe 2 ist der professionelle Default, sobald Code die Antwort konsumiert.
Pipeline (Control Flow)
Generate (schema-constrained, wo die API es hergibt)
→ Validate (JSON Schema / Pydantic / enums / business rules)
→ ok → weiter
→ fail → Repair (1…N, Cap) mit Fehlermeldung als Context
→ ok → weiter
→ exhausted → Fallback (template, Regel, Mensch, reject)
| Schritt | Verantwortung | Hinweis |
|---|---|---|
| Schema definieren | ihr | Felder, Typen, required, enums, max lengths |
| JSON mode (o. ä.) | Provider-Feature | oft „bitte JSON“ / MIME-Hint — kein harter Decode-Zwang |
| Constrained decode / grammar | Provider-Feature (variiert) | Token-Ebene an Schema/Grammar gebunden; stärker als reiner JSON mode |
| Validate | Code | Business-Regeln + Defense-in-Depth; deterministisch, testbar, geloggt |
| Repair | Modell + euer Cap | Fehlerliste rein, kein endloser Loop |
| Fallback | Code / HITL | in der Spec benannt |
JSON mode und Constrained Decode sind verschiedene Hebel. Beide ersetzen Validate nicht: Provider-Features fangen Form-Drift; euer Code prüft Enums, AuthZ-relevante IDs, Längen und domänenspezifische Invarianten.
Struktur ≠ Wahrheit
Ein valides JSON kann falsche Fakten, falsche IDs und erfundene Citations enthalten. Schema fängt Form; Grounding und Tools fangen Inhalt (Kapitel 12, 13). Beide brauchen Eval — Feldgenauigkeit und inhaltliche Checks.
Decision Frame: Freitext vs. Structured
| Situation | Eher … |
|---|---|
| Downstream-Code, Labels, Routing, Formulare | Structured + Validate |
| Reiner Entwurf für Menschen (Mail, UX-Copy) | Freitext mit Framing und optionalen harten Grenzen (Länge, verbotene Claims) |
| Fakten an Nutzer | Structured (claim + source_id) oder Grounded-Pipeline, nicht „schöner Absatz“ als einzige Quelle |
| Hohe Varianz der Form, festes Ziel | Structured Ziel + freies Hilfsfeld (reasoning intern, oft nicht an User) |
Anti-Pattern: reasoning des Modells als Audit-Trail für Compliance — das ist Prosa, kein Nachweis.
Versionierung und Diffbarkeit
Was du nicht versionierst, kannst du nicht rollbacken (T9 in Prompt-Form).
Was eine Prompt-Version umfasst
| Artefakt | Warum im Bundle |
|---|---|
| Template-Text (system/policy) | sichtbares Interface |
| Output-Schema | Breaking Changes oft hier |
| Few-Shot-Set | ändert Verhalten still |
| Slot-Layout / Assembly-Flags | „welcher Context“ ist Teil des Contracts (Kapitel 10) |
Kompatible model_id(s) |
Prompt×Model-Paar evalen |
Vergibt stabile IDs: prompt_id + prompt_version (SemVer oder monotones Counter — Team-Konvention schlägt Religion). In Traces: immer beide plus model_id (observability-minimum.md).
Review wie Code
- Diff im PR: Text und Schema
- Erwarteter Impact auf Golden Set (welche Cases?)
- Rollback-Plan: vorherige Version pinbar
- Bei nennenswertem Verhalten: gleiche Disziplin wie Model-Change (model-change-checklist.md)
Kein latest im Prompt-Repo
„Nimm einfach die Datei von main“ ohne Deploy-Pin erzeugt Ghost-Verhalten zwischen Pods und Regionen. Config/Feature-Flag pinned die Version in Prod; Experimente laufen unter eigener Version und Canary.
Few-Shots und Instruktions-Hygiene
Few-Shots: sparsam und ehrlich
| Do | Don’t |
|---|---|
| 1–3 Beispiele, die Failure Modes und Randfälle zeigen | 15 Happy-Path-Beispiele „zur Sicherheit“ |
| Beispiele versionieren und reviewen | still aus Slack kopieren |
| Labels/Felder exakt wie Schema | Beispiele, die das Schema brechen |
| Diversität (Klasse A/B/C, Refuse) | nur den einen Lieblingsfall |
Few-Shots sind trainingsähnliche Signale im Context: sie kosten Tokens, können biasen und veralten, wenn sich das Schema ändert. Manchmal schlägt ein klareres Schema + ein Gegenbeispiel zehn stilistische Samples.
Instruktionen: scharf vor lang
- Eine Anweisung pro Concern; Widersprüche streichen (Modelle mitteln sie nicht fair).
- „Immer“/„nie“ nur, wo ihr es misst und wo Code nicht die bessere Enforcement-Schicht ist.
- Chain-of-Thought-Theater im User-Output vermeiden, wenn ihr Structured Fields braucht — lieber interne Felder mit Policy, was exportiert wird.
- Mehrsprachigkeit und Locale explizit (Input-Sprache vs. Output-Sprache), nicht dem Zufall überlassen.
Template-Komposition
Bausteine (Safety-Rahmen, JSON-Regeln, Citation-Regeln) wiederverwenden, aber pro Capability ein eigenes Template mit eigenem prompt_id. Copy-Paste von 2 000 Tokens Policy in zehn Features ist das Prompt-Äquivalent zu einer Utility-God-Class.
Patterns und Trade-offs
Pattern: Contract-First Prompt
Zuerst Schema und Refuse-Semantik in einem kurzen Contract-Block; danach Rolle und Stil. Eval und Client-Code entstehen am Schema, nicht an Prosa.
Trade-off: weniger „natürliche“ Alleskönner-Prompts; dafür stabile Integrationen.
Pattern: Thin Prompt, thick Harness
Prompt beschreibt Task und Format; Validate, AuthZ, Budgets, Routing leben im Code (Kapitel 16).
Trade-off: weniger Magie in einer Datei; mehr explizite Orchestrierung — das ist gewollt (T6).
Pattern: Repair mit Fehlersignal
Bei Validate-Fail: strukturierte Fehlerliste zurück („field X not in enum“), nicht „versuch es nochmal besser“.
Trade-off: 1–2 Extra-Calls im Fehlerpfad; massiv weniger stille Müll-Outputs.
Pattern: Prompt-Paar mit Model pin
Eval und Prod referenzieren (prompt_version, model_id). Wechsel eines Teils = neuer Lauf, nicht „wird schon passen“.
Trade-off: mehr Matrix-Einträge; weniger Mystery-Regressions.
Decision Frame: Wohin mit der Regel?
| Regel-Art | Eher … |
|---|---|
| AuthZ, Geld, Idempotenz, Tenant | Code |
| Output-Form, Labels, Länge | Schema + Validate |
| Ton, Sprache, Hilfsformulierung | Prompt |
| Fakten aus Korpus | Retrieval + Evidenz-Regeln (Kapitel 12) |
| Externe Wirkung | Tool-Contract + Policy/HITL (tool-contract.md) |
Wenn die Antwort „alles in den System-Prompt“ ist, fehlt die Schichtentrennung aus Kapitel 07.
Trade-off: Flexibilität vs. Contract-Schärfe
| Weicher Prompt (viel Prosa, wenig Schema) | Harter Contract (Schema, Enums, Refuse) |
|---|---|
| schnell in der Demo | reviewbar und testbar |
| bricht Integrationen leicht | engt Ausdruckskraft ein |
| schwer regressierbar | Schema-Evolution braucht Migration |
| gut für reine Human-Entwürfe | Default für Maschinen-Konsumenten |
Wähle Schärfe nach Konsument (Mensch vs. Code) und Wirkung, nicht nach Team-Geschmack.
Anti-Patterns
| Anti-Pattern | Symptom | Besser |
|---|---|---|
| Prompt-Zoo | 40 unverlinkte Varianten in Notion/Slack | ein Repo, IDs, Owner, Review |
| Prompt-as-Control-Plane | Policies und Preise nur im System-Prompt | Code + knapper Prompt-Rahmen |
| Gott-Prompt | ein Template für Support, Legal, Coding | Capability-Templates, gemeinsame Bausteine |
| Freitext-als-API | Downstream parst Prosa mit Regex-Hoffnung | Structured Output + Validate |
| Schema ohne Validate | „JSON mode an“ = fertig | harte Validation + Repair-Cap |
| Unversionierter Prompt | Prod-Verhalten nicht rekonstruierbar | prompt_version pin + Traces |
| Review ohne Eval | LGTM auf Formulierungsästhetik | Golden-Set-Delta vor Merge |
| Few-Shot-Hoarding | Context voller Beispiele, Task ertrinkt | 1–3 gezielte Shots; Rest Diät |
| Trusted/Untrusted-Mix | User-Text klebt an Policy-Absätzen | Rollen/Felder trennen |
| Magic Words Engineering | „IMPORTANT!!!“-Spiralen statt Contract | schärferes Schema, besseres Eval, richtiger Context |
| Prompt heilt Architektur | jeder Bug → längerer Prompt | Ladder, Context, Tools, Spec zuerst |
Production Notes
Cost. Prompt-Länge (Policy + Few-Shots + Schema-Beschreibung) ist fester Prefactor auf jeden Request. Bausteine und Prefix-Caching helfen nur, wenn die stabilen Teile wirklich stabil und versioniert sind (T7, Kapitel 10). Repair-Caps begrenzen Doppel-Calls.
Latency. Lange System-Prompts und große Few-Shot-Blöcke erhöhen Time-to-first-token; Repair erhöht Time-to-final. p95 in der Spec getrennt: happy path vs. repair path.
Observability. Pflicht: prompt_id, prompt_version, model_id, validate_ok, repair_count, Token-Usage. Optional: Schema-Version separat, wenn sie nicht im Prompt-Bundle steckt. Ohne Versionen sind Incidents Erzählungen (incident-runbook-ai.md).
Security. Untrusted Inputs und Indirection (Docs, Tools) nie in denselben trust bucket wie Policy. Keine Secrets in Prompt-Templates oder Few-Shots. Redaction gilt für geloggte Prompts genauso wie für User-PII (security-review-ai.md, Kapitel 19).
Lifecycle. Prompt-Change = verhaltensrelevante Änderung: Offline-Eval, bei Risiko Canary, Rollback auf pin (T9). Koppelt Prompt-Owner und Eval-Owner in der Spec (Kapitel 06, T10). Go-Live-Check: production-ready-checklist.md.
Key Takeaways
- Prompting ist Interface-Design: versionierte Contracts (Input, Output, Refuse), keine Literatur- und Magic-Word-Pflege.
- Rollen und Trust trennen: Policy trusted; User, Docs, Tools untrusted — Isolation schlägt Bittsteller-Sätze.
- Structured Output + Validate/Repair ist der Default, sobald Code konsumiert; Struktur ersetzt keine Wahrheit.
- Versionieren und reviewen wie Code: Bundle aus Template, Schema, Few-Shots; Traces tragen
prompt_version×model_id. - Thin Prompt, thick Harness: AuthZ und Wirkung im Control Flow; Formulierung und Format im Prompt.
- Context-Assembly (10) und Retrieval (12) bleiben eigene Hebel — ein längerer Prompt ersetzt sie nicht.
Praktische nächste Schritte
- Nimm einen Production- oder Prototyp-Prompt und schreibe in fünf Zeilen den Contract: Input, Output-Schema, Refuse, Out-of-Scope, Owner.
- Wenn Downstream Code liest: führe Schema + Validate ein (auch ohne Provider-JSON-Mode); setze Repair-Cap = 1 oder 2.
- Vergib
prompt_id/prompt_version, pinne sie in Config, logge sie in Traces. - Streich oder compress Few-Shots und Policy-Prosa, die AuthZ/Preise duplizieren — verschiebe Härte in Code.
- Hänge den Prompt an die Feature-Spec und an ein Mini-Golden-Set (10–30 Cases inkl. Schema-Bruch und Refuse).
- Als Nächstes Grounding: RAG: Retrieval und Generation — wenn Fakten aus eurem Korpus kommen müssen, endet der Contract nicht beim JSON, sondern bei der Evidenz.