2026-05-22 21:52:18 +02:00
# Planungs-KI: Übungssuche & Kontext für Neu-Anlage
2026-05-23 10:42:17 +02:00
**Version:** 0.2
**Datum:** 2026-05-23
2026-05-23 12:02:57 +02:00
**Status:** P0– P2 ✅ · Phase A/B/B2 ✅ · **Phase C1– C3 ✅** · **Phase E ✅** (Semantik + Pfad-QA)
2026-05-22 21:52:18 +02:00
**Bezüge:** `AI_PLANNING_KI_MULTISTAGE_FORECAST.md` · `AI_PROMPT_TARGET_ARCHITECTURE.md` · `SKILL_SCORING_SPEC.md` · `TRAINING_FRAMEWORK_SPEC.md` §3 (Progressionsgraph)
---
## 1. Ziel
Trainer in der **Trainingsplanung** sollen Übungen finden oder anlegen können mit natürlichen Anfragen wie:
- „Vertiefung zu Übung XY“
- „Nächste sinnvolle Übung im Progressionsgraph Z“
- „Baut auf der bisherigen Planung auf — Reaktionsschnelligkeit mit Partnern“
- **Preset:** „Schlage mir die nächste Übung vor“
**Suche** (Bibliothek) und **Neu mit KI-Assistent** (Anlage) nutzen dasselbe ** `PlanningExerciseContextPack` ** — unterschiedliches Ergebnis (Treffer vs. Entwurf).
---
## 2. Architektur (Mehrstufig)
| Stufe | Name | Technik | P0 |
|-------|------|---------|-----|
| **S0** | Kontext-Pack | SQL/API, deterministisch | ✅ |
2026-05-22 22:15:19 +02:00
| **S1a** | Intent strukturieren | LLM `planning_exercise_search_intent` (Szenario-Pipeline) | ✅ P1 |
2026-05-22 22:04:34 +02:00
| **S1b** | Hybrid-Retrieval | Score: Volltext + Graph + Skills + Plan + **Profil** | ✅ |
| **S1b+** | Profil-Vorselektion | `ExerciseMatchProfile` × `PlanningTargetProfile` | ✅ `profile_v1` |
2026-05-22 21:52:18 +02:00
| **S1c** | Rerank + Begründung | Optional LLM `planning_exercise_search_rank` | Regelbasierte `reasons[]` |
| **S2** | Neu-Anlage | Bestehende `suggestExerciseAi` + Pack als Zusatzkontext | Später |
Zwischen jeder Stufe: **nur erlaubte `exercise_id`s** (Governance / Sichtbarkeit).
---
## 3. Intent-Typen
| `intent_hint` | Bedeutung | Retrieval-Gewichtung (P0) |
|---------------|-----------|---------------------------|
| `suggest_next` | Nächste Übung (Default bei leerer/kurzer Query) | Progression + Skill-Overlap + Plan-Kontinuität |
| `progression_next` | Explizit Graph-Folge | Progression hoch |
| `deepen_exercise` | Vertiefung zu Anker-Übung | Skill-Overlap hoch, ähnlicher Fokus |
| `continue_plan_goal` | Auf bisherigen Plan aufbauen | Plan-Kontinuität, Wiederholungsstrafe |
| `free_search` | Freitext / Stichwort | Volltext hoch |
**S1a (später):** Freitext → JSON `{ intent, skill_hints[], requires_partner, level_hint, … }` validiert per Pydantic.
**P0:** `intent_hint` vom Client oder Keyword-Heuristik auf `query` .
---
## 4. PlanningExerciseContextPack (S0)
Serverseitig aus Request + DB (tokenbewusst für spätere LLM-Stufen):
| Feld | Quelle | UI-Chip |
|------|--------|---------|
| `unit_id` , Titel, `group_id` , Gruppenname | `training_units` + `training_groups` | Gruppe · Einheit |
| `section_order_index` , Abschnittstitel | `training_unit_sections` | Abschnitt |
| `planned_exercise_ids[]` | Items der Einheit (Reihenfolge) | „N Übungen im Plan“ |
| `anchor_exercise_id` , Titel | Request oder letzte Übung vor Einfügepunkt | Anker |
| `anchor_skill_ids[]` | `exercise_skills` | (intern) |
2026-05-23 10:42:17 +02:00
| `progression_graph_id` | Request oder **Auto-Match** vom Anker (sichtbarer Graph mit passenden Ausgangskanten) | Graph |
| `progression_graph_name` , `progression_graph_auto_resolved` | Response `context_summary` | Graph (auto) |
| `anchor_exercise_variant_id` | Request / Abschnitt-Item / DB | (intern) |
| `progression_successor_ids[]` | `exercise_progression_edges` ab Anker (variantenbewusst, Migration **034** ) | (intern) |
| `progression_successor_variants` | `to_exercise_variant_id` pro Nachfolger | (intern) |
2026-05-22 21:52:18 +02:00
| `group_recent_exercise_ids[]` | Letzte Einheiten derselben Gruppe | Wiederholungsstrafe |
| `framework_slot_notes` | Rahmen-Slot falls `framework_slot_id` | (später) |
**Berechtigung:** `get_tenant_context` + `_assert_training_unit_permission` wie `GET /training-units/{id}` .
---
## 5. Hybrid-Retrieval (S1b, P0)
Kandidaten: sichtbare Übungen (`library_content_visibility_sql`), ohne `archived` , max. ~400 (recent).
**Score** (0– 1, gewichtet nach Intent):
```
score = w_ft * fulltext_rank
+ w_prog * progression_hit
+ w_skill * skill_jaccard(anchor, candidate)
+ w_plan * plan_affinity
2026-05-22 22:04:34 +02:00
+ w_profile * profile_match(exercise, target)
2026-05-22 21:52:18 +02:00
+ w_repeat * (candidate in unit_plan ? -1 : 0)
+ w_group_repeat * (candidate in group_recent ? -0.5 : 0)
```
2026-05-22 22:04:34 +02:00
**`profile_match`** (0– 1): siehe §12– §13 — Katalog-Dimensionen + Skill-Gewichte + Skill-Gap.
**`reasons[]`** (regelbasiert, Deutsch): z. B. „Nachfolger im Progressionsgraph“, „Fähigkeiten passen zur Anker-Übung“, „Fokusbereich passend zum Planungsziel“, „Deckt Skill-Lücke im bisherigen Plan“, „Volltext-Treffer“.
2026-05-22 21:52:18 +02:00
---
## 6. API
### `POST /api/planning/exercise-suggest`
**Body:**
```json
{
"unit_id": 123,
"section_order_index": 0,
"phase_order_index": null,
"parallel_stream_order_index": null,
"anchor_exercise_id": 456,
2026-05-23 10:42:17 +02:00
"anchor_exercise_variant_id": 12,
2026-05-22 21:52:18 +02:00
"progression_graph_id": 7,
"query": "Schlage mir die nächste Übung vor",
"intent_hint": "suggest_next",
"limit": 20,
"exercise_kind_any": ["simple"]
}
```
**Response:**
```json
{
"context_summary": {
"unit_title": "…",
"group_name": "…",
"section_title": "Hauptteil",
"planned_count": 4,
"anchor_title": "Partner-Fangspiel"
},
2026-05-22 22:04:34 +02:00
"target_profile_summary": {
"sources": ["framework_catalog", "current_unit_plan", "anchor_exercise"],
"focus_areas": ["Reaktion & Abwehr"],
"top_skills": [{ "skill_id": 12, "name": "Reaktionsgeschwindigkeit", "weight": 1.0 }],
"has_skill_gap": true
},
"retrieval_phase": "profile_v1",
2026-05-22 21:52:18 +02:00
"intent_resolved": "suggest_next",
"hits": [
{
"id": 99,
"title": "…",
"summary": "…",
"score": 0.78,
2026-05-22 22:04:34 +02:00
"reasons": ["Nachfolger im Progressionsgraph", "Fokusbereich passend zum Planungsziel"],
2026-05-22 21:52:18 +02:00
"focus_area": "…"
}
]
}
```
2026-05-22 22:04:34 +02:00
**Modul:** `backend/planning_exercise_suggest.py` · `backend/planning_exercise_profiles.py` · Router `backend/routers/planning_exercise_suggest.py`
2026-05-22 21:52:18 +02:00
---
## 7. Frontend
| Ort | Verhalten |
|-----|-----------|
| `ExercisePickerModal` | Prop `planningContext` → Planungs-API statt reiner `listExercises` ; Kontext-Chips; `reasons` unter Treffer |
| `TrainingUnitEditPage` | `planningContext` aus Einheit + Picker-Ziel (Anker = letzte Übung im Abschnitt) |
2026-05-23 10:42:17 +02:00
| ** `ExercisesListPageRoot` ** | Schalter ** „Neu mit KI-Assistent“**: Planungs-KI-Suche (frei, ohne `unit_id` ) + Neuanlage im Modal; ** „+ Neu“** ausgeblendet |
2026-05-22 21:52:18 +02:00
| Rahmen / Kombi-Formular | analog, sobald `unit_id` / Slot-Blueprint bekannt |
2026-05-23 10:42:17 +02:00
| Übungsliste (ohne KI-Schalter) | weiter Volltext |
2026-05-22 21:52:18 +02:00
**Zweites Suchfeld** im Picker: Query = Volltext + ergänzender Begriff (ODER in P0 als Konkatenation an Backend).
---
## 8. Neu-Anlage (Anbindung, Phase P1)
Wenn `hits` leer oder Trainer wählt „Mit KI anlegen“:
2026-06-08 15:15:03 +02:00
- `planning_context` im Request-Body → `planning_context_json` in Übungs-Prompts (Migration **085** ); Pfad-Builder + Picker ✅ **0.8.208**
2026-05-22 21:52:18 +02:00
- Kurzbeschreibung optional leer (freier Vorschlag) oder aus Intent/Skizze
---
## 9. Phasen-Roadmap
2026-05-23 10:42:17 +02:00
| Phase | Inhalt | Status |
|-------|--------|--------|
| **P0** | Context-Pack, Hybrid-Score, API, Picker in Planung | ✅ |
| **P0.1** | `ExerciseMatchProfile` / `PlanningTargetProfile` , `profile_v1` | ✅ |
| **P1** | Szenario-Pipeline + LLM Query-Intent → Erwartungsprofil | ✅ |
| **P2 / B2** | LLM-Rerank bei engem Top-Feld (max. 2 Calls) | ✅ |
| **P3** | Skill-Discovery / Framework-Ziele im Pack | 🔲 |
| **A** | Voll-Library Hybrid-Ranking | ✅ **0.8.177** |
| **B** | Text-Signale guidance/Rahmen-Ziele | ✅ **0.8.181** |
| **C1** | Graph auto-match + variantenbewusste Nachfolger | ✅ **0.8.183** |
2026-05-23 11:39:18 +02:00
| **C2** | Varianten in Trefferliste / Picker | ✅ **0.8.184** |
2026-05-23 11:46:25 +02:00
| **C3** | Graph-Builder (Ziel → Pfad → speichern) | ✅ **0.8.185** |
2026-05-23 12:02:57 +02:00
| **E** | Semantik-Schicht + Pfad-QA (Lücken/Brücken/LLM-QS) | ✅ **0.8.186** |
2026-05-23 12:32:14 +02:00
| **E2** | Pfad-Neuordnung + KI-Lückenfüller | ✅ **0.8.187** |
2026-06-08 15:15:03 +02:00
| **D** | Neu-Anlage: `planning_context` an `suggestExerciseAi` (Migration **085** ) | ✅ **0.8.208** |
2026-05-22 21:52:18 +02:00
---
## 10. Changelog
2026-05-23 10:42:17 +02:00
- **2026-05-23:** Phase C1 — Graph auto-match, variantenbewusste Nachfolger (`planning_exercise_progression.py`).
- **2026-05-23:** Phase B2 — Rerank bei engem Top-Feld; Phase B — Text-Signale; Phase A — Voll-Library (siehe §17– §19).
2026-05-22 21:52:18 +02:00
- **2026-05-22:** Erstfassung; P0 API + Planungs-Picker.
- **2026-05-22:** P0 implementiert (`planning_exercise_suggest.py`, Router, Picker); unsaved Formular-Plan noch nicht an API (nur persistierte Einheit).
2026-05-22 22:04:34 +02:00
- **2026-05-22:** P0.1 — `planning_exercise_profiles.py` , Profil-Score in Hybrid-Retrieval, `retrieval_phase: profile_v1` , `target_profile_summary` .
2026-05-22 22:09:28 +02:00
- **2026-05-22:** P2 — LLM-Rerank optional (`include_llm_rank`); Client `planned_exercise_ids[]` ; Prompt Migration 072.
2026-05-22 21:52:18 +02:00
---
2026-05-23 10:42:17 +02:00
## 11. Bekannte Lücken & Backlog
2026-05-22 21:52:18 +02:00
2026-05-22 22:09:28 +02:00
- **Ungespeicherte Plan-Änderungen:** ✅ Client übergibt `planned_exercise_ids[]` aus Formular (TrainingUnitEditPage).
2026-05-23 10:42:17 +02:00
- **Progressionsgraph-ID:** ✅ Auto-Match vom Anker (**C1**); manuelle Auswahl in UI noch offen.
2026-05-23 11:39:18 +02:00
- **Anker-Variante:** ✅ Client + DB (**C1**); Picker wählt Variante bei Treffer (**C2** — Dropdown + Graph-Vorschlag).
2026-05-23 11:46:25 +02:00
- **Graph-Builder (C3):** Ziel → Pfad vorschlagen → in Graph speichern — ✅ **0.8.185**
2026-05-23 10:42:17 +02:00
- **Varianten-Suche:** Library-Picker nutzt `include_variants` ; Planungs-KI rankt primär **Übungsebene** — Varianten-Expansion nur gezielt (**C2**).
- **Enrichment:** Superadmin-Tool für Skills; Datenqualität der Bibliothek entscheidend für Profil-Score.
2026-05-22 22:15:19 +02:00
- **LLM-Intent:** ✅ P1 Szenario-Pipeline + `planning_exercise_search_intent` (Migration 073).
2026-05-23 10:42:17 +02:00
- **Preset + LLM:** ✅ Erwartungs-LLM (074) bei Planungsbezug; Preset ohne Plan = kein Erwartungs-LLM.
2026-05-22 22:15:19 +02:00
---
## 16. Szenario-Pipeline & Query-Erwartungsprofil (P1)
Komplexe Planungsanfragen brauchen **Schritte vor** dem Profil-Match — nicht jede Query ist gleich.
### 16.1 Szenario-Klassen
| `scenario_kind` | Typische Anfrage | LLM Intent? |
|-----------------|------------------|-------------|
2026-05-23 10:42:17 +02:00
| `preset_next` | „Nächste Übung vorschlagen“ (Preset) | Erwartungs-LLM (074) wenn Planungsbezug |
2026-05-22 22:15:19 +02:00
| `progression` | Progressionsgraph / Pfad | Ja (wenn Freitext) |
| `deepen` | Vertiefung Anker | Ja |
| `continue_plan` | Auf bisherigen Plan aufbauen | Ja |
| `additive_constraint` | Plan ** +** Zusatz (z. B. Schnellkraft) | Ja |
| `free_search` | Offene Stichwortsuche | Ja |
**Routing:** `planning_exercise_target_pipeline.classify_planning_scenario()` → `should_run_llm_intent_pipeline()` .
### 16.2 Pipeline (Reihenfolge)
```
S0 Kontext-Pack
→ Heuristik-Intent + Szenario
→ [optional] LLM planning_exercise_search_intent
→ Basis PlanningTargetProfile (Rahmen, Plan, Anker, Gap)
→ Merge Query-Overlay (Katalog-IDs aus Hints)
→ Hybrid-Retrieval + Profil-Score
→ [optional] LLM-Rerank
```
Module: `planning_exercise_target_pipeline.py` · `planning_exercise_intent.py`
### 16.3 API (Erweiterung)
| Request | Default | Bedeutung |
|---------|---------|-----------|
| `include_llm_intent` | `true` | LLM nur wenn Szenario ≠ preset_next und Query nicht leer |
| Response | Bedeutung |
|----------|-----------|
| `scenario_kind` | Szenario-Klasse |
| `query_intent_summary` | intent, llm_applied, rationale, skill_hints_resolved |
| `intent_heuristic` | Heuristik vor LLM |
| `retrieval_phase` | z. B. `profile_v1+query_intent+llm_rank` |
**Prompt 073:** `planning_exercise_search_intent` — Ausgabe JSON mit `skill_hints` , `focus_hints` , `emphasis` (`additive`|`replace`).
2026-05-22 22:09:28 +02:00
---
## 15. LLM-Rerank (P2)
**Request:**
| Feld | Typ | Default | Bedeutung |
|------|-----|---------|-----------|
| `planned_exercise_ids` | `int[]` | — | Optional: Reihenfolge aus Formular (überschreibt DB-Plan) |
2026-05-23 10:42:17 +02:00
| `include_llm_rank` | `bool` | `true` (Client) | Backend gated (B2): Rerank nur bei engem Top-Feld, max. 2 LLM-Calls |
2026-05-22 22:09:28 +02:00
**Response:**
| Feld | Wert |
|------|------|
| `retrieval_phase` | `profile_v1` oder `profile_v1+llm_rank` |
| `llm_rank_applied` | `true` wenn LLM erfolgreich sortiert hat |
| `hits[].llm_rank` | optional: Position nach LLM (1…n) |
**Fallback:** Kein API-Key, inaktiver Prompt oder Parse-Fehler → Hybrid-Reihenfolge unverändert, `llm_rank_applied: false` .
**Prompt:** Migration **072** , Slug `planning_exercise_search_rank` — Kandidaten als JSON mit Titel, summary, goal (Plaintext), skills; Ausgabe `{ ranked_ids, reasons }` .
2026-05-22 22:04:34 +02:00
---
## 12. ExerciseMatchProfile & PlanningTargetProfile (Phase 1)
Ziel: deterministische Vorselektion über **Profil-Dimensionen** statt nur Titel/Jaccard.
### 12.1 ExerciseMatchProfile (pro Übung)
| Feld | Quelle |
|------|--------|
| `focus_area_ids` | `exercise_focus_areas` (Primary = 1.0, sonst 0.85) |
| `style_direction_ids` | `exercise_style_directions` |
| `training_type_ids` | `exercise_training_types` |
| `target_group_ids` | `exercise_target_groups` |
| `skill_weights` | `exercise_skills` × Intensitäts-Multiplikator (`skill_scoring._skill_link_multiplier`) |
Bulk-Lader: `load_exercise_match_profiles_bulk(cur, exercise_ids)` .
### 12.2 PlanningTargetProfile (Planungsziel)
Zusammensetzung aus mehreren Quellen (`sources[]`):
| Quelle | Inhalt |
|--------|--------|
| `framework_catalog` | Fokus/Stil/Trainingsstil/Zielgruppe aus `training_framework_program_*` |
| `framework_slot_skill_profile` | Skill-Profil des Slot-Blueprints (`profile_for_occurrences`) |
| `framework_overall_skill_profile` | Fallback: alle Blueprint-Einheiten des Rahmens |
| `current_unit_plan` | Skill-Profil der bereits eingeplanten Übungen dieser Einheit |
| `anchor_exercise` | Katalog + Skills der Anker-Übung (Intent-abhängig) |
| `skill_gap_vs_plan` | `target_skills − plan_skills` (normalisiert, Schwelle > 0.08) |
Builder: `build_planning_target_profile(cur, unit=…, planned_exercise_ids=…, anchor_exercise_id=…, intent=…)` .
Rahmen-Anbindung über `unit.framework_slot_id` oder `origin_framework_slot_id` .
---
## 13. Profil-Score (Formeln)
**Gewichtete Überlappung** (Katalog + Skills):
```
overlap(a, b) = Σ min(a[k], b[k]) / Σ max(a[k], b[k])
```
**Skill-Gap-Abdeckung:**
```
gap_coverage(gap, candidate) = Σ min(gap[k], candidate[k]) / Σ gap[k]
```
**Profil-Score** (intent-gewichtet, Summe Dimensionen = 1.0):
```
profile_score = w_focus * overlap(focus)
+ w_style * overlap(style)
+ w_tt * overlap(training_type)
+ w_tg * overlap(target_group)
+ w_skill * overlap(skill_weights)
+ w_gap * gap_coverage(skill_gap)
```
Intent-Gewichte (Auszug): `deepen_exercise` → Skill hoch; `continue_plan_goal` → Gap hoch; `free_search` → Gap + Skill moderat.
Scorer: `score_exercise_against_target(exercise_profile, target_profile, intent=…) → (score, reasons[])` .
---
## 14. Hybrid + Profil (P0.1)
Im Hybrid-Score kommt ** `w_profile * profile_score` ** hinzu (Intent-abhängig ~0.15– 0.35). Jaccard auf Anker-Skills bleibt parallel (schneller Anker-Fokus).
**Response-Felder:**
| Feld | Bedeutung |
|------|-----------|
| `retrieval_phase` | `"profile_v1"` — Phase-1 aktiv, kein LLM-Rerank |
| `target_profile_summary` | Lesbare Kurzinfo für UI-Chips (Fokus, Top-Skills, Quellen) |
2026-05-23 10:42:17 +02:00
**Phase 2 (P2 / B2):** siehe §15 und §18 — `include_llm_rank: true` vom Client, Backend entscheidet.
---
## 17. Phase A — Voll-Library-Ranking (0.8.177)
- Kein OR-Profil-Pool (~500 Übungen) mehr.
- Alle sichtbaren Übungen (bis 8000) werden hybrid gescored (`fetch_all_visible_exercise_rows` + `rank_visible_library_hits` ).
- API: `full_library_ranked: true` , `retrieval_phase` enthält `+full_library+` .
---
## 18. Phase B / B2 — Text-Signale & Rerank-Gates (0.8.181– 0.8.182)
**B — Text-Signale (`planning_exercise_text_signals.py`):**
- `section_guidance_notes` , Rahmen-Ziele/Notizen → Skill-/Katalog-Gewichte ohne LLM.
- `requires_partner` aus Intent filtert Kandidaten.
- `retrieval_phase +text_signals` .
**B2 — Rerank bei unklarem Ranking:**
- `hybrid_ranking_ambiguous(hits)` (Top-4-/Top-10-Gap).
- Rerank auch nach Erwartungs-/Intent-LLM, wenn Scores eng beieinander.
- Budget: max. **2** LLM-Calls (Profil + optional Rerank).
---
## 19. Phase C1 — Progressionsgraph im Planungskontext (0.8.183)
**Modul:** `planning_exercise_progression.py`
### Auto-Match Graph
Wenn `progression_graph_id` fehlt und Anker-Übung gesetzt: sichtbarer Graph mit passender `next_exercise` -Kante vom Anker (variantenbewusst). Bevorzugung: variantenspezifische Kanten > Anzahl Kanten.
### Variantenbewusste Nachfolger (Migration 034)
Generische Kante (`from_exercise_variant_id IS NULL`) gilt für jeden Anker; variantenspezifische Kante nur bei passender Anker-Variante.
Treffer: optional `hits[].suggested_variant_id` .
### Request / Response
| Feld | Bedeutung |
|------|-----------|
| `anchor_exercise_variant_id` | Request — Variante der Anker-Übung |
| `progression_graph_name` | Response — Name des (auto-)Graphs |
| `progression_graph_auto_resolved` | Response — Auto-Match aktiv |
---
2026-05-23 11:39:18 +02:00
## 20. Phase C2 — Varianten in Treffern (0.8.184) ✅
2026-05-23 10:42:17 +02:00
2026-05-23 11:39:18 +02:00
- API: `variants[]` , `suggested_variant_name` pro Treffer (Batch aus `exercise_variants` ).
- **`ExercisePickerModal`:** Dropdown pro Treffer; Graph-`suggested_variant_id` vorausgewählt; Übernahme setzt `exercise_variant_id` .
- **`hydrateExercisePlanningRow`:** übernimmt `exercise_variant_id` / `suggested_variant_id` in die Planungszeile.
2026-05-23 10:42:17 +02:00
2026-05-23 11:39:18 +02:00
---
2026-05-23 11:46:25 +02:00
## 21. Phase C3 — Graph-Builder (0.8.185) ✅
2026-05-23 11:39:18 +02:00
2026-05-23 11:46:25 +02:00
**API:** `POST /api/planning/progression-path-suggest`
| Feld | Bedeutung |
|------|-----------|
| `query` | Ziel / Entwicklungsrichtung (Freitext, min. 3 Zeichen) |
| `max_steps` | 2– 10, Default 5 |
| `progression_graph_id` | optional — Graph-Kontext für Nachfolger ab Schritt 2 |
| `include_llm_intent` | LLM nur Schritt 1 (Budget) |
**Response:** `steps[]` mit `exercise_id` , `variant_id` , `title` , `reasons` , `variants` ; `retrieval_phase: …+path_builder` .
**Algorithmus:** Iterativ Hybrid-Ranking — Schritt 1 aus Zielprofil, Folgeschritte mit Anker = letzte Übung, ohne Duplikate.
**UI:** `ExerciseProgressionPathBuilder` im Progressionsgraph-Panel — Review, Varianten, `POST …/edges/sequence` .
---
2026-05-23 12:02:57 +02:00
## 22. Phase E — Semantik-Schicht + Pfad-QA (0.8.186) ✅
### Semantic Brief (`planning_exercise_semantics.py`)
Parallel zum Katalog-Overlay — **nicht ersetzend** :
| Feld | Bedeutung |
|------|-----------|
| `primary_topic` | z. B. `mae geri` |
| `must_phrases` / `exclude_phrases` | Phrasen-Match in Titel/Ziel/Varianten |
| `development_arc` | einstieg → … → perfektion |
| `semantic_strength` | 0– 1 — steuert dynamisches Blend im Hybrid-Score |
| `retrieval_query` | fokussierte Volltext-Query (nicht ganzer Satz) |
Optional LLM: Prompt `planning_exercise_query_semantics` (Migration **075** ).
**Hybrid-Score:** neuer Term `w_semantic * semantic_score` — Profil/Volltext werden bei hoher `semantic_strength` relativ abgeschwächt.
### Pfad-QA (`planning_exercise_path_qa.py`)
Nach Pfad-Bildung:
1. **Lücken-Messung** zwischen benachbarten Schritten (Skill-Jaccard + Semantik zum erwarteten Phasen-Segment)
2. **Brücken-Übungen** bei großen Lücken (zusätzliche Schritte, markiert `is_bridge` )
3. **LLM-QS** (Prompt `planning_exercise_path_qa` ): Reihenfolge, Themen-Abdeckung, Empfehlungen
**API-Erweiterung** `progression-path-suggest` : `include_path_qa` , `include_llm_path_qa` · Response: `semantic_brief_summary` , `path_qa` .
**Pfad-Schritte:** Semantic Brief + Entwicklungsphase in **allen** Schritten (nicht nur Schritt 1).
2026-05-23 12:32:14 +02:00
### Phase E2 (0.8.187)
- **LLM-QS → Neuordnung:** `ordered_step_indices` im Prompt `planning_exercise_path_qa` (Migration **076** )
- **KI-Lückenfüller:** `planning_exercise_path_ai_fill.py` — `is_ai_proposal` wenn Bibliothek keine Brücke liefert
- Request: `include_path_reorder` , `include_ai_gap_fill`
2026-05-23 12:02:57 +02:00
---
2026-06-08 08:10:53 +02:00
## 23. Phase E3 (0.8.203) ✅
- Off-Topic aus Pfad entfernen; `gap_fill_offers` mit `goal_for_ai` ; voller KI-Call im UI (kein Pre-Vorschlag)
- Migration **077** `suggested_new_exercises` im Pfad-QS-Prompt
---
2026-06-10 07:50:29 +02:00
## 24. Phase F — Roadmap-first Progressionsgraph (0.8.204– 217) ✅
2026-06-08 08:10:53 +02:00
**Entscheidung:** Progressionsgraph plant **vom Ziel rückwärts** (Roadmap → Stufenspezifikation → Bibliothek/KI). **Keine Gruppenanalyse** — die gehört zur Trainingsplanung.
2026-06-10 07:50:29 +02:00
**Ist-Stand (vollständig):** `docs/architecture/PLANNING_PROGRESSION_GRAPH_KI.md`
2026-06-08 08:10:53 +02:00
**Spec:** `working/PLANNING_PROGRESSION_ROADMAP_SPEC.md` · **Roadmap:** `docs/architecture/PLANNING_KI_ROADMAP.md`
| Teil | Modul / API |
|------|-------------|
| Pipeline | `planning_progression_roadmap.py` (Workflow-lite) |
2026-06-10 07:50:29 +02:00
| Match | `planning_exercise_path_builder.py` — `roadmap_first` , `roadmap_override` |
| Skills | `planning_skill_expectations.py` — pro Stufe + Pfad |
| Gap-KI | `planning_exercise_form_context.py` , `planning_exercise_path_ai_fill.py` |
| Persistenz | `planning_roadmap` JSONB (Migration **088** ) |
| API | `progression-path-suggest` , `PUT` Graph, `POST …/edges/sequence` |
| Prompts | **078/079/087** — Slugs nur in `ai_prompts` |
| UI | `ExerciseProgressionPathBuilder` , `ExerciseGapFillPrepModal` |
2026-06-08 08:10:53 +02:00
2026-06-10 07:50:29 +02:00
**Graph-Bias:** `progression_graph_id` bevorzugt **bestehende Nachfolger** ab Schritt 2 (Gewicht ~4– 10 %), baut aber **keinen** Pfad aus vorhandenen Knoten — siehe Ist-Doku §5.
2026-06-08 08:10:53 +02:00
**Mitai Workflow-Engine:** bewusst **nicht** jetzt — Pipeline workflow-ready für spätere Anbindung.
---
## 25. Backlog (offen)
2026-06-10 07:50:29 +02:00
Siehe priorisierte Liste in ** `docs/architecture/PLANNING_PROGRESSION_GRAPH_KI.md` ** §10:
1. UI-Wizard (Progressionsgraph) — separater Chat
2. Graph-Erweiterungsmodus (Start ab Knoten)
3. Trainingsplanung Phase G (Gruppenkontext, `planning_skill_expectations` )
4. Kontext auf allen Pfad-Schritten in der UI
5. Enrichment / Prompt-Feintuning
6. Mitai Workflow-Engine (langfristig)