Interaktiver 12-Fragen-Entscheidungsbaum für die AI Act Klassifikation auf zwei Achsen: High-Risk (Anhang III, Q1-Q7) und GPAI (Art. 51-56, Q8-Q12). Deterministische Auswertung ohne LLM. Backend (Go): - Neue Structs: GPAIClassification, DecisionTreeAnswer, DecisionTreeResult - Decision Tree Engine mit BuildDecisionTreeDefinition() und EvaluateDecisionTree() - Store-Methoden für CRUD der Ergebnisse - API-Endpoints: GET/POST /decision-tree, GET/DELETE /decision-tree/results - 12 Unit Tests (alle bestanden) Frontend (Next.js): - DecisionTreeWizard: Wizard-UI mit Ja/Nein-Fragen, Dual-Progress-Bar, Ergebnis-Ansicht - AI Act Page refactored: Tabs (Übersicht | Entscheidungsbaum | Ergebnisse) - Proxy-Route für decision-tree Endpoints Migration 083: ai_act_decision_tree_results Tabelle Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
326 lines
12 KiB
Go
326 lines
12 KiB
Go
package ucca
|
||
|
||
// ============================================================================
|
||
// AI Act Decision Tree Engine
|
||
// ============================================================================
|
||
//
|
||
// Two-axis classification:
|
||
// Axis 1 (Q1–Q7): High-Risk classification based on Annex III
|
||
// Axis 2 (Q8–Q12): GPAI classification based on Art. 51–56
|
||
//
|
||
// Deterministic evaluation — no LLM involved.
|
||
//
|
||
// ============================================================================
|
||
|
||
// Question IDs
|
||
const (
|
||
Q1 = "Q1" // Uses AI?
|
||
Q2 = "Q2" // Biometric identification?
|
||
Q3 = "Q3" // Critical infrastructure?
|
||
Q4 = "Q4" // Education / employment / HR?
|
||
Q5 = "Q5" // Essential services (credit, insurance)?
|
||
Q6 = "Q6" // Law enforcement / migration / justice?
|
||
Q7 = "Q7" // Autonomous decisions with legal effect?
|
||
Q8 = "Q8" // Foundation Model / GPAI?
|
||
Q9 = "Q9" // Generates content (text, image, code, audio)?
|
||
Q10 = "Q10" // Trained with >10^25 FLOP?
|
||
Q11 = "Q11" // Model provided as API/service for third parties?
|
||
Q12 = "Q12" // Significant EU market penetration?
|
||
)
|
||
|
||
// BuildDecisionTreeDefinition returns the full decision tree structure for the frontend
|
||
func BuildDecisionTreeDefinition() *DecisionTreeDefinition {
|
||
return &DecisionTreeDefinition{
|
||
ID: "ai_act_two_axis",
|
||
Name: "AI Act Zwei-Achsen-Klassifikation",
|
||
Version: "1.0.0",
|
||
Questions: []DecisionTreeQuestion{
|
||
// === Axis 1: High-Risk (Annex III) ===
|
||
{
|
||
ID: Q1,
|
||
Axis: "high_risk",
|
||
Question: "Setzt Ihr System KI-Technologie ein?",
|
||
Description: "KI im Sinne des AI Act umfasst maschinelles Lernen, logik- und wissensbasierte Ansätze sowie statistische Methoden, die für eine gegebene Reihe von Zielen Ergebnisse wie Inhalte, Vorhersagen, Empfehlungen oder Entscheidungen erzeugen.",
|
||
ArticleRef: "Art. 3 Nr. 1",
|
||
},
|
||
{
|
||
ID: Q2,
|
||
Axis: "high_risk",
|
||
Question: "Wird das System für biometrische Identifikation oder Kategorisierung natürlicher Personen verwendet?",
|
||
Description: "Dazu zählen Gesichtserkennung, Stimmerkennung, Fingerabdruck-Analyse, Gangerkennung oder andere biometrische Merkmale zur Identifikation oder Kategorisierung.",
|
||
ArticleRef: "Anhang III Nr. 1",
|
||
SkipIf: Q1,
|
||
},
|
||
{
|
||
ID: Q3,
|
||
Axis: "high_risk",
|
||
Question: "Wird das System in kritischer Infrastruktur eingesetzt (Energie, Verkehr, Wasser, digitale Infrastruktur)?",
|
||
Description: "Betrifft KI-Systeme als Sicherheitskomponenten in der Verwaltung und dem Betrieb kritischer digitaler Infrastruktur, des Straßenverkehrs oder der Wasser-, Gas-, Heizungs- oder Stromversorgung.",
|
||
ArticleRef: "Anhang III Nr. 2",
|
||
SkipIf: Q1,
|
||
},
|
||
{
|
||
ID: Q4,
|
||
Axis: "high_risk",
|
||
Question: "Betrifft das System Bildung, Beschäftigung oder Personalmanagement?",
|
||
Description: "KI zur Festlegung des Zugangs zu Bildungseinrichtungen, Bewertung von Prüfungsleistungen, Bewerbungsauswahl, Beförderungsentscheidungen oder Überwachung von Arbeitnehmern.",
|
||
ArticleRef: "Anhang III Nr. 3–4",
|
||
SkipIf: Q1,
|
||
},
|
||
{
|
||
ID: Q5,
|
||
Axis: "high_risk",
|
||
Question: "Betrifft das System den Zugang zu wesentlichen Diensten (Kreditvergabe, Versicherung, öffentliche Leistungen)?",
|
||
Description: "KI zur Bonitätsbewertung, Risikobewertung bei Versicherungen, Bewertung der Anspruchsberechtigung für öffentliche Unterstützungsleistungen oder Notdienste.",
|
||
ArticleRef: "Anhang III Nr. 5",
|
||
SkipIf: Q1,
|
||
},
|
||
{
|
||
ID: Q6,
|
||
Axis: "high_risk",
|
||
Question: "Wird das System in Strafverfolgung, Migration, Asyl oder Justiz eingesetzt?",
|
||
Description: "KI für Lügendetektoren, Beweisbewertung, Rückfallprognose, Asylentscheidungen, Grenzkontrolle, Risikobewertung bei Migration oder Unterstützung der Rechtspflege.",
|
||
ArticleRef: "Anhang III Nr. 6–8",
|
||
SkipIf: Q1,
|
||
},
|
||
{
|
||
ID: Q7,
|
||
Axis: "high_risk",
|
||
Question: "Trifft das System autonome Entscheidungen mit rechtlicher Wirkung für natürliche Personen?",
|
||
Description: "Entscheidungen, die Rechtsverhältnisse begründen, ändern oder aufheben, z.B. Kreditablehnungen, Kündigungen, Sozialleistungsentscheidungen — ohne menschliche Überprüfung im Einzelfall.",
|
||
ArticleRef: "Art. 22 DSGVO / Art. 14 AI Act",
|
||
SkipIf: Q1,
|
||
},
|
||
|
||
// === Axis 2: GPAI (Art. 51–56) ===
|
||
{
|
||
ID: Q8,
|
||
Axis: "gpai",
|
||
Question: "Handelt es sich um ein Foundation Model oder General-Purpose AI (GPAI)?",
|
||
Description: "Ein GPAI-Modell ist ein KI-Modell mit erheblicher Allgemeinheit, das kompetent eine breite Palette unterschiedlicher Aufgaben erfüllen kann, z.B. GPT, Claude, LLaMA, Gemini, Stable Diffusion.",
|
||
ArticleRef: "Art. 3 Nr. 63 / Art. 51",
|
||
},
|
||
{
|
||
ID: Q9,
|
||
Axis: "gpai",
|
||
Question: "Kann das System Inhalte generieren (Text, Bild, Code, Audio, Video)?",
|
||
Description: "Generative KI erzeugt neue Inhalte auf Basis von Eingaben — dazu zählen Chatbots, Bild-/Videogeneratoren, Code-Assistenten, Sprachsynthese und ähnliche Systeme.",
|
||
ArticleRef: "Art. 50 / Art. 52",
|
||
SkipIf: Q8,
|
||
},
|
||
{
|
||
ID: Q10,
|
||
Axis: "gpai",
|
||
Question: "Wurde das Modell mit mehr als 10²⁵ FLOP trainiert oder hat es gleichwertige Fähigkeiten?",
|
||
Description: "GPAI-Modelle mit einem kumulativen Rechenaufwand von mehr als 10²⁵ Gleitkommaoperationen gelten als Modelle mit systemischem Risiko (Art. 51 Abs. 2).",
|
||
ArticleRef: "Art. 51 Abs. 2",
|
||
SkipIf: Q8,
|
||
},
|
||
{
|
||
ID: Q11,
|
||
Axis: "gpai",
|
||
Question: "Wird das Modell als API oder Service für Dritte bereitgestellt?",
|
||
Description: "Stellen Sie das Modell anderen Unternehmen oder Entwicklern zur Nutzung bereit (API, SaaS, Plattform-Integration)?",
|
||
ArticleRef: "Art. 53",
|
||
SkipIf: Q8,
|
||
},
|
||
{
|
||
ID: Q12,
|
||
Axis: "gpai",
|
||
Question: "Hat das Modell eine signifikante Marktdurchdringung in der EU (>10.000 registrierte Geschäftsnutzer)?",
|
||
Description: "Modelle mit hoher Marktdurchdringung können auch ohne 10²⁵ FLOP als systemisches Risiko eingestuft werden, wenn die EU-Kommission dies feststellt.",
|
||
ArticleRef: "Art. 51 Abs. 3",
|
||
SkipIf: Q8,
|
||
},
|
||
},
|
||
}
|
||
}
|
||
|
||
// EvaluateDecisionTree evaluates the answers and returns the combined result
|
||
func EvaluateDecisionTree(req *DecisionTreeEvalRequest) *DecisionTreeResult {
|
||
result := &DecisionTreeResult{
|
||
SystemName: req.SystemName,
|
||
SystemDescription: req.SystemDescription,
|
||
Answers: req.Answers,
|
||
}
|
||
|
||
// Evaluate Axis 1: High-Risk
|
||
result.HighRiskResult = evaluateHighRiskAxis(req.Answers)
|
||
|
||
// Evaluate Axis 2: GPAI
|
||
result.GPAIResult = evaluateGPAIAxis(req.Answers)
|
||
|
||
// Combine obligations and articles
|
||
result.CombinedObligations = combineObligations(result.HighRiskResult, result.GPAIResult)
|
||
result.ApplicableArticles = combineArticles(result.HighRiskResult, result.GPAIResult)
|
||
|
||
return result
|
||
}
|
||
|
||
// evaluateHighRiskAxis determines the AI Act risk level from Q1–Q7
|
||
func evaluateHighRiskAxis(answers map[string]DecisionTreeAnswer) AIActRiskLevel {
|
||
// Q1: Uses AI at all?
|
||
if !answerIsYes(answers, Q1) {
|
||
return AIActNotApplicable
|
||
}
|
||
|
||
// Q2–Q6: Annex III high-risk categories
|
||
if answerIsYes(answers, Q2) || answerIsYes(answers, Q3) ||
|
||
answerIsYes(answers, Q4) || answerIsYes(answers, Q5) ||
|
||
answerIsYes(answers, Q6) {
|
||
return AIActHighRisk
|
||
}
|
||
|
||
// Q7: Autonomous decisions with legal effect
|
||
if answerIsYes(answers, Q7) {
|
||
return AIActHighRisk
|
||
}
|
||
|
||
// AI is used but no high-risk category triggered
|
||
return AIActMinimalRisk
|
||
}
|
||
|
||
// evaluateGPAIAxis determines the GPAI classification from Q8–Q12
|
||
func evaluateGPAIAxis(answers map[string]DecisionTreeAnswer) GPAIClassification {
|
||
gpai := GPAIClassification{
|
||
Category: GPAICategoryNone,
|
||
ApplicableArticles: []string{},
|
||
Obligations: []string{},
|
||
}
|
||
|
||
// Q8: Is GPAI?
|
||
if !answerIsYes(answers, Q8) {
|
||
return gpai
|
||
}
|
||
|
||
gpai.IsGPAI = true
|
||
gpai.Category = GPAICategoryStandard
|
||
gpai.ApplicableArticles = append(gpai.ApplicableArticles, "Art. 51", "Art. 53")
|
||
gpai.Obligations = append(gpai.Obligations,
|
||
"Technische Dokumentation erstellen (Art. 53 Abs. 1a)",
|
||
"Informationen für nachgelagerte Anbieter bereitstellen (Art. 53 Abs. 1b)",
|
||
"Urheberrechtsrichtlinie einhalten (Art. 53 Abs. 1c)",
|
||
"Trainingsdaten-Zusammenfassung veröffentlichen (Art. 53 Abs. 1d)",
|
||
)
|
||
|
||
// Q9: Generative AI — adds transparency obligations
|
||
if answerIsYes(answers, Q9) {
|
||
gpai.ApplicableArticles = append(gpai.ApplicableArticles, "Art. 50")
|
||
gpai.Obligations = append(gpai.Obligations,
|
||
"KI-generierte Inhalte kennzeichnen (Art. 50 Abs. 2)",
|
||
"Maschinenlesbare Kennzeichnung synthetischer Inhalte (Art. 50 Abs. 2)",
|
||
)
|
||
}
|
||
|
||
// Q10: Systemic risk threshold (>10^25 FLOP)
|
||
if answerIsYes(answers, Q10) {
|
||
gpai.IsSystemicRisk = true
|
||
gpai.Category = GPAICategorySystemic
|
||
gpai.ApplicableArticles = append(gpai.ApplicableArticles, "Art. 55")
|
||
gpai.Obligations = append(gpai.Obligations,
|
||
"Modellbewertung nach Stand der Technik durchführen (Art. 55 Abs. 1a)",
|
||
"Systemische Risiken bewerten und mindern (Art. 55 Abs. 1b)",
|
||
"Schwerwiegende Vorfälle melden (Art. 55 Abs. 1c)",
|
||
"Angemessenes Cybersicherheitsniveau gewährleisten (Art. 55 Abs. 1d)",
|
||
)
|
||
}
|
||
|
||
// Q11: API/Service provider — additional downstream obligations
|
||
if answerIsYes(answers, Q11) {
|
||
gpai.Obligations = append(gpai.Obligations,
|
||
"Downstream-Informationspflichten erfüllen (Art. 53 Abs. 1b)",
|
||
)
|
||
}
|
||
|
||
// Q12: Significant market penetration — potential systemic risk
|
||
if answerIsYes(answers, Q12) && !gpai.IsSystemicRisk {
|
||
// EU Commission can designate as systemic risk
|
||
gpai.ApplicableArticles = append(gpai.ApplicableArticles, "Art. 51 Abs. 3")
|
||
gpai.Obligations = append(gpai.Obligations,
|
||
"Achtung: EU-Kommission kann GPAI mit hoher Marktdurchdringung als systemisches Risiko einstufen (Art. 51 Abs. 3)",
|
||
)
|
||
}
|
||
|
||
return gpai
|
||
}
|
||
|
||
// combineObligations merges obligations from both axes
|
||
func combineObligations(highRisk AIActRiskLevel, gpai GPAIClassification) []string {
|
||
var obligations []string
|
||
|
||
// High-Risk obligations
|
||
switch highRisk {
|
||
case AIActHighRisk:
|
||
obligations = append(obligations,
|
||
"Risikomanagementsystem einrichten (Art. 9)",
|
||
"Daten-Governance sicherstellen (Art. 10)",
|
||
"Technische Dokumentation erstellen (Art. 11)",
|
||
"Protokollierungsfunktion implementieren (Art. 12)",
|
||
"Transparenz und Nutzerinformation (Art. 13)",
|
||
"Menschliche Aufsicht ermöglichen (Art. 14)",
|
||
"Genauigkeit, Robustheit und Cybersicherheit (Art. 15)",
|
||
"EU-Datenbank-Registrierung (Art. 49)",
|
||
)
|
||
case AIActMinimalRisk:
|
||
obligations = append(obligations,
|
||
"Freiwillige Verhaltenskodizes empfohlen (Art. 95)",
|
||
)
|
||
case AIActNotApplicable:
|
||
// No obligations
|
||
}
|
||
|
||
// GPAI obligations
|
||
obligations = append(obligations, gpai.Obligations...)
|
||
|
||
// Universal obligation for all AI users
|
||
if highRisk != AIActNotApplicable {
|
||
obligations = append(obligations,
|
||
"KI-Kompetenz sicherstellen (Art. 4)",
|
||
"Verbotene Praktiken vermeiden (Art. 5)",
|
||
)
|
||
}
|
||
|
||
return obligations
|
||
}
|
||
|
||
// combineArticles merges applicable articles from both axes
|
||
func combineArticles(highRisk AIActRiskLevel, gpai GPAIClassification) []string {
|
||
articles := map[string]bool{}
|
||
|
||
// Universal
|
||
if highRisk != AIActNotApplicable {
|
||
articles["Art. 4"] = true
|
||
articles["Art. 5"] = true
|
||
}
|
||
|
||
// High-Risk
|
||
switch highRisk {
|
||
case AIActHighRisk:
|
||
for _, a := range []string{"Art. 9", "Art. 10", "Art. 11", "Art. 12", "Art. 13", "Art. 14", "Art. 15", "Art. 26", "Art. 49"} {
|
||
articles[a] = true
|
||
}
|
||
case AIActMinimalRisk:
|
||
articles["Art. 95"] = true
|
||
}
|
||
|
||
// GPAI
|
||
for _, a := range gpai.ApplicableArticles {
|
||
articles[a] = true
|
||
}
|
||
|
||
var result []string
|
||
for a := range articles {
|
||
result = append(result, a)
|
||
}
|
||
return result
|
||
}
|
||
|
||
// answerIsYes checks if a question was answered with "yes" (true)
|
||
func answerIsYes(answers map[string]DecisionTreeAnswer, questionID string) bool {
|
||
a, ok := answers[questionID]
|
||
if !ok {
|
||
return false
|
||
}
|
||
return a.Value
|
||
}
|