Strukturierte Multi-Persona-Content-Generierung mit Azure OpenAI und SSE-Streaming

Veröffentlicht von Rhein-Ruhr-Informatik am

In diesem Tutorial erstellen wir ein Content-Generation-Studio, das ein einzelnes Marketing-Briefing mithilfe verschiedener KI-Personas in drei strukturierte Content-Variationen umwandelt. Das Frontend wird mit Next.js und TypeScript entwickelt, das Backend verwendet Python mit FastAPI und Azure OpenAI übernimmt die strukturierte Generierung sowie das native Server-Sent-Events-Streaming (SSE), während Azure Content Safety für automatisierte Moderations-Guardrails sorgt.

Anstatt unvorhersehbaren Rohtext zu erzeugen, erzwingt unsere Anwendung garantierte Datenschemata (title, body und seoKeywords), Echtzeit-Fortschritts-Feedback via SSE-Streaming und drei unterschiedliche Perspektiven, die auf bestimmte Zielgruppen zugeschnitten sind: Friendly SaaS Marketer, Technical Blogger und Skeptical CFO.

Next.js (TypeScript) → FastAPI → Azure Content Safety (Guardrails)
                                      ↓
                               Azure OpenAI (GPT-4.1 / Structured Outputs)
                                      ↓
                               Server-Sent Events (SSE-Stream)
                                      ↓
                               3 Persona-Variationen (Title, Body, SEO Keywords)

Voraussetzungen

  • Python und Node.js müssen auf Ihrem Computer installiert sein.
  • Eine Azure-OpenAI-Ressource mit einem bereitgestellten Modell (z. B. GPT-4.1-mini oder GPT-4o).
  • Eine Azure-Content-Safety-Ressource.
  • Grundkenntnisse in FastAPI, Next.js und TypeScript.
  • Grundlegendes Verständnis von Server-Sent Events (SSE) und Pydantic-Schemas.

Schritt 1: Pydantic-Schema definieren

Zunächst definieren wir die Struktur, die unsere Anwendung vom Modell erwartet. Dazu erstellen wir Pydantic-Modelle für die einzelnen Variationen und den übergeordneten Antwort-Container:

class Variation(BaseModel):
    id: int
    title: str
    body: str
    seoKeywords: list[str] = Field(default_factory=list)

class ResultSchema(BaseModel):
    variations: list[Variation]

Dieses Schema fungiert als doppelter Vertrag: Es garantiert die Struktur unserer Backend-API-Antworten für das Next.js-Frontend und wird direkt an die Structured-Outputs-Engine von Azure OpenAI übergeben um das JSON-Schema des Modells strikt einzuschränken.

Schritt 2: Persona-System-Prompts implementieren

Marketingtexte erfordern je nach Kanal und Zielgruppe unterschiedliche Tonalitäten. In unserer Anwendung definieren wir drei System-Prompts:

PERSONAS = {
    „friendly“: {
        „name“: „Friendly SaaS Marketer“,
        „system“: (
            „You are a friendly SaaS marketer. „
            „Write in a warm, benefit-led, conversational tone. „
            „Prefer short sentences and a clear call to action.“
        ),
    },
    „technical“: {
        „name“: „Technical Blogger“,
        „system“: (
            „You are a technical blogger. „
            „Write in a precise, credible, educational tone. „
            „Include concrete details, trade-offs, and one practical tip.“
        ),
    },
    „cfo“: {
        „name“: „Skeptical CFO“,
        „system“: (
            „You are a skeptical CFO. „
            „Write in a direct, evidence-driven, ROI-focused tone. „
            „Quantify impact where possible and flag risks explicitly.“
        ),
    },
}

Sobald eine Anfrage eingeht, kombiniert das Backend den ausgewählten Persona-System-Prompt dynamisch mit den Benutzeranweisungen, die das Briefing, die Zielgruppe, das Format (LinkedIn-Post, Marketing-E-Mail oder Landingpage-Text) und die Ausgabesprache enthalten.

Schritt 3: Content-Moderation mit Azure Content Safety

Bevor das Sprachmodell aufgerufen wird, validiert das Backend das Briefing mit Azure Content Safety. Dadurch werden schädliche Eingaben in Kategorien wie Gewalt, Hassrede, Selbstverletzung und sexuelle Inhalte erkannt:

response = content_safety_client.analyze_text(
    AnalyzeTextOptions(text=req.brief)
)
is_safe = all(item.severity < 2 for item in response.categories_analysis)

Werden schädliche Inhalte erkannt, gibt die API ein strukturiertes 400 Bad Request mit detaillierten Kategorieangaben zurück. Dies verhindert Prompt-Injections und Missbrauch und spart gleichzeitig Token-Kosten bei blockierten Prompts. Als Fallback steht zudem eine lokale Heuristik bereit.

Schritt 4: Echtzeit-SSE-Streaming und inkrementelles Parsing

Die Generierung von drei vollständigen Marketing-Variationen dauert einige Sekunden. Anstatt den Benutzer auf die gesamte Antwort warten zu lassen, nutzen wir Server-Sent Events (SSE) über die StreamingResponse von FastAPI:

@app.post(„/generate/stream“)
def generate_stream(req: GenerateRequest):
    def events():
        yield _sse_event(„safety“, {„safe“: True})
        yield _sse_event(„start“, {„request_id“: request_id})
        with client.responses.stream(
            model=DEPLOYMENT,
            instructions=system,
            input=user_prompt,
            text_format=ResultSchema,
        ) as stream:
            for event in stream:
                if event.type == „response.output_text.delta“:
                    yield _sse_event(„delta“, {„text“: event.delta})
                    # Inkrementell abgeschlossene JSON-Variation-Objekte extrahieren
                    for v in _complete_variations_from_json(accumulated_text):
                        yield _sse_event(„variation“, {„variation“: v.dict()})
    return StreamingResponse(events(), media_type=“text/event-stream“)

Der Streaming-Generator parst die JSON-Chunks in Echtzeit. Sobald die schließende Klammer einer Variation erreicht ist, wird ein variation-SSE-Event gesendet. Dadurch kann das Next.js-Frontend jede Content-Karte sofort rendern, sobald sie fertiggestellt ist, was eine schnelle und reaktionsfreudige Benutzeroberfläche ermöglicht.

Schritt 5: FastAPI und Next.js mit Observability verbinden

Das Next.js-Frontend verbindet sich direkt über Standard-fetch mit dem FastAPI-Stream und liest die Datenblöcke mit einem ReadableStreamDefaultReader. Es rendert den Live-Fortschritt, zeigt Persona-Badges an und unterstützt sofortiges Kopieren, eine JSON-Ansicht und den Datei-Export. Zusätzlich erfasst jede Anfrage umfassende Observability-Daten:

  • Latenz in Millisekunden.
  • Prompt-, Completion- und Gesamt-Token-Verbrauch.
  • Geschätzte Ausführungskosten basierend auf den Azure-OpenAI-Token-Preisen.
  • Pro-Client-Generierungsprotokolle, die in SQLite und im Arbeitsspeicher gespeichert werden.

Warum Personas und Structured Outputs wichtig sind

Ohne Persona-Steuerung und Structured Outputs neigen KI-Antworten dazu, generisch, unvorhersehbar und in Produktionsanwendungen schwer zu parsen zu sein. Die Kombination aus expliziten Persona-Anweisungen und Pydantic-Schemas liefert vorhersehbare, hochwertige Ergebnisse, die direkt auf reale Marketing-Workflows zugeschnitten sind.

  • Das Frontend erhält ein garantiertes, typsicheres Datenschema.
  • Im Anwendungscode ist kein Entfernen von Markdown-Codeblöcken oder Regex-Parsing nötig.
  • Personas sorgen für eine konsistente Markenstimme und klare Positionierung.
  • Streaming eliminiert die wahrgenommene Wartezeit und verbessert die Benutzererfahrung.

Fazit

Mit Next.js, FastAPI, Azure OpenAI und Azure Content Safety haben wir eine End-to-End-Content-Generierungsanwendung mit unternehmensweiten Guardrails und Echtzeit-Streaming entwickelt.

FastAPI-Backend      → Steuert Sicherheitsprüfungen, Persona-Mapping, Streaming und Token-Logs
Azure OpenAI         → Liefert strukturierte, Persona-gesteuerte Generierung über GPT-4.1
Azure Content Safety → Blockiert schädliche Prompts vor der Ausführung
Next.js-Frontend     → Bietet eine reaktive, mehrsprachige UI mit Live-SSE-Karten-Rendering

Diese Kombination verwandelt generative KI von einem unvorhersehbaren Chat-Experiment in eine verlässliche, produktionsreife Content-Engineering-Pipeline.

Ich hoffe, dieses kurze Tutorial war hilfreich.

Now let’s code!

Kategorien: Artikel

de_DEDeutsch