Merge llama-swap branch into main
#1
by wrenchpilot - opened
- .env.example +46 -10
- .gitignore +2 -0
- README.md +97 -5
- docker-compose.yml +2 -2
- llama-swap-presets/gemma-4-12b-it-qat.ini +24 -0
- llama-swap-presets/gemma-4-26b-a4b-it-qat-mtp.ini +24 -0
- llama-swap-presets/ornith-1.5-35b-a3b-mtp.ini +33 -0
- llama-swap-presets/qwen3.6-35b-mtp.ini +33 -0
- llama-swap-presets/qwopus3.5-35b-mtp.ini +33 -0
- llama-swap.sh +177 -0
- llama-swap.yaml +106 -0
- preset.ini +16 -0
- server.sh +183 -22
.env.example
CHANGED
|
@@ -1,20 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
MODELS_ROOT="/path/to/MODELS"
|
| 2 |
-
PRESETS_DIR="${MODELS_ROOT}/
|
| 3 |
-
LLAMA_DIR="${MODELS_ROOT}/
|
| 4 |
-
MODELS_DIR="${MODELS_ROOT}/
|
| 5 |
-
|
| 6 |
-
|
|
|
|
|
|
|
| 7 |
CUDA_IMAGE="nvidia/cuda:12.9.1-devel-ubuntu24.04"
|
| 8 |
BUILDER_IMAGE="llama-cuda12-builder:local"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
BUILD_CONTAINER_NAME="llama-build"
|
| 10 |
SERVER_CONTAINER_NAME="llama-server"
|
| 11 |
BENCH_CONTAINER_PREFIX="llama-bench"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
SERVER_HOST="0.0.0.0"
|
| 13 |
SERVER_PORT="8080"
|
| 14 |
-
CUDA_ARCHITECTURES="52;75"
|
| 15 |
-
CUDA_FLAGS="-Wno-deprecated-gpu-targets"
|
| 16 |
-
BENCH_REPETITIONS="3"
|
| 17 |
SERVER_INTERNAL_PORT="8080"
|
| 18 |
-
RPC_HOSTS="HOST
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
HF_TOKEN=""
|
| 20 |
-
LLAMA_API_KEY=""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copy this file to .env and replace the placeholder values.
|
| 2 |
+
# Keep .env private: it may contain access tokens and API keys.
|
| 3 |
+
|
| 4 |
+
# -----------------------------------------------------------------------------
|
| 5 |
+
# Paths
|
| 6 |
+
# -----------------------------------------------------------------------------
|
| 7 |
MODELS_ROOT="/path/to/MODELS"
|
| 8 |
+
PRESETS_DIR="${MODELS_ROOT}/presets"
|
| 9 |
+
LLAMA_DIR="${MODELS_ROOT}/llama.cpp"
|
| 10 |
+
MODELS_DIR="${MODELS_ROOT}/models"
|
| 11 |
+
|
| 12 |
+
# -----------------------------------------------------------------------------
|
| 13 |
+
# CUDA and Docker images
|
| 14 |
+
# -----------------------------------------------------------------------------
|
| 15 |
CUDA_IMAGE="nvidia/cuda:12.9.1-devel-ubuntu24.04"
|
| 16 |
BUILDER_IMAGE="llama-cuda12-builder:local"
|
| 17 |
+
CUDA_BUILD="12"
|
| 18 |
+
CUDA_ARCHITECTURES="52;75"
|
| 19 |
+
CUDA_FLAGS="-Wno-deprecated-gpu-targets"
|
| 20 |
+
|
| 21 |
+
# -----------------------------------------------------------------------------
|
| 22 |
+
# Container names
|
| 23 |
+
# -----------------------------------------------------------------------------
|
| 24 |
BUILD_CONTAINER_NAME="llama-build"
|
| 25 |
SERVER_CONTAINER_NAME="llama-server"
|
| 26 |
BENCH_CONTAINER_PREFIX="llama-bench"
|
| 27 |
+
LLAMA_SWAP_CONTAINER_NAME="llama-swap"
|
| 28 |
+
|
| 29 |
+
# -----------------------------------------------------------------------------
|
| 30 |
+
# llama.cpp server and RPC server
|
| 31 |
+
# -----------------------------------------------------------------------------
|
| 32 |
SERVER_HOST="0.0.0.0"
|
| 33 |
SERVER_PORT="8080"
|
|
|
|
|
|
|
|
|
|
| 34 |
SERVER_INTERNAL_PORT="8080"
|
| 35 |
+
RPC_HOSTS="HOST"
|
| 36 |
+
RPC_PORT="50052"
|
| 37 |
+
|
| 38 |
+
# -----------------------------------------------------------------------------
|
| 39 |
+
# Authentication and Hugging Face access
|
| 40 |
+
# -----------------------------------------------------------------------------
|
| 41 |
HF_TOKEN=""
|
| 42 |
+
LLAMA_API_KEY=""
|
| 43 |
+
|
| 44 |
+
# -----------------------------------------------------------------------------
|
| 45 |
+
# llama-swap gateway
|
| 46 |
+
# -----------------------------------------------------------------------------
|
| 47 |
+
LLAMA_SWAP_VERSION="unified-cuda"
|
| 48 |
+
LLAMA_SWAP_IMAGE="ghcr.io/mostlygeek/llama-swap:${LLAMA_SWAP_VERSION}"
|
| 49 |
+
LLAMA_SWAP_PORT="8080"
|
| 50 |
+
LLAMA_SWAP_API_KEY="${LLAMA_API_KEY}"
|
| 51 |
+
|
| 52 |
+
# -----------------------------------------------------------------------------
|
| 53 |
+
# Service lifecycle
|
| 54 |
+
# -----------------------------------------------------------------------------
|
| 55 |
+
# Graceful Docker stop timeout used by server.sh and llama-swap.sh.
|
| 56 |
+
STOP_TIMEOUT="30"
|
.gitignore
CHANGED
|
@@ -1,5 +1,7 @@
|
|
| 1 |
__pycache__/
|
| 2 |
*.log
|
|
|
|
|
|
|
| 3 |
|
| 4 |
.env
|
| 5 |
.bench-state/
|
|
|
|
| 1 |
__pycache__/
|
| 2 |
*.log
|
| 3 |
+
llama-swap-logs/
|
| 4 |
+
llama-swap-state/
|
| 5 |
|
| 6 |
.env
|
| 7 |
.bench-state/
|
README.md
CHANGED
|
@@ -103,24 +103,116 @@ The image includes `libssl-dev`, so llama.cpp can download Hugging Face models o
|
|
| 103 |
### Server
|
| 104 |
|
| 105 |
```bash
|
| 106 |
-
./server.sh # Start
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
```
|
| 108 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
`server.sh` uses the prebuilt CUDA 12.9 image, exposes port `8080`, and serves both GPUs. From another computer:
|
| 110 |
|
| 111 |
```text
|
| 112 |
http://<host-ip>:8080
|
| 113 |
```
|
| 114 |
|
| 115 |
-
The server runs in router mode and loads models on demand. Set
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
|
| 117 |
## Quick Start
|
| 118 |
|
| 119 |
```bash
|
| 120 |
-
cd
|
| 121 |
./create-build-image.sh
|
| 122 |
./build-llama.cpp.sh
|
| 123 |
-
./server.sh
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
```
|
| 125 |
|
| 126 |
-
Then use the
|
|
|
|
| 103 |
### Server
|
| 104 |
|
| 105 |
```bash
|
| 106 |
+
./server.sh # Start in the background with preset.ini
|
| 107 |
+
./server.sh start # Same as above
|
| 108 |
+
./server.sh start custom.ini
|
| 109 |
+
./server.sh status
|
| 110 |
+
./server.sh restart custom.ini
|
| 111 |
+
./server.sh stop
|
| 112 |
```
|
| 113 |
|
| 114 |
+
`start` and `daemon` launch the Docker container in detached mode, so the
|
| 115 |
+
script returns while the server continues running in the background. The
|
| 116 |
+
container name is used for lifecycle tracking; no host PID file is needed.
|
| 117 |
+
The legacy form `./server.sh custom.ini` is also supported.
|
| 118 |
+
|
| 119 |
`server.sh` uses the prebuilt CUDA 12.9 image, exposes port `8080`, and serves both GPUs. From another computer:
|
| 120 |
|
| 121 |
```text
|
| 122 |
http://<host-ip>:8080
|
| 123 |
```
|
| 124 |
|
| 125 |
+
The server runs in router mode and loads models on demand. Set `LLAMA_API_KEY`
|
| 126 |
+
before exposing the legacy server beyond a trusted LAN.
|
| 127 |
+
|
| 128 |
+
### llama-swap gateway
|
| 129 |
+
|
| 130 |
+
`llama-swap.sh` runs the five active models from `llama-swap.yaml` through the
|
| 131 |
+
custom CUDA build, swapping the corresponding `llama-server` process on demand:
|
| 132 |
+
|
| 133 |
+
- `Qwen3.6-35B-MTP`
|
| 134 |
+
- `Ornith-1.5-35B-A3B-MTP`
|
| 135 |
+
- `gemma-4-12B-it-qat`
|
| 136 |
+
- `gemma-4-26B-A4B-it-qat-MTP`
|
| 137 |
+
- `Qwopus3.6-35B-A3B-Coder-MTP`
|
| 138 |
+
|
| 139 |
+
On the target server, from the presets directory configured in `.env`:
|
| 140 |
+
|
| 141 |
+
```bash
|
| 142 |
+
./llama-swap.sh start
|
| 143 |
+
./llama-swap.sh status
|
| 144 |
+
./llama-swap.sh restart
|
| 145 |
+
./llama-swap.sh stop
|
| 146 |
+
```
|
| 147 |
+
|
| 148 |
+
`./llama-swap.sh` and `./llama-swap.sh daemon` are aliases for `start`. The
|
| 149 |
+
gateway runs as a detached Docker container and remains active after the
|
| 150 |
+
shell script exits.
|
| 151 |
+
|
| 152 |
+
The gateway is available at `http://<server-host>:<port>/v1`. Its API key is read
|
| 153 |
+
from `LLAMA_API_KEY`; the key is passed to llama-swap only, while the upstream
|
| 154 |
+
llama-server processes remain bound to the container loopback interface. Each
|
| 155 |
+
model receives an available internal port from llama-swap, and the proxy uses
|
| 156 |
+
that same assigned port.
|
| 157 |
+
|
| 158 |
+
Authentication is API-key based; there is no separate llama-swap username or
|
| 159 |
+
password. The web UI and API endpoints require the key:
|
| 160 |
+
|
| 161 |
+
- In a browser prompt, enter any non-empty username and use the value of
|
| 162 |
+
`LLAMA_API_KEY` as the password.
|
| 163 |
+
- For OpenAI-compatible clients, set the base URL to
|
| 164 |
+
`http://<server-host>:<port>/v1` and use the same value as the API key. The client
|
| 165 |
+
should send it as `Authorization: Bearer <API key>`.
|
| 166 |
+
- `http://<server-host>:<port>/health` is unauthenticated and returns `OK`.
|
| 167 |
+
|
| 168 |
+
The derived single-model presets are in `llama-swap-presets/`, and model logs
|
| 169 |
+
are written to `${PRESETS_DIR}/llama-swap-logs/`. Activity history and metrics
|
| 170 |
+
are stored in `${PRESETS_DIR}/llama-swap-state/activity.sqlite`, so the
|
| 171 |
+
llama-swap Activity page retains previous requests and runs across restarts.
|
| 172 |
+
|
| 173 |
+
The state directory is created automatically by `llama-swap.sh` and is mounted
|
| 174 |
+
into the container through the existing `/presets` volume. The currently loaded
|
| 175 |
+
model process is still intentionally restarted and must be loaded again after a
|
| 176 |
+
container restart; only historical activity and metrics are persisted.
|
| 177 |
+
|
| 178 |
+
Models are automatically unloaded after 30 minutes of inactivity because
|
| 179 |
+
`globalTTL` is set to `1800` seconds. Increase this value to reduce reloads, or
|
| 180 |
+
set it to `0` to keep the active model loaded indefinitely.
|
| 181 |
+
|
| 182 |
+
The gateway is configured with an exclusive `single-model` group. The Pi agent
|
| 183 |
+
selects the model by sending its exact model ID in each OpenAI-compatible
|
| 184 |
+
request. When that ID changes, llama-swap unloads the current model before
|
| 185 |
+
starting the requested one; the Pi agent must not call `/models/sse`.
|
| 186 |
+
|
| 187 |
+
To discover the available IDs, call `GET /v1/models` with the API key. A chat
|
| 188 |
+
request should use the selected ID in its `model` field:
|
| 189 |
+
|
| 190 |
+
```json
|
| 191 |
+
{
|
| 192 |
+
"model": "Qwen3.6-35B-MTP",
|
| 193 |
+
"messages": [
|
| 194 |
+
{"role": "user", "content": "Hello"}
|
| 195 |
+
]
|
| 196 |
+
}
|
| 197 |
+
```
|
| 198 |
|
| 199 |
## Quick Start
|
| 200 |
|
| 201 |
```bash
|
| 202 |
+
cd <presets-directory>
|
| 203 |
./create-build-image.sh
|
| 204 |
./build-llama.cpp.sh
|
| 205 |
+
./server.sh start
|
| 206 |
+
./server.sh status
|
| 207 |
+
```
|
| 208 |
+
|
| 209 |
+
Then use the OpenAI-compatible API on port 8080. Run `server.sh` and
|
| 210 |
+
`llama-swap.sh` separately; they both use port `8080` by default. To use the
|
| 211 |
+
gateway instead, stop the standalone server and run:
|
| 212 |
+
|
| 213 |
+
```bash
|
| 214 |
+
./server.sh stop
|
| 215 |
+
./llama-swap.sh start
|
| 216 |
```
|
| 217 |
|
| 218 |
+
Then use the authenticated gateway at `http://<server-host>:<port>/v1`.
|
docker-compose.yml
CHANGED
|
@@ -20,10 +20,10 @@ services:
|
|
| 20 |
bash -c '
|
| 21 |
set -euo pipefail
|
| 22 |
git config --global --add safe.directory /src
|
| 23 |
-
cmake -S /src -B /src/build-${CUDA_BUILD} \
|
| 24 |
-DGGML_CUDA=ON -DGGML_CUDA_GRAPH=ON -DGGML_VULKAN=ON \
|
| 25 |
-DCMAKE_CUDA_ARCHITECTURES="${CUDA_ARCHITECTURES}" \
|
| 26 |
-DCMAKE_CUDA_FLAGS="${CUDA_FLAGS}" \
|
| 27 |
-DBUILD_SHARED_LIBS=OFF -DGGML_RPC=ON
|
| 28 |
-
cmake --build /src/build-${CUDA_BUILD} --config Release -j$$(nproc)
|
| 29 |
'
|
|
|
|
| 20 |
bash -c '
|
| 21 |
set -euo pipefail
|
| 22 |
git config --global --add safe.directory /src
|
| 23 |
+
cmake -S /src -B /src/build-${CUDA_BUILD:-12} \
|
| 24 |
-DGGML_CUDA=ON -DGGML_CUDA_GRAPH=ON -DGGML_VULKAN=ON \
|
| 25 |
-DCMAKE_CUDA_ARCHITECTURES="${CUDA_ARCHITECTURES}" \
|
| 26 |
-DCMAKE_CUDA_FLAGS="${CUDA_FLAGS}" \
|
| 27 |
-DBUILD_SHARED_LIBS=OFF -DGGML_RPC=ON
|
| 28 |
+
cmake --build /src/build-${CUDA_BUILD:-12} --config Release -j$$(nproc)
|
| 29 |
'
|
llama-swap-presets/gemma-4-12b-it-qat.ini
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version = 1
|
| 2 |
+
|
| 3 |
+
[*]
|
| 4 |
+
fa = on
|
| 5 |
+
jinja = true
|
| 6 |
+
metrics = false
|
| 7 |
+
reasoning = on
|
| 8 |
+
reasoning-budget-message = "OK, I've thought long enough. Let's answer."
|
| 9 |
+
np = 1
|
| 10 |
+
c = 131072
|
| 11 |
+
image-min-tokens = 1024
|
| 12 |
+
device = CUDA0,CUDA1
|
| 13 |
+
split-mode = layer
|
| 14 |
+
main-gpu = 0
|
| 15 |
+
device-draft = CUDA1
|
| 16 |
+
mmproj-device = CUDA1
|
| 17 |
+
models-max = 1
|
| 18 |
+
|
| 19 |
+
[gemma-4-12B-it-qat]
|
| 20 |
+
hf = unsloth/gemma-4-12B-it-qat-GGUF:UD-Q4_K_XL
|
| 21 |
+
spec-type = draft-mtp
|
| 22 |
+
spec-draft-n-max = 2
|
| 23 |
+
load-mode = none
|
| 24 |
+
lazy-mode = auto
|
llama-swap-presets/gemma-4-26b-a4b-it-qat-mtp.ini
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version = 1
|
| 2 |
+
|
| 3 |
+
[*]
|
| 4 |
+
fa = on
|
| 5 |
+
jinja = true
|
| 6 |
+
metrics = false
|
| 7 |
+
reasoning = on
|
| 8 |
+
reasoning-budget-message = "OK, I've thought long enough. Let's answer."
|
| 9 |
+
np = 1
|
| 10 |
+
c = 131072
|
| 11 |
+
image-min-tokens = 1024
|
| 12 |
+
device = CUDA0,CUDA1
|
| 13 |
+
split-mode = layer
|
| 14 |
+
main-gpu = 0
|
| 15 |
+
device-draft = CUDA1
|
| 16 |
+
mmproj-device = CUDA1
|
| 17 |
+
models-max = 1
|
| 18 |
+
|
| 19 |
+
[gemma-4-26B-A4B-it-qat-MTP]
|
| 20 |
+
hf = unsloth/gemma-4-26B-A4B-it-qat-GGUF:UD-Q4_K_XL
|
| 21 |
+
spec-type = draft-mtp
|
| 22 |
+
spec-draft-n-max = 2
|
| 23 |
+
load-mode = none
|
| 24 |
+
lazy-mode = auto
|
llama-swap-presets/ornith-1.5-35b-a3b-mtp.ini
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version = 1
|
| 2 |
+
|
| 3 |
+
[*]
|
| 4 |
+
fa = on
|
| 5 |
+
jinja = true
|
| 6 |
+
metrics = false
|
| 7 |
+
reasoning = on
|
| 8 |
+
reasoning-budget-message = "OK, I've thought long enough. Let's answer."
|
| 9 |
+
np = 1
|
| 10 |
+
c = 131072
|
| 11 |
+
image-min-tokens = 1024
|
| 12 |
+
device = CUDA0,CUDA1
|
| 13 |
+
split-mode = layer
|
| 14 |
+
main-gpu = 0
|
| 15 |
+
device-draft = CUDA1
|
| 16 |
+
mmproj-device = CUDA1
|
| 17 |
+
models-max = 1
|
| 18 |
+
|
| 19 |
+
[Ornith-1.5-35B-A3B-MTP]
|
| 20 |
+
hf = ornith-ai/Ornith-1.5-35B-A3B-GGUF:Q4_K_M
|
| 21 |
+
temp = 0.85
|
| 22 |
+
top-p = 0.95
|
| 23 |
+
top-k = 40
|
| 24 |
+
min-p = 0.05
|
| 25 |
+
repeat-penalty = 1.1
|
| 26 |
+
presence-penalty = 0.0
|
| 27 |
+
spec-type = draft-mtp
|
| 28 |
+
spec-draft-n-max = 2
|
| 29 |
+
load-mode = none
|
| 30 |
+
lazy-mode = auto
|
| 31 |
+
device = CUDA0
|
| 32 |
+
split-mode = layer
|
| 33 |
+
main-gpu = 0
|
llama-swap-presets/qwen3.6-35b-mtp.ini
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version = 1
|
| 2 |
+
|
| 3 |
+
[*]
|
| 4 |
+
fa = on
|
| 5 |
+
jinja = true
|
| 6 |
+
metrics = false
|
| 7 |
+
reasoning = on
|
| 8 |
+
reasoning-budget-message = "OK, I've thought long enough. Let's answer."
|
| 9 |
+
np = 1
|
| 10 |
+
c = 131072
|
| 11 |
+
image-min-tokens = 1024
|
| 12 |
+
device = CUDA0,CUDA1
|
| 13 |
+
split-mode = layer
|
| 14 |
+
main-gpu = 0
|
| 15 |
+
device-draft = CUDA1
|
| 16 |
+
mmproj-device = CUDA1
|
| 17 |
+
models-max = 1
|
| 18 |
+
|
| 19 |
+
[Qwen3.6-35B-MTP]
|
| 20 |
+
hf = unsloth/Qwen3.6-35B-A3B-MTP-GGUF:UD-Q4_K_XL
|
| 21 |
+
temp = 0.6
|
| 22 |
+
top-p = 0.95
|
| 23 |
+
top-k = 20
|
| 24 |
+
presence-penalty = 0.0
|
| 25 |
+
min-p = 0.00
|
| 26 |
+
repeat-penalty = 1.0
|
| 27 |
+
spec-type = draft-mtp
|
| 28 |
+
spec-draft-n-max = 2
|
| 29 |
+
device = CUDA0
|
| 30 |
+
split-mode = layer
|
| 31 |
+
main-gpu = 0
|
| 32 |
+
load-mode = none
|
| 33 |
+
lazy-mode = auto
|
llama-swap-presets/qwopus3.5-35b-mtp.ini
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version = 1
|
| 2 |
+
|
| 3 |
+
[*]
|
| 4 |
+
fa = on
|
| 5 |
+
jinja = true
|
| 6 |
+
metrics = false
|
| 7 |
+
reasoning = on
|
| 8 |
+
reasoning-budget-message = "OK, I've thought long enough. Let's answer."
|
| 9 |
+
np = 1
|
| 10 |
+
c = 131072
|
| 11 |
+
image-min-tokens = 1024
|
| 12 |
+
device = CUDA0,CUDA1
|
| 13 |
+
split-mode = layer
|
| 14 |
+
main-gpu = 0
|
| 15 |
+
device-draft = CUDA1
|
| 16 |
+
mmproj-device = CUDA1
|
| 17 |
+
models-max = 1
|
| 18 |
+
|
| 19 |
+
[Qwopus3.6-35B-A3B-Coder-MTP-GGUF]
|
| 20 |
+
hf = Jackrong/Qwopus3.6-35B-A3B-Coder-MTP-GGUF:Q4_K_M
|
| 21 |
+
temp = 0.6
|
| 22 |
+
top-p = 0.95
|
| 23 |
+
top-k = 20
|
| 24 |
+
presence-penalty = 0.0
|
| 25 |
+
min-p = 0.00
|
| 26 |
+
repeat-penalty = 1.0
|
| 27 |
+
spec-type = draft-mtp
|
| 28 |
+
spec-draft-n-max = 2
|
| 29 |
+
device = CUDA0
|
| 30 |
+
split-mode = layer
|
| 31 |
+
main-gpu = 0
|
| 32 |
+
load-mode = none
|
| 33 |
+
lazy-mode = auto
|
llama-swap.sh
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
set -euo pipefail
|
| 3 |
+
|
| 4 |
+
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
| 5 |
+
ENV_FILE="${SCRIPT_DIR}/.env"
|
| 6 |
+
if [[ ! -f "${ENV_FILE}" ]]; then
|
| 7 |
+
printf 'Missing environment file: %s\n' "${ENV_FILE}" >&2
|
| 8 |
+
exit 1
|
| 9 |
+
fi
|
| 10 |
+
|
| 11 |
+
set -a
|
| 12 |
+
# shellcheck disable=SC1090
|
| 13 |
+
source "${ENV_FILE}"
|
| 14 |
+
set +a
|
| 15 |
+
|
| 16 |
+
CUDA_BUILD="${CUDA_BUILD:-12}"
|
| 17 |
+
DOCKER=(sudo docker)
|
| 18 |
+
|
| 19 |
+
usage() {
|
| 20 |
+
cat <<EOF
|
| 21 |
+
Usage: $(basename "$0") [command]
|
| 22 |
+
|
| 23 |
+
Commands:
|
| 24 |
+
start Start llama-swap in the background (default)
|
| 25 |
+
daemon Alias for start
|
| 26 |
+
stop Gracefully stop llama-swap
|
| 27 |
+
restart Stop and start llama-swap
|
| 28 |
+
status Show the Docker container state and published port
|
| 29 |
+
EOF
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
container_state() {
|
| 33 |
+
local state
|
| 34 |
+
if state="$("${DOCKER[@]}" inspect --format='{{.State.Status}}' "${LLAMA_SWAP_CONTAINER_NAME}" 2>/dev/null)"; then
|
| 35 |
+
printf '%s\n' "${state}"
|
| 36 |
+
else
|
| 37 |
+
printf 'missing\n'
|
| 38 |
+
fi
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
remove_stale_container() {
|
| 42 |
+
if [[ "$(container_state)" != "missing" ]]; then
|
| 43 |
+
"${DOCKER[@]}" rm --force "${LLAMA_SWAP_CONTAINER_NAME}" >/dev/null
|
| 44 |
+
fi
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
start_llama_swap() {
|
| 48 |
+
: "${MODELS_ROOT:?MODELS_ROOT must be set in .env}"
|
| 49 |
+
: "${LLAMA_DIR:?LLAMA_DIR must be set in .env}"
|
| 50 |
+
: "${PRESETS_DIR:?PRESETS_DIR must be set in .env}"
|
| 51 |
+
: "${MODELS_DIR:?MODELS_DIR must be set in .env}"
|
| 52 |
+
: "${BUILDER_IMAGE:?BUILDER_IMAGE must be set in .env}"
|
| 53 |
+
: "${LLAMA_SWAP_CONTAINER_NAME:?LLAMA_SWAP_CONTAINER_NAME must be set in .env}"
|
| 54 |
+
: "${LLAMA_SWAP_PORT:?LLAMA_SWAP_PORT must be set in .env}"
|
| 55 |
+
: "${LLAMA_SWAP_API_KEY:?LLAMA_SWAP_API_KEY must be set in .env}"
|
| 56 |
+
: "${LLAMA_SWAP_IMAGE:?LLAMA_SWAP_IMAGE must be set in .env}"
|
| 57 |
+
|
| 58 |
+
if [[ ! -f "${PRESETS_DIR}/llama-swap.yaml" ]]; then
|
| 59 |
+
printf 'Missing llama-swap configuration: %s\n' "${PRESETS_DIR}/llama-swap.yaml" >&2
|
| 60 |
+
return 1
|
| 61 |
+
fi
|
| 62 |
+
|
| 63 |
+
if [[ ! -x "${LLAMA_DIR}/build-${CUDA_BUILD}/bin/llama-server" ]]; then
|
| 64 |
+
printf 'Missing custom llama-server: %s\n' "${LLAMA_DIR}/build-${CUDA_BUILD}/bin/llama-server" >&2
|
| 65 |
+
printf 'Build llama.cpp before starting llama-swap.\n' >&2
|
| 66 |
+
return 1
|
| 67 |
+
fi
|
| 68 |
+
|
| 69 |
+
if [[ "$(container_state)" == "running" ]]; then
|
| 70 |
+
printf '%s is already running\n' "${LLAMA_SWAP_CONTAINER_NAME}" >&2
|
| 71 |
+
return 1
|
| 72 |
+
fi
|
| 73 |
+
|
| 74 |
+
mkdir -p "${PRESETS_DIR}/llama-swap-logs" "${PRESETS_DIR}/llama-swap-state"
|
| 75 |
+
remove_stale_container
|
| 76 |
+
|
| 77 |
+
"${DOCKER[@]}" run --detach --rm \
|
| 78 |
+
--name "${LLAMA_SWAP_CONTAINER_NAME}" \
|
| 79 |
+
--gpus all \
|
| 80 |
+
--device=/dev/dri \
|
| 81 |
+
--ulimit memlock=-1:-1 \
|
| 82 |
+
--publish "${LLAMA_SWAP_PORT}:8080" \
|
| 83 |
+
--env "CUDA_BUILD=${CUDA_BUILD}" \
|
| 84 |
+
--env "HF_HOME=/models" \
|
| 85 |
+
--env "HF_TOKEN=${HF_TOKEN:-}" \
|
| 86 |
+
--env "LLAMA_SWAP_API_KEY=${LLAMA_SWAP_API_KEY}" \
|
| 87 |
+
--env "LLAMA_SWAP_CONFIG=/presets/llama-swap.yaml" \
|
| 88 |
+
--volume "${LLAMA_DIR}:/src:ro" \
|
| 89 |
+
--volume "${PRESETS_DIR}:/presets" \
|
| 90 |
+
--volume "${MODELS_DIR}:/models" \
|
| 91 |
+
--workdir /models \
|
| 92 |
+
"${LLAMA_SWAP_IMAGE}"
|
| 93 |
+
printf 'Started %s in the background\n' "${LLAMA_SWAP_CONTAINER_NAME}"
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
stop_llama_swap() {
|
| 97 |
+
local state timeout
|
| 98 |
+
state="$(container_state)"
|
| 99 |
+
timeout="${STOP_TIMEOUT:-30}"
|
| 100 |
+
|
| 101 |
+
if [[ "${state}" == "missing" ]]; then
|
| 102 |
+
printf '%s is not running\n' "${LLAMA_SWAP_CONTAINER_NAME}"
|
| 103 |
+
return 0
|
| 104 |
+
fi
|
| 105 |
+
|
| 106 |
+
if [[ "${state}" == "running" || "${state}" == "created" || "${state}" == "restarting" ]]; then
|
| 107 |
+
"${DOCKER[@]}" stop --time="${timeout}" "${LLAMA_SWAP_CONTAINER_NAME}" >/dev/null
|
| 108 |
+
else
|
| 109 |
+
remove_stale_container
|
| 110 |
+
fi
|
| 111 |
+
printf 'Stopped %s\n' "${LLAMA_SWAP_CONTAINER_NAME}"
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
status_llama_swap() {
|
| 115 |
+
local state port
|
| 116 |
+
state="$(container_state)"
|
| 117 |
+
if [[ "${state}" == "missing" ]]; then
|
| 118 |
+
printf '%s: stopped (container missing)\n' "${LLAMA_SWAP_CONTAINER_NAME}"
|
| 119 |
+
return 1
|
| 120 |
+
fi
|
| 121 |
+
|
| 122 |
+
port="$("${DOCKER[@]}" port "${LLAMA_SWAP_CONTAINER_NAME}" 8080/tcp 2>/dev/null || true)"
|
| 123 |
+
if [[ -n "${port}" ]]; then
|
| 124 |
+
printf '%s: %s (%s)\n' "${LLAMA_SWAP_CONTAINER_NAME}" "${state}" "${port}"
|
| 125 |
+
else
|
| 126 |
+
printf '%s: %s\n' "${LLAMA_SWAP_CONTAINER_NAME}" "${state}"
|
| 127 |
+
fi
|
| 128 |
+
[[ "${state}" == "running" ]]
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
if [[ $# -gt 0 ]]; then
|
| 132 |
+
COMMAND="$1"
|
| 133 |
+
else
|
| 134 |
+
COMMAND="start"
|
| 135 |
+
fi
|
| 136 |
+
case "${COMMAND}" in
|
| 137 |
+
start|daemon|restart)
|
| 138 |
+
if [[ $# -gt 1 ]]; then
|
| 139 |
+
printf 'Unexpected argument for %s: %s\n' "${COMMAND}" "$2" >&2
|
| 140 |
+
usage >&2
|
| 141 |
+
exit 2
|
| 142 |
+
fi
|
| 143 |
+
;;
|
| 144 |
+
stop|status)
|
| 145 |
+
if [[ $# -gt 1 ]]; then
|
| 146 |
+
printf 'Unexpected argument for %s: %s\n' "${COMMAND}" "$2" >&2
|
| 147 |
+
usage >&2
|
| 148 |
+
exit 2
|
| 149 |
+
fi
|
| 150 |
+
;;
|
| 151 |
+
help|-h|--help)
|
| 152 |
+
usage
|
| 153 |
+
exit 0
|
| 154 |
+
;;
|
| 155 |
+
*)
|
| 156 |
+
printf 'Unknown command: %s\n' "${COMMAND}" >&2
|
| 157 |
+
usage >&2
|
| 158 |
+
exit 2
|
| 159 |
+
;;
|
| 160 |
+
esac
|
| 161 |
+
|
| 162 |
+
: "${LLAMA_SWAP_CONTAINER_NAME:?LLAMA_SWAP_CONTAINER_NAME must be set in .env}"
|
| 163 |
+
case "${COMMAND}" in
|
| 164 |
+
start|daemon)
|
| 165 |
+
start_llama_swap
|
| 166 |
+
;;
|
| 167 |
+
stop)
|
| 168 |
+
stop_llama_swap
|
| 169 |
+
;;
|
| 170 |
+
restart)
|
| 171 |
+
stop_llama_swap
|
| 172 |
+
start_llama_swap
|
| 173 |
+
;;
|
| 174 |
+
status)
|
| 175 |
+
status_llama_swap
|
| 176 |
+
;;
|
| 177 |
+
esac
|
llama-swap.yaml
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# yaml-language-server: $schema=https://raw.githubusercontent.com/mostlygeek/llama-swap/refs/heads/main/config-schema.json
|
| 2 |
+
# The API key is injected by llama-swap.sh and is intentionally not stored here.
|
| 3 |
+
healthCheckTimeout: 1800
|
| 4 |
+
logLevel: info
|
| 5 |
+
# Store the Activity page's request history and metrics in a file-backed SQLite
|
| 6 |
+
# database so they survive llama-swap/container restarts.
|
| 7 |
+
store:
|
| 8 |
+
path: /presets/llama-swap-state/activity.sqlite
|
| 9 |
+
# Keep the active model warm for 30 minutes, then reclaim its VRAM when idle.
|
| 10 |
+
globalTTL: 1800
|
| 11 |
+
unloadTimeout: 30
|
| 12 |
+
globalConcurrencyLimit: 1
|
| 13 |
+
sendLoadingState: true
|
| 14 |
+
logToStdout: proxy
|
| 15 |
+
compat:
|
| 16 |
+
# ignoreWebsockets: do not let websocket connections load a stopped model
|
| 17 |
+
# or count toward concurrency, TTL activity, or swap decisions
|
| 18 |
+
# - optional, default: false
|
| 19 |
+
ignoreWebsockets: true
|
| 20 |
+
apiKeys:
|
| 21 |
+
- "${env.LLAMA_SWAP_API_KEY}"
|
| 22 |
+
|
| 23 |
+
# Shared command fragments keep model definitions consistent. The environment
|
| 24 |
+
# macro is expanded by llama-swap inside the container, and ${PORT} is assigned
|
| 25 |
+
# separately for each model.
|
| 26 |
+
macros:
|
| 27 |
+
llama_server: "/src/build-${env.CUDA_BUILD}/bin/llama-server"
|
| 28 |
+
llama_server_args: >-
|
| 29 |
+
--host 127.0.0.1
|
| 30 |
+
--port ${PORT}
|
| 31 |
+
|
| 32 |
+
groups:
|
| 33 |
+
single-model:
|
| 34 |
+
swap: true
|
| 35 |
+
exclusive: true
|
| 36 |
+
members:
|
| 37 |
+
- "Qwen3.6-35B-MTP"
|
| 38 |
+
- "Ornith-1.5-35B-A3B-MTP"
|
| 39 |
+
- "gemma-4-12B-it-qat"
|
| 40 |
+
- "gemma-4-26B-A4B-it-qat-MTP"
|
| 41 |
+
- "Qwopus3.6-35B-A3B-Coder-MTP"
|
| 42 |
+
|
| 43 |
+
models:
|
| 44 |
+
"Qwen3.6-35B-MTP":
|
| 45 |
+
cmd: |
|
| 46 |
+
${llama_server}
|
| 47 |
+
${llama_server_args}
|
| 48 |
+
--models-preset /presets/llama-swap-presets/qwen3.6-35b-mtp.ini
|
| 49 |
+
--log-file /presets/llama-swap-logs/qwen3.6-35b-mtp.log
|
| 50 |
+
proxy: http://127.0.0.1:${PORT}
|
| 51 |
+
checkEndpoint: /health
|
| 52 |
+
concurrencyLimit: 0
|
| 53 |
+
capabilities:
|
| 54 |
+
tools: true
|
| 55 |
+
disableAuto: false
|
| 56 |
+
|
| 57 |
+
"Qwopus3.6-35B-A3B-Coder-MTP":
|
| 58 |
+
cmd: |
|
| 59 |
+
${llama_server}
|
| 60 |
+
${llama_server_args}
|
| 61 |
+
--models-preset /presets/llama-swap-presets/qwopus3.6-35b-mtp.ini
|
| 62 |
+
--log-file /presets/llama-swap-logs/qwopus3.6-35b-mtp.log
|
| 63 |
+
proxy: http://127.0.0.1:${PORT}
|
| 64 |
+
checkEndpoint: /health
|
| 65 |
+
concurrencyLimit: 0
|
| 66 |
+
capabilities:
|
| 67 |
+
tools: true
|
| 68 |
+
disableAuto: false
|
| 69 |
+
|
| 70 |
+
"Ornith-1.5-35B-A3B-MTP":
|
| 71 |
+
cmd: |
|
| 72 |
+
${llama_server}
|
| 73 |
+
${llama_server_args}
|
| 74 |
+
--models-preset /presets/llama-swap-presets/ornith-1.5-35b-a3b-mtp.ini
|
| 75 |
+
--log-file /presets/llama-swap-logs/ornith-1.5-35b-a3b-mtp.log
|
| 76 |
+
proxy: http://127.0.0.1:${PORT}
|
| 77 |
+
checkEndpoint: /health
|
| 78 |
+
concurrencyLimit: 0
|
| 79 |
+
capabilities:
|
| 80 |
+
tools: true
|
| 81 |
+
disableAuto: false
|
| 82 |
+
|
| 83 |
+
"gemma-4-12B-it-qat":
|
| 84 |
+
cmd: |
|
| 85 |
+
${llama_server}
|
| 86 |
+
${llama_server_args}
|
| 87 |
+
--models-preset /presets/llama-swap-presets/gemma-4-12b-it-qat.ini
|
| 88 |
+
--log-file /presets/llama-swap-logs/gemma-4-12b-it-qat.log
|
| 89 |
+
proxy: http://127.0.0.1:${PORT}
|
| 90 |
+
checkEndpoint: /health
|
| 91 |
+
capabilities:
|
| 92 |
+
tools: true
|
| 93 |
+
disableAuto: false
|
| 94 |
+
|
| 95 |
+
"gemma-4-26B-A4B-it-qat-MTP":
|
| 96 |
+
cmd: |
|
| 97 |
+
${llama_server}
|
| 98 |
+
${llama_server_args}
|
| 99 |
+
--models-preset /presets/llama-swap-presets/gemma-4-26b-a4b-it-qat-mtp.ini
|
| 100 |
+
--log-file /presets/llama-swap-logs/gemma-4-26b-a4b-it-qat-mtp.log
|
| 101 |
+
proxy: http://127.0.0.1:${PORT}
|
| 102 |
+
checkEndpoint: /health
|
| 103 |
+
concurrencyLimit: 0
|
| 104 |
+
capabilities:
|
| 105 |
+
tools: true
|
| 106 |
+
disableAuto: false
|
preset.ini
CHANGED
|
@@ -108,3 +108,19 @@ spec-type = draft-mtp
|
|
| 108 |
spec-draft-n-max = 2
|
| 109 |
load-mode = none
|
| 110 |
lazy-mode = auto
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
spec-draft-n-max = 2
|
| 109 |
load-mode = none
|
| 110 |
lazy-mode = auto
|
| 111 |
+
|
| 112 |
+
[Qwopus3.6-35B-A3B-Coder-MTP]
|
| 113 |
+
hf = Jackrong/Qwopus3.6-35B-A3B-Coder-MTP-GGUF:Q4_K_M
|
| 114 |
+
temp = 0.6
|
| 115 |
+
top-p = 0.95
|
| 116 |
+
top-k = 20
|
| 117 |
+
presence-penalty = 0.0
|
| 118 |
+
min-p = 0.00
|
| 119 |
+
repeat-penalty = 1.0
|
| 120 |
+
spec-type = draft-mtp
|
| 121 |
+
spec-draft-n-max = 2
|
| 122 |
+
device = CUDA0
|
| 123 |
+
split-mode = layer
|
| 124 |
+
main-gpu = 0
|
| 125 |
+
load-mode = none
|
| 126 |
+
lazy-mode = auto
|
server.sh
CHANGED
|
@@ -1,29 +1,190 @@
|
|
| 1 |
#!/usr/bin/env bash
|
| 2 |
set -euo pipefail
|
|
|
|
| 3 |
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
set -a
|
| 5 |
-
|
|
|
|
| 6 |
set +a
|
| 7 |
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
"$
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
# --rpc "${RPC_HOSTS}:${RPC_PORT}"
|
|
|
|
| 1 |
#!/usr/bin/env bash
|
| 2 |
set -euo pipefail
|
| 3 |
+
|
| 4 |
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
| 5 |
+
ENV_FILE="${SCRIPT_DIR}/.env"
|
| 6 |
+
if [[ ! -f "${ENV_FILE}" ]]; then
|
| 7 |
+
printf 'Missing environment file: %s\n' "${ENV_FILE}" >&2
|
| 8 |
+
exit 1
|
| 9 |
+
fi
|
| 10 |
+
|
| 11 |
set -a
|
| 12 |
+
# shellcheck disable=SC1090
|
| 13 |
+
source "${ENV_FILE}"
|
| 14 |
set +a
|
| 15 |
|
| 16 |
+
CUDA_BUILD="${CUDA_BUILD:-12}"
|
| 17 |
+
DOCKER=(sudo docker)
|
| 18 |
+
|
| 19 |
+
usage() {
|
| 20 |
+
cat <<EOF
|
| 21 |
+
Usage: $(basename "$0") [command] [preset]
|
| 22 |
+
|
| 23 |
+
Commands:
|
| 24 |
+
start [preset] Start the server in the background (default)
|
| 25 |
+
daemon [preset] Alias for start
|
| 26 |
+
stop Gracefully stop the server
|
| 27 |
+
restart [preset] Stop and start the server
|
| 28 |
+
status Show the Docker container state and published port
|
| 29 |
+
|
| 30 |
+
Legacy form:
|
| 31 |
+
$(basename "$0") [preset]
|
| 32 |
+
EOF
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
container_state() {
|
| 36 |
+
local state
|
| 37 |
+
if state="$("${DOCKER[@]}" inspect --format='{{.State.Status}}' "${SERVER_CONTAINER_NAME}" 2>/dev/null)"; then
|
| 38 |
+
printf '%s\n' "${state}"
|
| 39 |
+
else
|
| 40 |
+
printf 'missing\n'
|
| 41 |
+
fi
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
remove_stale_container() {
|
| 45 |
+
if [[ "$(container_state)" != "missing" ]]; then
|
| 46 |
+
"${DOCKER[@]}" rm --force "${SERVER_CONTAINER_NAME}" >/dev/null
|
| 47 |
+
fi
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
start_server() {
|
| 51 |
+
: "${LLAMA_DIR:?LLAMA_DIR must be set in .env}"
|
| 52 |
+
: "${PRESETS_DIR:?PRESETS_DIR must be set in .env}"
|
| 53 |
+
: "${MODELS_DIR:?MODELS_DIR must be set in .env}"
|
| 54 |
+
: "${BUILDER_IMAGE:?BUILDER_IMAGE must be set in .env}"
|
| 55 |
+
: "${SERVER_HOST:?SERVER_HOST must be set in .env}"
|
| 56 |
+
: "${SERVER_PORT:?SERVER_PORT must be set in .env}"
|
| 57 |
+
: "${SERVER_INTERNAL_PORT:?SERVER_INTERNAL_PORT must be set in .env}"
|
| 58 |
+
|
| 59 |
+
if [[ "$(container_state)" == "running" ]]; then
|
| 60 |
+
printf '%s is already running\n' "${SERVER_CONTAINER_NAME}" >&2
|
| 61 |
+
return 1
|
| 62 |
+
fi
|
| 63 |
+
|
| 64 |
+
if [[ ! -f "${PRESETS_DIR}/${PRESET}" ]]; then
|
| 65 |
+
printf 'Missing server preset: %s\n' "${PRESETS_DIR}/${PRESET}" >&2
|
| 66 |
+
return 1
|
| 67 |
+
fi
|
| 68 |
+
|
| 69 |
+
if [[ ! -x "${LLAMA_DIR}/build-${CUDA_BUILD}/bin/llama-server" ]]; then
|
| 70 |
+
printf 'Missing custom llama-server: %s\n' \
|
| 71 |
+
"${LLAMA_DIR}/build-${CUDA_BUILD}/bin/llama-server" >&2
|
| 72 |
+
printf 'Build llama.cpp before starting the server.\n' >&2
|
| 73 |
+
return 1
|
| 74 |
+
fi
|
| 75 |
+
|
| 76 |
+
remove_stale_container
|
| 77 |
+
|
| 78 |
+
"${DOCKER[@]}" run --detach --rm \
|
| 79 |
+
--name "${SERVER_CONTAINER_NAME}" \
|
| 80 |
+
--gpus all \
|
| 81 |
+
--device=/dev/dri \
|
| 82 |
+
--ulimit memlock=-1:-1 \
|
| 83 |
+
--publish "${SERVER_PORT}:${SERVER_INTERNAL_PORT}" \
|
| 84 |
+
--env "HF_HOME=/models" \
|
| 85 |
+
--env "LLAMA_API_KEY=${LLAMA_API_KEY:-}" \
|
| 86 |
+
--env "HF_TOKEN=${HF_TOKEN:-}" \
|
| 87 |
+
--volume "${LLAMA_DIR}:/src" \
|
| 88 |
+
--volume "${PRESETS_DIR}:/presets" \
|
| 89 |
+
--volume "${MODELS_DIR}:/models" \
|
| 90 |
+
--workdir /models \
|
| 91 |
+
"${BUILDER_IMAGE}" \
|
| 92 |
+
"/src/build-${CUDA_BUILD}/bin/llama-server" \
|
| 93 |
+
--host "${SERVER_HOST}" \
|
| 94 |
+
--port "${SERVER_PORT}" \
|
| 95 |
+
--models-preset "/presets/${PRESET}" \
|
| 96 |
+
--log-file /presets/llama-server.log
|
| 97 |
+
printf 'Started %s in the background with preset %s\n' \
|
| 98 |
+
"${SERVER_CONTAINER_NAME}" "${PRESET}"
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
stop_server() {
|
| 102 |
+
local state timeout
|
| 103 |
+
state="$(container_state)"
|
| 104 |
+
timeout="${STOP_TIMEOUT:-30}"
|
| 105 |
+
|
| 106 |
+
if [[ "${state}" == "missing" ]]; then
|
| 107 |
+
printf '%s is not running\n' "${SERVER_CONTAINER_NAME}"
|
| 108 |
+
return 0
|
| 109 |
+
fi
|
| 110 |
+
|
| 111 |
+
if [[ "${state}" == "running" || "${state}" == "created" || "${state}" == "restarting" ]]; then
|
| 112 |
+
"${DOCKER[@]}" stop --time="${timeout}" "${SERVER_CONTAINER_NAME}" >/dev/null
|
| 113 |
+
else
|
| 114 |
+
remove_stale_container
|
| 115 |
+
fi
|
| 116 |
+
printf 'Stopped %s\n' "${SERVER_CONTAINER_NAME}"
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
status_server() {
|
| 120 |
+
local state port
|
| 121 |
+
state="$(container_state)"
|
| 122 |
+
if [[ "${state}" == "missing" ]]; then
|
| 123 |
+
printf '%s: stopped (container missing)\n' "${SERVER_CONTAINER_NAME}"
|
| 124 |
+
return 1
|
| 125 |
+
fi
|
| 126 |
+
|
| 127 |
+
port="$("${DOCKER[@]}" port "${SERVER_CONTAINER_NAME}" "${SERVER_INTERNAL_PORT}/tcp" 2>/dev/null || true)"
|
| 128 |
+
if [[ -n "${port}" ]]; then
|
| 129 |
+
printf '%s: %s (%s)\n' "${SERVER_CONTAINER_NAME}" "${state}" "${port}"
|
| 130 |
+
else
|
| 131 |
+
printf '%s: %s\n' "${SERVER_CONTAINER_NAME}" "${state}"
|
| 132 |
+
fi
|
| 133 |
+
[[ "${state}" == "running" ]]
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
if [[ $# -gt 0 ]]; then
|
| 137 |
+
COMMAND="$1"
|
| 138 |
+
else
|
| 139 |
+
COMMAND="start"
|
| 140 |
+
fi
|
| 141 |
+
PRESET="preset.ini"
|
| 142 |
+
case "${COMMAND}" in
|
| 143 |
+
start|daemon|restart)
|
| 144 |
+
if [[ $# -gt 0 ]]; then
|
| 145 |
+
shift
|
| 146 |
+
fi
|
| 147 |
+
PRESET="${1:-preset.ini}"
|
| 148 |
+
;;
|
| 149 |
+
stop|status)
|
| 150 |
+
shift
|
| 151 |
+
if [[ $# -gt 0 ]]; then
|
| 152 |
+
printf 'Unexpected argument for %s: %s\n' "${COMMAND}" "$1" >&2
|
| 153 |
+
usage >&2
|
| 154 |
+
exit 2
|
| 155 |
+
fi
|
| 156 |
+
;;
|
| 157 |
+
help|-h|--help)
|
| 158 |
+
usage
|
| 159 |
+
exit 0
|
| 160 |
+
;;
|
| 161 |
+
*)
|
| 162 |
+
# Preserve the original ./server.sh [preset] interface.
|
| 163 |
+
PRESET="${COMMAND}"
|
| 164 |
+
COMMAND="start"
|
| 165 |
+
;;
|
| 166 |
+
esac
|
| 167 |
+
|
| 168 |
+
if [[ ("${COMMAND}" == "start" || "${COMMAND}" == "daemon" || "${COMMAND}" == "restart") && $# -gt 1 ]]; then
|
| 169 |
+
printf 'Too many arguments for %s\n' "${COMMAND}" >&2
|
| 170 |
+
usage >&2
|
| 171 |
+
exit 2
|
| 172 |
+
fi
|
| 173 |
+
|
| 174 |
+
: "${SERVER_CONTAINER_NAME:?SERVER_CONTAINER_NAME must be set in .env}"
|
| 175 |
+
case "${COMMAND}" in
|
| 176 |
+
start|daemon)
|
| 177 |
+
start_server
|
| 178 |
+
;;
|
| 179 |
+
stop)
|
| 180 |
+
stop_server
|
| 181 |
+
;;
|
| 182 |
+
restart)
|
| 183 |
+
stop_server
|
| 184 |
+
start_server
|
| 185 |
+
;;
|
| 186 |
+
status)
|
| 187 |
+
status_server
|
| 188 |
+
;;
|
| 189 |
+
esac
|
| 190 |
# --rpc "${RPC_HOSTS}:${RPC_PORT}"
|