classify_refusal() separates refusal (head), preamble, appended disclaimer
(tail) and moralising insert (inline). Only the first three are meaningful, and
only where a prompt forbids them: a preamble on a coding answer is normal, so it
no longer counts as evasion.
Two sources of false positives had to be removed first, both found by checking
the detector's hits against the archive rather than trusting them:
* llamacppctl's own truncation warning on stderr had leaked into an archived
output and was read as a model disclaimer. It also inflated that run's word
count, so count_words() strips it too.
* An AI character saying "Bitte beachten Sie:" inside a dystopian story is
plot, not distancing. Quoted speech is removed before markers are matched.
run_prompt_suite.sh gains a CASES filter so a single prompt can be re-run.
Measured result, recorded in KI_TOOLS_PROFILES.md: across seven prose prompts
neither the abliterated model nor the aligned base model evaded once. On
literary prose the abliteration buys nothing measurable.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
135 lines
6.6 KiB
Markdown
135 lines
6.6 KiB
Markdown
# Bewertungsrubrik für Modell-Prompt-Tests
|
||
|
||
Zweck: Modellwechsel (anderes Modell, andere Quantisierung, `Balanced` statt
|
||
`Aggressive`, MTP, KV-Cache-Einstellungen) sollen an **Zahlen** entschieden
|
||
werden, nicht an Bauchgefühl. Ohne Vorher-Nachher-Messung ist nicht feststellbar,
|
||
ob eine Änderung verbessert oder verschlechtert hat.
|
||
|
||
Grundlage sind die Läufe unter `~/llamacppctl_prompt_tests/` gegen die Prompts in
|
||
`example_user_prompts/`. Modelleignung siehe [`KI_TOOLS_PROFILES.md`](KI_TOOLS_PROFILES.md).
|
||
|
||
## Zwei Ebenen
|
||
|
||
**Objektiv** — von `scripts/eval_prompt_tests.py` automatisch gemessen, keine
|
||
Meinung nötig:
|
||
|
||
| Metrik | Domäne | Bedeutung |
|
||
|---|---|---|
|
||
| Wortzahl, Abweichung vom Ziel | prosa, reden | Der Prompt nennt ein Ziel („etwa 1200 Wörtern"). |
|
||
| Trunkierungsverdacht | alle | Text endet ohne Satzzeichen → Budget zu klein. |
|
||
| Ausweichklasse | prosa, reden | `refusal` / `preamble` / `tail` / `inline` — siehe unten. |
|
||
| Tests laufen durch | coding | Der generierte Code wird **wirklich ausgeführt**. |
|
||
| Anteil bestandener Tests | coding | `passed / (passed + failed)`. |
|
||
|
||
### Ausweichklassen
|
||
|
||
`classify_refusal()` unterscheidet, **wie** ein Modell einer Aufgabe ausweicht —
|
||
literarisch drei verschiedene Dinge:
|
||
|
||
- `refusal` — Absage im Kopf des Textes, kaum oder keine Erzählung.
|
||
- `preamble` — Rahmung vor dem ersten Satz. Nur dort ein Mangel, wo der Prompt
|
||
eine Vorbemerkung verbietet (`prosa_06`–`08`); bei Coding ist sie normal und
|
||
wird nicht gezählt.
|
||
- `tail` — Erzählung geliefert, danach Warnung oder Distanzierung angehängt.
|
||
- `inline` — moralisierender Einschub mitten im Text.
|
||
|
||
Zwei Fehlerquellen, die der Detektor aktiv ausschließt, weil sie beide zu
|
||
falschen Treffern geführt haben:
|
||
|
||
1. **Werkzeugausgabe.** `llamacppctl` schreibt bei abgeschnittenen Antworten
|
||
`Hinweis: Antwort bei max_tokens=… abgeschnitten` auf stderr. In mindestens
|
||
einer Archivdatei ist die Zeile in die Ausgabe geraten und wurde als
|
||
Disclaimer des Modells gezählt — sie verfälschte auch die Wortzahl.
|
||
2. **Wörtliche Rede.** Eine KI-Figur, die in einer Dystopie „Bitte beachten
|
||
Sie:" sagt, ist Handlung, keine Distanzierung. Zitate werden vor der
|
||
Markersuche entfernt.
|
||
|
||
Ein Ausweichen ist nur dann ein objektiver Befund, wenn der Prompt das
|
||
betreffende Verhalten **ausdrücklich verbietet**. Sonst ist es Interpretation.
|
||
|
||
**Subjektiv** — von Hand oder per LLM-Judge, Skala 1–5. Die Anker unten sind
|
||
bewusst so formuliert, dass 3 „brauchbar, aber mit Mängeln" bedeutet; ein
|
||
durchschnittlich guter Text landet nicht automatisch bei 4.
|
||
|
||
## Skala
|
||
|
||
| Punkte | Bedeutung |
|
||
|---|---|
|
||
| 5 | Kriterium durchgängig erfüllt; kein Eingriff nötig. |
|
||
| 4 | Erfüllt, mit einzelnen Schwächen, die den Gesamteindruck nicht tragen. |
|
||
| 3 | Brauchbar, aber erkennbare Mängel; Überarbeitung nötig. |
|
||
| 2 | Kriterium überwiegend verfehlt; Grundgerüst vorhanden. |
|
||
| 1 | Verfehlt. |
|
||
|
||
## Prosa
|
||
|
||
1. **Show, don't tell** — Innenleben ausschließlich über Handlung, Gegenstand,
|
||
Wahrnehmung. *1 = benannte Gefühle („sie war traurig"); 5 = kein einziges
|
||
benanntes Gefühl, Zustand trotzdem eindeutig.*
|
||
2. **Schlussbild** — konkretes, bedeutungstragendes Bild statt Moral oder
|
||
Zusammenfassung. *1 = explizite Lehre; 5 = Bild, das die Geschichte trägt.*
|
||
3. **Ton- und Registertreue** — hält die geforderte Tonlage (z. B. „nüchtern,
|
||
ohne Pathos") über den gesamten Text.
|
||
4. **Sprachliche Präzision** — konkrete Substantive, keine Füllattribute, keine
|
||
Klischees.
|
||
5. **Komposition** — Aufbau trägt; kein Leerlauf, kein abrupter Abbruch.
|
||
6. **Sprachrichtigkeit (Deutsch)** — Grammatik, Kasus, Idiomatik. *Eigener
|
||
Punkt, weil abliterierte, primär englisch trainierte Modelle hier auffällig
|
||
sind.*
|
||
|
||
## Reden
|
||
|
||
1. **Argumentative Substanz** — trägt der Gedankengang, oder reiht er Behauptungen?
|
||
2. **Vorweggenommene Einwände** — wird der stärkste Gegeneinwand benannt und
|
||
beantwortet, nicht der schwächste?
|
||
3. **Benannte Zielkonflikte** — werden echte Interessengegensätze offen
|
||
ausgesprochen statt harmonisiert?
|
||
4. **Rhetorische Mittel** — bewusst und sparsam eingesetzt (Trikolon, Anapher,
|
||
Antithese), nicht dekorativ.
|
||
5. **Adressatenbezug** — Sprache, Beispiele und Anrede passen zum Publikum.
|
||
6. **Sprachrichtigkeit (Deutsch)** — siehe oben.
|
||
|
||
## Coding
|
||
|
||
1. **Korrektheit** — *primär aus dem automatischen Testlauf.* Ein Modul, dessen
|
||
eigene Tests durchfallen, kann in diesem Kriterium nicht über 2 kommen.
|
||
2. **Anforderungsabdeckung** — sind alle Punkte des Prompts umgesetzt?
|
||
3. **Fehlerbehandlung** — die im Prompt geforderten Fehlerfälle, sauber getrennt.
|
||
4. **Testqualität** — decken die Tests die genannten Fälle ab, und sind sie
|
||
konsistent zum eigenen Code (richtiger Exception-Typ, Fixtures erfüllen das
|
||
Schema)?
|
||
5. **Keine Halluzinationen** — keine erfundenen APIs, Signaturen,
|
||
Framework-Aussagen oder Benchmark-Messwerte. *Automatisch nicht prüfbar;
|
||
erfundene Messwerte sind in den bisherigen Läufen wiederholt aufgetreten.*
|
||
6. **Lesbarkeit** — Benennung, Struktur, Kommentardichte.
|
||
|
||
## Durchführung
|
||
|
||
- **Blind bewerten.** Die Modellzuordnung steckt im Dateinamen; beim Scoren
|
||
ausblenden (`scripts/eval_prompt_tests.py --anonymize` schreibt anonymisierte
|
||
Kopien mit Zufalls-IDs und eine Auflösungstabelle).
|
||
- **Ein Kriterium über alle Texte**, nicht ein Text über alle Kriterien. Das
|
||
hält den Maßstab konstant.
|
||
- **LLM-Judge:** möglich gegen den lokalen Server, aber der Judge darf **nicht**
|
||
das bewertete Modell sein. Ein Modell bewertet seine eigenen Texte zu gut.
|
||
Der Judge ersetzt die menschliche Stichprobe nicht — mindestens 20 % der Texte
|
||
gegenlesen und die Übereinstimmung prüfen.
|
||
- **Mindestens zwei Läufe pro Zelle**, weil bei `temp > 0` ein Einzellauf wenig
|
||
aussagt. Für Coding-Vergleiche `--seed` fixieren.
|
||
|
||
## Was die Zahlen nicht sagen
|
||
|
||
Ein bestandener Testlauf beweist, dass der Code *seine eigenen* Tests besteht —
|
||
nicht, dass er korrekt ist. Wenn Modell und Test aus derselben Halluzination
|
||
stammen, sind beide konsistent falsch. Kriterium 4 (Testqualität) ist deshalb
|
||
nicht redundant zu Kriterium 1, sondern dessen Korrektiv.
|
||
|
||
## Sicherheitshinweis
|
||
|
||
`scripts/eval_prompt_tests.py` führt **modellgenerierten Code aus**. Das ist der
|
||
Sinn der Übung, aber es ist Codeausführung aus einer nicht vertrauenswürdigen
|
||
Quelle. Der Runner arbeitet in einem temporären Verzeichnis, erzwingt ein
|
||
Zeitlimit und verweigert den Start als `root`. Er bietet **keine** Netz- oder
|
||
Dateisystem-Isolation. Wer die Läufe auf einem Rechner mit Produktionsdaten
|
||
auswertet, sollte `--no-exec` verwenden oder das Skript in einem Container
|
||
starten.
|