- Introduced migration 068 for `ai_skill_retrieval_profiles`, enabling configurable weights and quotes for skill catalog prioritization in exercise AI suggestions. - Updated the `POST /api/exercises/ai/suggest` endpoint to include an optional `focus_areas_context` field, allowing for enhanced context in AI-generated suggestions. - Enhanced the `exercise_ai` module to utilize context-based skill selection, incorporating scoring, category caps, and keyword patches for improved AI responses. - Updated the ExerciseFormPageRoot component to pass focus area context to the AI suggestion API, streamlining user interaction with AI-generated content. - Incremented version numbers in `backend/version.py` to reflect the latest changes and ensure accurate tracking in the changelog.
5.3 KiB
KI Skill-Retrieval-Profile (ai_skill_retrieval_profiles)
Version: 0.1
Datum: 2026-05-29
Status: Umsetzung gestartet (Migration 068)
Ziel: Für POST /api/exercises/ai/suggest (Skill-Katalogauszug) Gewichte und Quoten steuerbar machen:
- gebunden an Übungs-Fokusbereich (
focus_areas.id), - ein Standardprofil ohne Fokus,
- optional zusammengeführte Profile bei mehreren Fokusbereichen,
- optional Keyword-Übersteuerungen aus Ziel/Durchführung (z. B. Rollenspiel vs. Befreiung).
Technische Basis: Skills mit skills.main_category_id → skill_main_categories.slug (karate | allgemeine) und skills.category_id → skill_categories.slug (kondition, selbstverteidigung, …).
Bezüge: .claude/docs/working/AI_EXERCISE_IMPLEMENTATION_PLAN.md · backend/exercise_ai.py
1. Datenmodell
Tabelle ai_skill_retrieval_profiles
| Spalte | Typ | Beschreibung |
|---|---|---|
id |
serial | Primärschlüssel |
focus_area_id |
int NULL FK → focus_areas(id) ON DELETE SET NULL |
NULL nur für Standardeintrag möglich (siehe is_default) |
is_default |
boolean | Genau eine Zeile mit true |
name |
varchar | Kurzer Name (Admin später) |
description |
text | Hinweise für Pflege |
active |
boolean | Nur aktive werden geladen |
config |
jsonb | Siehe §2 |
Constraints / Indizes
- Eindeutig:
(focus_area_id)WHEREfocus_area_id IS NOT NULL - Eindeutig:
(is_default)WHEREis_default = true
2. JSON-Konfiguration config.version = 1
Alle Schlüssel optional; fehlende Werte fallen auf einprogrammierten Fallback in exercise_ai.py zurück (entspricht bisher grob „neutral“).
2.1 Gewichtungen (Ranking)
| Schlüssel | Typ | Bedeutung |
|---|---|---|
main_slug_weights |
object[str, float] |
Multiplikator pro Hauptkategorie-Slug (karate, allgemeine) |
category_slug_weights |
object[str, float] |
Multiplikator pro skill_categories.slug |
Basis-Score (vereinfacht):
(importance oder 3) × main_w × cat_w × text_overlap_bonus × importance_multiplier
2.2 Kapazitätsbegrenzung (Liste)
_MAX_SKILLS_CATALOG_LINES (aktuell 240) Zeilen Gesamt:
| Schlüssel | Typ | Bedeutung |
|---|---|---|
category_max_share |
object[str, float] |
Max. Anteil dieser Unterkategorie am Endergebnis (0–1), z. B. { "kondition": 0.25 } |
main_min_share |
object[str, float] |
Mindest-Zielanteil Hauptkategorie beim Auswahl-Greedy (weich; Rest nach Score aufgefüllt) |
2.3 Text / Token-Sparen
| Schlüssel | Typ | Standard | Bedeutung |
|---|---|---|---|
description_plain_max_len |
int | 160 | Gekürzte Beschreibung pro Zeile |
karate_relevance_max_len |
int | 0 oder 80 | 0 = Feld karate_relevance/relevance_level in der Promptzeile weglassen |
2.4 Keyword-Overrides (optional)
Liste keyword_overrides: jedes Element:
{
"keywords_any": ["befreiung", "haltegriff"],
"case_insensitive": true,
"patch": {
"category_slug_weights": { "selbstverteidigung": 2.5 },
"category_max_share": { "koordination": 0.1 }
}
}
Textsuche in verkettetem Korpus Titel, Ziel, Durchführung, Focus-Hint (bereits plaintext). Reihenfolge: erst Basis-Profile zusammenmergen, dann alle treffenden Overrides‑patch‑Objekte flach zusammenführen (Gewichte multiplikativ übereinander, Caps den strengsten Wert nehmen – aktuelle Implementierung im Code dokumentiert).
3. Mehrere Fokusbereiche auf der Übung
Request-Body: focus_areas_context: [{ "focus_area_id": n, "is_primary": bool }, …]
Aktuelle Merge-Strategie (v1): Profile laden → gleichgewichtete Mittelwert-Bildung der numerischen Gewichte / Caps (implementiert für main_slug_weights, category_slug_weights, category_max_share, main_min_share, *_max_len). Anschließend Keyword-Overrides anwenden.
Primär-Fokus: Im Frontend soll die primäre Zeile aus focus_areas_multi zuerst in der Liste stehen; die Merge-Strategie kann später zu „Primär dominate“ erweitert werden.
Ohne Kontext oder ohne Treffer auf aktive Profile: nur Standardprofil (is_default).
4. Seed-Daten (Migration)
is_default=true: ausgewogene Standard-Gewichte, moderate Caps aufkondition/koordination, Karate-Relevanz gekürzt.Gewaltschutz:focus_area_idper(SELECT id FROM focus_areas WHERE name = 'Gewaltschutz' LIMIT 1)— höhere Gewichte fürkognition,psychische_faehigkeiten,soziale_faehigkeiten,selbstverteidigung; gedrosselteskondition/koordination;karate_relevance_max_len: 0; Keyword-Patches wie oben können nachgeschärft werden.
Weitere Profile (Karate-Schwerpunkt etc.) später per Admin-SQL oder UI.
5. API
ExerciseAiSuggestBody erweitert um focus_areas_context (Liste). Feld focus_area_hint bleibt für den Prompt-Kontext (bestehende Prompts).
POST …/ai/regenerate nutzt später dieselbe Retrieval-Logik aus den Detail-Daten der Übung (To-do: dort focus_areas_context aus exercise_focus_areas ableiten).
6. Changelog
- 2026-05-29: Erstellt; gekoppelt an Migration 068 und erste
exercise_ai-Integration.