llamacppctl/docs/EVAL_RUBRIC.md
dschlueter b0c215abbb feat(scripts): detect how a model evades, not just whether
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>
2026-07-10 17:10:39 +02:00

6.6 KiB
Raw Blame History

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.

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_0608); 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 15. 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. Korrektheitprimä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.