Files
breakpilot-compliance/docs-src/services/sdk-modules/control-generator-pipeline.md
Benjamin Admin 148c7ba3af
Some checks failed
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Failing after 42s
CI/CD / test-python-backend-compliance (push) Successful in 34s
CI/CD / test-python-document-crawler (push) Successful in 21s
CI/CD / test-python-dsms-gateway (push) Successful in 20s
CI/CD / validate-canonical-controls (push) Successful in 12s
CI/CD / Deploy (push) Has been skipped
feat(qa): recital detection, review split, duplicate comparison
Add _detect_recital() to QA pipeline — flags controls where
source_original_text contains Erwägungsgrund markers instead of
article text (28% of controls with source text affected).

- Recital detection via regex + phrase matching in QA validation
- 10 new tests (TestRecitalDetection), 81 total
- ReviewCompare component for side-by-side duplicate comparison
- Review mode split: Duplikat-Verdacht vs Rule-3-ohne-Anchor tabs
- MkDocs: recital detection documentation
- Detection script for bulk analysis (scripts/find_recital_controls.py)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 08:20:02 +01:00

20 KiB

Control Generator Pipeline

Automatische Generierung von Canonical Controls aus dem gesamten RAG-Korpus (~105.000 Chunks aus Gesetzen, Verordnungen und Standards).

Backend: backend-compliance/compliance/services/control_generator.py Routes: backend-compliance/compliance/api/control_generator_routes.py API-Prefix: /api/compliance/v1/canonical/generate


Pipeline-Uebersicht

Die Pipeline durchlaeuft 7 Stufen, um aus RAG-Chunks eigenstaendige Security/Compliance Controls zu erzeugen:

flowchart TD
    A[1. RAG Scan] -->|Alle Chunks laden| B[2. License Classify]
    B -->|Rule 1/2| C[3a. Structure Batch]
    B -->|Rule 3| D[3b. Reform Batch]
    C --> E[4. Harmonize]
    D --> E
    E -->|Duplikat| F[Als Duplikat markieren]
    E -->|Neu| G[5. Anchor Search]
    G --> H[6. Store Control]
    H --> I[7. Mark Processed]
Stufe Name Beschreibung
1 RAG Scan Laedt unverarbeitete Chunks aus Qdrant (Scroll-API), filtert per SHA-256-Hash
2 License Classify Bestimmt die Lizenzregel (Rule 1/2/3) anhand regulation_code
3a Structure (Batch) Rule 1+2: Strukturiert Originaltext als Control (Anthropic API)
3b Reform (Batch) Rule 3: Vollstaendige Reformulierung ohne Originaltext (Anthropic API)
4 Harmonize Embedding-basierte Duplikaterkennung (bge-m3, Cosine > 0.85)
5 Anchor Search Findet Open-Source-Referenzen (OWASP, NIST, ENISA)
6 Store Persistiert Control in canonical_controls mit Metadaten
7 Mark Processed Markiert jeden Chunk als verarbeitet (auch bei Skip/Error/Duplikat)

Pipeline-Versionen

Die Pipeline hat zwei Versionen. Die Version wird als pipeline_version auf canonical_controls und canonical_processed_chunks gespeichert.

v1 (Original)

Eigenschaft Wert
Vorfilter Lokales LLM (llama3.2 3B) entscheidet ob Chunk relevant
Anthropic-Prompt Alter Prompt ohne null-Skip
Annexe/Anhaenge Kein Schutz — wurden haeufig faelschlich als irrelevant uebersprungen
pipeline_version 1

v2 (Aktuell)

Eigenschaft Wert
Vorfilter Optional (skip_prefilter). Wenn aktiviert, entscheidet Anthropic API selbst
Anthropic-Prompt Neuer Prompt mit null-Skip: API gibt null fuer Chunks ohne Anforderung zurueck
Annexe/Anhaenge Explizit geschuetzt — Prompt-Anweisung: "Anhaenge/Annexe enthalten oft KONKRETE technische Anforderungen — diese MUESSEN als Control erfasst werden!"
pipeline_version 2

Wesentliche Aenderungen v1 → v2

  1. Relevanz-Entscheidung an Anthropic delegiert — Das lokale LLM (Vorfilter) ist optional. Die Anthropic API entscheidet selbst, welche Chunks Controls enthalten, indem sie null fuer irrelevante Chunks zurueckgibt.
  2. null-Skip im JSON-Array — Das Ergebnis-Array enthaelt null-Eintraege fuer Chunks ohne umsetzbare Anforderung. Kein separater Vorfilter-Schritt noetig.
  3. Annexe/Anhaenge geschuetzt — Explizite Prompt-Anweisung verhindert, dass technische Anforderungen in Anhaengen uebersprungen werden.

Datenbank-Feld

-- Migration 062
ALTER TABLE canonical_controls
    ADD COLUMN pipeline_version smallint NOT NULL DEFAULT 1;

ALTER TABLE canonical_processed_chunks
    ADD COLUMN pipeline_version smallint NOT NULL DEFAULT 1;

Neue Controls erhalten automatisch pipeline_version = 2. Bestehende (v1) behalten 1, damit sie spaeter identifiziert und ggf. reprocessiert werden koennen.


Konfiguration

Request-Parameter (GenerateRequest)

Parameter Typ Default Beschreibung
collections List[str] Alle 5 Collections Qdrant-Collections zum Durchsuchen
domain str Filter auf eine Domain (z.B. AUTH, NET)
regulation_filter List[str] Prefix-Matching auf regulation_code (z.B. ["eu_2023_1230", "owasp_"])
skip_prefilter bool false Ueberspringt lokalen LLM-Vorfilter, sendet alle Chunks an die Anthropic API
batch_size int 5 Chunks pro Anthropic-API-Call
max_controls int 50 Maximale Anzahl Controls pro Job (0 = unbegrenzt)
max_chunks int 1000 Maximale Chunks pro Job (0 = unbegrenzt, respektiert Dokumentgrenzen)
skip_web_search bool false Ueberspringt Web-Suche in der Anchor-Findung (Stufe 5)
dry_run bool false Trockenlauf ohne DB-Schreibzugriffe (synchron, mit Controls im Response)

!!! info "regulation_filter — Prefix-Matching" Der Filter vergleicht den regulation_code jedes Chunks per Prefix. Beispiel: ["eu_2023_1230"] erfasst nur Chunks aus der Maschinenverordnung. ["owasp_"] erfasst alle OWASP-Dokumente (OWASP ASVS, OWASP SAMM, etc.). Gross-/Kleinschreibung wird ignoriert.

Umgebungsvariablen

Variable Default Beschreibung
ANTHROPIC_API_KEY API-Key fuer Anthropic Claude (Pflicht)
CONTROL_GEN_ANTHROPIC_MODEL claude-sonnet-4-6 Anthropic-Modell fuer Strukturierung/Reformulierung
OLLAMA_URL http://host.docker.internal:11434 Lokaler Ollama-Server (Vorfilter + QA)
CONTROL_GEN_OLLAMA_MODEL qwen3.5:35b-a3b Lokales LLM-Modell fuer Vorfilter und QA-Arbitrierung
CONTROL_GEN_LLM_TIMEOUT 180 Timeout in Sekunden pro Anthropic-API-Call

Pipeline-interne Konstanten

Konstante Wert Beschreibung
PIPELINE_VERSION 2 Aktuelle Pipeline-Version
HARMONIZATION_THRESHOLD 0.85 Cosine-Similarity-Schwelle fuer Duplikaterkennung
max_tokens 8192 Maximale Token-Laenge der LLM-Antwort

API Endpoints

Alle Endpoints unter /api/compliance/v1/canonical/.

Uebersicht

Methode Pfad Beschreibung
POST /generate Generierungs-Job starten (laeuft im Hintergrund)
GET /generate/status/{job_id} Status eines laufenden Jobs abfragen
GET /generate/jobs Alle Jobs auflisten (paginiert)
GET /generate/processed-stats Verarbeitungsstatistik pro Collection
GET /generate/review-queue Controls zur manuellen Pruefung
POST /generate/review/{control_id} Review eines einzelnen Controls abschliessen
POST /generate/bulk-review Bulk-Review nach release_state
POST /generate/qa-reclassify QA-Reklassifizierung bestehender Controls
GET /blocked-sources Gesperrte Quellen (Rule 3) auflisten
POST /blocked-sources/cleanup Cleanup-Workflow fuer gesperrte Quellen starten

POST /v1/canonical/generate — Job starten

Startet einen Generierungs-Job im Hintergrund. Gibt sofort eine job_id zurueck.

Request:

{
  "collections": ["bp_compliance_gesetze"],
  "regulation_filter": ["eu_2023_1230"],
  "skip_prefilter": false,
  "batch_size": 5,
  "max_chunks": 500,
  "max_controls": 0,
  "skip_web_search": false,
  "dry_run": false
}

Response (200):

{
  "job_id": "a1b2c3d4-...",
  "status": "running",
  "message": "Generation started in background. Poll /generate/status/{job_id} for progress."
}

Beispiel:

# Alle Chunks der Maschinenverordnung verarbeiten
curl -X POST https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate \
  -H 'Content-Type: application/json' \
  -H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000' \
  -d '{
    "collections": ["bp_compliance_ce"],
    "regulation_filter": ["eu_2023_1230"],
    "max_chunks": 200,
    "batch_size": 5
  }'
# Dry Run: Keine DB-Aenderungen, Controls im Response
curl -X POST https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate \
  -H 'Content-Type: application/json' \
  -H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000' \
  -d '{
    "collections": ["bp_compliance_gesetze"],
    "max_chunks": 10,
    "dry_run": true
  }'
# Ohne Vorfilter: Alle Chunks direkt an Anthropic API
curl -X POST https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate \
  -H 'Content-Type: application/json' \
  -H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000' \
  -d '{
    "collections": ["bp_compliance_gesetze"],
    "regulation_filter": ["bdsg"],
    "skip_prefilter": true,
    "max_chunks": 100
  }'

!!! warning "Kosten beachten" Ohne regulation_filter und mit max_chunks: 0 werden alle 105.000 Chunks verarbeitet. Das verursacht erhebliche Anthropic-API-Kosten ($700).


GET /v1/canonical/generate/status/{job_id} — Job-Status

Gibt den vollstaendigen Status eines Jobs zurueck inkl. Metriken und Fehler.

Beispiel:

curl https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate/status/a1b2c3d4-... \
  -H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000'

Response:

{
  "id": "a1b2c3d4-...",
  "status": "completed",
  "total_chunks_scanned": 500,
  "controls_generated": 48,
  "controls_verified": 45,
  "controls_needs_review": 3,
  "controls_too_close": 0,
  "controls_duplicates_found": 12,
  "controls_qa_fixed": 5,
  "config": { "..." },
  "started_at": "2026-03-17T10:00:00+00:00",
  "completed_at": "2026-03-17T10:15:32+00:00"
}

GET /v1/canonical/generate/jobs — Alle Jobs

Paginierte Liste aller Generierungs-Jobs.

Query-Parameter:

Parameter Default Beschreibung
limit 20 Anzahl Jobs (1-100)
offset 0 Offset fuer Paginierung

Beispiel:

curl "https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate/jobs?limit=5" \
  -H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000'

GET /v1/canonical/generate/review-queue — Review-Queue

Listet Controls auf, die eine manuelle Pruefung benoetigen.

Query-Parameter:

Parameter Default Beschreibung
release_state needs_review Filter: needs_review, too_close, duplicate
limit 50 Anzahl (1-200)

Beispiel:

curl "https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate/review-queue?release_state=needs_review&limit=10" \
  -H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000'

POST /v1/canonical/generate/review/{control_id} — Review abschliessen

Schliesst die manuelle Pruefung eines Controls ab.

Request:

{
  "action": "approve",
  "release_state": "draft",
  "notes": "Inhaltlich korrekt, Severity passt."
}

Moegliche action-Werte:

Action Neuer State Beschreibung
approve draft (oder per release_state ueberschreiben) Control freigeben
reject deprecated Control verwerfen
needs_rework needs_review Zurueck in die Queue

Beispiel:

curl -X POST https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate/review/AUTH-042 \
  -H 'Content-Type: application/json' \
  -H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000' \
  -d '{"action": "approve", "release_state": "draft"}'

POST /v1/canonical/generate/bulk-review — Bulk-Review

Aendert den release_state aller Controls, die einen bestimmten State haben.

Request:

{
  "release_state": "needs_review",
  "action": "approve",
  "new_state": "draft"
}

Beispiel:

# Alle needs_review Controls auf draft setzen
curl -X POST https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate/bulk-review \
  -H 'Content-Type: application/json' \
  -H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000' \
  -d '{"release_state": "needs_review", "action": "approve", "new_state": "draft"}'

GET /v1/canonical/generate/processed-stats — Verarbeitungsstatistik

Liefert Statistiken pro RAG-Collection.

Beispiel:

curl https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate/processed-stats \
  -H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000'

Response:

{
  "stats": [
    {
      "collection": "bp_compliance_gesetze",
      "processed_chunks": 45200,
      "direct_adopted": 1850,
      "llm_reformed": 120,
      "skipped": 43230,
      "total_chunks_estimated": 0,
      "pending_chunks": 0
    }
  ]
}

Kosten und Performance

Kostenabschaetzung

Metrik Wert
Kosten pro Chunk ~$0.0067 (Anthropic API, Batch-Modus)
Yield (Controls/Chunks) ~4.5-10% (nur Chunks mit konkreten Anforderungen erzeugen Controls)
Vorfilter-Ersparnis ~55% der API-Kosten wenn aktiviert (irrelevante Chunks werden lokal aussortiert)

Performance-Kennzahlen

Metrik Wert
Batch-Groesse 5 Chunks pro API-Call (Default)
API-Aufrufe Reduktion ~80% weniger Aufrufe durch Batching
LLM-Timeout 180 Sekunden pro Call
QA-Overhead ~2s pro Control (nur bei Disagreement, ~10-15% der Controls)

RAG Collections

Collection Inhalte Erwartete Regel
bp_compliance_gesetze Deutsche Gesetze (BDSG, TTDSG, TKG etc.) Rule 1
bp_compliance_datenschutz Datenschutz-Leitlinien + EU-Verordnungen Rule 1/2
bp_compliance_ce CE/Sicherheitsstandards Rule 1/2/3
bp_dsfa_corpus DSFA-Korpus Rule 1/2
bp_legal_templates Rechtsvorlagen Rule 1

Aktuelle Groessenordnung

Metrik Wert
RAG-Chunks gesamt ~105.000 (nach Dedup 2026-03-16)
Verarbeitete Chunks ~105.000
Generierte Controls ~4.738
Konversionsrate ~4,5%

Lizenz-Klassifikation (3-Regel-System)

Jeder Chunk wird basierend auf regulation_code einer Lizenzregel zugeordnet:

Regel Typ Original erlaubt? Beispiele
Rule 1 (free_use) EU-Gesetze, NIST, DE-Gesetze, Public Domain Ja DSGVO, BDSG, NIS2, AI Act
Rule 2 (citation_required) CC-BY, CC-BY-SA Ja, mit Zitation OWASP ASVS, OWASP SAMM
Rule 3 (restricted) Proprietaer Nein, volle Reformulierung BSI TR-03161, ISO 27001

Verarbeitung nach Regel

  • Rule 1+2 → _structure_batch(): Anthropic strukturiert den Originaltext als Control. Ein API-Call fuer den gesamten Batch.
  • Rule 3 → _reformulate_batch(): Anthropic reformuliert vollstaendig — kein Originaltext, keine Quellennamen. Ein API-Call fuer den gesamten Batch.

Batch Processing

Die Pipeline sammelt Chunks in Batches (Default: 5 Chunks) und sendet sie in einem einzigen Anthropic-API-Call.

  1. Relevante Chunks werden mit Lizenz-Info in pending_batch gesammelt
  2. Bei batch_size erreicht → _flush_batch()
  3. Batch wird nach Lizenzregel getrennt: Rule 1+2 → _structure_batch(), Rule 3 → _reformulate_batch()
  4. Ergebnis: JSON-Array mit genau N Elementen (null fuer irrelevante Chunks)

Fallback: Bei Batch-Fehler (Timeout, Parsing-Error) wird automatisch auf Einzelverarbeitung zurueckgefallen.


Chunk-Tracking (Processed Chunks)

Tabelle canonical_processed_chunks

Spalte Typ Beschreibung
chunk_hash VARCHAR(64) SHA-256 Hash des Chunk-Textes
collection VARCHAR(100) Qdrant-Collection
regulation_code VARCHAR(100) Quell-Regulation (z.B. bdsg, eu_2016_679)
license_rule INTEGER 1, 2 oder 3
processing_path VARCHAR(20) Wie der Chunk verarbeitet wurde
generated_control_ids JSONB UUIDs der generierten Controls
pipeline_version SMALLINT Pipeline-Version (1 oder 2)
job_id UUID Referenz auf den Generierungs-Job

UNIQUE Constraint: (chunk_hash, collection, document_version) — verhindert Doppelverarbeitung.

Processing Paths

Wert Stufe Bedeutung
prefilter_skip 2 Lokaler LLM-Vorfilter: Chunk nicht relevant
structured 3a Einzelner Chunk strukturiert (Rule 1/2)
structured_batch 3a Batch-Strukturierung (Rule 1/2)
llm_reform 3b Einzelner Chunk reformuliert (Rule 3)
llm_reform_batch 3b Batch-Reformulierung (Rule 3)
no_control 3 LLM konnte kein Control ableiten (null im Array)
store_failed 6 DB-Speichern fehlgeschlagen
error Unerwarteter Fehler

QA Validation (Automatische Qualitaetspruefung)

Die QA-Stufe validiert die Klassifizierung jedes generierten Controls:

  1. LLM-Category: Anthropic liefert category und domain im JSON-Response
  2. Keyword-Detection: _detect_category(chunk.text) liefert eine zweite Meinung
  3. Stimmen beide ueberein? → Schneller Pfad (kein QA noetig)
  4. Bei Disagreement: Lokales LLM (Ollama) arbitriert
  5. Auto-Fix: Category/Domain werden automatisch korrigiert

Die QA-Metriken werden in generation_metadata gespeichert:

{
  "qa_category_fix": {"from": "authentication", "to": "finance", "reason": "IFRS-Thema"},
  "qa_domain_fix": {"from": "AUTH", "to": "FIN", "reason": "Finanzregulierung"}
}

Recital-Erkennung (Erwägungsgrund-Detektion)

Die QA-Stufe prueft zusaetzlich, ob der source_original_text eines Controls tatsaechlich aus einem Gesetzesartikel stammt — oder aus einem Erwaegungsgrund (Recital). Erwaegungsgruende enthalten keine normativen Pflichten und fuehren zu falsch zugeordneten Controls.

Erkennungsmethoden:

Methode Pattern Beispiel
Regex \((\d{1,3})\)\s*\n — Erwaegungsgrund-Nummern (126)\nUm den Verwaltungsaufwand...
Phrasen Typische Recital-Formulierungen (≥2 Treffer) "daher sollte", "in Erwägung nachstehender Gründe"

Ergebnis bei Verdacht:

  • release_state wird auf needs_review gesetzt
  • generation_metadata.recital_suspect = true
  • generation_metadata.recital_detection enthaelt Details:
{
  "recital_suspect": true,
  "recital_detection": {
    "recital_suspect": true,
    "recital_numbers": ["126", "127"],
    "recital_phrases": ["daher sollte"],
    "detection_method": "regex+phrases"
  }
}

Funktion: _detect_recital(text) in control_generator.py

Hintergrund: Bei der Analyse von ~5.500 Controls mit Quelltext wurden 1.555 (28%) als Erwaegungsgrund-Verdacht identifiziert. Der Document Crawler unterschied nicht zwischen Artikeltext und Erwaegungsgruenden, was zu falschen article/paragraph-Zuordnungen fuehrte.

QA-Reklassifizierung bestehender Controls

# Dry Run: Welche AUTH-Controls sind falsch klassifiziert?
curl -X POST https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate/qa-reclassify \
  -H 'Content-Type: application/json' \
  -H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000' \
  -d '{"limit": 50, "dry_run": true, "filter_domain_prefix": "AUTH"}'

# Korrekturen anwenden:
curl -X POST https://api-dev.breakpilot.ai/api/compliance/v1/canonical/generate/qa-reclassify \
  -H 'Content-Type: application/json' \
  -H 'X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000' \
  -d '{"limit": 50, "dry_run": false, "filter_domain_prefix": "AUTH"}'

Quelldateien

Datei Beschreibung
backend-compliance/compliance/services/control_generator.py 7-Stufen-Pipeline mit Batch Processing
backend-compliance/compliance/api/control_generator_routes.py REST API Endpoints
backend-compliance/compliance/services/license_gate.py Lizenz-Gate-Logik
backend-compliance/compliance/services/similarity_detector.py Too-Close-Detektor (5 Metriken)
backend-compliance/compliance/services/rag_client.py RAG-Client (Qdrant Search + Scroll)
backend-compliance/migrations/046_control_generator.sql Job-Tracking, Chunk-Tracking Tabellen
backend-compliance/migrations/048_processing_path_expand.sql Erweiterte Processing-Path-Werte
backend-compliance/migrations/062_pipeline_version.sql pipeline_version Spalte
backend-compliance/tests/test_control_generator.py 81+ Tests (Lizenz, Domain, Batch, Pipeline, Recital)

Verwandte Dokumentation