From 653aad57e3fdaa4727a0c2b46d418a62420379b0 Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Tue, 17 Mar 2026 16:44:01 +0100 Subject: [PATCH] Let Anthropic API decide chunk relevance instead of local prefilter Updated both structure_batch and reformulate_batch prompts to return null for chunks without actionable requirements (definitions, TOCs, scope-only). Explicit instruction to always process annexes/appendices as they often contain concrete technical requirements. Co-Authored-By: Claude Opus 4.6 --- .../compliance/services/control_generator.py | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/backend-compliance/compliance/services/control_generator.py b/backend-compliance/compliance/services/control_generator.py index 6de48f2..6ed5e2e 100644 --- a/backend-compliance/compliance/services/control_generator.py +++ b/backend-compliance/compliance/services/control_generator.py @@ -1102,12 +1102,15 @@ Gib JSON zurück mit diesen Feldern: Du DARFST den Originaltext verwenden (Quellen sind jeweils angegeben). {doc_context} WICHTIG: -- Erstelle fuer JEDEN Chunk ein separates Control mit verstaendlicher, praxisorientierter Formulierung. +- Pruefe JEDEN Chunk: Enthaelt er eine konkrete Pflicht, Anforderung oder Massnahme? +- Wenn JA: Erstelle ein vollstaendiges, eigenstaendiges Control mit praxisorientierter Formulierung. +- Wenn NEIN (reines Inhaltsverzeichnis, Begriffsbestimmung ohne Pflicht, Geltungsbereich ohne Anforderung, reine Verweiskette): Gib null fuer diesen Chunk zurueck. +- BEACHTE: Anhaenge/Annexe enthalten oft KONKRETE technische Anforderungen — diese MUESSEN als Control erfasst werden! - Jedes Control muss eigenstaendig und vollstaendig sein — nicht auf andere Controls verweisen. -- Qualitaet ist wichtiger als Geschwindigkeit. Jedes Control muss die gleiche Qualitaet haben wie ein einzeln erstelltes. +- Qualitaet ist wichtiger als Geschwindigkeit. - Antworte IMMER auf Deutsch. -Gib ein JSON-Array zurueck mit GENAU {len(chunks)} Objekten. Jedes Objekt hat diese Felder: +Gib ein JSON-Array zurueck mit GENAU {len(chunks)} Elementen. Fuer Chunks ohne Anforderung gib null zurueck. Fuer Chunks mit Anforderung ein Objekt mit diesen Feldern: - chunk_index: 1-basierter Index des Chunks (1, 2, 3, ...) - title: Kurzer praegnanter Titel auf Deutsch (max 100 Zeichen) - objective: Was soll erreicht werden? (1-3 Saetze, Deutsch) @@ -1131,7 +1134,12 @@ Gib ein JSON-Array zurueck mit GENAU {len(chunks)} Objekten. Jedes Objekt hat di # Map results back to chunks by chunk_index (or by position if no index) controls: list[Optional[GeneratedControl]] = [None] * len(chunks) + skipped_by_api = 0 for pos, data in enumerate(results): + # API returns null for chunks without actionable requirements + if data is None: + skipped_by_api += 1 + continue # Try chunk_index first, fall back to position idx = data.get("chunk_index") if idx is not None: @@ -1195,15 +1203,19 @@ Gib ein JSON-Array zurueck mit GENAU {len(chunks)} Objekten. Jedes Objekt hat di f"Text (nur zur Analyse, NICHT kopieren, NICHT referenzieren):\n{chunk.text[:1500]}" ) joined = "\n\n".join(chunk_entries) - prompt = f"""Analysiere die folgenden {len(chunks)} Pruefaspekte und formuliere fuer JEDEN ein EIGENSTAENDIGES Security Control. + prompt = f"""Analysiere die folgenden {len(chunks)} Pruefaspekte und formuliere fuer JEDEN mit konkreter Anforderung ein EIGENSTAENDIGES Security Control. KOPIERE KEINE Saetze. Verwende eigene Begriffe und Struktur. NENNE NICHT die Quellen. Keine proprietaeren Bezeichner (kein O.Auth_*, TR-03161, BSI-TR etc.). WICHTIG: +- Pruefe JEDEN Aspekt: Enthaelt er eine konkrete Pflicht, Anforderung oder Massnahme? +- Wenn JA: Erstelle ein vollstaendiges, eigenstaendiges Control. +- Wenn NEIN (reines Inhaltsverzeichnis, Begriffsbestimmung ohne Pflicht, Geltungsbereich ohne Anforderung): Gib null fuer diesen Aspekt zurueck. +- BEACHTE: Anhaenge/Annexe enthalten oft KONKRETE technische Anforderungen — diese MUESSEN erfasst werden! - Jedes Control muss eigenstaendig und vollstaendig sein — nicht auf andere Controls verweisen. -- Qualitaet ist wichtiger als Geschwindigkeit. Jedes Control muss die gleiche Qualitaet haben wie ein einzeln erstelltes. +- Qualitaet ist wichtiger als Geschwindigkeit. -Gib ein JSON-Array zurueck mit GENAU {len(chunks)} Objekten. Jedes Objekt hat diese Felder: +Gib ein JSON-Array zurueck mit GENAU {len(chunks)} Elementen. Fuer Aspekte ohne Anforderung gib null zurueck. Fuer Aspekte mit Anforderung ein Objekt mit diesen Feldern: - chunk_index: 1-basierter Index des Aspekts (1, 2, 3, ...) - title: Kurzer eigenstaendiger Titel (max 100 Zeichen) - objective: Eigenstaendige Formulierung des Ziels (1-3 Saetze) @@ -1225,6 +1237,8 @@ Gib ein JSON-Array zurueck mit GENAU {len(chunks)} Objekten. Jedes Objekt hat di controls: list[Optional[GeneratedControl]] = [None] * len(chunks) for pos, data in enumerate(results): + if data is None: + continue idx = data.get("chunk_index") if idx is not None: idx = int(idx) - 1