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
This commit is contained in:
parent
5f6bcac282
commit
0d26cad549
@ -71,6 +71,52 @@ def load_context_file(name: str) -> str:
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
USER_PROMPT_TEMPLATE = """Analysiere den folgenden Antrag:
|
||||||
|
|
||||||
|
<kontext>
|
||||||
|
{bundesland_context}
|
||||||
|
</kontext>
|
||||||
|
|
||||||
|
<wahlprogramm_zitate>
|
||||||
|
{quotes_context}
|
||||||
|
</wahlprogramm_zitate>
|
||||||
|
|
||||||
|
<antrag>
|
||||||
|
{text}
|
||||||
|
</antrag>
|
||||||
|
|
||||||
|
**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 ``<wahlprogramm_zitate>`` 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:
|
def get_system_prompt() -> str:
|
||||||
"""Build the system prompt with GWÖ matrix context."""
|
"""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:
|
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 = find_relevant_quotes(text, fraktionen, bundesland=bundesland)
|
||||||
quotes_context = format_quote_for_prompt(quotes)
|
quotes_context = format_quote_for_prompt(quotes)
|
||||||
|
|
||||||
user_prompt = f"""Analysiere den folgenden Antrag:
|
user_prompt = USER_PROMPT_TEMPLATE.format(
|
||||||
|
bundesland_context=bundesland_context,
|
||||||
<kontext>
|
quotes_context=quotes_context if quotes_context else "Keine relevanten Zitate gefunden.",
|
||||||
{bundesland_context}
|
text=text,
|
||||||
</kontext>
|
pflicht_fraktionen=", ".join(BUNDESLAENDER[bundesland].landtagsfraktionen),
|
||||||
|
)
|
||||||
<wahlprogramm_zitate>
|
|
||||||
{quotes_context if quotes_context else "Keine relevanten Zitate gefunden."}
|
|
||||||
</wahlprogramm_zitate>
|
|
||||||
|
|
||||||
<antrag>
|
|
||||||
{text}
|
|
||||||
</antrag>
|
|
||||||
|
|
||||||
**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 ``<wahlprogramm_zitate>`` 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."""
|
|
||||||
|
|
||||||
# LLM-Call über den Port. Retry-Loop + Markdown-Stripping wohnen im
|
# LLM-Call über den Port. Retry-Loop + Markdown-Stripping wohnen im
|
||||||
# Adapter (``QwenBewerter``). Bei exhausted retries wirft er
|
# Adapter (``QwenBewerter``). Bei exhausted retries wirft er
|
||||||
|
|||||||
@ -1735,6 +1735,7 @@ async def methodik_page(request: Request, current_user: Optional[dict] = Depends
|
|||||||
"""Transparenz-/Methodik-Seite (#96)."""
|
"""Transparenz-/Methodik-Seite (#96)."""
|
||||||
from .bundeslaender import aktive_bundeslaender, BUNDESLAENDER
|
from .bundeslaender import aktive_bundeslaender, BUNDESLAENDER
|
||||||
from .embeddings import get_indexing_status
|
from .embeddings import get_indexing_status
|
||||||
|
from .analyzer import get_system_prompt, get_user_prompt_template
|
||||||
|
|
||||||
bl_list = []
|
bl_list = []
|
||||||
for bl in aktive_bundeslaender():
|
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),
|
"programme_count": status.get("total", 0),
|
||||||
"chunk_count": sum(p.get("chunks", 0) for p in status.get("programmes", [])),
|
"chunk_count": sum(p.get("chunks", 0) for p in status.get("programmes", [])),
|
||||||
"bundeslaender": sorted(bl_list, key=lambda x: x["name"]),
|
"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),
|
**_v2_template_context(current_user),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -138,6 +138,7 @@
|
|||||||
<a href="#was-macht">Was macht der Prüfer?</a>
|
<a href="#was-macht">Was macht der Prüfer?</a>
|
||||||
<a href="#matrix">Die Matrix 2.0</a>
|
<a href="#matrix">Die Matrix 2.0</a>
|
||||||
<a href="#pipeline">Analyse-Pipeline</a>
|
<a href="#pipeline">Analyse-Pipeline</a>
|
||||||
|
<a href="#prompts">LLM-Prompts</a>
|
||||||
<a href="#qualitaet">Qualitätssicherung</a>
|
<a href="#qualitaet">Qualitätssicherung</a>
|
||||||
<a href="#einschraenkungen">Einschränkungen</a>
|
<a href="#einschraenkungen">Einschränkungen</a>
|
||||||
<a href="#datenquellen">Datenquellen</a>
|
<a href="#datenquellen">Datenquellen</a>
|
||||||
@ -365,6 +366,42 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section id="prompts">
|
||||||
|
<h2>LLM-Prompts</h2>
|
||||||
|
<div class="v2-kasten outline-blue">
|
||||||
|
<p>
|
||||||
|
Volle Transparenz: hier liegen die exakten Anweisungen, mit denen das
|
||||||
|
Sprachmodell ({{ model_name }}) jeden Antrag bewertet. Der
|
||||||
|
<strong>System-Prompt</strong> ist statisch und enthält die GWÖ-Matrix
|
||||||
|
plus Ausgabe-Schema. Der <strong>User-Prompt</strong> wird pro Antrag
|
||||||
|
dynamisch gefüllt — die Platzhalter <code>{kontext}</code>,
|
||||||
|
<code>{wahlprogramm_zitate}</code>, <code>{antrag}</code> und
|
||||||
|
<code>{pflicht_fraktionen}</code> sind unten als
|
||||||
|
<code>{...}</code> markiert.
|
||||||
|
</p>
|
||||||
|
<p style="font-size:11px;opacity:0.7;">
|
||||||
|
Quelle: <a href="https://repo.toppyr.de/tobias/gwoe-antragspruefer/src/branch/main/app/analyzer.py" target="_blank"><code>app/analyzer.py</code></a>
|
||||||
|
(<code>get_system_prompt()</code> und <code>get_user_prompt_template()</code>).
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<details style="margin-top:1rem;">
|
||||||
|
<summary style="cursor:pointer;color:var(--ecg-teal);font-weight:700;padding:6px 0;font-family:var(--font-display);">
|
||||||
|
System-Prompt anzeigen
|
||||||
|
<span style="font-family:var(--font-mono);font-size:11px;opacity:0.6;font-weight:400;">({{ system_prompt|length }} Zeichen)</span>
|
||||||
|
</summary>
|
||||||
|
<pre style="background:var(--ecg-bg-subtle);border:1px solid var(--ecg-border);border-radius:4px;padding:14px 16px;margin-top:8px;font-family:var(--font-mono);font-size:11px;line-height:1.5;white-space:pre-wrap;word-break:break-word;color:var(--ecg-dark);overflow-x:auto;">{{ system_prompt }}</pre>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details style="margin-top:0.75rem;">
|
||||||
|
<summary style="cursor:pointer;color:var(--ecg-teal);font-weight:700;padding:6px 0;font-family:var(--font-display);">
|
||||||
|
User-Prompt-Template anzeigen
|
||||||
|
<span style="font-family:var(--font-mono);font-size:11px;opacity:0.6;font-weight:400;">({{ user_prompt_template|length }} Zeichen)</span>
|
||||||
|
</summary>
|
||||||
|
<pre style="background:var(--ecg-bg-subtle);border:1px solid var(--ecg-border);border-radius:4px;padding:14px 16px;margin-top:8px;font-family:var(--font-mono);font-size:11px;line-height:1.5;white-space:pre-wrap;word-break:break-word;color:var(--ecg-dark);overflow-x:auto;">{{ user_prompt_template }}</pre>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section id="qualitaet">
|
<section id="qualitaet">
|
||||||
<h2>Qualitätssicherung</h2>
|
<h2>Qualitätssicherung</h2>
|
||||||
<div class="v2-kasten outline-green">
|
<div class="v2-kasten outline-green">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user