diff --git a/MULTITOOL_AUSBAU_PLAN.md b/MULTITOOL_AUSBAU_PLAN.md new file mode 100644 index 0000000..3a5518e --- /dev/null +++ b/MULTITOOL_AUSBAU_PLAN.md @@ -0,0 +1,222 @@ +# MULTITOOL-AUSBAU — Orchestrierungs-KI, Sicherheit & feinkörnige Nutzerprofile + +> Planungsdokument. Erstellt 2026-06-26. Umsetzung geplant ab nächster Woche +> (neues Wochen-Kontingent). Selbst-enthaltend, damit eine frische Session den +> Kontext ohne Vorwissen versteht. +> +> Status: **PLAN — noch nichts implementiert.** Branch: `jamulix-optimized`. + +--- + +## 0. Ausgangsfrage (wörtlich sinngemäß vom Nutzer) + +> „Könnte unser System auch so umgebaut werden, dass es ein Orchestrierungs-KI-Tool +> als zentrales KI-Modell benutzt, das seinerseits wieder OpenRouter-KI-Modelle +> aufruft, um bestimmte Dienste (z. B. Recherche im Internet) zu leisten?" + +Zusatzwunsch des Nutzers: feinkörniges **Management der Nutzerprofile** — festlegen, +**wer was darf**, um Gefahren auszuschließen und Risiken klein zu halten. Begründung: +Senioren sind unterschiedlich kompetent; ab einem gewissen Stadium ist schon der +Umgang mit dem Mobilgerät eine Überforderung. + +--- + +## 1. Architektur-Befund: das System ist dafür gebaut + +Die LLM-Achse ist eine **austauschbare Achse hinter einem winzigen Interface** +(`app/providers/llm/base.py`): + +```python +async def complete(text, history, session_id, language) -> str +async def stream(...) -> AsyncIterator[str] # Default: complete() als ein Chunk +``` + +Ein „Orchestrierungs-Tool" ist aus Kern-Sicht **nur ein weiterer LLM-Provider**, der +intern beliebig viel tun darf (Tool-Calls, mehrere Modelle, Websuche) und am Ende +Text liefert/streamt. **Kein Kern-Code muss geändert werden** — ein Registry-Eintrag +(`LLM_REGISTRY` in `app/dependencies.py`) genügt. Der **gerade gebaute Modell-Dropdown** +(Admin › System › Status, `config/models.yaml`, `app/model_presets.py`) ist der +natürliche Umschalter; Auswahl/Umstellung läuft über die Laufzeit-Overrides +(`RUNTIME_SETTABLE`, wirkt ohne Neustart). + +### Drei Andock-Formen (alle ohne Architektur-Bruch) +1. **OpenRouter-nativ (am leichtesten).** Der OpenRouter-Provider baut nur ein simples + `{model, messages, stream}`-JSON (`app/providers/llm/openrouter.py`). Erweiterbar um + OpenRouters **Websuche** (Web-Plugin bzw. `modell:online`) und/oder den **Auto-Router** + `openrouter/auto`. → „Recherche" + „Modell-Orchestrierung light" praktisch ohne Agent-Code, + nur ein neues Preset im Dropdown. +2. **Eigener Orchestrator-Provider.** `app/providers/llm/orchestrator.py` implementiert das + ABC und fährt intern eine **begrenzte Tool-Schleife** (OpenRouter-Tool-Calling) mit Werkzeugen + wie `web_search`, `call_model(model, prompt)`, `datum/zeit`. Plug-in als + `default_llm_provider="orchestrator"` (ein Registry-Eintrag, ein Preset). **= genau das vom + Nutzer gewünschte Bild.** +3. **Externer Orchestrierungs-Dienst.** Agent-Framework (LangGraph/Flowise/n8n/eigener + MCP-Host) mit **OpenAI-kompatibler `/chat/completions`**-Fassade; der vorhandene + `local_openai_compatible`-Provider zeigt per `base_url` darauf → **null neuer Provider-Code**. + +**Verifizieren (gegen aktuelle OpenRouter-Doku, Wissensstand kann hinterherhinken):** +Web-Plugin / `:online`-Suffix, Perplexity-„sonar"-Modelle (native Online-Suche), +`openrouter/auto`-Router, Tool-/Function-Calling-Passthrough, Kosten der Websuche. + +--- + +## 2. Diskussion & Entscheidungen + +### 2.1 Latenz — gelöst über Füllsprache (Nutzer-Idee, bestätigt) +Voice braucht „erster Ton in ~1–2 s"; eine Agenten-Schleife + Web-Fetch dauern 5–20 s mit +Totstille. Lösung (Nutzer): Frage **zusammenfassen + vorlesen**, dann in **30–50 Varianten** +sinngemäß „Ich kümmere mich darum, eine gute Antwort zu finden. Lass mich kurz lesen und +nachdenken." → zwischendurch „Habe noch ein bisschen Geduld, ich bin gleich soweit." → dann +die Antwort. + +**Ergänzungen/Verbesserungen:** +- Das **Vorlesen der zusammengefassten Frage = Verständnis-Rückversicherung** (gegen STT-/ + Missverständnis-Fehler) — doppelter Nutzen. +- Varianten **an verstrichene/erwartete Restzeit koppeln** (nicht „gleich soweit" beim Start). +- Füllsätze müssen **barge-in-fähig** sein (Nutzer korrigiert → sofort abbrechen + neu zuhören). + Nutzt die bereits gebaute **entkoppelte, satzweise TTS + Barge-in**: Füllsatz wird sofort + gesprochen, während die Recherche läuft; danach streamt die echte Antwort in dieselbe + geordnete TTS-Queue. +- **Graceful give-up**, falls Zeitbudget reißt („ich konnte es nicht sicher herausfinden"). +- Optional multimodale Beruhigung (Bubble „🔎 liest…"). +- Varianten + Sicherheits-Antworten **pro Sprache** pflegen. + +### 2.2 Selektives Routing — Muss (Nutzer bestätigt) +- **Intent-Gate** (billig/schnell, Regeln oder kleines Modell): „einfacher Plausch/Frage" vs. + „braucht Recherche/Tools". Die meisten Senioren-Turns dürfen NICHT die Agenten-Steuer zahlen. +- Entscheidung berücksichtigt **auch Nutzerprofil/Berechtigungen** (§ 2.6), nicht nur das Intent. +- Im Zweifel **rückfragen** statt selbstsicher veraltet antworten. Entscheidung **protokollieren**. +- Muster existiert schon: der nicht-blockierende Notruf-LLM-Klassifikator (`app/safety/`). + +### 2.3 Kosten — Deckel + Logging (Nutzer bestätigt) +- Budget **pro Turn _und_ pro Nutzer/Tag _und_ global**; **inkl. Websuche-Kosten** (extra zu Tokens). +- **Circuit-Breaker** bei Kostenausreißern; Kosten als **Admin-Metrik** sichtbar + (`app/metrics.py`, vorhandenes Tageskontingent `app/quota.py` zählt heute nur Turns → um + Token-/Kosten-Konten erweitern). + +### 2.4 Sicherheit — der EIGENTLICHE Kern (Nutzer-Schwerpunkt: Medizin/gefährliche Ratschläge) +Prompt-Injection ist beherrschbar; **falsche/gefährliche, v. a. medizinische Ratschläge** sind +das große Risiko (Senioren reden gern über Krankheiten). **Eigener Arbeitsstrang.** +- **Unterscheiden:** *über Krankheit reden* (Empathie, zuhören, KEINE Ratschläge) vs. + *um medizinischen Rat fragen* (immer an Arzt/Apotheke/Betreuer verweisen). Themen-Detektor + (analog Notruf-Klassifikator) → **sicherer Antwortmodus**. +- **Harte Tabus:** keine Dosierungen, keine Diagnosen, kein „Medikament absetzen/ändern". + Nachgelagerter Output-Check (billiger Klassifikator), der unsicheren medizinischen Inhalt + blockt/umschreibt. +- **Web bei Gesundheit:** ganz aus ODER nur **kuratierte, seriöse Quellen**. +- **Datenschutz:** Gesundheitsdaten = DSGVO-**besondere Kategorie**. Sensible medizinische Frage + evtl. **lokal (Ollama, keine Cloud, kein Web)** beantworten → verbindet Routing + Sicherheit + + Datenschutz. +- **Betreuer-Schleife:** riskante Themen → Kontakt informieren (nutzt Notruf-Benachrichtigungs- + Infrastruktur `app/safety/emergency.py`). +- **Scam-/Betrugsschutz:** „soll ich Geld an … überweisen?" → Warn-Layer (Senioren sind Ziel). + +### 2.5 Notruf-Invariante bleibt schnell & getrennt (Klarstellung zu meinem Punkt 5) +Heute läuft die **Notruf-Stichwort-Erkennung VOR dem LLM**, unabhängig von jedem Modell +(`app/safety/emergency.py`, Hot-Path). Wenn das „zentrale Modell" ein **langsamer Orchestrator** +(5–20 s) wird, darf die Notruf-Erkennung **nicht** durch ihn laufen — sonst verzögert eine +Recherche einen echten Notruf. **Der schnelle Sicherheits-Pfad bleibt getrennt und schnell.** + +### 2.6 Feinkörnige Nutzerprofile = Policy-Schicht des Systems (Nutzer-Grundsatzpunkt) +Kein Nebenpunkt, sondern **die zentrale Policy-Schicht**, die Router/Orchestrator/Sicherheit +konsultieren. Passt auf die vorhandenen **Pro-Nutzer-Prefs** (`user.prefs`, gerade um +per-User-Notrufpause erweitert). +- **Kompetenz-Stufen als Vorlagen** (z. B. *Selbstständig · Begleitet · Stark eingeschränkt*) + mit Defaults + **Pro-Nutzer-Feinjustierung** (nicht 20 Schalter pro Person). +- Jede Stufe legt fest: **Web-Recherche an/aus, Medizin-Modus, Modell-Stufe (schnell vs. + Orchestrator), Antwort-Komplexität/-Länge, Freitext vs. „einfacher Modus", Auslöser für + Betreuer-Benachrichtigung.** +- **„Einfacher Modus"-UI** für Überforderte (großer Sprechknopf + SOS, keine Menüs/Tabs) — + eigener kleiner Strang (UX). +- **Vom Betreuer/Admin konfiguriert** (Admin › Nutzer › Notfall-/Profil-Bereich), der Senior + kann Sicherheitseinstellungen **nicht selbst aufweichen**. + +### 2.7 Verlässlichkeit (Nutzer bestätigt) +Agenten sind weniger deterministisch. Orchestrierung **opt-in/selektiv**, nicht Default — +der normale, schnelle Assistenzbetrieb darf nicht leiden. + +--- + +## 3. Querschnitts-Anforderungen (gelten für alle Phasen) +- **Hartes Wall-Clock-Budget** je Turn (z. B. ≤ 6–8 s) + max. 1–2 Tool-Schritte + Timeouts. +- **Füllsprache** (barge-in-fähig, zeit-gekoppelt, mehrsprachig, graceful give-up). +- **Routing-Policy** konsultiert Intent **und** Nutzerprofil/Berechtigungen. +- **Kostenkonto** (Turn/Nutzer/global) inkl. Websuche; Circuit-Breaker; Admin-Sichtbarkeit. +- **Sicherheits-Guardrails** (Medizin/gefährlich/Scam) mit sicherem Antwortmodus + Output-Check. +- **Notruf-Hot-Path bleibt getrennt & schnell.** +- **Graceful Degradation** (Web/Modell/Budget aus → sichere gesprochene Notlösung; Fallback-Ketten + `app/providers/fallback.py` nutzen). +- **DSGVO/Consent** für Sprach- & Gesundheitsdaten; sensible Themen ggf. lokal (Ollama). +- **Auditierbarkeit** (Routing, Tool-Use, Kosten, Sicherheits-Trigger) für Betreuer/Admin + (`app/audit.py`, Admin-Log). +- **Eval-/Guardrail-Testset** (Medizin-Verweigerung, Injection, Latenz, Routing-Korrektheit). +- Hinweis: Profil nimmt **ein Nutzer pro Gerät/Login** an (Besuch/zweite Person nicht modelliert). + +--- + +## 4. Phasenplan + +### Phase 0 — Realitätstest „Recherche" (fast gratis) +Ziel: **Ist die Latenz für Senioren überhaupt erträglich?** — vor jedem Agenten-Bau. +- OpenRouter-Websuche (Web-Plugin / `:online`) an EINEM Modell aktivieren; als Dropdown-Preset + „… (Recherche)" in `config/models.yaml` (Provider-Payload in `openrouter.py` um Plugin/Suffix + erweitern). +- Erste, einfache **Füllsprache** (1–2 Varianten) im Streaming-Pfad testen. +- Messen: End-to-End-Latenz, „Time-to-first-Füllsatz", Antwortqualität, Kosten/Turn. +- **Akzeptanzkriterium** (mit Nutzer festzulegen): z. B. „bis ~5 s, mit gesprochenem ‚ich schaue nach'". + +### Phase 1 — Eigener Orchestrator-Provider (falls Phase 0 trägt) +- `app/providers/llm/orchestrator.py` (ABC): **Intent-Gate → begrenzte Tool-Schleife + (web_search, call_model) → Füllsatz-Streaming → hartes Zeitbudget**. Registry-Eintrag + Preset. +- **Routing** mit Profil-Berücksichtigung (§ 2.6) verdrahten. +- **Kostenkonto** + Circuit-Breaker (`app/quota.py`/`metrics.py` erweitern). +- **Füllsprache** voll ausbauen (30–50 Varianten, zeit-gekoppelt, mehrsprachig, barge-in). + +### Phase 2 — Medizin-/Sicherheits-Guardrails (parallel ab Phase 1, hohe Priorität) +- Themen-Detektor (Medizin/gefährlich/Scam) → **sicherer Antwortmodus** (Empathie + Verweis, + harte Tabus, Output-Check). +- Sensible Themen → **lokales Modell (Ollama), kein Web**; optional Betreuer-Benachrichtigung. +- Eval-/Guardrail-Testset. + +### Phase 3 — Nutzerprofil-/Berechtigungs-Management +- **Kompetenz-Stufen (Vorlagen) + Pro-Nutzer-Overrides** in `user.prefs` + (Schema `AdminUserPrefsUpdate`, Admin-UI im Notfall-/Profil-Bereich erweitern). +- Policy-Schicht, die Router/Orchestrator/Guardrails konsultieren. +- **„Einfacher Modus"-UI** (großer Sprechknopf + SOS, keine Menüs) als gegateter Strang. + +### Phase 4 (optional, falls es wächst) — Externer Agenten-Dienst +- Orchestrator in separaten Dienst auslagern (OpenAI-kompatible Fassade → `local_openai_compatible` + per `base_url`); Gateway bleibt schlank; Tools via MCP. + +--- + +## 5. Risiken & offene Fragen (für nächste Woche) +- **Latenz-Akzeptanz** der Senioren — durch Phase 0 empirisch klären. +- **Medizin-Sicherheit**: genaue Linie „zuhören vs. verweisen", kuratierte Quellenliste, Output-Check-Modell. +- **Kostenmodell**: konkrete Deckel pro Turn/Nutzer/Tag; Websuche-Preis. +- **Profil-Stufen**: welche Stufen genau, welche Schalter pro Stufe (Default-Matrix entwerfen). +- **DSGVO**: Consent-Fluss, Speicherung von Gesundheitsthemen (auch im Auto-Memory-Extractor). +- **Wer testet die Guardrails** (Red-Team-Promptset) und wie oft (CI?). +- **OpenRouter-Features** gegen aktuelle Doku verifizieren (Namen/Preise/Verfügbarkeit). + +## 6. Konkrete erste Schritte (Start nächste Woche) +1. OpenRouter-Doku prüfen: Websuche/`:online`, `openrouter/auto`, sonar, Tool-Calling, Preise. +2. Phase 0: Recherche-Preset + minimale Füllsprache, Latenz/Kosten messen, Akzeptanzkriterium mit + Nutzer fixieren. +3. Default-Matrix der Kompetenz-Stufen entwerfen (Tabelle Stufe × Schalter). +4. Medizin-Safety-Linie skizzieren (was sagt das System bei Krankheitsthemen — Beispiele sammeln). + +--- + +## 7. Bezug zum bestehenden Code (Andockpunkte) +- LLM-Provider/Interface: `app/providers/llm/{base,openrouter,local_openai_compatible}.py` +- Registry/Routing: `app/dependencies.py` (`LLM_REGISTRY`, `resolve_route`) +- Laufzeit-Umschaltung: `app/runtime_config.py` (`RUNTIME_SETTABLE`) + Admin-Config-Endpunkte +- Modell-Dropdown (Umschalter): `config/models.yaml`, `app/model_presets.py`, Admin › System › Status +- Pro-Nutzer-Policy: `user.prefs`, `app/schemas.py` (`AdminUserPrefsUpdate`), Admin › Nutzer +- Sicherheit/Notruf (Muster + Invariante): `app/safety/` (`emergency.py`, `llm_classifier.py`) +- Kosten/Quota/Metriken: `app/quota.py`, `app/metrics.py` +- Resilienz/Fallback: `app/providers/fallback.py` +- Audit: `app/audit.py` +- Streaming/TTS-Entkopplung + Barge-in (Basis für Füllsprache): `app/core/orchestrator.py`, + `app/pipeline/sentence_chunker.py`, `app/api/ws.py`