175 lines
12 KiB
Markdown
175 lines
12 KiB
Markdown
# Eigener OpenAI-kompatibler Endpunkt
|
||
|
||
Die Übersicht steuert den API-Listener: Start, Stopp, Erreichbarkeit, Port,
|
||
aktivierte/ausführbare Profile pro Kategorie und tatsächlich geladener Worker.
|
||
Die Demo-API wurde entfernt. Einstellungen → **Endpunkt & Profile** konfiguriert
|
||
Port und Veröffentlichungen. Alternativ kann jedes ausführbare Profil direkt
|
||
im Profileditor am Endpunkt aktiviert werden. Neue Profile sind standardmäßig
|
||
nicht veröffentlicht. Profilfreigabe lädt noch keine Gewichte.
|
||
|
||
## Zugriff und Port
|
||
|
||
UI und Inferenz-API sind getrennte Listener. Standard für Inferenz: **8120**.
|
||
Der vorhandene Deck-API-Token gilt für alle Inferenzrouten; Kennwort/Cookie gelten
|
||
nur für die Verwaltung. Tokenrotation wirkt sofort auf neue Anfragen. Keine
|
||
Token, Prompts oder Antworten werden in Zugriffslogs geschrieben. Intern erhält
|
||
llama.cpp einen unabhängigen kurzlebigen Schlüssel in einer Datei mit Modus 0600.
|
||
|
||
Die aktuelle Docker-Testinstallation veröffentlicht ausschließlich Host-Loopback
|
||
**8120–8124**. Innerhalb dieses Bereichs ist der Port bei gestopptem Endpunkt
|
||
in der GUI frei wählbar. Der Installer prüft neue Ports vor dem Ersetzen des
|
||
eigenen Containers; vorhandene fremde Dienste werden nie gestoppt.
|
||
Anderer Bereich: `./install.sh --update --api-ports 8130-8134 --directory <Installation>`.
|
||
Danach gegebenenfalls den gespeicherten API-Port in der GUI korrigieren.
|
||
Bei nativem Betrieb ist jeder freie Port 1024–65535 möglich; standardmäßig wird
|
||
nur an 127.0.0.1 gebunden. Kein automatischer Firewall-, WireGuard- oder DNS-Umbau.
|
||
|
||
Auf dem Arbeitsplatz für API-Zugriff, zusätzlich zum bestehenden UI-Tunnel:
|
||
|
||
```sh
|
||
ssh -i /Users/mike_i386/.ssh/athena_key -o BatchMode=yes \
|
||
-o ExitOnForwardFailure=yes -o ServerAliveInterval=30 \
|
||
-N -L 8120:127.0.0.1:8120 root@192.168.1.212
|
||
```
|
||
|
||
Client-Basisadresse: `http://127.0.0.1:8120/v1`. Bei Portänderung den Tunnel
|
||
entsprechend anpassen. Der Endpunkt merkt sich Start/Stopp; nach regulärem
|
||
Deck-Neustart startet nur der Listener automatisch, kein Modell.
|
||
|
||
## Routen
|
||
|
||
Alle Inferenzrouten benötigen `Authorization: Bearer <Deck-API-Token>`.
|
||
|
||
| Methode | Pfad | Verhalten |
|
||
|---|---|---|
|
||
| GET | `/v1/models` | Nur freigegebene, ausführbare Chatprofile; kein Modellstart |
|
||
| GET | `/health` | Listener-Health, ebenfalls authentifiziert |
|
||
| POST | `/v1/chat/completions` | Textchat, JSON und SSE-Streaming, Sampling-Defaults aus dem Profil |
|
||
| POST | `/v1/images/generations` | Qwen-Image-2.1-Rezept, n=1, `b64_json` |
|
||
| POST | `/v1/audio/speech` | Qwen3-TTS CustomVoice, WAV-Ausgabe |
|
||
| POST | `/v1/audio/transcriptions` | Qwen3-ASR, Multipart-WAV → JSON-Transkript |
|
||
|
||
`model` ist immer der **API-Profilname**, nicht der GGUF-Dateiname. Bildaufträge
|
||
verwenden die gespeicherte Auflösung, Schritte, Guidance und Seed; eine explizite
|
||
`size` muss der Profilauflösung entsprechen. Das Bild liegt wie beim GUI-Test im
|
||
eigenen Jobverzeichnis. Kein Bildprompt wird persistiert; PNG-Metadaten sind
|
||
deaktiviert. n=1; Ausgabe zunächst als Base64, keine öffentlich abrufbaren Bild-URLs.
|
||
Die API ist bewusst ein Teilumfang: noch keine `/v1/responses`, Embeddings,
|
||
Vision-Eingaben, Bildbearbeitung, Video oder Musik-/Voice-Worker. TTS/STT benötigen keinen
|
||
eigenen Port, sondern eigene Routen und Worker hinter demselben Listener.
|
||
|
||
Chat akzeptiert übliche Nachrichten, Tools, response_format, Sampling-Overrides
|
||
und Streaming-Optionen; unbekannte Erweiterungsfelder werden abgelehnt. Maximal
|
||
1 MiB JSON pro Anfrage, 16 MiB gepufferte Chatantwort. Keine Chunked-Uploads oder
|
||
Cross-Origin-Browserfreigabe. Internes llama.cpp-HTTP-Zeitlimit: 120 Sekunden ohne
|
||
Antwortdaten, maximal 600 Sekunden für laufende SSE-Ausgabe.
|
||
|
||
## Prozesssteuerung und Speicher
|
||
|
||
- Eigener nativer llama-server aus dem gewählten, geprüften CUDA-Build. Kein
|
||
produktiver Container wird gestartet, gestoppt oder umkonfiguriert.
|
||
- Start erfolgt nach Anfrage. Mehrere Profile dürfen dieselbe Modelldatei nutzen.
|
||
Ein anderes Profil bzw. eine neue Profilrevision entlädt zunächst den eigenen
|
||
Worker und startet ihn mit den gespeicherten Parametern neu.
|
||
- FIFO-Warteschlange (maximal 16 wartende Aufträge, 600 Sekunden Wartezeit).
|
||
Gleiches Chatprofil darf bis zur konfigurierten Slotzahl parallel antworten.
|
||
Ein wartender Wechsel verhindert, dass neue Chats ihn dauerhaft überholen.
|
||
Streaming hält die Modellreservierung bis zum Ende der Ausgabe.
|
||
- Bildaufträge benötigen beide freien GPUs. GUI-Bildtests und API nutzen dieselbe
|
||
Reservierung. GUI meldet bei belegter Reservierung einen Konflikt; API wartet.
|
||
Das Sprachmodell wird vor Bildgenerierung entladen. ComfyUI wird nach jedem Bild
|
||
vollständig beendet; die nächste Textanfrage lädt ihr Profil erneut.
|
||
- Stoppen nimmt keine neuen Anfragen an, verwirft wartende Anfragen und lässt
|
||
bereits laufende Antworten/Generierungen fertig werden, dann wird entladen.
|
||
SIGTERM beendet eigene Worker. Keine Garantie für SIGKILL bei nativem Betrieb;
|
||
das spätere systemd-Paket muss Prozesse über seine Cgroup vollständig aufräumen.
|
||
- GPU-Auswahl über UUID-Reihenfolge; busy GPUs werden abgewiesen. Speicherprüfung
|
||
vor jedem Start: reale freie GPU-/RAM-Kapazität, Cgroup-Limit, Reserven. Inaktiver,
|
||
reclaimbarer Dateicache wird vom Cgroup-Verbrauch abgezogen, anonyme Belegung nicht.
|
||
Ein zusätzlicher GPU-Prozess während des Betriebs beendet nur den Deck-Worker.
|
||
- llama.cpp: Gesamtkontext und Slots bleiben unverändert. Shared KV (`--kv-unified`),
|
||
K/V q4_0, Flash Attention on, load-mode none; derzeit diese festen Backend-Defaults.
|
||
Fit ist eine **Prognose**, kein OOM-Test. Feste Tensor-Splits werden separat per
|
||
`--fit-print` geprüft; falls nötig wird in höchstens zehn Schritten eine passende
|
||
GPU-Layerzahl gesucht. Verhältnisse und Kontext werden dabei nicht umgeschrieben.
|
||
Ohne feste Verteilung verwendet Deck die geprüften Fit-Parameter des Builds.
|
||
|
||
Aktive Modellstarts bleiben an freie Ressourcen gebunden. Der alte Router kann
|
||
weiterlaufen; fordert er dieselben GPUs an, beendet Deck bei erkanntem Konflikt
|
||
seinen eigenen Worker. Das ersetzt keine serverweite Ressourcenkoordination.
|
||
|
||
## Interne Verwaltungs-API
|
||
|
||
Nur angemeldete Oberflächensitzungen plus `X-Athena-Deck: 1`, kein API-Token:
|
||
|
||
| Methode | Route | JSON |
|
||
|---|---|---|
|
||
| GET | `/api/v1/endpoint` | Status, Port, Zähler, Worker, Warteschlange, Profile |
|
||
| POST | `/api/v1/endpoint/start` | `{}` |
|
||
| POST | `/api/v1/endpoint/stop` | `{}` |
|
||
| POST | `/api/v1/endpoint/config` | `{"port":8120}`; nur gestoppt |
|
||
| POST | `/api/v1/endpoint/profile` | `{"id":"<Profil-ID>","enabled":true}` |
|
||
|
||
Persistenz: `endpoint.json` im Deck-Zustandsverzeichnis. Aktivierte, später
|
||
unvollständige/gelöschte Profile verschwinden aus `/v1/models`; bestehende Requests
|
||
nutzen ihren konsistenten Profilsnapshot. Wartende Requests eines geänderten oder
|
||
deaktivierten Profils werden abgewiesen. Aktive Buildänderungen gelten nach dem
|
||
nächsten Entladen; Modellprofile selbst werden nicht automatisch verändert.
|
||
|
||
## Verifiziert am 28.09.2026
|
||
|
||
Isolierte HTTP-/Scheduler-Tests: Tokenrotation, Adminschutz, explizite Freigabe,
|
||
Profilwechsel, Streaming-Leases, ungültige Anfragen, Warteschlange und Portkonflikte.
|
||
GUI: Freigabe, Start/Stopp, Status und Portformular.
|
||
|
||
Echter Test auf Athena mit separaten Testprofilen und synthetischen Eingaben:
|
||
Qwen IQ4_XS Pure, Medium 160000/2 Slots/85:15 → zweites Profil 4096/1 Slot mit SSE
|
||
→ Qwen-Image-Rezept (512×512, 4 Schritte) → LLM. PNG geprüft; anschließend eigener
|
||
Listener gestoppt und Modell entladen. Keine vorhandenen Nutzerprompts oder
|
||
Anwendungslogs gelesen. Testprofile und Testzugang gehören nicht zur normalen
|
||
Deck-Konfiguration. Der Test weist keine vollständige OpenAI-Kompatibilität oder
|
||
Langzeitstabilität nach.
|
||
|
||
|
||
## Sprachmodelle → Testen
|
||
|
||
Der interne Testchat verwendet denselben Scheduler und llama.cpp-Worker wie der
|
||
API-Endpunkt, braucht aber keine Veröffentlichung des Profils und keinen
|
||
API-Token im Browser. Profilauswahl, fortlaufender Textchat, Antwortlimit (bis
|
||
4096 Token), Abbrechen und explizites Entladen stehen bereit. Der Modellprozess
|
||
bleibt nach einer Antwort geladen; andere Profile/Bildaufträge wechseln regulär.
|
||
Entladen wird bei aktiven Anfragen abgewiesen. Abbrechen schließt nur die eigene
|
||
Chatverbindung; während des eigenen Modellstarts bricht es diesen Start ab.
|
||
|
||
Der Verlauf liegt nur im Browser-Arbeitsspeicher. Beim Wechsel der Ansicht oder
|
||
des Profils beginnt ein neuer Verlauf. Der Server hält nur den aktuellen Testjob
|
||
mit gestreamter Antwort vorübergehend im RAM; weder Prompt noch Antwort werden
|
||
als Chatdatei oder Log gespeichert. Reguläre Admin-Sitzung/CSRF-Schutz gelten für
|
||
GET `/api/v1/chat-tests` und POST `/api/v1/chat-tests/start`, `/cancel`, `/unload`.
|
||
Start: `profile_id`, Textnachrichten `messages`, `max_tokens`. Kein Bearer-Zugriff.
|
||
|
||
Diagnose zeigt Ladephase, Wartezeit/Reservierungen, reale GPU-Belegung und die
|
||
Speicherprognose mit Reserve je GPU, RAM-Budget und GPU-Layerlimit. Eine Prognose
|
||
ist kein Nachweis für fehlerfreien Betrieb. Bestätigte Cgroup-OOM-Kills werden
|
||
als RAM-OOM gemeldet; ein GPU-OOM wird ohne eindeutigen Nachweis nicht behauptet.
|
||
Ein nicht eindeutig diagnostizierter Prozessabbruch nennt Speicher, Modell/Build
|
||
oder Zeitlimit als mögliche Ursachen. Bestehende Anwendungslogs werden nicht gelesen.
|
||
|
||
Der interne Chat-Test liefert `job.timings` (Prefill/Generierung: Token, Millisekunden und Token/s) und `job.usage` aus der finalen llama.cpp-Streamantwort. Fehlende Messwerte bleiben leer, insbesondere bei Abbruch. Prefill zählt berechnete Token, usage die gesamte Eingabe inklusive wiederverwendetem Kontext. Modellladen und Warteschlange sind nicht Teil der Token/s.
|
||
|
||
Profilfreigaben: mehrere Chatprofile, höchstens ein Bildprofil. Die Auswahl eines Bildprofils entfernt atomar alle anderen Bildfreigaben; laufende Antworten werden dadurch nicht abgebrochen. Der Haken in der Profilkarte zeigt die gespeicherte Freigabe, nicht den Ladezustand. Beim Laden alter Konfigurationen mit mehreren Bildfreigaben bleibt die erste gespeicherte Bild-ID ausgewählt.
|
||
|
||
### Sprachausgabe
|
||
|
||
`POST /v1/audio/speech` verwendet ein ausdrücklich freigegebenes TTS-Profil als `model`, `input` (1–1000 Zeichen), optional `voice` (Standard Ryan), `language` (Standard German), `speed` (0,25–4; sonst Profilwert) und `response_format: "wav"`. Antwort: WAV-Datei, kein JSON. MP3 und Streaming sind noch nicht unterstützt. TTS teilt sich die Reservierung mit Chat und Bildern; fremde GPU-Prozesse werden nicht beendet. Das Modell wird nach jeder Ausgabe entladen.
|
||
|
||
### Spracherkennung
|
||
|
||
`POST /v1/audio/transcriptions` benötigt Bearer-Token und ein explizit freigegebenes STT-Profil. Multipart-Felder: `model` (API-Profilname), `file` (PCM16-WAV, mono, 16 kHz, maximal 120 Sekunden / 8 MiB), optional `language` (`de`, `en`, `auto`, Standard `de`), `response_format` (`json`). Antwort: `{"text":"…"}`. Andere Formate, Chunked-Uploads, Zeitstempel und Streaming werden abgelehnt. Ein STT-Auftrag zur Zeit; CPU-Worker wird danach beendet. Keine Nutzung des alten Routers.
|
||
|
||
### Modelllisten für Clients
|
||
|
||
`GET /v1/models` listet ausschließlich Chatprofile, damit Chatclients keine Bild-/Audio-Profile anbieten. Deck-Erweiterungen: `GET /v1/images/models` für Bildprofile, `GET /v1/audio/speech/models` für TTS und `GET /v1/audio/transcriptions/models` für STT. Alle Listen erfordern denselben Bearer-Token und enthalten nur freigegebene, ausführbare Profile. Die Inferenzrouten bleiben unverändert. Die Verwaltungs-API liefert weiterhin die Gesamtübersicht.
|
||
|
||
Chat akzeptiert `reasoning_effort`: `none`, `minimal`, `low`, `medium`, `high`, `xhigh` werden unverändert an llama.cpp weitergereicht; `null` wird wie ein fehlendes Feld behandelt. Der installierte Build unterstützt das Feld; die konkrete Wirkung hängt vom Modell-Chattemplate ab. `none` deaktiviert dort das Reasoning. Deck erfindet keine Tokenbudgets und ignoriert gesetzte Werte nicht stillschweigend.
|