Deployment-Anleitung¶
Installations-, Betriebs- und Wartungsanleitung für den AVS Chatbot.
Inhaltsverzeichnis¶
Voraussetzungen¶
Hardware¶
| Komponente | Minimum | Empfohlen |
|---|---|---|
| GPU | 1x GPU mit 24 GB VRAM | 2x NVIDIA RTX 4090 (24 GB) |
| RAM | 16 GB | 32 GB |
| Festplatte | 50 GB SSD | 100 GB NVMe SSD |
| CPU | 8 Kerne | 16 Kerne |
GPU-Zuweisung¶
| GPU | Service | VRAM-Bedarf |
|---|---|---|
| GPU 0 | vLLM (Qwen3-14B INT4) | ~7 GB |
| GPU 1 | Embedding (e5-large) + Re-Ranking | ~4 GB |
Software¶
- Ubuntu 22.04 oder 24.04 LTS
- Docker >= 24.0 und Docker Compose v2
- NVIDIA-Treiber >= 535
- NVIDIA Container Toolkit
- Git
- Python 3.11+ (nur für Indexierung und Entwicklung)
Erstinstallation¶
1. Repository klonen¶
2. Umgebungsvariablen konfigurieren¶
Folgende Werte in .env anpassen:
| Variable | Beschreibung | Aktion |
|---|---|---|
POSTGRES_PASSWORD |
Datenbankpasswort | Sicheres Passwort setzen |
MINIO_ROOT_PASSWORD |
MinIO-Admin-Passwort | Sicheres Passwort setzen |
GRAFANA_ADMIN_PASSWORD |
Grafana-Admin-Passwort | Sicheres Passwort setzen |
VLLM_MODEL |
LLM-Modell | Standard: Qwen/Qwen2.5-7B-Instruct |
CORS_ORIGINS |
Erlaubte Origins | AVS-Domains eintragen |
3. Stack starten¶
Beim Erststart werden Docker-Images heruntergeladen und das LLM-Modell von HuggingFace geladen. Dies kann 10-30 Minuten dauern (je nach Internetverbindung).
4. Status prüfen¶
Warten bis alle Services den Status healthy zeigen. vLLM braucht am längsten (~5 Min. für Model-Loading).
5. Dokumente indexieren¶
# Dokumente in data/documents/ ablegen
cp /pfad/zu/handbuecher/*.pdf data/documents/
# Indexierung starten
python scripts/index_documents.py data/documents/
6. API verifizieren¶
curl -X POST http://localhost:8080/api/v1/query \
-H "Content-Type: application/json" \
-d '{"question": "Wie konfiguriere ich das Gerät?"}'
7. Widget einbetten¶
Das Chat-Widget auf der AVS-Website einbinden:
<script src="https://chatbot.avs.de/widget/avs-chat-widget.min.js"></script>
<avs-chat-widget api-url="https://chatbot.avs.de/api/v1"></avs-chat-widget>
Updates¶
Standard-Update¶
cd /opt/avs-chatbot
# Neuesten Stand holen
git pull origin main
# Services neu bauen und starten
docker compose build
docker compose up -d
# Health-Check
curl http://localhost:8080/health
Widget-Update¶
cd src/widget
npm install
npm run build
# dist/avs-chat-widget.min.js wird automatisch über Nginx ausgeliefert
Modell-Wechsel¶
Um ein anderes LLM-Modell zu verwenden:
# .env anpassen
VLLM_MODEL=Qwen/Qwen3-14B
# vLLM-Service neu starten
docker compose up -d vllm
# Warten bis healthy (~5-10 Min.)
Backup und Recovery¶
Was muss gesichert werden?¶
| Service | Daten | Backup-Priorität |
|---|---|---|
| Qdrant | Vektordatenbank (indexierte Chunks) | Mittel (kann neu indexiert werden) |
| PostgreSQL | Sessions, Feedback, Metadaten | Hoch |
| MinIO | Originaldokumente | Hoch (falls einzige Kopie) |
| Redis | Response-Cache | Niedrig (regeneriert sich automatisch) |
Backup-Befehle¶
PostgreSQL:
Qdrant:
# Snapshot erstellen
curl -X POST http://localhost:6333/collections/avs_handbuecher/snapshots
# Snapshot-Dateien liegen im Docker-Volume avs-qdrant-data
MinIO:
docker exec avs-minio mc mirror /data /backup
# Oder direkt das Docker-Volume sichern:
docker run --rm -v avs-minio-data:/data -v $(pwd):/backup alpine tar czf /backup/minio_$(date +%Y%m%d).tar.gz /data
Recovery¶
PostgreSQL wiederherstellen:
Qdrant wiederherstellen:
# Snapshot-Datei wiederherstellen
curl -X PUT http://localhost:6333/collections/avs_handbuecher/snapshots/recover \
-H "Content-Type: application/json" \
-d '{"location": "/qdrant/storage/snapshots/<snapshot-name>"}'
Alternativ — Neu-Indexierung:
Monitoring¶
Dashboards¶
| Service | URL | Zugangsdaten |
|---|---|---|
| Grafana | http://server:3000 | admin / (aus .env) |
| Prometheus | http://server:9090 | Kein Login |
| Qdrant Dashboard | http://server:6333/dashboard | Kein Login |
| MinIO Console | http://server:9001 | aus .env |
Wichtige Metriken¶
| Metrik | Beschreibung | Alarm-Schwelle |
|---|---|---|
avs_query_duration_seconds |
Query-Latenz | p95 > 10s |
avs_cache_hits_total / avs_cache_misses_total |
Cache-Hit-Rate | < 30% |
avs_guardrail_rejections_total |
Geblockte Anfragen | > 50/h (Angriff?) |
avs_no_retrieval_match_total |
Fragen ohne Treffer | > 20% (fehlende Docs?) |
| GPU-Auslastung | nvidia-smi |
> 90% dauerhaft |
| Qdrant Speicher | Collection-Größe | > 80% Disk |
Metriken-Endpoint¶
Troubleshooting¶
vLLM startet nicht¶
Symptom: Container avs-vllm startet nicht oder bleibt im Status starting.
# Logs prüfen
docker compose logs vllm
# Häufige Ursachen:
# 1. VRAM reicht nicht aus
nvidia-smi # VRAM-Verbrauch prüfen
# 2. Modell nicht gefunden / Download fehlgeschlagen
docker exec avs-vllm ls /root/.cache/huggingface/
# 3. CUDA-Version inkompatibel
docker exec avs-vllm nvidia-smi
Lösung: Kleineres Modell in .env setzen (Qwen/Qwen2.5-7B-Instruct) oder GPU-Memory-Utilization anpassen.
Qdrant nicht erreichbar¶
# Status prüfen
docker compose logs qdrant
curl http://localhost:6333/readiness
# Häufige Ursache: Disk Space
df -h # Festplattenplatz prüfen
Langsame Antworten¶
-
GPU-Auslastung prüfen:
-
Cache-Hit-Rate prüfen:
Bei niedriger Hit-Rate: TTL erhöhen oder häufige Fragen vorwärmen. -
Latenz-Benchmark:
Widget lädt nicht¶
-
CORS prüfen: Nginx muss
Access-Control-Allow-Originfür die AVS-Domain setzen. -
Netzwerk prüfen: Widget muss die API-URL erreichen können.
-
Browser-Konsole: Fehlermeldungen in den Browser DevTools prüfen (F12).
Redis-Cache leeren¶
# Gesamten Cache leeren (z.B. nach Dokument-Änderungen):
docker exec avs-redis redis-cli FLUSHALL
# Nur AVS-Cache-Keys leeren:
docker exec avs-redis redis-cli --scan --pattern "avs:cache:*" | xargs -r docker exec -i avs-redis redis-cli DEL
Lasttests ausführen¶
Lasttests mit k6 prüfen die API unter simulierter Last.
Voraussetzungen:
- k6 installiert (k6 version)
- Stack läuft (docker compose up -d)
- Optional: LOADTEST_SECRET in .env gesetzt (umgeht Rate Limiting)
# Alle drei Szenarien nacheinander:
make loadtest
# Einzelnes Szenario:
k6 run --env SCENARIO=baseline tests/load/loadtest.js
k6 run --env SCENARIO=rampup tests/load/loadtest.js
k6 run --env SCENARIO=spike tests/load/loadtest.js
# Mit Rate-Limit-Bypass:
k6 run --env SCENARIO=baseline --env LOADTEST_SECRET=your_secret tests/load/loadtest.js
Szenarien: | Szenario | VUs | Dauer | Ziel | |----------|-----|-------|------| | baseline | 10 | 5 min | Normalbetrieb | | rampup | 5→50 | 10 min | Skalierungsgrenze finden | | spike | 100→10 | 5 min | Recovery-Verhalten |
Schwellwerte (Dev-Server): p95 < 15s, Error-Rate < 5%, Rate-Limited < 10%
Staging-Checklist¶
Vor der Übergabe an AVS die automatisierte Checklist ausführen:
Prüft 16 Punkte: API-Health, Qdrant, vLLM, Redis, PostgreSQL, Admin-Auth, Widget, DE/EN-Queries, Cache, Feedback, Rate Limiting, Guardrails, Prometheus Metriken, Grafana.
Ergebnis: PASS (alle Checks grün) oder FAIL mit Details.
Sicherheits-Audit¶
Automatisierte Sicherheitsprüfung:
Prüft: .env nicht im Git, Admin-Passwort gesetzt, CORS-Origins,
IP-Hashing, PII in Logs, Rate Limiting aktiv, Guardrails aktiv,
Health/Metrics-Endpoints korrekt konfiguriert.