CHRISTIAN OHLE
Zurück zu Bauen

Bauen

Topic-Ranker-Agent: Wie Claude 60 News-Headlines bewertet

Build-in-Public Teil 2: Wie der Topic-Ranker-Agent in 5 Sekunden 60 News-Headlines auf 5 Kriterien bewertet — mit Score 0–110 und transparentem Reasoning.

7 Min Lesezeit topic ranker agent · claude news ranking · ki agent scoring · haiku 4.5 ranking · multi-agent pipeline · news bewertung ki
Hero-Image: Topic-Ranker-Agent: Wie Claude 60 News-Headlines bewertet

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

  • Wie der Topic-Ranker-Agent in der christianohle-Multi-Agent-Pipeline 60 Headlines pro Run auswertet.
  • Welche 5 Kriterien Score 0–110 liefern und warum die Gewichte so verteilt sind.
  • Den vollständigen System-Prompt, der Claude Haiku zum konsistenten Bewerter macht.
  • Wie der Topic-Ranker-Agent mit dem Script-Generator-Agent verzahnt ist.
  • Was beim Bauen schiefging — Truncation-Bugs, Markdown-Fences, JSON-Parser-Crashes.

Im vorherigen Teil habe ich gezeigt, wie 15 Agenten zusammenarbeiten, um aus einer News-Headline ein YouTube-Video zu produzieren. Heute schaue ich mir den ersten Agent in der Kette an — den Topic-Ranker-Agent. Sein Job: aus 60 RSS- und Hacker-News-Headlines die eine identifizieren, die ein 6-Minuten-Video tragen kann.

Klingt nach trivialer Sortierung. Ist es nicht. Wer einfach nach Recency sortiert, landet bei OpenAI-PR und Recycling-News. Wer manuell auswählt, verbringt jeden Morgen 30 Minuten mit Scrollen. Der Topic-Ranker-Agent löst beide Probleme — er bewertet jede Headline in 5 Sekunden auf fünf Kriterien und liefert eine sortierte Liste mit transparentem Reasoning pro Eintrag.

“Vor dem Topic-Ranker-Agent hatte ich tatsächlich morgens manuell Headlines durchgescrollt. ~25 Min pro Tag, um die eine richtige Story zu finden. Der Agent macht das jetzt in 5 Sekunden, mit besserer Auswahl als ich. Das war der Moment, an dem ich verstanden habe, wofür Multi-Agent-Setups eigentlich gut sind.”

Was der Topic-Ranker-Agent konkret tut

Der Topic-Ranker-Agent bekommt einen Stapel News-Items vom News-Scraper-Agent (RSS, Hacker News, arXiv-Feeds). Er bewertet die ersten 60 davon mit Claude Haiku 4.5 auf fünf Kriterien — Neuigkeit, Relevanz, Viral-Potenzial, Erklärbarkeit, Agent-Fokus. Pro Headline gibt er einen total_score von 0–110 zurück, plus einen 1-Satz-reasoning.

Der Output wird mit den ursprünglichen Items zusammengeführt, nach Score absteigend sortiert und an den nächsten Agent in der Kette weitergereicht — den Script-Generator-Agent.

Der Run-Befehl im Daily-Workflow:

from src.script.select import rank_with_claude
ranked = rank_with_claude(news_items)
log(f"  Top-Score: {ranked[0]['score']} ({ranked[0]['title'][:80]})", log_path)

Ein Beispiel-Log aus einem realen Run:

[07:01:14] [2/6] Claude-Ranking + Duplikat-Schutz...
[07:01:19]   Top-Score: 96 (Anthropic verschiebt Claude Code GA-Launch — neue Sub-Agent-API)
[07:01:19]   Bereits verarbeitete Topics: 47
[07:01:19]   Gewählt: Anthropic verschiebt Claude Code GA-Launch (score=96)

Fünf Sekunden Wartezeit, dann hat der Agent entschieden. Das wäre manuell nicht zu schaffen.

Die 5 Bewertungs-Kriterien im Detail

Der System-Prompt definiert klar, wonach Claude bewertet. Hier der Kern:

RANK_SYSTEM = """Du bewertest KI-News-Headlines für einen
deutschsprachigen YouTube-Kanal namens christianohle.
Zielgruppe: technisch interessierte Laien und Early-Stage-Entwickler im DACH-Raum.

Bewertungskriterien:
1. NEUIGKEITSWERT (0-20): wirklich neu, nicht recycelt
2. RELEVANZ (0-20): wichtig für jemanden, der KI praktisch nutzt oder versteht
3. VIRAL_POTENZIAL (0-20): Hook-fähig, kontrovers, überraschend, oder big-name
4. ERKLÄRBARKEIT (0-20): kann visuell mit Diagrammen/Animationen erklärt werden
5. AGENT_FOKUS (0-30): christianohle fokussiert strategisch auf KI-Agenten...
"""

Die Verteilung ist nicht zufällig. Agent-Fokus bekommt 30 Punkte — weil das mein strategisches Thema ist. Wenn eine Headline nichts mit Agents zu tun hat, hat sie selbst bei perfekter Bewertung in den anderen vier Kriterien maximal 80/110. Eine schwache Agent-relevante Story kommt schon bei 60/110 raus und liegt vor flachen 80er-PR-Meldungen.

Das ist Bias-Engineering im Score-Schema, nicht im Prompt-Text. Damit kann ich die Pipeline strategisch fokussieren, ohne jedes Mal einzelne Items manuell zu filtern.

“Diese 30-Punkte-Gewichtung war eine bewusste Entscheidung nach drei Wochen Pipeline-Betrieb. Ohne sie kamen ständig Schul-/Rechts-/Gesundheits-KI-Stories nach oben, die mein Publikum nicht erreichen. Mit dem Bias picke ich konsistent die Agent-Themen, die christianohle aufbauen.”

Wie der Agent das JSON zurückgibt

Anthropics Tool-Use-Format wäre overkill für eine reine Score-Aufgabe. Stattdessen lasse ich Claude direkt JSON zurückgeben — über die system-Direktive plus klares Output-Schema:

RANK_SYSTEM = """...
Antwort STRENG als JSON-Array, KEIN Markdown, KEIN Vorspann.

Schema:
[
  {"id": "<id>", "total_score": <int>, "reasoning": "<string>"},
  ...
]
"""

Der eigentliche Call ist dann unspektakulär:

resp = client.messages.create(
    model=CLAUDE_MODEL_RANK,  # "claude-haiku-4-5"
    max_tokens=8000,
    system=RANK_SYSTEM,
    messages=[{"role": "user", "content": user_msg}],
)
text = "".join(b.text for b in resp.content if b.type == "text").strip()

Was das Tool-Use-Pattern ersetzt: ein gut strukturiertes JSON-Schema im System-Prompt plus eine Defensive-Parse-Logik (siehe nächste Sektion).

Die Bugs, die ich beim Bauen unterschätzt habe

Der erste Versuch dieses Agents lief am Test-Tag eine Stunde sauber durch. Am zweiten Tag krachte er: Claude hatte JSON-Output mit Markdown-Fences zurückgegeben (` json...`), obwohl der System-Prompt das explizit verbot. Mein erster Parser-Versuch starb am JSONDecodeError.

Lösung: Defensive Cleanup vor dem Parsen.

# Falls Claude doch Markdown-Fences setzt, strippen
if text.startswith("```"):
    text = text.strip("`")
    if text.startswith("json"):
        text = text[4:]
    text = text.strip()

Das war Bug Nummer 1. Bug Nummer 2 kam zwei Wochen später: bei großen News-Pools mit vielen langen Reasonings hat Claude Haiku gegen den max_tokens=8000-Schwellenwert gestoßen und ein abgeschnittenes JSON zurückgegeben. Der Parser warf Unterminated string, der Daily-Run scheiterte.

Lösung: Truncation-Detection mit automatischem Retry bei höherem Limit.

except json.JSONDecodeError as e:
    if "Unterminated" in str(e) or "Expecting" in str(e):
        console.print(f"[yellow]JSON truncated, retry mit groesserem Limit...[/yellow]")
        resp = client.messages.create(
            model=CLAUDE_MODEL_RANK,
            max_tokens=12000,
            system=RANK_SYSTEM,
            messages=[{"role": "user", "content": user_msg}],
        )
        # ... clean + retry-parse

“Wer Claude im Production-Loop nutzt, lernt schnell: defensiver Parser ist Pflicht. Markdown-Fences kommen unangekündigt zurück. Token-Limits beißen bei Edge-Cases. Mein Daumenregel inzwischen: jeden JSON-Output 2× wrappen — einmal stripping, einmal retry-on-truncation.”

Wie der Topic-Ranker mit dem nächsten Agent verzahnt ist

Der Topic-Ranker-Agent gibt eine sortierte Liste an den Daily-Run-Orchestrator zurück. Aber bevor diese an den Script-Generator-Agent geht, läuft eine Duplikat-Filter-Stage:

existing = get_existing_topic_ids(SCRIPT_DIR)
log(f"  Bereits verarbeitete Topics: {len(existing)}", log_path)

chosen = select_first_unseen(ranked, existing)
if chosen is None:
    log("Kein neues, unverarbeitetes Topic im Ranking gefunden.", log_path)
    return 1

Das ist eine wichtige Architektur-Entscheidung: der Topic-Ranker-Agent kennt selbst keine Memory. Er bewertet jede Headline frisch, jeden Tag. Der Duplikat-Schutz ist eine separate Filter-Stage, die das Filesystem als State-Source nutzt — alle existierenden *.topic.json-Files werden als “schon verarbeitet” markiert.

Vorteil dieser Trennung: ich kann den Topic-Ranker isoliert testen (ohne Filesystem-Setup), und der Duplikat-Schutz ist ein 30-Zeilen-Helper, der unabhängig vom LLM-Verhalten funktioniert.

Wenn eine Headline auch beim höchsten Score schon verarbeitet ist, geht der Daily-Run zur nächst-höchsten. Was passiert, wenn alle Top-15 schon verarbeitet sind? return 1 — keine neuen Topics, der Daily-Run beendet sich sauber. Das passiert ~1× pro 3 Wochen, wenn ich an einem Wochenende viele manuelle Topics gepusht habe.

Was der Agent mich täglich kostet

Pro Run gemessen aus den Anthropic-Logs:

  • Input-Tokens: ~3.500 (60 News-Items × ~60 Tokens für id+title+source+summary)
  • Output-Tokens: ~2.800 (60 Score-Objekte mit Reasoning)
  • Modell: Claude Haiku 4.5 (Input ~0,80 USD/M Tokens, Output ~4 USD/M Tokens)

Pro Run: ~0,02 USD = ~0,02 €.

Bei Mo/Mi/Fr-Trigger: ~0,06 €/Woche, ~0,25 €/Monat. Das ist die billigste Stage der gesamten Multi-Agent-Pipeline. Würde ich mit Sonnet ranken, wären es ~0,25 €/Run = ~3 €/Monat — Faktor 12 teurer für marginal bessere Auswahl. Mit Opus reden wir über ~1,40 €/Run — die Pipeline würde an dieser einen Stage mehr kosten als alle anderen 14 Agenten zusammen.

“Ich hab tatsächlich Opus mal als A/B-Test laufen lassen — 7 Tage parallel zu Haiku. Die Top-3-Auswahl hat zu 85 % übereingestimmt. Bei den restlichen 15 % war Opus nicht sichtbar besser, nur anders. Faktor 60 Preisdifferenz für ‘anders’ ist nicht zu rechtfertigen.”

Was als nächstes in der Serie kommt

Im nächsten Teil schaue ich mir den Script-Generator-Agent an — der den Output des Topic-Rankers in ein 14–20-Szenen-Video-Script verwandelt. Spoiler: hier kommt Claude Opus zum Einsatz, hier validiert ein Pydantic-Schema das Output, und hier sehe ich, ob Topic-Ranker und Script-Generator wirklich gut zusammenarbeiten — oder ob der Ranker manchmal Topics bewertet, die der Generator nicht zu echtem Video-Substanz machen kann.

Meine Einschätzung

Ich habe den Topic-Ranker unterschätzt, als ich ihn gebaut habe. Heute ist er der Agent, der mir am meisten Zeit spart — nicht weil er besonders clever ist, sondern weil er eine Entscheidung automatisiert, die mich vorher jeden Morgen 25 Minuten gekostet hat. Meine wichtigste Lernnotiz daraus: Die wertvollsten Agents sind oft nicht die technisch anspruchsvollsten, sondern die, die eine tägliche Mikro-Entscheidung wegnehmen. Und Haiku reicht dafür fast immer. Ich sehe zu viele Leute, die Opus für Klassifikations-Tasks einsetzen und sich dann über die Kosten wundern. Das richtige Modell für den richtigen Job — das ist die eigentliche Architektur-Entscheidung.

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.