Provision OpenWebUI workspace model presets

This commit is contained in:
Mikei386
2026-08-22 11:37:30 +02:00
parent 41b9c17f0f
commit 95ed583a66
6 changed files with 267 additions and 12 deletions
+1 -1
View File
@@ -470,7 +470,7 @@ services:
- ./platform/openwebui/theme/loader.js:/app/build/static/loader.js:ro
environment:
WEBUI_SECRET_KEY: "${WEBUI_SECRET_KEY:?WEBUI_SECRET_KEY is required}"
DEFAULT_MODELS: qwen-medium
DEFAULT_MODELS: mikeai-medium
OLLAMA_BASE_URL: ""
OPENAI_API_BASE_URLS: http://router:8081/v1
OPENAI_API_KEYS: "${ROUTER_API_KEY:?ROUTER_API_KEY is required}"
+11 -4
View File
@@ -22,8 +22,9 @@ laufen, sondern alle fachlichen Funktionen geprüft wurden.
- [ ] llama.cpp entspricht dem festgelegten Commit
- [ ] Modelldateien stimmen mit SHA256 überein
- [ ] Fast startet mit 76.800 Kontext
- [ ] Medium startet mit 94.208 Kontext
- [ ] Long startet mit 131.072 Kontext
- [ ] Medium startet mit 160.000 Kontext und ist Standard
- [ ] Large startet mit 192.000 Kontext
- [ ] Ultra startet mit 262.144 Kontext und bleibt text-only
- [ ] GPU-/CPU-Verteilung entspricht den Profilen
- [ ] Fast erreicht den festgelegten Geschwindigkeitstoleranzbereich
- [ ] MTP funktioniert und verursacht keine Qualitätsregression
@@ -36,7 +37,7 @@ laufen, sondern alle fachlichen Funktionen geprüft wurden.
- [ ] geschützte Endpunkte liefern ohne Key 401
- [ ] Router-Key erscheint weder im Upstream noch im Journal
- [ ] `/status` meldet den richtigen Upstream
- [ ] `/v1/models` liefert drei virtuelle Modelle
- [ ] `/v1/models` liefert vier virtuelle Modelle
- [ ] `/fast`, `/medium`, `/large` und `/ultra` wechseln zuverlässig
- [ ] automatischer Wechsel über virtuellen Modellnamen funktioniert
- [ ] paralleler Wechsel wird sauber gesperrt
@@ -49,6 +50,11 @@ laufen, sondern alle fachlichen Funktionen geprüft wurden.
## Phase D – Web und MCP
- [ ] OpenWebUI zeigt nur die vier MikeAI-Arbeitsbereichsmodelle
- [ ] rohe `qwen-*`-Routermodelle sind ausgeblendet
- [ ] Medium ist die gespeicherte Standardauswahl
- [ ] Filter und Quick Actions sind allen vier Presets zugeordnet
- [ ] SearXNG und TinySearch gesund
- [ ] Websuche liefert kompakte, quellengebundene Ergebnisse
- [ ] GitHub- und Hugging-Face-Routing geprüft
@@ -86,7 +92,8 @@ laufen, sondern alle fachlichen Funktionen geprüft wurden.
## Phase G – Fachlicher Benchmark
Der gespeicherte Standardbenchmark wird mindestens mit Fast und Long ausgeführt:
Der gespeicherte Standardbenchmark wird mindestens mit Fast und Medium sowie
für Kontextgrenzen zusätzlich mit Large und Ultra ausgeführt:
- Home-Assistant-Automatisierung analysieren
- Logs lesen und Fehlerursache begründen
+17 -5
View File
@@ -95,6 +95,18 @@ Zusätzlich prüfen: Uni-LAN sieht keine KI-Ports; Heimnetz erreicht beide;
gestopptes WireGuard lässt KI-Container nicht ins Internet; jeder Profilwechsel
startet exakt einen llama-Container; Text, Tool Call, Bild und Sprachausgabe funktionieren.
Nach dem ersten Anlegen des OpenWebUI-Administrators werden Filter, Quick
Actions und die vier Arbeitsbereichsmodelle reproduzierbar eingespielt:
```bash
sudo /opt/mike-ai/stack/platform/openwebui/install-filters.sh
sudo /opt/mike-ai/stack/platform/openwebui/install-models.sh
```
Danach sind nur die vier benannten MikeAI-Presets sichtbar; die rohen
Router-Aliase sind ausgeblendet und Medium ist die Standardauswahl. Beide
Skripte sichern die OpenWebUI-Datenbank vor jeder Änderung.
## Werkzeug-Container
Der Installer startet Websuche automatisch in einem privaten Docker-Netz.
@@ -122,11 +134,11 @@ Kein MCP-Port wird auf dem Host veröffentlicht. Externe Clients wie Hermes
benötigen später den authentifizierten WireGuard-Gateway und dürfen nicht
direkt auf das interne Werkzeugnetz zugreifen.
Die öffentliche Standardkonfiguration nutzt `UD-IQ4_XS`. Das bislang schnellste
Referenzprofil nutzt dagegen die lokal vorhandene `IQ4-MIX`-Datei. Für eine
bitgenaue Migration diese Datei anhand der in `CURRENT_REFERENCE.md`
dokumentierten SHA256 in das Modellverzeichnis kopieren und die drei
`*_MODEL_FILE`-Werte anpassen. Der Installer löscht vorhandene Modelle nicht.
Die Standardkonfiguration lädt IQ4-MIX für Fast und IQ4_XS Pure für Medium,
Large und Ultra aus den dokumentierten Hugging-Face-Repositories. URLs,
Dateinamen und SHA256 stehen vollständig in `config/install.env.example`.
Der Installer lädt jede identische Datei nur einmal und löscht vorhandene
Modelle nicht.
Open-WebUI-Daten liegen in einem Docker-Volume und müssen separat gesichert
werden. Geheimnisse und Chatdaten gehören nie in Git.
+16
View File
@@ -29,6 +29,22 @@ einer vorherigen Datenbanksicherung installiert beziehungsweise aktualisiert:
sudo /opt/mike-ai/stack/platform/openwebui/install-filters.sh
```
Die sichtbaren Arbeitsbereichsmodelle und die versteckten Router-Aliase werden
separat und ebenfalls mit vorheriger Datenbanksicherung installiert:
```bash
sudo /opt/mike-ai/stack/platform/openwebui/install-models.sh
```
Dadurch erscheinen ausschließlich `MikeAI · Fast`, `MikeAI · Medium`,
`MikeAI · Large` und `MikeAI · Ultra`. Medium ist die Standardauswahl. Alle
vier erhalten die geprüften Filter und Quick Actions sowie Piper-Stimme
`alloy`. Vision ist nur bei Fast, Medium und Large aktiviert; Ultra bleibt
bewusst text-only. Bildgenerierung wird erst als Fähigkeit freigeschaltet,
wenn ein echter Generator-Worker im Stack aktiv ist. Websuche und Codewerkzeuge
bleiben verfügbar, werden aber nicht automatisch jeder Nachricht beigelegt,
damit Werkzeugschemas den Kontext nicht unnötig füllen.
Bei mehreren Administratoren muss der gewünschte Eigentümer explizit über
`OPENWEBUI_FILTER_OWNER_ID` gesetzt werden. Das Skript liest oder verändert
keine Chats. Es deaktiviert zugleich global die automatisch erzeugten
+4 -2
View File
@@ -15,7 +15,10 @@ und einer bewussten Aktualisierung dieser Datei.
- Medium ist nach Neuinstallation und bewusstem Plattformstart das aktive
Standardprofil.
- Open WebUI erhält `qwen-medium` als Standardmodell.
- Open WebUI erhält `mikeai-medium` als Standardmodell.
- Im OpenWebUI-Arbeitsbereich ist dieses auf `qwen-medium` basierende Preset
`mikeai-medium` die sichtbare Standardauswahl; die vier rohen `qwen-*`-Aliase
bleiben ausgeblendet.
- Ein explizit gewähltes anderes Modell löst den zugehörigen Containerwechsel
aus; es ist immer nur ein Inferenzcontainer aktiv.
- Ultra reserviert den verfügbaren Speicher für nativen 256K-Textkontext und
@@ -30,4 +33,3 @@ und einer bewussten Aktualisierung dieser Datei.
- Large 192K: Pure 86:14 mit MTP3, 75,28 Tok/s.
- Ultra 256K: Pure 80:20 mit MTP2, 68,19 Tok/s; 220.190 Tokens
erfolgreich verarbeitet und Sentinel korrekt wiedergefunden.
+218
View File
@@ -0,0 +1,218 @@
#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
CONTAINER=${OPENWEBUI_CONTAINER:-mike-ai-open-webui}
VOLUME=${OPENWEBUI_VOLUME:-mike-ai_open-webui-data}
die() { printf 'FEHLER: %s\n' "$*" >&2; exit 1; }
[[ $EUID -eq 0 ]] || die "Bitte als root ausführen."
volume_path=$(docker volume inspect -f '{{.Mountpoint}}' "$VOLUME")
db=$volume_path/webui.db
[[ -s $db ]] || die "OpenWebUI-Datenbank fehlt: $db"
was_running=false
if [[ $(docker inspect -f '{{.State.Running}}' "$CONTAINER" 2>/dev/null || true) == true ]]; then
was_running=true
docker stop "$CONTAINER" >/dev/null
fi
restart_on_exit() {
if [[ $was_running == true ]]; then
docker start "$CONTAINER" >/dev/null 2>&1 || true
fi
}
trap restart_on_exit EXIT
stamp=$(date +%Y%m%d-%H%M%S)
backup=$volume_path/webui.db.before-model-install-$stamp
cp -a "$db" "$backup"
rm -f "$volume_path/webui.db-wal" "$volume_path/webui.db-shm"
python3 - "$db" "${OPENWEBUI_MODEL_OWNER_ID:-}" <<'PY'
import json
import sqlite3
import sys
import time
db, requested_owner = sys.argv[1:]
con = sqlite3.connect(db)
columns = {row[1] for row in con.execute("pragma table_info(model)")}
required = {
"id", "user_id", "base_model_id", "name", "params", "meta",
"is_active", "updated_at", "created_at",
}
if not required <= columns:
raise SystemExit("Unbekanntes OpenWebUI-Modellschema; keine Änderung vorgenommen.")
owner = requested_owner
if not owner:
row = con.execute(
"select user_id from model where id in "
"('mikeai-fast','mikeai-medium','mikeai-large','mikeai-ultra',"
"'mikeai---fast-72k') order by updated_at desc limit 1"
).fetchone()
if row:
owner = row[0]
if not owner:
admins = con.execute("select id from user where role='admin'").fetchall()
if len(admins) != 1:
raise SystemExit(
"Modelleigentümer ist nicht eindeutig; OPENWEBUI_MODEL_OWNER_ID setzen."
)
owner = admins[0][0]
now = int(time.time())
filter_ids = [
"reasoning_default_off",
"thinking",
"stability_guard",
"secret_redaction",
"local_performance_metrics",
]
def capabilities(vision: bool) -> dict:
return {
"file_context": True,
"vision": vision,
"file_upload": True,
"web_search": True,
"image_generation": False,
"code_interpreter": True,
"terminal": True,
"citations": True,
"status_updates": True,
"memory": True,
"builtin_tools": True,
}
profiles = [
{
"id": "mikeai-fast",
"base": "qwen-fast",
"name": "MikeAI · Fast · 76K",
"description": (
"Schnelles Alltags- und Agentenprofil: Qwen3.8-27B IQ4-MIX, "
"76.800 Token, RTX 5080, MTP2 und Bildanalyse."
),
"vision": True,
"tags": ["MikeAI", "Schnell", "Vision"],
},
{
"id": "mikeai-medium",
"base": "qwen-medium",
"name": "MikeAI · Medium · 160K · Standard",
"description": (
"Verbindliches Standardprofil: Qwen3.8-27B IQ4_XS Pure, "
"160.000 Token, RTX 5080 + RTX 3060 (90:10), MTP3 und Bildanalyse."
),
"vision": True,
"tags": ["MikeAI", "Standard", "Vision"],
},
{
"id": "mikeai-large",
"base": "qwen-large",
"name": "MikeAI · Large · 192K",
"description": (
"Großes Agenten- und MCP-Profil: Qwen3.8-27B IQ4_XS Pure, "
"192.000 Token, RTX 5080 + RTX 3060 (86:14), MTP3 und Bildanalyse."
),
"vision": True,
"tags": ["MikeAI", "Großer Kontext", "Vision"],
},
{
"id": "mikeai-ultra",
"base": "qwen-ultra",
"name": "MikeAI · Ultra · 256K · Text",
"description": (
"Maximaler Textkontext: Qwen3.8-27B IQ4_XS Pure, 262.144 Token, "
"RTX 5080 + RTX 3060 (80:20), MTP2; bewusst ohne Bildanalyse."
),
"vision": False,
"tags": ["MikeAI", "Maximaler Kontext", "Nur Text"],
},
]
params = {
"temperature": 0.2,
"top_p": 0.8,
"top_k": 20,
"max_tokens": 32768,
}
def upsert(model_id, base_model_id, name, model_params, meta, active=True):
existing = con.execute(
"select created_at from model where id=?", (model_id,)
).fetchone()
created_at = existing[0] if existing else now
con.execute(
"""
insert into model
(id,user_id,base_model_id,name,params,meta,is_active,updated_at,created_at)
values (?,?,?,?,?,?,?,?,?)
on conflict(id) do update set
user_id=excluded.user_id,
base_model_id=excluded.base_model_id,
name=excluded.name,
params=excluded.params,
meta=excluded.meta,
is_active=excluded.is_active,
updated_at=excluded.updated_at
""",
(
model_id, owner, base_model_id, name,
json.dumps(model_params, ensure_ascii=False),
json.dumps(meta, ensure_ascii=False),
active, now, created_at,
),
)
with con:
# Hide the raw router aliases while keeping them resolvable as bases for
# the user-facing workspace presets.
for raw_id in ("qwen-fast", "qwen-medium", "qwen-large", "qwen-ultra"):
upsert(
raw_id, None, raw_id, {},
{
"description": "Interner Router-Alias; bitte das zugehörige MikeAI-Profil verwenden.",
"hidden": True,
},
)
for profile in profiles:
meta = {
"profile_image_url": "/static/favicon.png",
"description": profile["description"],
"capabilities": capabilities(profile["vision"]),
"knowledge": None,
"suggestion_prompts": None,
"tags": [{"name": tag} for tag in profile["tags"]],
# Features remain available but are not forced on every request;
# this avoids needlessly injecting large tool schemas.
"defaultFeatureIds": [],
"filterIds": filter_ids,
"actionIds": ["quick_actions"],
"tts": {"voice": "alloy"},
"hidden": False,
}
upsert(
profile["id"], profile["base"], profile["name"], params, meta
)
# Exact legacy entries from the experimental 72K/Long setup. The database
# backup above makes the cleanup fully recoverable.
con.execute(
"delete from model where id in ('mikeai---fast-72k','qwen-long')"
)
con.execute(
"""
insert into config (key,value,updated_at) values (?,?,?)
on conflict(key) do update set value=excluded.value, updated_at=excluded.updated_at
""",
("ui.default_models", json.dumps("mikeai-medium"), now),
)
print("OpenWebUI-Modelle installiert: Fast, Medium (Standard), Large, Ultra")
PY
printf 'Datenbanksicherung: %s\n' "$backup"