gwoe-antragspruefer/docs/adr/0011-aktuelle-themen-pm-generator.md
Dotty Dotter 1ba9d8e5d9 docs(adr): 0010 Stimmverhalten×GWÖ-Aggregat + 0011 Aktuelle-Themen+PM
ADR 0010 dokumentiert die JOIN-Aggregat-Entscheidung (Option B) mit
4 Aggregat-Funktionen, Heuchelei- und Konsistenz-Markern im Detail,
Sample-Size-Ehrlichkeit und Cache-Strategie.

ADR 0011 dokumentiert Aktuelle-Themen mit Persona-Prompt-Strategie,
Versionierung statt Force-Override, AI-Bann-Quellen-Filter und
json_object_mode-Recovery.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 15:39:29 +02:00

5.8 KiB
Raw Blame History

0011 — Aktuelle-Themen-Dashboard mit PM-Generator

Status accepted
Datum 2026-05-06
Refs #170, MEMORY/project_aktuelle_themen.md

Kontext

Vor diesem ADR existierte kein Bezug zwischen aktuellen Nachrichten (Tagespresse, Bundestagsmeldungen) und den GWÖ-bewerteten Parlamentsanträgen. Die User-Anforderung war:

„Pressemitteilungen zu aktuellen Themen × Anträgen — Matching warum es ein Thema ist, plus Knopf für PM-Generierung."

Initial-Vorschlag war ein RND-Abo (rnd.de), aber dort verbietet robots.txt per User-agent: ClaudeBot/GPTBot Disallow: / die KI-Verarbeitung. Damit waren nur Quellen mit AI-erlaubender Lizenz zulässig: öffentlich-rechtlich (Tagesschau-API) und parlamentarisch (Bundestag-RSS).

Zweitens stellte sich die Frage: Wie generiert man aus einem politischen Antrag plus einer News-Lage einen brauchbaren PM-Text? Erste qwen-max-Versuche produzierten den GWÖ-Score als Zahl, listeten GWÖ-Werte auf und nutzten Matrix-Codes wie „D2 Würde×Mitarbeitende". Für eine Pressemitteilung an Bürger:innen unbrauchbar.

Optionen

Option A — Auto-PM auf jeden News-Match

Beim Aggregator-Lauf für jeden News-Antrag-Match einen LLM-Call.

  • Pro: Maximale Abdeckung.
  • Kontra: LLM-Kosten unkontrollierbar, viele PMs sind irrelevant oder qualitativ schwach. Falsches Outcome-Gewicht.

Option B — Manueller „Generieren"-Knopf pro Match

User entscheidet, der Match liefert nur das Match. PM-Erzeugung ist ein expliziter LLM-Call mit qwen-max.

  • Pro: Kostenkontrolle, Qualitätsprüfung pro Stück.
  • Kontra: Volume gering — aber das ist OK, PMs sind editorial.

Option C — Pre-aggregiertes Cluster, ein PM pro Cluster

Cluster die News-Matches und schlage pro Cluster eine PM vor.

  • Pro: Konsolidiert ähnliche News.
  • Kontra: Cluster-Qualität auf den dünnen News-Volumen heute nicht trennscharf genug.

Entscheidung

Option B ist Hauptmodus, mit Option-C-Cluster-Anzeige als Übersicht (kein automatischer Cluster-PM).

Bausteine

  1. News-Aggregator (app/news_aggregator.py):

    • Cron-Wrapper scripts/auto-fetch-news.sh läuft alle 30 min.
    • Quellen: Tagesschau-API (/api2u/news?ressort=…), Bundestag-RSS. Quellen mit AI-Bann (RND, Spiegel, etc.) strikt ausgeschlossen siehe MEMORY/project_aktuelle_themen.md.
    • Ergebnis in news_articles (additiv: titel, url, source, ressort, summary, embedded_at, embedding).
    • Nach Insert: themen_matching.cache_clear().
  2. Match Engine (app/themen_matching.py):

    • Cosine-Similarity zwischen News-Embedding (v4) und Assessment-Embedding (v4) — beide in gleicher Vector-Space.
    • compute_relevance(matches) aggregiert pro News auf high|mid|low|none.
    • aggregate_top_themen(only_relevant, single_date, …) mit TTL-60s-Cache.
    • aggregate_news_cluster(days) als Greedy-Embedding-Cluster.
    • aggregate_top_antraege_with_news als Reverse-View.
  3. PM-Generator (app/presse_generator.py):

    • Persona-Prompt „Pressereferent:in einer GWÖ-Initiative" mit harter Verbotsliste (keine GWÖ-Werte-Listen, keine Scores, keine Matrix-Codes, keine Floskeln) und Few-Shot-Beispiel (Schlecht/Gut).
    • Konkrete Bürger:innen-Lebenslagen pro Absatz (Pflegebedürftige, Mieter:innen, Auszubildende, Pendler:innen, …) — der Antrag muss als „was ändert sich konkret" beschrieben werden.
    • 320380 Worte, 6 Absätze, getrennt durch \n\n.
    • json_object_mode=True + _recover_unescaped_newlines Fallback (qwen-max produziert gelegentlich rohe \n-Bytes im JSON-String, was den Standard-Parser brechen würde).
    • Sparsame fett-Hervorhebungen (max. 1 pro Absatz, nur Zahlen oder zentrale Effekte) — wird vom Mini-Markdown-Renderer im Frontend (renderPmBody) als <strong> gerendert.
  4. Versionierung statt Force-Override:

    • Neuer Draft pro force=True-Aufruf — alle Versionen bleiben in presse_drafts.
    • Frontend zeigt Dropdown mit allen Versionen für (drucksache, news_url).
    • _find_existing_draft() für Idempotenz-Schutz im Default-Pfad.
  5. Frontend (templates/v2/screens/aktuelle-themen.html):

    • 5 Tabs: News×Anträge, Themen-Cluster, GWÖ-Top-Anträge, News-Volumen-Zeitreihe, PM-Entwürfe.
    • Pre-Filter only_relevant (Default an).
    • GWÖ-Relevanz-Pills rot/orange/grün.
    • Chart-Click filtert auf Datum.
    • PM-Modal mit Versions-Dropdown, „Mail"-Direkt-Link (mailto: mit prefilled Subject+Body, Längen-Check), Clipboard, renderPmBody als Mini-Markdown-Renderer.

Konsequenzen

Positiv

  • LLM-Kosten kontrollierbar (manueller Trigger).
  • Keine Daten-Lecks zu Quellen mit AI-Bann.
  • Versionierung erlaubt Iteration ohne Verlust früherer Entwürfe.
  • Persona-Prompt + Few-Shot-Trick stabilisiert die Sprache; Smoketest zeigt qwen-max nutzt fett dezent (1 Hervorhebung pro PM).

Negativ

  • Modell-Lock-in auf qwen-max für PMs. Bei Modell-Wechsel müssen die Pattern-Recovery-Heuristiken (Newline-Recovery, Post-Process für ."Großbuchstabe-Patterns) neu kalibriert werden.
  • json_object_mode ist DashScope-spezifisch — falls künftig auf Anthropic/OpenAI ge-portet, braucht es eine eigene Adapter-Schicht (heute via LlmRequest.json_object_mode-Flag in qwen_bewerter._post_to_dashscope realisiert).

Folgen für andere ADRs

  • 0010 Stimmverhalten-Aggregat: Der Konsistenz-Block im Antrag-Detail („Mehrheit kontra GWÖ-Empfehlung") ist Anlass für PM-Generierung — kann in einer Phase-4-Iteration als PM-Auto-Vorschlag genutzt werden.
  • 0001 LLM-Citation-Binding: PM-Generator zitiert nicht aus Wahlprogrammen, daher ist Citation-Binding hier nicht einschlägig. Für News-Zitate gilt: News-URL als Quelle ist authoritativ, PM-Body darf paraphrasieren ohne wörtliches Zitat.