Bahn: aisupport, Analyse-O2C-C2S, awesome-bahn-mcp-servers, beam-mcp,
Confluence_Bot, db-planet-mcp-server, O2C-Harness, project-audit,
Projekt-KIQ-HP, teamlandkarte-mcp
Dhive: Jury-Voting
Privat: CV, NoteGraph (NOTE: NoteGraph needs complete redo after consolidation)
Shared: AI-Orchestrator, OrgMyLife, power_skills_and_more
Shared/references: symphony (read-only)
Bahn repos remain available as independent remotes - this monorepo
pulls them in via subtree, the originals are untouched.
121 lines
8.6 KiB
Markdown
121 lines
8.6 KiB
Markdown
# Implementation Plan: LLM-Kompetenz-Inferenz Bugfix
|
||
|
||
## Übersicht
|
||
|
||
Explorativer Bugfix-Workflow: Zuerst den Bug durch Tests bestätigen, dann Preservation sicherstellen, anschließend den Fix implementieren und validieren. Die `infer_competences`-Methode wird in `VocabularyCache` ergänzt und an drei Stellen im `mcp_server.py` integriert.
|
||
|
||
## Tasks
|
||
|
||
- [x] 1. Bug-Condition Explorationstest schreiben
|
||
- **Property 1: Fault Condition** - Kompetenz-Inferenz liefert stets leere Liste
|
||
- **CRITICAL**: Dieser Test MUSS auf dem unfixierten Code FEHLSCHLAGEN – das Fehlschlagen bestätigt den Bug
|
||
- **DO NOT** versuchen den Test oder den Code zu fixen wenn er fehlschlägt
|
||
- **NOTE**: Dieser Test kodiert das erwartete Verhalten – er validiert den Fix wenn er nach der Implementierung besteht
|
||
- **GOAL**: Counterexamples aufdecken, die demonstrieren dass der Bug existiert
|
||
- **Scoped PBT Approach**: Property auf konkrete Fälle scopen: nicht-leerer Task-Text mit vorhandenen Kompetenzen in der DB
|
||
- Test-Datei: `tests/test_competence_inference_fault_pbt.py`
|
||
- Hypothesis-Strategie: `st.text(min_size=1)` für Task-Text, `st.lists(st.text(min_size=1), min_size=1, max_size=50)` für Kompetenzliste
|
||
- Mock `AzureOpenAIClient.chat_completion` so dass er gültiges JSON mit Kompetenzen zurückgibt
|
||
- Assertion: `infer_competences(task_text)` liefert eine nicht-leere Liste von bis zu 10 Tupeln `(name, confidence)` wobei jeder Name in der Kompetenzliste enthalten ist und `confidence` in [0.0, 1.0] liegt
|
||
- Test auf UNFIXIERTEM Code ausführen – **ERWARTETES ERGEBNIS**: Test SCHLÄGT FEHL (bestätigt Bug)
|
||
- Counterexamples dokumentieren (z.B. "infer_competences('Python Backend') gibt [] zurück statt Kompetenzen")
|
||
- Task als abgeschlossen markieren wenn Test geschrieben, ausgeführt und Fehlschlag dokumentiert ist
|
||
- _Requirements: 1.1, 1.2, 1.3, 2.1, 2.2, 2.3_
|
||
|
||
- [x] 2. Preservation Property-Tests schreiben (VOR der Fix-Implementierung)
|
||
- **Property 2: Preservation** - Rollen-Inferenz und Leer-Eingaben unverändert
|
||
- **IMPORTANT**: Observation-First-Methodik befolgen
|
||
- Test-Datei: `tests/test_competence_inference_preservation_pbt.py`
|
||
- Beobachten: `infer_primary_role` liefert auf unfixiertem Code weiterhin eine Rolle mit Konfidenz
|
||
- Beobachten: Leerer Task-Text liefert auf unfixiertem Code `[]` (korrektes Verhalten)
|
||
- Beobachten: Leere Kompetenzliste in DB liefert auf unfixiertem Code `[]` (korrektes Verhalten)
|
||
- Property-Based Test 1: Für alle nicht-leeren Task-Texte liefert `infer_primary_role` weiterhin ein Tupel `(role_name, confidence)` oder `None` bei Fehler (aus Preservation Requirements)
|
||
- Property-Based Test 2: Für alle leeren Task-Texte (`st.just("")` oder `st.from_regex(r'^\s*$')`) liefert `infer_competences` stets `[]`
|
||
- Property-Based Test 3: Für leere Kompetenzliste in DB liefert `infer_competences` stets `[]`
|
||
- Tests auf UNFIXIERTEM Code ausführen – **ERWARTETES ERGEBNIS**: Tests BESTEHEN (bestätigt Baseline-Verhalten)
|
||
- Task als abgeschlossen markieren wenn Tests geschrieben, ausgeführt und bestanden auf unfixiertem Code
|
||
- _Requirements: 3.1, 3.2, 3.3, 3.4, 3.5_
|
||
|
||
- [x] 3. Fix für LLM-Kompetenz-Inferenz implementieren
|
||
|
||
- [x] 3.1 System-Prompt `_COMPETENCE_INFERENCE_SYSTEM_PROMPT` in `vocabulary.py` hinzufügen
|
||
- Modul-Level-Konstante analog zu `_ROLE_INFERENCE_SYSTEM_PROMPT`
|
||
- Prompt instruiert das LLM, aus einer Kompetenzliste bis zu 10 passende Kompetenzen für einen Task-Text auszuwählen
|
||
- Antwortformat: `{"competences": [{"name": "<name>", "confidence": <float>}]}`
|
||
- _Bug_Condition: isBugCondition(input) where task_text.strip() != "" AND len(competence_names) > 0 AND infer_competences(task_text) == []_
|
||
- _Expected_Behavior: Nicht-leere Liste von bis zu 10 (name, confidence)-Tupeln_
|
||
- _Requirements: 2.1, 2.2, 2.3_
|
||
|
||
- [x] 3.2 Methode `infer_competences` in `VocabularyCache` implementieren
|
||
- Signatur: `async def infer_competences(self, *, task_text: str, max_competences: int = 10) -> list[tuple[str, float]]`
|
||
- Kompetenzliste via `self._db.get_all_competence_names()` holen
|
||
- Bei leerer Liste oder leerem Text: `[]` zurückgeben
|
||
- LLM-Aufruf via `self._client.chat_completion(system, user)`
|
||
- JSON-Parsing, Validierung gegen DB-Kompetenzliste (nur bekannte Namen übernehmen)
|
||
- Bei Fehler (Exception, ungültiges JSON): leere Liste zurückgeben + Warning loggen
|
||
- _Bug_Condition: isBugCondition(input) where task_text.strip() != "" AND len(competence_names) > 0_
|
||
- _Expected_Behavior: expectedBehavior(result) = len(result) > 0 AND len(result) <= 10 AND all(name in competence_names for name, _ in result) AND all(0.0 <= conf <= 1.0 for _, conf in result)_
|
||
- _Preservation: Leerer Text → [], Leere DB → [], Fehler → [] + Warning_
|
||
- _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5_
|
||
|
||
- [x] 3.3 LLM-Aufruf in `validate_task_requirements` integrieren
|
||
- Ersetze `inferred_comps: list[tuple[str, float]] = []` durch `inferred_comps = await vocab_cache.infer_competences(task_text=task_text)`
|
||
- _Bug_Condition: validate_task_requirements aufgerufen mit Task der beschriebenen Text hat_
|
||
- _Expected_Behavior: inferred_comps enthält bis zu 10 Kompetenzen mit Konfidenz_
|
||
- _Preservation: Rollen-Inferenz und DB-Skills bleiben unverändert_
|
||
- _Requirements: 2.1, 3.1, 3.2_
|
||
|
||
- [x] 3.4 LLM-Aufruf in `extract_requirements` integrieren
|
||
- Ersetze `inferred_competences: list[tuple[str, float]] = []` durch `inferred_competences = await vocab_cache.infer_competences(task_text=desc)`
|
||
- _Bug_Condition: extract_requirements aufgerufen mit nicht-leerem Text_
|
||
- _Expected_Behavior: inferred_competences enthält bis zu 10 Kompetenzen_
|
||
- _Requirements: 2.2_
|
||
|
||
- [x] 3.5 LLM-Aufruf in `find_matching_tasks` (Score-Modus) integrieren
|
||
- Ersetze den bestehenden `inferred_comp_names`-Block durch LLM-Inferenz mit Fallback auf DB-Skills
|
||
- `inferred_comp_tuples = await vocab_cache.infer_competences(task_text=full_text)`
|
||
- `inferred_comp_names = [name for name, _conf in inferred_comp_tuples]`
|
||
- Fallback: `if not inferred_comp_names: inferred_comp_names = [str(x) for x in (getattr(t, "skills", None) or []) if x]`
|
||
- _Bug_Condition: find_matching_tasks im Score-Modus mit Task der beschriebenen Text hat_
|
||
- _Expected_Behavior: inferred_comp_names enthält LLM-inferierte Kompetenzen für Scoring_
|
||
- _Preservation: LLM-Fulltext-Modus bleibt unverändert_
|
||
- _Requirements: 2.3, 3.3_
|
||
|
||
- [x] 3.6 Unit-Tests für `infer_competences` mit gemocktem LLM-Client
|
||
- Test gültige JSON-Antwort → korrekte Tupel-Liste
|
||
- Test leerer Task-Text → `[]`
|
||
- Test leere Kompetenzliste in DB → `[]`
|
||
- Test LLM-Fehler (Exception) → `[]` + Warning geloggt
|
||
- Test ungültige JSON-Antwort → `[]`
|
||
- Test Kompetenz-Namen die nicht in DB sind → werden herausgefiltert
|
||
- Test max_competences Begrenzung auf 10
|
||
- _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5_
|
||
|
||
- [x] 3.7 Bug-Condition Explorationstest erneut ausführen – Verifizieren dass er jetzt besteht
|
||
- **Property 1: Expected Behavior** - Kompetenz-Inferenz liefert Ergebnisse
|
||
- **IMPORTANT**: Den GLEICHEN Test aus Task 1 erneut ausführen – KEINEN neuen Test schreiben
|
||
- Der Test aus Task 1 kodiert das erwartete Verhalten
|
||
- Wenn dieser Test besteht, bestätigt das dass das erwartete Verhalten erfüllt ist
|
||
- Bug-Condition Explorationstest aus Schritt 1 ausführen
|
||
- **ERWARTETES ERGEBNIS**: Test BESTEHT (bestätigt Bug ist behoben)
|
||
- _Requirements: 2.1, 2.2, 2.3_
|
||
|
||
- [x] 3.8 Preservation-Tests erneut ausführen – Verifizieren dass sie weiterhin bestehen
|
||
- **Property 2: Preservation** - Rollen-Inferenz und Leer-Eingaben unverändert
|
||
- **IMPORTANT**: Die GLEICHEN Tests aus Task 2 erneut ausführen – KEINE neuen Tests schreiben
|
||
- Preservation Property-Tests aus Schritt 2 ausführen
|
||
- **ERWARTETES ERGEBNIS**: Tests BESTEHEN (bestätigt keine Regressionen)
|
||
- Bestätigen dass alle Tests nach dem Fix weiterhin bestehen
|
||
- _Requirements: 3.1, 3.2, 3.3, 3.4, 3.5_
|
||
|
||
- [x] 4. Checkpoint - Sicherstellen dass alle Tests bestehen
|
||
- Alle Tests ausführen und sicherstellen dass sie bestehen, bei Fragen den User konsultieren.
|
||
|
||
## Hinweise
|
||
|
||
- Property-Based Tests verwenden Hypothesis mit `@settings(max_examples=100)`.
|
||
- Unit- und Integrationstests verwenden `pytest` (Run-once, kein Watch-Modus); der `AzureOpenAIClient` wird stets gemockt.
|
||
- Die Implementierungssprache ist Python (bestehende Codebase).
|
||
- Tasks referenzieren explizit Anforderungen aus `bugfix.md` zur lückenlosen Nachverfolgbarkeit.
|
||
- Der Fix ist additiv: bestehende Funktionalität (Rollen-Inferenz, DB-Skills, LLM-Fulltext-Matching) bleibt unverändert.
|