docs: add BEDIENUNGSANLEITUNG.md and INSTALL_FROM_ARCHIVE.md

Vollständige deutschsprachige Bedienungsanleitung (Installation, Konfiguration,
alle fünf Aktionen, Prompt-Quellen, Antwort-/Reasoning-Steuerung, Netzwerk/
Sicherheit, GPU/Kontext, Exit-Codes, Fehlersuche, Tests) sowie eine Anleitung
zur Installation aus dem .tar.gz-Archiv.

build_archive.py: beide Anleitungen in INCLUDE_FILES + REQUIRED_FILES (werden
gepackt und verifiziert).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-07-06 17:48:39 +02:00
commit b8ea6545f8
3 changed files with 401 additions and 0 deletions

283
BEDIENUNGSANLEITUNG.md Normal file
View file

@ -0,0 +1,283 @@
# Bedienungsanleitung — llamacppctl
`llamacppctl` startet, prüft, stoppt, wechselt und promptet einen
**llama.cpp-Server, der als Docker-Container** läuft — über **eine** CLI statt
mehrerer Shell-Skripte. Die OpenAI-kompatible API des Servers ist standardmäßig
nur auf `127.0.0.1` erreichbar.
Diese Anleitung deckt **Installation** und **Benutzung** vollständig ab. Zur
Installation aus dem fertigen Archiv siehe zusätzlich
[`INSTALL_FROM_ARCHIVE.md`](INSTALL_FROM_ARCHIVE.md). Details zum Sicherheits-
und Betriebsmodell stehen in [`docs/SECURITY_AND_OPERATIONS.md`](docs/SECURITY_AND_OPERATIONS.md);
die vollständige Optionsreferenz in der Manpage (`man/llamacppctl.1`).
---
## 1. Voraussetzungen
- **Docker** (Daemon läuft, Nutzer in der `docker`-Gruppe): `docker version` muss funktionieren.
- **NVIDIA-GPU** + Treiber + **NVIDIA Container Toolkit** (damit `--gpus` im Container greift): `nvidia-smi` funktioniert, und `docker run --rm --gpus all <cuda-image> nvidia-smi` zeigt die GPU.
- **Python ≥ 3.10**.
- Ein **GGUF-Modell** auf dem Host, das read-only in den Container gemountet wird.
- Das Docker-Image, z. B. `ghcr.io/ggml-org/llama.cpp:server-cuda` (wird beim ersten Start automatisch gezogen).
---
## 2. Installation
### 2.1 Aus dem Quellcode (empfohlen für Entwicklung)
```bash
cd llamacppctl
python3 -m venv .venv
source .venv/bin/activate
pip install -e . # editable: CLI == Quellcode in src/
# optional für Tests:
pip install -e ".[dev]"
```
> **Wichtig:** Bei `pip install .` (ohne `-e`) läuft das CLI aus einer Kopie in
> `site-packages` — Änderungen an `src/` wirken dann NICHT. Für Entwicklung immer
> `-e` verwenden. Kontrolle: `python -c "import llamacppctl.actions as a; print(a.__file__)"`
> muss auf `src/` zeigen.
### 2.2 Aus dem Archiv
Siehe [`INSTALL_FROM_ARCHIVE.md`](INSTALL_FROM_ARCHIVE.md).
### 2.3 Installation prüfen (ohne Docker)
```bash
llamacppctl --help
llamacppctl --print-effective-config --config llama.cpp.config --start --dry-run
```
---
## 3. Konfiguration
### 3.1 Datei anlegen
```bash
cp llama.cpp.config.example llama.cpp.config
# llama.cpp.config an den Host anpassen (Pfade, GPU, Ports)
```
Der Standard-Pfad ist `llama.cpp.config` im aktuellen Verzeichnis, überschreibbar
mit `--config <pfad>`.
### 3.2 Aufbau (INI)
- `[default]` — globale Werte, überschreiben die eingebauten Defaults.
- `[model.<name>]` — ein Modell-Profil, gewählt mit `--profile <name>`.
- `[prompt.<name>]` — ein *Fallback*-Systemprompt, gewählt mit `--system-prompt-profile <name>` (ein explizites `-s`/`--system-file`/`--system-url` gewinnt immer).
**Auflösungsreihenfolge** (niedrig → hoch): eingebaute Defaults → `[default]`
`[model.<profile>]` → CLI-Overrides.
### 3.3 Wichtige Felder
| Feld / CLI | Bedeutung |
|---|---|
| `image` / `--image` | Docker-Image (z. B. `ghcr.io/ggml-org/llama.cpp:server-cuda`) |
| `hf_home` / `--hf-home` | Host-Verzeichnis, read-only gemountet. **Env-Variablen erlaubt**, z. B. `hf_home = ${HF_HOME}` |
| `model_path` / `--model-path` | Modellpfad, relativ zu `hf_home` (oder absolut) |
| `container_name` / `--container-name` | **Pflicht**, eindeutig pro parallel laufendem Profil (Identitätsanker für Naming/Lock/Stop/Check) |
| `host_port` / `--host-port` | Host-Port (165535) |
| `container_port` / `--container-port` | Container-interner Port |
| `model_alias` / `--model-alias` | Modell-Alias in der API |
| `gpu_device` / `--gpu` | GPU-Device für `--gpus device=<id>` (auch mehrere: `1,2`) |
| `ctx_size` / `--ctx-size` | Kontextfenster (KV-Cache wächst damit) |
| `n_predict` / `--n-predict` | Server-seitige max. Vorhersage-Tokens |
| `temp`, `top_p`, `top_k`, `min_p`, `repeat_penalty` | Sampling (beim Start in den Container gebacken) |
| `expose` / `--expose` / `--no-expose` | Port auf allen Interfaces (LAN) statt nur `127.0.0.1`. **Default: aus** |
| `api_key` / `--api-key` | API-Key: Server verlangt ihn, Tool sendet ihn als Bearer-Token |
| `max_tokens` / `--max-tokens` | Antwortbudget für `--chat`/`--start`-Antwort (Default 2048) |
| `chat_temperature` / `--chat-temp` | Temperatur des Chat-Requests (leer = Server-`temp`) |
| `timeout` / `--timeout` | Readiness-Timeout in Sekunden |
| `reasoning` / `--reasoning {on,off}` | Reasoning-Modus |
Boolean-Schalter mit Paar-Form: `--jinja/--no-jinja`, `--fa/--no-fa`,
`--kv-unified/--no-kv-unified`, `--cont-batching/--no-cont-batching`,
`--no-context-shift/--context-shift`.
### 3.4 Beispiel
```ini
[default]
image = ghcr.io/ggml-org/llama.cpp:server-cuda
hf_home = ${HF_HOME}
model_path = models/qwen3/mein-modell-Q4_K_M.gguf
model_alias = mein_llm
container_name = llama_cpp_server
host_port = 8001
gpu_device = 1
ctx_size = 65536
max_tokens = 8192
[prompt.knapp]
system_prompt = Antworte kurz, präzise und technisch.
[model.zweitmodell]
model_path = models/qwen3/anderes-modell.gguf
model_alias = zweit_llm
container_name = llama_cpp_zweit
host_port = 8002
gpu_device = 2
```
---
## 4. Die fünf Aktionen
Genau **eine** Aktion pro Aufruf ist erforderlich.
### `--start` — Server starten
Entfernt einen vorhandenen Container gleichen Namens, startet neu, wartet per
echter Chat-Completion auf Readiness (nicht nur offener Port). Läuft unter Lock.
```bash
llamacppctl --start
llamacppctl --start --profile zweitmodell
llamacppctl --start -p "Sag kurz Hallo." # + Testantwort nach dem Start
llamacppctl --start --dry-run # nur das docker-run-Kommando zeigen
```
### `--check` — Status prüfen
Zeigt Container-/HTTP-Status; mit User-Prompt zusätzlich eine echte Chat-Probe.
**Scriptbar:** Exit 0 = läuft & erreichbar, sonst 5.
```bash
llamacppctl --check
llamacppctl --check -p "ping" && echo "OK" || echo "nicht bereit"
```
### `--stop` — Container stoppen und entfernen
```bash
llamacppctl --stop
llamacppctl --stop --force # auch bei Inkonsistenzen entfernen
```
### `--change` — Modell/Config wechseln
Stoppt, konfiguriert neu, startet — unter Lock. **Validiert den Modellpfad,
bevor** der laufende Container entfernt wird (kein unnötiger Ausfall).
```bash
llamacppctl --change --profile zweitmodell
llamacppctl --change --model-path models/qwen3/neues-modell.gguf --ctx-size 32768
```
### `--chat` — an laufenden Server prompten
```bash
llamacppctl --chat -p "Was ist 2+2?"
llamacppctl --chat -s "Du antwortest nur mit Zahlen." -p "Wie viel ist 6*7?"
llamacppctl --chat --stream -p "Schreibe eine kurze Geschichte."
```
---
## 5. Prompts (System & User)
Pro Feld genau **eine** Quelle:
| System-Prompt | User-Prompt | Quelle |
|---|---|---|
| `-s`, `--system` | `-p`, `--prompt` | Literaler Text |
| `--system-file` | `--prompt-file` | Lokale Datei (nur reguläre Dateien, UTF-8, Größenlimit) |
| `--system-url` | `--prompt-url` | HTTPS-URL (SSRF-gehärtet) |
```bash
llamacppctl --chat --system-file ./prompts/reviewer.md --prompt-file ./frage.txt
llamacppctl --start --system-prompt-profile knapp -p "Erkläre Backups."
```
URL-Quellen sind standardmäßig HTTPS-only, blockieren private/loopback/metadata-
IPs und Redirects; Details in `docs/SECURITY_AND_OPERATIONS.md`.
---
## 6. Antwortsteuerung & Reasoning
- `--max-tokens N` — Budget der Antwort (Default 2048).
- `--chat-temp F` — Temperatur des Requests (sonst gilt die Server-`temp`).
- `--stream` — Tokens live auf stdout, während sie generiert werden.
> **Reasoning-Modelle** (z. B. Qwen3.x mit `reasoning = on`) „denken" erst
> intern (oft mehrere tausend Tokens) und geben **dann** die eigentliche
> Antwort. Ist `--max-tokens` zu klein, endet die Generierung im Denken und der
> sichtbare `content` bleibt **leer** — das Tool warnt dann
> (`finish_reason=length`). Für lange Texte großzügig setzen (z. B. `--max-tokens 8000`).
---
## 7. Netzwerk & Sicherheit (Kurz)
- Der Port wird per Default nur auf **`127.0.0.1`** veröffentlicht — die
unauthentifizierte API ist **nicht** im LAN erreichbar.
- Für LAN-Zugriff: `--expose`/`expose = true`. **Dann unbedingt** `--api-key`/`api_key` setzen.
- Mit Key schützt llama.cpp `/v1/chat/completions` (ohne Key → 401); `/health`
und `/v1/models` bleiben bewusst offen (für Health-Checks).
- `hf_home` wird **read-only** gemountet; alle Docker-Aufrufe nutzen
Argumentlisten (keine Shell-Injection).
---
## 8. GPU & Kontextgröße
- Ein Modell muss samt KV-Cache in den GPU-Speicher passen. Der KV-Cache wächst
linear mit `ctx_size` und wird beim Laden komplett allokiert.
- Mehrere GPUs: `gpu_device = 1,2` (bzw. `--gpu 1,2`) verteilt das Modell.
- Vor einer Änderung mit `--dry-run` das Kommando prüfen, mit
`--print-effective-config` die aufgelösten Werte kontrollieren.
---
## 9. Exit-Codes
| Code | Bedeutung |
|---|---|
| 0 | Erfolg (bzw. `--check`: läuft & erreichbar) |
| 1 | Allgemeiner Fehler / leere Antwort trotz Budget |
| 2 | CLI-/Argument-Fehler |
| 3 | Modelldatei nicht gefunden |
| 4 | Docker-Fehler |
| 5 | HTTP/Readiness nicht bereit (auch `--check`, wenn nicht erreichbar) |
| 6 | Lock belegt (anderer `--start`/`--change` läuft; ggf. `--force`) |
---
## 10. Fehlersuche
| Symptom | Ursache | Lösung |
|---|---|---|
| `docker is not available on PATH` | Docker-CLI/-Daemon fehlt | Docker installieren/starten, Nutzer in `docker`-Gruppe |
| `model file not found: …` | `model_path`/`hf_home` falsch | Pfade prüfen; `${HF_HOME}` gesetzt? |
| `Server did not become ready within <n>s` | Modell lädt langsam / OOM | `--timeout` erhöhen, `--logs` für Log-Tail, ggf. `ctx_size` senken |
| Leere Antwort + Hinweis `finish_reason=length` | Reasoning verbraucht das Budget | `--max-tokens` erhöhen |
| `HTTP 401: Invalid API Key` | Server verlangt Key | `--api-key`/`api_key` passend setzen |
| `lock busy: …` | Paralleler `--start`/`--change` | warten oder `--force` (hängender Lock) |
| `--check` zeigt `health=unhealthy`, Server antwortet aber | bildeigener Docker-Healthcheck ≠ HTTP-Probe | unkritisch: `HTTP: OK` + Exit 0 zählt |
---
## 11. Tests
```bash
pip install -e ".[dev]"
pytest -q # Unit-Tests (kein Docker nötig)
```
End-to-End gegen einen echten Server (opt-in, braucht Docker + GPU + Modell):
```bash
SMOKE_GPU=1 scripts/smoke.sh
```
---
## 12. Weiterführend
- `man/llamacppctl.1` — vollständige Optionsreferenz (`man ./man/llamacppctl.1`).
- `docs/SECURITY_AND_OPERATIONS.md` — Architektur, Sicherheits- und Betriebsmodell.
- `README.md` — Kurzüberblick.
- `INSTALL_FROM_ARCHIVE.md` — Installation aus dem `.tar.gz`-Archiv.

114
INSTALL_FROM_ARCHIVE.md Normal file
View file

@ -0,0 +1,114 @@
# Installation aus dem Archiv — llamacppctl
Diese Anleitung beschreibt, wie du `llamacppctl` aus dem fertigen Archiv
`llamacppctl-installable.tar.gz` installierst. Für die vollständige Bedienung
siehe [`BEDIENUNGSANLEITUNG.md`](BEDIENUNGSANLEITUNG.md).
---
## 1. Voraussetzungen auf der Zielmaschine
- **Python ≥ 3.10** (`python3 --version`)
- **Docker** mit erreichbarem Daemon (`docker version`)
- **NVIDIA-GPU** + Treiber + **NVIDIA Container Toolkit** (für `--gpus`)
- Ein **GGUF-Modell** auf dem Host
> Für einen reinen Konfigurations-/Trockenlauf (`--print-effective-config`,
> `--dry-run`) reicht Python; Docker/GPU/Modell werden erst für echte
> `--start`/`--check`/`--chat`-Aufrufe gebraucht.
---
## 2. Integrität prüfen (optional, empfohlen)
```bash
gzip -t llamacppctl-installable.tar.gz && echo "Archiv OK"
tar tzf llamacppctl-installable.tar.gz | head # Inhalt ansehen
```
Das Archiv enthält ausschließlich Quellcode, Tests, Doku, Manpage,
`llama.cpp.config.example` und `scripts/smoke.sh`**keine** persönliche
`llama.cpp.config`, keine `.venv`, keine `.git`-Historie und keine Geheimnisse.
---
## 3. Entpacken und installieren
```bash
tar xzf llamacppctl-installable.tar.gz
cd llamacppctl
python3 -m venv .venv
source .venv/bin/activate
pip install .
```
Danach steht das Konsolen-Kommando `llamacppctl` zur Verfügung:
```bash
llamacppctl --help
```
> Zum Entwickeln stattdessen `pip install -e ".[dev]"` (editable + Tests).
---
## 4. Konfiguration anlegen
```bash
cp llama.cpp.config.example llama.cpp.config
# llama.cpp.config an den Host anpassen: hf_home (z. B. ${HF_HOME}),
# model_path, gpu_device, host_port, container_name …
```
Auflösung prüfen, ohne etwas zu starten:
```bash
llamacppctl --print-effective-config --config llama.cpp.config --start --dry-run
```
Das zeigt die vollständig aufgelöste Konfiguration als JSON **und** das
`docker run`-Kommando, das `--start` ausführen würde.
---
## 5. Erststart
```bash
llamacppctl --start --config llama.cpp.config
llamacppctl --check --config llama.cpp.config
llamacppctl --chat --config llama.cpp.config -p "Sag kurz Hallo."
```
Weitere Aktionen, Optionen und Fehlersuche: [`BEDIENUNGSANLEITUNG.md`](BEDIENUNGSANLEITUNG.md).
---
## 6. Tests (optional)
```bash
pip install -e ".[dev]"
pytest -q
```
---
## 7. Archiv selbst neu bauen / verifizieren
Das Archiv wird reproduzierbar von `build_archive.py` erzeugt. Es
1. prüft, ob alle erforderlichen Projektdateien vorhanden sind,
2. gleicht die deklarierten Abhängigkeiten in einer frischen venv ab,
3. lässt die komplette Test-Suite laufen,
4. baut das `.tar.gz` (nur Allowlist: `src/ tests/ docs/ man/ scripts/` + `pyproject.toml`, `README.md`, `requirements*.txt`, `llama.cpp.config.example`, `build_archive.py`, `BEDIENUNGSANLEITUNG.md`, `INSTALL_FROM_ARCHIVE.md`),
5. öffnet das Archiv erneut und verifiziert die enthaltenen Dateien,
6. installiert das Paket aus dem Archiv in einer weiteren frischen venv und testet das Konsolenskript.
```bash
python3 build_archive.py # -> ../llamacppctl-installable.tar.gz
python3 build_archive.py --output /pfad/x.tar.gz
python3 build_archive.py --skip-pip-check --skip-smoke-test # ohne Netz-Schritte
```
Weil `build_archive.py` selbst im Archiv liegt, lässt sich das Archiv jederzeit
unabhängig neu bauen und verifizieren.

View file

@ -72,6 +72,8 @@ REQUIRED_FILES = [
"tests/test_actions.py", "tests/test_actions.py",
"docs/How_to_use.md", "docs/How_to_use.md",
"scripts/smoke.sh", "scripts/smoke.sh",
"BEDIENUNGSANLEITUNG.md",
"INSTALL_FROM_ARCHIVE.md",
] ]
# Top-level directories to include wholesale (in addition to REQUIRED_FILES), # Top-level directories to include wholesale (in addition to REQUIRED_FILES),
@ -85,6 +87,8 @@ INCLUDE_FILES = [
"requirements-dev.txt", "requirements-dev.txt",
"llama.cpp.config.example", "llama.cpp.config.example",
"build_archive.py", "build_archive.py",
"BEDIENUNGSANLEITUNG.md",
"INSTALL_FROM_ARCHIVE.md",
] ]
EXCLUDE_DIR_NAMES = {"__pycache__", ".pytest_cache", ".venv", "venv", ".git", "*.egg-info"} EXCLUDE_DIR_NAMES = {"__pycache__", ".pytest_cache", ".venv", "venv", ".git", "*.egg-info"}