CHRISTIAN OHLE
Zurück zu Bauen

Bauen

B-Roll-Agent: Wie Claude visuelle Cutaways selbst auswählt

Build-in-Public Teil 5: Wie der B-Roll-Agent mit Claude Haiku Narration analysiert, Cutaway-Momente identifiziert und Pexels-Clips per ffmpeg überlagert.

7 Min Lesezeit b-roll agent · ki cutaway automation · claude haiku narration · pexels ffmpeg overlay · video b-roll automation · multi-agent pipeline
Hero-Image: B-Roll-Agent: Wie Claude visuelle Cutaways selbst auswählt

TL;DR — Was du nach diesem Artikel weißt

  • Wie der B-Roll-Agent Narration mit Claude Haiku analysiert und Cutaway-Momente findet.
  • Den vollständigen System-Prompt mit Pacing-Regeln (Standard 2–3 Cuts, Hook-Phase 3–4).
  • Wie der Agent als Mini-LLM-Stack mit eigenen Validierungs-Constraints arbeitet.
  • Warum Pexels-Stock-Clips für KI-Erklärvideos überraschend gut funktionieren.
  • Wo der B-Roll-Agent in der Pipeline-Reihenfolge sitzt — zwischen Visual und Voice.

Im vorherigen Teil habe ich den Visual-Orchestrator gezeigt, der 14 Szenen parallel an 6 Sub-Agents delegiert. Heute schaue ich mir einen viel kleineren, sehr fokussierten Agent an — den B-Roll-Agent. Sein Job: pro Szene 1–4 visuelle Cutaways identifizieren, passende Pexels-Clips holen und sie per ffmpeg über das Hauptvisual blenden, ohne den Voiceover anzutasten.

Das klingt nach einer 50-Zeilen-Heuristik. Ist es nicht. Der B-Roll-Agent macht genau das, was menschliche Video-Editor:innen täglich tun — nur in 5 Sekunden statt in 30 Minuten. Und er beweist, warum schmale, hochfokussierte Agents in einem Multi-Agent-Stack genauso wertvoll sind wie die großen Orchestratoren.

“Der B-Roll-Agent war ein Experiment, das mich überrascht hat. Ich hatte nicht erwartet, dass Claude Haiku Narration so präzise auf visuelle Cutaway-Anker analysiert. Heute ist er ein Pflicht-Step in meiner Pipeline — Videos ohne B-Roll wirken statisch und holpern visuell.”

Was der B-Roll-Agent konkret tut

Eingang: ein gerenderter Szenen-Visual (merged_NNN.mp4) plus die zugehörige Scene aus dem Skript. Ausgang: derselbe Visual, aber mit 1–4 eingeblendeten Pexels-Cutaways an klar definierten Zeitpunkten — Original-Audio bleibt erhalten.

def add_broll_to_visual(scene_video: Path, scene: Scene, broll_dir: Path) -> Path:
    """Fuegt Pexels-Cutaways in qualifizierende Visuals (comfy/manim, >=15s) ein."""

Die Filter-Logik im Visual-Orchestrator entscheidet, welche Szenen überhaupt qualifizieren:

BROLL_VISUAL_TYPES = {"comfy", "manim"}
MIN_SCENE_DURATION = 8.0  # title_card 3s wird ohnehin durch visual_type-Filter ausgenommen
BROLL_DURATION = 2.2  # Sekunden pro Cutaway (kurz fuer modernen Schnitt-Rhythmus)
MAX_BROLLS_PER_SCENE = 4  # Standard 3, bei Hook-Phase (Szene 1-2) bis 4
MIN_BROLLS_PER_SCENE = 2

Drei Constraints:

  • Nur Comfy- und Manim-Szenen kriegen B-Roll. Slides bleiben pur, weil Bullets nicht durch Pexels-Clips überschnitten werden sollen.
  • Mindestens 8 Sekunden Szene. Kurze Szenen sind nicht lang genug für sinnvolle Cuts.
  • Maximal 4 Cutaways pro Szene, in der Hook-Phase (Szenen 1–2) ausgenutzt, sonst max 3.

Der Cutaway-Detection-Prompt

Der Kern dieses Agents ist der System-Prompt, der Claude beibringt, was ein guter Cutaway ist:

BROLL_SYSTEM = """Du analysierst eine Video-Szene-Narration und identifizierst
1-2 visuelle Cutaway-Momente fuer B-Roll-Footage von Pexels.

REGELN:
- Standard: 2-3 Cutaways pro Szene (Pacing! 1 Cutaway reicht nicht)
- HOOK-PHASE (Szenen 1-2): 3-4 Cutaways pro Szene (mehr visueller Druck)
- Jeder Cutaway dauert 2-2.5 Sekunden (kurze Schnitte = modern)
- Cutaways NICHT in den ersten 1.5s der Szene (Hook braucht Original-Visual)
- Cutaways NICHT in den letzten 1.5s der Szene (Outro braucht Original-Visual)
- Mindestens 2.5 Sekunden Abstand zwischen zwei Cutaways
- Pexels-Query: konkrete englische Substantive (London skyline, chess board,
  server room, person typing). 2-4 Woerter, KEIN Adjektiv-Salat.
- WAEHLE nur Cutaways wenn die Narration konkrete visuelle Anker hat
  (Personen, Orte, Objekte, Handlungen). Bei abstrakten Konzepten
  (Theorie, Mathematik, Daten-Statistik) gib leeres Array zurueck.
"""

Drei Designprinzipien sitzen hier drin:

  1. Pacing-Regeln als Hard-Coded-Constraints. Statt zu hoffen, dass Claude “modern” inerpretiert, schreibe ich explizit “2–2,5 Sekunden, kurze Schnitte = modern”.
  2. Hook-Phase-Awareness. Die ersten zwei Szenen kriegen mehr Cutaways — weil YouTube-Retention in den ersten 30 Sekunden entschieden wird.
  3. Klare Abbruchkriterien. Wenn die Narration zu abstrakt ist (Mathe, Statistik), soll der Agent leeres Array zurückgeben statt zwanghaft Pexels-Queries zu erfinden.

“Die Regel ‘bei abstrakten Konzepten leeres Array’ war Iteration Nr. 4. Vorher hat Claude bei Mathe-Szenen versucht, ‘mathematician at chalkboard’ zu finden — was visuell wie Klischee wirkt. Heute lässt der Agent diese Szenen einfach in Ruhe.”

Der eigene Mini-LLM-Call pro Szene

Was den B-Roll-Agent von einem Skript unterscheidet: er macht pro Szene einen eigenen LLM-Call. Aus dem Code:

def find_cutaways(narration: str, scene_duration: float, scene_id: int) -> list[dict]:
    """Claude liefert 0-2 Cutaway-Momente pro Szene."""
    user_msg = f"""SZENEN-DAUER: {scene_duration:.1f} Sekunden
SZENEN-ID: {scene_id}

NARRATION:
{narration}

Identifiziere 1-2 Cutaway-Momente. Wenn nichts visuelles passt: leeres Array."""

    resp = client.messages.create(
        model="claude-haiku-4-5-20251001",
        max_tokens=600,
        system=BROLL_SYSTEM,
        messages=[{"role": "user", "content": user_msg}],
    )

Pro Szene: Narration + Dauer + ID rein, JSON mit Cutaways raus. Das ist klein und fokussiert — max_tokens=600 reicht völlig, weil das Output-Schema kompakt ist:

{
  "cutaways": [
    {
      "start_offset_sec": 5.2,
      "duration_sec": 2.5,
      "pexels_query": "london city skyline aerial",
      "rationale": "Bei 'London' als Standort kommt Skyline-Shot"
    }
  ]
}

Der rationale-Feld ist nicht für den Agent — der ist für mich, beim Debugging. Wenn ein Cutaway visuell daneben liegt, steht im Log warum Claude ihn ausgewählt hat.

Validierungs-Constraints nach dem LLM-Call

Claude liefert manchmal Cutaways, die nicht passen — z.B. einer beginnt 0,5s nach Szenen-Start (Hook-Schutz verletzt), oder zwei Cutaways überlappen. Der B-Roll-Agent enforct daher Post-Validierung:

# Validierung: Konflikte, Bounds
max_for_scene = MAX_BROLLS_PER_SCENE if scene_id <= 2 else 3
valid = []
for c in cutaways[:max_for_scene]:
    start = float(c.get("start_offset_sec", 0))
    dur = float(c.get("duration_sec", BROLL_DURATION))
    # Mindestens 1.5s Abstand zu Anfang/Ende
    if start < 1.5 or start + dur > scene_duration - 1.5:
        continue
    # Mindestens 4s Abstand zu vorherigem Cutaway
    if valid and start < valid[-1]["start_offset_sec"] + valid[-1]["duration_sec"] + 2.5:
        continue
    valid.append({
        "start_offset_sec": start,
        "duration_sec": min(dur, 2.5),
        "pexels_query": c.get("pexels_query", "").strip(),
    })

Drei harte Checks:

  • Cutaway nicht in den ersten 1,5 oder letzten 1,5 Sekunden
  • Mindestens 2,5 Sekunden Abstand zum vorherigen Cutaway
  • Maximale Dauer 2,5 Sekunden (auch wenn Claude längere vorschlägt)

Was hier passiert: ich vertraue Claude die kreative Entscheidung an (welche Pexels-Query, welcher Moment), aber NICHT die Pacing-Regeln. Die enforct der Code algorithmisch.

“Diese Trennung ‘kreativ vs. algorithmisch’ ist mein Lieblings-Pattern für Multi-Agent-Setups. Lass das LLM die Sprache verstehen. Lass den Code die harten Regeln enforcen. Beide zusammen liefern, was keine Seite allein kann.”

Wo der B-Roll-Agent im Pipeline-Flow sitzt

Im Pipeline-Code, nach dem Visual-Orchestrator und vor dem Voice-Agent:

# 1.5 B-Roll: Cutaways in qualifizierende Visuals einfuegen
console.print(f"[cyan]→ B-Roll-Generation...[/]")
broll_dir = raw / "broll"
broll_dir.mkdir(parents=True, exist_ok=True)
for s in script.scenes:
    try:
        new_visual = broll_g.add_broll_to_visual(visual_paths[s.scene_id], s, broll_dir)
        visual_paths[s.scene_id] = new_visual
    except Exception as e:
        console.print(f"[yellow]B-Roll scene {s.scene_id} fehlgeschlagen (non-fatal): {e}[/]")

Wichtig: B-Roll-Generation läuft seriell (pro Szene ein Pexels-Fetch + ffmpeg-Overlay) und ist non-fatal — wenn eine Szene scheitert, läuft die Pipeline weiter mit dem Original-Visual. Das ist eine bewusste Entscheidung: B-Roll ist Cherry-on-Top, nicht Pflicht.

Der Output ersetzt dann das visual_paths[s.scene_id] für die Assembly-Stage. Der Voice-Agent bekommt davon nichts mit — er rendert seine MP3s parallel zur B-Roll-Generation, basierend auf dem Skript-Narration.

ffmpeg-Overlay statt Crossfade

Eine kleine Architektur-Entscheidung: B-Roll wird mit Hard Cuts eingeblendet, nicht mit Crossfade. Aus dem Codekommentar im Generator:

# 4. Hard Cuts (kein Crossfade)

Warum keine weichen Übergänge? Drei Gründe:

  1. Crossfade braucht Encoding-Zwischenstufen. Hard Cut ist ein einziger ffmpeg-Filter. Crossfade verdoppelt die Render-Zeit.
  2. Modern wirkt anders. Schau dir aktuelle YouTube-Tech-Videos an — die meisten haben harte Cuts. Crossfade wirkt 2010er-Jahre.
  3. Voice bleibt erhalten. Bei Crossfade müsste ich auch das Audio crossfaden, was bei sauber synthetisiertem ElevenLabs-Voice unnötig ist.

“Diese ‘Hard-Cuts’-Entscheidung ist eine, die ich am Anfang nicht getroffen hätte. Ich war auf ‘sieht professionell aus’-Modus mit Crossfades. Drei Tests später war klar: Hart-Cuts sind besser, schneller, billiger. Eine Architektur-Lektion, die ich auch außerhalb der Video-Pipeline nutze.”

Was der B-Roll-Agent insgesamt kostet

Pro Pipeline-Run (ein Video):

  • Cutaway-Detection mit Claude Haiku 4.5: ~10 qualifizierende Szenen × 600 Tokens × 0,80 USD/M = ~0,005 USD
  • Pexels-API-Calls: kostenlos (Free-Tier 200/h reicht weit)
  • ffmpeg-Overlay: lokal, 0 € Kosten, ~30 Sek pro Szene Render-Zeit

Gesamt: ~0,005 € pro Video. Statistisch nicht messbar im Pipeline-Budget, aber visueller Mehrwert ist enorm. Das ist der Grund, warum schmale Agents genauso wertvoll sind wie die großen.

Was als nächstes in der Serie kommt

Im nächsten Teil zeige ich, wie Voice-Agent und Subtitle-Agent Hand in Hand arbeiten — der eine produziert MP3 mit ElevenLabs, der andere transkribiert sie mit Whisper auf Word-Level-Timing und re-segmentiert sie auf Untertitel-Format. Spoiler: Word-Level-Timing ist die Stage, an der ich die meisten Iterationen gebraucht habe, um saubere Untertitel zu kriegen.

Meine Einschätzung

Ich war ehrlich gesagt skeptisch, ob ein Mini-Agent mit Claude Haiku wirklich brauchbare Cutaway-Entscheidungen treffen kann. Nach sechs Wochen Production-Betrieb muss ich sagen: Er trifft bessere Entscheidungen als ich es manuell in der Hälfte der Fälle tun würde. Das bestätigt ein Muster aus meinen eigenen Pipeline-Tests: Kleine, fokussierte Agents mit klaren Constraints liefern oft bessere Ergebnisse als große, generische Setups. Der B-Roll-Agent kostet 0,005 Euro pro Video und hebt die visuelle Qualität messbar. Wer solche Low-Cost-High-Impact-Agents ignoriert, verschenkt den eigentlichen Wert von Multi-Agent-Architekturen.

Quellen

Porträt von Christian Ohle

Geschrieben von

Christian Ohle

Builder · Schmied der christianohle

Seit 2005 mit dem Web. Online-Marketing, Coding, lokale KI. Schreibt auf christianohle über Agents, MCP, lokale LLMs und Workflow-Automation — alles selbst getestet. Wöchentlicher Newsletter mit aktuellen News & Tutorials.