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>
5.8 KiB
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
-
News-Aggregator (
app/news_aggregator.py):- Cron-Wrapper
scripts/auto-fetch-news.shlä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().
- Cron-Wrapper
-
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 aufhigh|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_newsals Reverse-View.
-
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.
- 320–380 Worte, 6 Absätze, getrennt durch
\n\n. json_object_mode=True+_recover_unescaped_newlinesFallback (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.
-
Versionierung statt Force-Override:
- Neuer Draft pro
force=True-Aufruf — alle Versionen bleiben inpresse_drafts. - Frontend zeigt Dropdown mit allen Versionen für
(drucksache, news_url). _find_existing_draft()für Idempotenz-Schutz im Default-Pfad.
- Neuer Draft pro
-
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,renderPmBodyals 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_modeist DashScope-spezifisch — falls künftig auf Anthropic/OpenAI ge-portet, braucht es eine eigene Adapter-Schicht (heute viaLlmRequest.json_object_mode-Flag inqwen_bewerter._post_to_dashscoperealisiert).
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.