From 0d26cad5497461f4e198ffcaa2effb9b875eddb2 Mon Sep 17 00:00:00 2001 From: Dotty Dotter Date: Tue, 28 Apr 2026 01:50:25 +0200 Subject: [PATCH] feat(#145): LLM-Prompts auf /methodik als Transparenz-Block System- und User-Prompt-Template stehen jetzt collapsed unter dem neuen Abschnitt 'LLM-Prompts'. Der User-Prompt wird auf eine eigene Konstante USER_PROMPT_TEMPLATE umgestellt und via .format(...) gerendert, sodass das gleiche Template auf der Methodik-Seite gezeigt werden kann ohne den f-string-Code zu duplizieren. Closes #145 --- app/analyzer.py | 86 ++++++++++++++++---------- app/main.py | 3 + app/templates/v2/screens/methodik.html | 37 +++++++++++ 3 files changed, 92 insertions(+), 34 deletions(-) diff --git a/app/analyzer.py b/app/analyzer.py index 914c850..c5eb46f 100644 --- a/app/analyzer.py +++ b/app/analyzer.py @@ -71,6 +71,52 @@ def load_context_file(name: str) -> str: return "" +USER_PROMPT_TEMPLATE = """Analysiere den folgenden Antrag: + + +{bundesland_context} + + + +{quotes_context} + + + +{text} + + +**PFLICHT-FRAKTIONEN:** Du MUSST ALLE folgenden Fraktionen der aktuellen Wahlperiode in `wahlprogrammScores` bewerten — keine auslassen: +{pflicht_fraktionen} + +Bewerte nach GWÖ-Matrix 2.0 für Gemeinden: +1. GWÖ-Treue (0-10) mit Matrix-Zuordnung und Symbolen (++/+/○/−/−−) +2. Wahlprogrammtreue JEDER der oben genannten Pflicht-Fraktionen (0-10) +3. Parteiprogrammtreue JEDER der oben genannten Pflicht-Fraktionen (0-10) +4. Bis zu 3 Verbesserungsvorschläge in Redline-Syntax +5. Themen-Tags für Kategorisierung + +**ZITATEREGEL — STRIKT:** In jedem ``wahlprogrammScores[].wahlprogramm.zitate[].quelle`` +und ``parteiprogrammScores[].parteiprogramm.zitate[].quelle`` musst du **wortgleich** +einen der oben in ```` aufgelisteten Quellen-Labels (Programm-Name + +Seite) übernehmen — z.B. ``"CDU Mecklenburg-Vorpommern Wahlprogramm 2021, S. 33"``. +Erfinde keine Quellen aus deinem Trainingswissen. Nimm keine Quelle aus einem anderen +Bundesland (z.B. NRW 2022) als die hier aufgelisteten — selbst wenn dir die dortigen +Programme bekannter sind. Findest du oben für eine Partei keinen passenden Chunk, lass +``zitate`` leer (``[]``) und vermerke das in der ``begruendung``. + +Ausgabe als reines JSON ohne Markdown-Codeblöcke.""" + + +def get_user_prompt_template() -> str: + """Public Template-String fuer Transparenz-Seite (#145). + + Enthaelt die Platzhalter ``{bundesland_context}``, ``{quotes_context}``, + ``{text}`` und ``{pflicht_fraktionen}`` — gerendert wird in + ``analyze_text`` direkt via ``.format(...)``. + """ + return USER_PROMPT_TEMPLATE + + def get_system_prompt() -> str: """Build the system prompt with GWÖ matrix context.""" return """Du bist ein Experte für Gemeinwohl-Ökonomie (GWÖ) und parlamentarische Analyse. Du bewertest Anträge aus Landesparlamenten systematisch nach drei Dimensionen: @@ -316,40 +362,12 @@ async def analyze_antrag( quotes = find_relevant_quotes(text, fraktionen, bundesland=bundesland) quotes_context = format_quote_for_prompt(quotes) - user_prompt = f"""Analysiere den folgenden Antrag: - - -{bundesland_context} - - - -{quotes_context if quotes_context else "Keine relevanten Zitate gefunden."} - - - -{text} - - -**PFLICHT-FRAKTIONEN:** Du MUSST ALLE folgenden Fraktionen der aktuellen Wahlperiode in `wahlprogrammScores` bewerten — keine auslassen: -{', '.join(BUNDESLAENDER[bundesland].landtagsfraktionen)} - -Bewerte nach GWÖ-Matrix 2.0 für Gemeinden: -1. GWÖ-Treue (0-10) mit Matrix-Zuordnung und Symbolen (++/+/○/−/−−) -2. Wahlprogrammtreue JEDER der oben genannten Pflicht-Fraktionen (0-10) -3. Parteiprogrammtreue JEDER der oben genannten Pflicht-Fraktionen (0-10) -4. Bis zu 3 Verbesserungsvorschläge in Redline-Syntax -5. Themen-Tags für Kategorisierung - -**ZITATEREGEL — STRIKT:** In jedem ``wahlprogrammScores[].wahlprogramm.zitate[].quelle`` -und ``parteiprogrammScores[].parteiprogramm.zitate[].quelle`` musst du **wortgleich** -einen der oben in ```` aufgelisteten Quellen-Labels (Programm-Name + -Seite) übernehmen — z.B. ``"CDU Mecklenburg-Vorpommern Wahlprogramm 2021, S. 33"``. -Erfinde keine Quellen aus deinem Trainingswissen. Nimm keine Quelle aus einem anderen -Bundesland (z.B. NRW 2022) als die hier aufgelisteten — selbst wenn dir die dortigen -Programme bekannter sind. Findest du oben für eine Partei keinen passenden Chunk, lass -``zitate`` leer (``[]``) und vermerke das in der ``begruendung``. - -Ausgabe als reines JSON ohne Markdown-Codeblöcke.""" + user_prompt = USER_PROMPT_TEMPLATE.format( + bundesland_context=bundesland_context, + quotes_context=quotes_context if quotes_context else "Keine relevanten Zitate gefunden.", + text=text, + pflicht_fraktionen=", ".join(BUNDESLAENDER[bundesland].landtagsfraktionen), + ) # LLM-Call über den Port. Retry-Loop + Markdown-Stripping wohnen im # Adapter (``QwenBewerter``). Bei exhausted retries wirft er diff --git a/app/main.py b/app/main.py index 5bf5ee0..1c4fd51 100644 --- a/app/main.py +++ b/app/main.py @@ -1735,6 +1735,7 @@ async def methodik_page(request: Request, current_user: Optional[dict] = Depends """Transparenz-/Methodik-Seite (#96).""" from .bundeslaender import aktive_bundeslaender, BUNDESLAENDER from .embeddings import get_indexing_status + from .analyzer import get_system_prompt, get_user_prompt_template bl_list = [] for bl in aktive_bundeslaender(): @@ -1755,6 +1756,8 @@ async def methodik_page(request: Request, current_user: Optional[dict] = Depends "programme_count": status.get("total", 0), "chunk_count": sum(p.get("chunks", 0) for p in status.get("programmes", [])), "bundeslaender": sorted(bl_list, key=lambda x: x["name"]), + "system_prompt": get_system_prompt(), + "user_prompt_template": get_user_prompt_template(), **_v2_template_context(current_user), }) diff --git a/app/templates/v2/screens/methodik.html b/app/templates/v2/screens/methodik.html index 4bc3e8f..32068af 100644 --- a/app/templates/v2/screens/methodik.html +++ b/app/templates/v2/screens/methodik.html @@ -138,6 +138,7 @@ Was macht der Prüfer? Die Matrix 2.0 Analyse-Pipeline + LLM-Prompts Qualitätssicherung Einschränkungen Datenquellen @@ -365,6 +366,42 @@ +
+

LLM-Prompts

+
+

+ Volle Transparenz: hier liegen die exakten Anweisungen, mit denen das + Sprachmodell ({{ model_name }}) jeden Antrag bewertet. Der + System-Prompt ist statisch und enthält die GWÖ-Matrix + plus Ausgabe-Schema. Der User-Prompt wird pro Antrag + dynamisch gefüllt — die Platzhalter {kontext}, + {wahlprogramm_zitate}, {antrag} und + {pflicht_fraktionen} sind unten als + {...} markiert. +

+

+ Quelle: app/analyzer.py + (get_system_prompt() und get_user_prompt_template()). +

+ +
+ + System-Prompt anzeigen + ({{ system_prompt|length }} Zeichen) + +
{{ system_prompt }}
+
+ +
+ + User-Prompt-Template anzeigen + ({{ user_prompt_template|length }} Zeichen) + +
{{ user_prompt_template }}
+
+
+
+

Qualitätssicherung