my_voice_assistant_v3_jamulix/MULTITOOL_AUSBAU_PLAN.md
dschlueter 25f35ad2cb docs: Planungsdokument Multitool-Ausbau (Orchestrierungs-KI, Safety, Nutzerprofile)
Selbst-enthaltendes Planungsdokument für den Umbau zu einer
Orchestrierungs-KI als zentrales Modell (ruft OpenRouter-Modelle für
Teildienste), inkl. Medizin-/Safety-Überlegungen und feinkörnigem
Management der Nutzerprofile (wer was darf). Status: PLAN, noch nichts
implementiert; Umsetzung ab nächster Woche.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 23:24:28 +02:00

13 KiB
Raw Blame History

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):

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 ~12 s"; eine Agenten-Schleife + Web-Fetch dauern 520 s mit Totstille. Lösung (Nutzer): Frage zusammenfassen + vorlesen, dann in 3050 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 (520 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. ≤ 68 s) + max. 12 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 (12 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 (3050 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