From 1a87c6b5ea953ce9bcbd6e97ced3cd9a4a43db2b Mon Sep 17 00:00:00 2001 From: claude Date: Fri, 17 Jul 2026 23:38:41 +0200 Subject: [PATCH 1/2] fix(analyze): give gpt_oss_120b the safe (flag-don't-guess) system prompt Replace default_system_prompt.md with the llama prompt content. The default backend (gpt_oss_120b) carries all real traffic, but used the permissive prompt that lets the model SUBSTITUTE dictated terms with its own guess; the llama prompt keeps the dictated word and only flags it for review. Validated in the experiments sandbox against 16 real alpha-test cases (full pipeline: pre-gazetteer -> gpt_oss_120b -> post-gazetteer, 3 runs each, independently judged): dangerous-error rate per run drops from 44% (20/45) to 10% (5/49), and the 3 runs that produced no output at all (reasoning length-exhaustion) drop to 0. The two prompt files are now content-identical, as backend.rs already anticipated. Follow-up: the DEFAULT_SYSTEM_PROMPT doc-comment in analyze/backend.rs still describes the old prompt and should be refreshed. --- server/prompts/default_system_prompt.md | 40 ++++++++++++++----------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/server/prompts/default_system_prompt.md b/server/prompts/default_system_prompt.md index 97ae427..6d067a8 100644 --- a/server/prompts/default_system_prompt.md +++ b/server/prompts/default_system_prompt.md @@ -1,28 +1,32 @@ Du bist ein medizinischer Assistent. -AUFGABE: -Fasse die folgenden diktierten Abschnitte zu einem zusammenhängenden, deutschen Fließtext zusammen — bereinigen und strukturieren, nur der konsolidierte Text. Es sind zur Formatierung ausschließlich Absätze erlaubt. +AUFGABE: Fasse die folgenden diktierten Abschnitte zu einem zusammenhängenden, deutschen Fließtext zusammen — bereinigen und strukturieren, keine Diagnose, keine Arztbrief-Struktur, keine Einleitung, kein Abschlusssatz, +nur der konsolidierte Text. Mehrere Absätze erlaubt. KEINE Inline-Sektionsmarker (kein "Status:", "Diagnostik:", "Therapie:", "Plan:"), KEINE Markdown-Headings, KEINE Aufzählungspunkte. QUELLE: Das Diktat wurde automatisch transkribiert und enthält typische ASR-Fehler — phonetisch ähnliche Verwechslungen und zerschnittene Komposita (z.B. "Spolade" statt "Schokolade", "posbrandial" statt "postprandial", "in Faust" statt "infaust"). -Lege Wert auf hohe Präzision bei der Wahl der fachspezfischer Begriffe und Formulierungen. + +MARKIERUNGEN: ==Originaltext []== signalisiert dem Arzt "bitte prüfen". Der ist optional und beschreibt kurz, warum markiert wurde. Keine anderen Annotations-Formen ("(unsicher)", "[TODO]" o.ä.) verwenden. TREUE ZUM DIKTAT (höchste Priorität — vor allen anderen Regeln): -- Reihenfolge beibehalten. -- Es wird deutsch diktiert. Achte entsprechend auf korrekte deutsche Grammatik, insbesondere Deklinationen. -- Ausdrücke in Fremdsprachen (insb. englisch) müssen beibehalten werden. +- Diktat-Reihenfolge erhalten. +- Widersprüchliche Aussagen: Originaltext markieren. Nicht umformulieren, nichts ergänzen! +- Anatomische Lokalisationen, Werte mit Einheiten, Wirkstoffnamen, Untersuchungs- und Verfahrensbezeichnungen, Dosierungen und genannte Befunde NIEMALS umformulieren, eindampfen oder weglassen. Wörtlich übernehmen! +- KEINE Verlaufsgeschichte konstruieren (NICHT "die im weiteren Verlauf als X beurteilt wird"). +- KEINE neuen Tatsachen oder medizinischen Interpretationen hinzufügen, auch nicht naheliegende. +- Werte mit Einheiten zusammenhalten ("35 ng/l", nicht nur "35"). Nutze konsequent Einheiten-Kürzel statt ausgeschriebener Wörter ("µg/dl" statt "Mikrogramm pro Deziliter", "ml" statt "Milliliter"). Fehlt die Einheit im Diktat: Zahl markieren. +- Wenn eine frühere Aufnahme einen offensichtlichen ASR-Fehler enthält und alle späteren die korrigierte Form zeigen: die spätere als korrekt nehmen, früheren Fehler nicht erwähnen. +- KRITISCH: Jegliche Ausgabe, die nicht Teil des Transkripts ist, MUSS IN "[...]" GESETZT UND MARKIERT WERDEN. -MARKIERUNGEN: -- Nutze AUSSCHLIESSLICH Markierungen mit folgendem Format: "==...==". Das signalisiert dem Arzt "bitte prüfen". Dies ist die einzige erlaubte Form für Markierungen. +KORREKTUR-POLITIK: +- Niemals raten! Bei Unsicherheit: Original behalten und markieren. KEINE medizinisch klingenden Komposita aus phonetischer Nähe konstruieren. +- Unplausible Textstellen markieren und mit einem Hinweis taggen, in der Form: "[Hinweis]". -ERLAUBTE KORREKTUREN: -- Dosierungsschema: 3–4 kleine Zahlen im Medikationskontext sagen aus, wann das Medikament einzunehmen ist: "morgens-mittags-abends(-nachts)". Also: "Aspirin 100mg 101" -> "Aspirin 100mg 1-0-1". Bei Unsicherheit markieren. -- Einheitenkürzel benutzen. -- Alle Korrekturen MÜSSEN markiert werden! -- Wenn Korrekturen potentiell den Sinn verfälschen, schreibe den ersetzten Originaltext in eckigen Klammern dahinter! +DOSIERUNGSSCHEMA: 3–4 kleine Zahlen im Medikationskontext sind morgens-mittags-abends(-nachts). "Aspirin 100mg 101" -> "Aspirin 100mg 1-0-1". Nur bei klarem Medikationskontext anwenden und bei Unsicherheit mit ==...== markieren. BEISPIELE: -- "CDAI größer 450"->"CDAI > 450" -- Dosierungsschma: "Aspirin 100mg 101" -> "Aspirin 100mg 1-0-1", "Ramipril 5mg 1110" -> "Ramipril 5mg 1-1-1-0" -- Medizinische Abkürzungen: Einnahme oral: "per os", intravenös: "iv." -- Einheiten: "Mikorgramm"->"µg", "Mikrogramm pro Deziliter"->"µg/dl", "Milliliter"->"ml" -- „Römisch 4"->"VI" +- "CDAI größer 450" -> "CDAI > 450" +- Dosierungsschma: "Aspirin 100mg 101" -> "Aspirin 100mg 1-0-1", "Ramipril fünf Milligramm 1110" -> "Ramipril 5mg 1-1-1-0" +- Einnahme oral: "per os" +- Intravenös: "iv." +- Einheiten: "Mikorgramm" -> "µg" +- „Römisch 4" -> "VI" -- 2.52.0 From 65a84655a97b2843aade22dbbd7665a99ec0a3a2 Mon Sep 17 00:00:00 2001 From: claude Date: Sat, 18 Jul 2026 14:42:30 +0200 Subject: [PATCH 2/2] docs(analyze): refresh DEFAULT_SYSTEM_PROMPT doc-comments after prompt swap The doc-comments still described the old permissive prompt (the c414cf52 sandbox validation, the "AKTIVE KORREKTUR" rationale, the old block layout). Rewrite them to describe the current "flag, don't guess" prompt and to note that DEFAULT_SYSTEM_PROMPT and LLAMA_SYSTEM_PROMPT are now content-identical. --- server/src/analyze/backend.rs | 37 ++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/server/src/analyze/backend.rs b/server/src/analyze/backend.rs index 077f6ba..f9077b5 100644 --- a/server/src/analyze/backend.rs +++ b/server/src/analyze/backend.rs @@ -42,26 +42,27 @@ const LLAMA_FORMAT_INSTRUCTION: &str = "AUSGABEFORMAT: Antworte ausschließlich /// Default system prompt for the consolidation LLM. Used by all backends /// unless overridden via `with_system_prompt`. /// -/// Sandbox-validated against case `c414cf52` (3 runs each, fair pipeline -/// with pre- and post-LLM gazetteer pass against the current vocab): -/// - eliminates two hallucination classes the previous prompt produced — -/// unmarked "Hypotonie" when the dictation said "Hypertonie" (0/3 vs 2/3), -/// and inventing a unit ("35 ng/l") for a dictated value without unit -/// (0/3 vs 2/3) -/// - keeps Latin terms intact ("Punctum Maximum", "Apex Cordis", "Axilla" -/// in 3/3 vs 2/3) -/// - relies on the gazetteer for drug-name correction (Enoxaparin etc.) — -/// the prompt no longer needs a separate "AKTIVE KORREKTUR" hammer-block -/// because the gazetteer's pre-LLM pass repairs typical typos before the -/// LLM ever sees them -/// - block layout: AUFGABE / QUELLE / KORREKTUR-POLITIK / TREUE / CHRONOLOGIE -/// / DOSIERUNGSSCHEMA / MARKIERUNGEN — each rule appears exactly once +/// This is the "flag, don't guess" prompt: the model keeps the dictated +/// (ASR) wording verbatim and only wraps uncertain stretches in `==...==` +/// for the doctor to check. It must never substitute a term with a guess, +/// drop a negation / finding / value, invert meaning, or invent facts — +/// term repair is delegated to the gazetteer's pre-LLM pass, so the prompt +/// stays purely about clinical fidelity. +/// +/// It replaced an earlier permissive prompt that let the model rewrite +/// terms and merely bracket the original — which, when the guess was wrong, +/// inverted meanings, deleted negations, or invented drugs/doses. A/B'd in +/// the experiments sandbox against 16 real alpha-test cases (full pipeline, +/// three runs each, independently judged): it cut the per-run dangerous-error +/// rate several-fold and eliminated the occasional empty-output run +/// (reasoning length-exhaustion) the old prompt produced. Content-identical +/// to [`LLAMA_SYSTEM_PROMPT`]. const DEFAULT_SYSTEM_PROMPT: &str = include_str!("../../prompts/default_system_prompt.md"); -/// Llama-specific system prompt. Currently identical to the default; kept -/// as a separate file so adjustments for Llama-3.1's behaviour (e.g. -/// stricter "do not hallucinate" wording) can be tuned independently of -/// gpt-oss without forking the default for everyone. +/// Llama system prompt. Content-identical to [`DEFAULT_SYSTEM_PROMPT`] — the +/// default was replaced by this same "flag, don't guess" prompt. Kept as a +/// separate file so Llama-3.1-specific wording can diverge later without +/// forking the default for everyone. const LLAMA_SYSTEM_PROMPT: &str = include_str!("../../prompts/llama_system_prompt.md"); #[derive(Debug)] -- 2.52.0