This commit is contained in:
team 1
2026-05-12 11:26:05 +02:00
parent 6e2ca15e97
commit 3f914c1efd
2 changed files with 174 additions and 18 deletions

View File

@@ -37,6 +37,17 @@
</div>
{% endif %}
<div class="alert alert-secondary border-secondary bg-black text-light shadow-sm mb-4">
<div class="fw-semibold text-warning mb-1">
<i class="bi bi-compass"></i> Kurz erklärt
</div>
<div class="small text-secondary">
Ein Eval-Case ist ein wiederholbarer Test. Du trägst ein, <strong class="text-light">was der Nutzer fragt</strong>
und <strong class="text-light">woran RetrieX gemessen werden soll</strong>. Der Test verändert keine Daten im Shop oder im RAG-Wissen,
sondern prüft nur, ob ein bekannter Fall weiterhin richtig läuft.
</div>
</div>
<div class="row g-4">
<div class="col-xl-8">
<div class="card bg-black border-secondary text-light shadow-sm">
@@ -48,7 +59,7 @@
<form method="post" action="{{ path('admin_evals_case_create') }}">
<input type="hidden" name="_token" value="{{ csrf_token('admin_eval_case_create') }}">
<div class="mb-3">
<div class="mb-4">
<label class="form-label">Eval-Typ</label>
<select name="type" class="form-select bg-dark text-light border-secondary">
{% for type, label in types %}
@@ -58,11 +69,18 @@
{% endfor %}
</select>
<div class="form-text text-secondary">
Der Typ entscheidet, in welche Datei geschrieben wird: <code>tests/evals/cases/&lt;type&gt;.ndjson</code>.
Wähle zuerst, <strong class="text-light">was genau geprüft werden soll</strong>. Der Typ entscheidet auch,
in welche Datei der Case geschrieben wird: <code>tests/evals/cases/&lt;type&gt;.ndjson</code>.
</div>
<div class="small text-secondary mt-2 border border-secondary rounded p-3 bg-dark">
<div class="mb-1"><strong class="text-light">retrieval</strong>: prüft, ob die richtige Wissensquelle oder das richtige Dokument gefunden wird.</div>
<div class="mb-1"><strong class="text-light">shop_query</strong>: prüft, welche Suchquery an den Shop geschickt würde.</div>
<div class="mb-1"><strong class="text-light">followup</strong>: prüft eine Folgefrage, die den vorherigen Chatverlauf braucht.</div>
<div><strong class="text-light">answer_guard</strong>: prüft, dass RetrieX bei Unsinn oder fehlender Evidenz nichts erfindet.</div>
</div>
</div>
<div class="mb-3">
<div class="mb-4">
<label class="form-label">Neue Case-ID</label>
<input type="text"
name="id"
@@ -71,11 +89,18 @@
placeholder="followup_testomat808_device_price_001"
required>
<div class="form-text text-secondary">
Eindeutig über alle Eval-Typen. Erlaubt: Buchstaben, Zahlen, <code>_</code> und <code>-</code>.
Das ist der <strong class="text-light">interne Name des Tests</strong>. Er erscheint später in der Eval-Auswertung,
damit du den Fall wiedererkennst. Verwende keine Leerzeichen. Erlaubt sind Buchstaben, Zahlen, <code>_</code> und <code>-</code>.
</div>
<div class="small text-secondary mt-2 border border-secondary rounded p-3 bg-dark">
Gute Beispiele: <code>retrieval_lieferbedingungen_versand_001</code>,
<code>shop_query_testomat808_indikator300_001</code>,
<code>followup_testomat808_device_price_001</code>.<br>
Faustregel: <code>typ_thema_ziel_nummer</code>.
</div>
</div>
<div class="mb-3">
<div class="mb-4">
<label class="form-label">Prompt</label>
<textarea name="prompt"
rows="3"
@@ -83,22 +108,48 @@
placeholder="und was kostet das gerät selber"
required>{{ case_draft.prompt|default('') }}</textarea>
<div class="form-text text-secondary">
Exakt der Nutzerprompt, der abgesichert werden soll. Tippfehler bewusst so eintragen, wenn sie Teil des Tests sind.
Hier kommt <strong class="text-light">genau die Nutzerfrage</strong> hinein, die getestet werden soll.
Nicht die erwartete Antwort eintragen, sondern den Satz, den ein Nutzer in den Chat schreiben würde.
</div>
<div class="small text-secondary mt-2 border border-secondary rounded p-3 bg-dark">
Tippfehler dürfen bewusst drin bleiben, wenn genau dieser Tippfehler abgesichert werden soll.
Beispiel: <code>ich würde gern chlor im schwinnbad messen</code> prüft dann auch die Korrektur Richtung <code>schwimmbad</code>.
</div>
</div>
<div class="mb-3">
<div class="mb-4">
<label class="form-label">Assert-JSON</label>
<textarea name="assert_json"
rows="9"
class="form-control bg-dark text-light border-secondary font-monospace"
spellcheck="false">{{ case_draft.assert_json|default('{}') }}</textarea>
<div class="form-text text-secondary">
Muss ein gültiges JSON-Objekt sein. Beispiel: <code>{"expected_query":"testomat 808"}</code>.
Hier steht, <strong class="text-light">was der Test erwarten soll</strong>. Das Feld muss gültiges JSON sein,
also mit <code>{</code> anfangen und mit <code>}</code> enden. Keine Kommentare und kein Komma nach dem letzten Eintrag.
</div>
<div class="small text-secondary mt-2 border border-secondary rounded p-3 bg-dark">
<div class="mb-2"><strong class="text-light">Wenn eine Shopquery exakt stimmen soll:</strong></div>
<pre class="bg-black border border-secondary rounded p-2 small text-light mb-3"><code>{
"expected_query": "testomat 808"
}</code></pre>
<div class="mb-2"><strong class="text-light">Wenn bestimmte Wörter enthalten sein müssen:</strong></div>
<pre class="bg-black border border-secondary rounded p-2 small text-light mb-3"><code>{
"must_include_terms": [
"testomat",
"808"
]
}</code></pre>
<div class="mb-2"><strong class="text-light">Wenn ein Dokument gefunden werden muss:</strong></div>
<pre class="bg-black border border-secondary rounded p-2 small text-light mb-0"><code>{
"min_results": 1,
"must_include_one_of_document_ids": [
"DOKUMENT-ID"
]
}</code></pre>
</div>
</div>
<div class="mb-3">
<div class="mb-4">
<label class="form-label">History-JSON <span class="text-secondary">optional</span></label>
<textarea name="history_json"
rows="8"
@@ -106,7 +157,18 @@
spellcheck="false"
placeholder='[{"prompt":"vorherige Frage","answer":"vorherige Antwort"}]'>{{ case_draft.history_json|default('') }}</textarea>
<div class="form-text text-secondary">
Für Follow-up-Cases empfohlen. Muss eine JSON-Liste sein. Leer lassen für direkte Prompts.
Nur ausfüllen, wenn die aktuelle Frage den <strong class="text-light">vorherigen Chatverlauf</strong> braucht.
Für direkte Einzelprompts leer lassen. Das Feld muss eine JSON-Liste sein, also mit <code>[</code> anfangen und mit <code>]</code> enden.
</div>
<div class="small text-secondary mt-2 border border-secondary rounded p-3 bg-dark">
Typischer Einsatz: Der Nutzer fragt zuerst nach dem niedrigsten Grenzwert, danach nach dem Indikator
und anschließend <code>was kostet der indikator</code>. Dann braucht der Test die vorherigen Fragen und Antworten als History.
<pre class="bg-black border border-secondary rounded p-2 small text-light mt-2 mb-0"><code>[
{
"prompt": "mit welchem indikator",
"answer": "Der Wert 0,02 °dH wird beim Testomat 808 mit Indikatortyp 300 gemessen."
}
]</code></pre>
</div>
</div>
@@ -117,7 +179,12 @@
class="form-control bg-dark text-light border-secondary"
placeholder="Nur für Spezialfälle, wenn History nicht ausreicht.">{{ case_draft.request_context_hint|default('') }}</textarea>
<div class="form-text text-secondary">
Normalerweise leer lassen. Für reguläre Regressionen lieber History-JSON verwenden.
Dieses Feld kannst du fast immer <strong class="text-light">leer lassen</strong>. Es ist nur für Sonderfälle gedacht,
wenn der Test Zusatzkontext braucht, der nicht sauber als History darstellbar ist.
</div>
<div class="small text-secondary mt-2 border border-secondary rounded p-3 bg-dark">
Beispiel für einen Sonderfall: <code>Im vorherigen Ergebnis waren mehrere Shop-Produkte sichtbar, aber keine normale Chatantwort.</code>
Für normale Regressionen ist <strong class="text-light">History-JSON die bessere Wahl</strong>.
</div>
</div>
@@ -139,14 +206,26 @@
<div class="card bg-black border-secondary text-light shadow-sm mb-4">
<div class="card-body">
<h5 class="text-info mb-3">
<i class="bi bi-info-circle"></i> Feld-Checkliste
<i class="bi bi-info-circle"></i> Welcher Typ ist richtig?
</h5>
<ul class="small text-secondary mb-0">
<li><strong class="text-light">retrieval</strong>: richtiges Dokument / richtige Chunks prüfen.</li>
<li><strong class="text-light">shop_query</strong>: direkte Shopquery prüfen.</li>
<li><strong class="text-light">followup</strong>: Prompt plus History prüfen.</li>
<li><strong class="text-light">answer_guard</strong>: No-Answer- oder Evidenzfälle prüfen.</li>
</ul>
<div class="small text-secondary">
<div class="mb-3">
<strong class="text-light">Du willst prüfen, ob das richtige Dokument gefunden wird?</strong><br>
Dann nimm <code>retrieval</code>.
</div>
<div class="mb-3">
<strong class="text-light">Du willst prüfen, welche Suchwörter an den Shop gehen?</strong><br>
Dann nimm <code>shop_query</code>.
</div>
<div class="mb-3">
<strong class="text-light">Die Frage bezieht sich auf die vorherige Antwort?</strong><br>
Dann nimm <code>followup</code> und fülle <code>History-JSON</code> aus.
</div>
<div>
<strong class="text-light">RetrieX soll bei Unsinn nichts erfinden?</strong><br>
Dann nimm <code>answer_guard</code>.
</div>
</div>
</div>
</div>
@@ -168,6 +247,14 @@
]
}</code></pre>
<div class="small text-secondary mb-2">Begriffe dürfen nicht enthalten sein:</div>
<pre class="bg-dark border border-secondary rounded p-2 small text-light"><code>{
"must_not_include_terms": [
"indikator",
"300"
]
}</code></pre>
<div class="small text-secondary mb-2">Dokument muss enthalten sein:</div>
<pre class="bg-dark border border-secondary rounded p-2 small text-light"><code>{
"min_results": 1,
@@ -178,6 +265,21 @@
</div>
</div>
<div class="card bg-black border-secondary text-light shadow-sm mb-4">
<div class="card-body">
<h5 class="text-info mb-3">
<i class="bi bi-check2-square"></i> Vor dem Speichern prüfen
</h5>
<ul class="small text-secondary mb-0">
<li>Prüft der Case genau einen Zweck?</li>
<li>Ist die Case-ID eindeutig und ohne Leerzeichen?</li>
<li>Ist der Prompt eine echte Nutzerfrage?</li>
<li>Ist Assert-JSON gültiges JSON?</li>
<li>Ist History nur bei echten Folgefragen gefüllt?</li>
</ul>
</div>
</div>
<div class="card bg-black border-secondary text-light shadow-sm">
<div class="card-body">
<h5 class="text-info mb-3">
@@ -185,6 +287,8 @@
</h5>
<p class="small text-secondary mb-0">
Ein guter Eval-Case prüft genau einen Zweck. Lieber mehrere kleine Cases anlegen als einen großen, empfindlichen Case.
Wenn du unsicher bist, starte mit <code>expected_query</code> bei Shop-/Follow-up-Fällen oder mit
<code>must_include_one_of_document_ids</code> bei Retrieval-Fällen.
</p>
</div>
</div>