TL;DR — Was du nach diesem Artikel weißt
- Wie Schema-First-Generation mit Pydantic den LLM-Output deterministisch macht.
- Den vollständigen
VideoScript- undScene-Schema-Code aus dem Repo.- Welche Hook-Phase-Constraints das Skript einhalten muss (3s title_card, danach 18-20s comfy/manim).
- Warum Claude Opus 4.7 hier wirklich das richtige Modell ist — Trade-off-Analyse.
- Wie der Script-Generator-Agent die Brücke zum Visual-Orchestrator schlägt.
Der Topic-Ranker-Agent aus dem letzten Teil wählt das Topic des Tages. Aber ein Topic ist noch lange kein Video. Es braucht eine strukturierte Story — Hook in den ersten 3 Sekunden, Kontext in 30, technischer Kern, Einordnung, CTA. Plus für jede einzelne Szene: Narration auf Deutsch, ein Visual-Type, ein Visual-Prompt, eventuell ein Bewegungs-Hint, eventuell On-Screen-Text.
Genau diesen Job übernimmt der Script-Generator-Agent. Er ist die kreativste Stage der gesamten Multi-Agent-Pipeline — und gleichzeitig die strengste, weil sein Output gegen ein Pydantic-Schema validiert wird, bevor irgendein anderer Agent ihn anfasst.
“Mein erster Script-Generator-Versuch war ein einziger Prompt mit detaillierten Format-Regeln in Prosa. Hat zu 60 % funktioniert — der Rest war Halluzination, falsche Visual-Types, fehlende Felder. Mit Pydantic-Schema bin ich bei 95 %+ Erfolgsrate, und die fehlenden 5 % fängt ein einziger automatischer Retry ab.”
Was der Script-Generator-Agent konkret tut
Eingang: ein topic.json aus dem Topic-Ranker-Agent. Ausgang: ein script.json mit kompletter Video-Struktur. Vereinfacht:
from src.script.generate import generate as script_generate
script_path = script_generate(topic_path)
Was zwischen Eingang und Ausgang passiert:
- URL des Topics wird gefetched (Faktenbasis)
- System-Prompt + Topic + URL-Inhalt geht an Claude Opus 4.7
- Claude generiert vollständiges JSON-Script
- Pydantic validiert das JSON gegen
VideoScript-Schema - Bei Validierungs-Fehler: Retry mit angereicherter Fehler-Info
- Output wird als
*.script.jsongespeichert
Der Output ist ein einziges JSON-Objekt mit topic_id, title, description, tags, thumbnail_text und einer Liste von scenes. Beispiel aus einem realen Run (gekürzt):
{
"topic_id": "2026-05-02-wie-funktionieren-agenten",
"title": "Wie KI-Agenten wirklich funktionieren – die Architektur dahinter",
"thumbnail_text": "So denkt ein Agent",
"scenes": [
{
"scene_id": 1,
"duration_sec": 3.0,
"narration": "Ein Agent ist kein Zauber. Es sind vier Teile.",
"visual_type": "title_card",
"visual_prompt": "Titel: 'Wie KI-Agenten funktionieren'. ...",
"on_screen_text": "Lernreihe #2"
},
...
]
}
Diese Struktur ist deterministisch. Der Visual-Orchestrator weiß genau, was er bekommt — keine Halluzinations-Toleranz im Datenfluss.
Das Pydantic-Schema — der Vertrag zwischen den Agenten
Der Kern dieses Agents ist nicht der LLM-Call, sondern das Pydantic-Schema. Es ist der Vertrag, an den sich Claude halten muss, und das Tor, durch das der Output zum nächsten Agent gehen darf.
Hier das Schema:
from typing import Literal
from pydantic import BaseModel, Field
VisualType = Literal["manim", "comfy", "slide", "stock", "code", "title_card", "code_slide"]
class Scene(BaseModel):
scene_id: int
duration_sec: float = Field(ge=2.0, le=180.0)
narration: str = Field(description="Was die KI-Stimme sagt. Deutsch, klare Sätze.")
visual_type: VisualType
visual_prompt: str
motion_hint: str | None = None
on_screen_text: str | None = None
class VideoScript(BaseModel):
topic_id: str
title: str = Field(description="Finaler YouTube-Titel, max 70 Zeichen")
description: str = Field(description="YouTube-Description, ~600 Zeichen")
tags: list[str] = Field(min_length=8, max_length=15)
thumbnail_text: str
scenes: list[Scene] = Field(min_length=4)
@property
def total_duration(self) -> float:
return sum(s.duration_sec for s in self.scenes)
Was dieses Schema bewirkt:
VisualTypeals Literal-Type: Claude kann nicht “video” oder “animation” zurückgeben. Nur die 7 erlaubten Werte sind valid. Pydantic lehnt jedes andere Wort ab.duration_sec-Range 2.0–180.0: Halluzinierte 0-Sekunden- oder 5-Stunden-Szenen werden gefangen.tags-Length 8–15: Kein YouTube-Upload mit nur 2 Tags oder mit 50 Tags-Spam.scenes-min_length=4: Kein 1-Szenen-Video als “Skript”.@property total_duration: Wird später vom Pipeline-Orchestrator genutzt, um Render-Aufwand abzuschätzen.
“Pydantic-Schemas sind das, was meinen Multi-Agent-Stack stabil macht. Jeder Agent kennt das Eingangs- und Ausgangs-Schema des nächsten. Wenn ich morgen den Script-Generator austausche — gegen GPT-5, gegen ein lokales Modell, gegen ein anderes Framework — muss nur das Schema-Verhalten gleich bleiben. Alle anderen Agenten merken nichts.”
Hook-Phase-Constraints — wo das Skript wirklich entscheidet
Der System-Prompt im Script-Generator-Agent ist mit konkreten Pacing-Regeln versehen. Auszug:
SCRIPT_SYSTEM = f"""...
HARTE VORGABEN:
- Mindestens 14 Szenen, max 20.
- Jede Szene mindestens 18 Sekunden Sprechdauer
(außer title_card und CTA).
- title_card am Anfang: GENAU 3 Sekunden (nicht länger).
- CTA am Ende: 8-15 Sekunden.
- Pro Szene mindestens 40 deutsche Wörter Narration
(außer title_card mit ~6-8 Wörtern und CTA mit ~20-30 Wörtern).
STRUKTUR (Pflicht):
1. HOOK (5-10s): Provokante Frage, überraschende Zahl, oder direkter Konflikt.
Niemals 'Hallo und willkommen'. Niemals 'In diesem Video'.
2. KONTEXT (30-45s): Worum geht es konkret, was ist passiert.
3. KERN (3-4 Min): Wie funktioniert das technisch?
4. EINORDNUNG (45-60s): Was bedeutet das praktisch?
5. BRIDGE/CTA (10-15s): NICHT 'Daumen hoch und abonnieren'.
"""
Diese Regeln lassen sich nicht im Pydantic-Schema validieren — sie sind inhaltlich, nicht strukturell. Sie sind im System-Prompt verankert. Trotzdem: Pydantic fängt das Wichtigste — Längen-Range pro Szene, Min-Anzahl von Szenen, Visual-Type-Beschränkung.
Der Rest ist Prompt-Engineering. Ich habe die HOOK-Regeln über drei Iterationen geschärft, bis Claude konsistent provokante Hooks lieferte. Wer “Hallo und willkommen” verboten will, muss es explizit schreiben — sonst kommt es zu 30 % der Zeit zurück.
“Die HOOK-Phase-Regeln sind das Resultat von ~50 manuell gesichteten Test-Skripten. Bei jedem Versuch hab ich notiert, was Claude trotz Regel produziert hat, dann die Regel verschärft. Heute krieg ich Hooks wie ‘Sam Altman zieht UBI zurück’ statt ‘Heute reden wir über Universal Basic Income’.”
Defensive Validierung mit Retry-on-Error
Pydantic-Validation ist hart — bei jedem Schema-Fehler bricht der Validator ab. Ein zu kurzer tags-Array, ein nicht erlaubter visual_type, eine duration_sec außerhalb des Range — alles ValidationError.
Was beim Bauen herausgekommen ist: Claude macht diese Fehler tatsächlich gelegentlich, vor allem bei langen Skripten. Lösung: Retry-Logic, die den Validierungs-Fehler als Feedback in den Retry-Prompt einbaut.
try:
script = VideoScript.model_validate_json(text)
except ValidationError as e:
# Retry mit Fehler-Info
retry_msg = f"""Dein letzter Output war ungültig. Pydantic-Fehler:
{e}
Bitte korrigiere das und liefere wieder das vollständige JSON-Skript."""
resp = client.messages.create(
model=CLAUDE_MODEL_SCRIPT,
max_tokens=8000,
system=SCRIPT_SYSTEM,
messages=[
{"role": "user", "content": user_msg},
{"role": "assistant", "content": text},
{"role": "user", "content": retry_msg},
],
)
text = "".join(b.text for b in resp.content if b.type == "text").strip()
script = VideoScript.model_validate_json(text)
Wichtig: der Retry zeigt Claude was er falsch gemacht hat. Das ist deutlich effektiver als ein blindes “versuch’s nochmal”. Bei meinem aktuellen Setup liegt die First-Try-Erfolgsrate bei 87 %, mit einem Retry steige ich auf 99 %. Den letzten 1 %-Fall behandele ich manuell (passiert ~1× pro 2 Monate).
Warum Claude Opus, nicht Sonnet oder Haiku?
Topic-Ranking läuft auf Haiku (~0,02 €/Run). Script-Generator läuft auf Opus (~0,15 €/Run). Faktor 7 Preisunterschied. Warum?
Was Opus liefert, das Sonnet nicht:
- Konsistente Hook-Phase-Pacing. Opus hält die 3s/18s/18s-Choreografie der ersten drei Szenen zuverlässig ein. Sonnet vergisst das in ~20 % der Fälle.
- Diversität in Visual-Types. Opus nutzt im Schnitt 4–5 verschiedene
visual_type-Werte pro Skript. Sonnet tendiert zu 2–3 (oft slide-lastig). - Story-Bogen. Opus baut echte narrative Übergänge zwischen Szenen. Sonnet liefert mehr “und dann… und dann…” ohne Verbindung.
Was Haiku überhaupt nicht kann:
- Lange strukturierte Outputs >3.000 Tokens
- Pacing-Regeln zuverlässig einhalten
- Pydantic-Schema beim ersten Try treffen (Erfolgsrate unter 60 %)
“Ich hab mit allen drei Tier getestet. Sonnet 4.6 schreibt brauchbare Skripte, aber jedes 5. ist flach. Haiku ist für diese kreative Aufgabe nicht geeignet — die Skripte wirken roboterhaft. Opus ist der Sweet-Spot. Bei 0,15 € pro Skript ist das die einfachste Investitions-Entscheidung der ganzen Pipeline.”
Wie der Script-Generator-Agent mit dem Visual-Orchestrator verzahnt ist
Sobald die Validierung durch ist, wird das VideoScript-Objekt persistiert:
out = SCRIPT_DIR / f"{script.topic_id}.script.json"
out.write_text(script.model_dump_json(indent=2), encoding="utf-8")
console.print(f"[green]✓ Script:[/green] {out.name}")
return out
Genau diese Datei lädt der Visual-Orchestrator als nächstes:
script = VideoScript.model_validate_json(script_path.read_text(encoding="utf-8"))
topic_id = script.topic_id
Beachte: der Visual-Orchestrator validiert das JSON erneut beim Einlesen. Doppelt validiert hält besser — wenn jemand die Datei manuell editiert hat (kommt vor), wird der Fehler sofort gefangen, nicht erst beim Renderer.
Das ist der Vorteil des Schema-First-Patterns: jeder Agent kann das Datenformat des nächsten als Vertragsgrundlage verstehen. Ohne Schema wäre jeder Agent ein potenzieller Fehler-Multiplier — mit Schema sind Fehler lokalisiert.
Was als nächstes in der Serie kommt
Im nächsten Teil zeige ich den Visual-Orchestrator — den Agent, der das script.json öffnet und 14 Szenen parallel an 6 verschiedene Sub-Agents delegiert (Manim, Slide, Comfy, Stock, Code, Fal-Video). Spoiler: das ist die Stage, wo Multi-Agent-Architektur wirklich sichtbar wird
Meine Einschätzung
Ich bin ein überzeugter Verfechter von Schema-First-Ansätzen — und zwar nicht nur bei Video-Pipelines. In meinen eigenen Tests brechen Setups mit Regex oder String-Matching schneller, als man denkt: Es funktioniert drei Wochen, dann kommt eine Modell-Aktualisierung und alles fällt auseinander. Pydantic-Validierung ist die stabilste Methode, die ich kenne, um LLM-Output wirklich deterministisch zu machen. Ja, es kostet Upfront-Aufwand, das Schema zu definieren. Aber wer das einmal sauber macht, spart sich Wochen an Debugging downstream. Meine Faustregel: Wenn ein LLM-Output an eine andere Stage weitergereicht wird, gehört ein Schema dazwischen. Immer.
Quellen
- Pydantic Dokumentation
- Anthropic Claude API Documentation
- Pydantic BaseModel â Structured Output
- Anthropic Structured Outputs Guide


