Default 122B server to 128k context, add health-check script

- 11_start_server_122b.sh: raise MAX_MODEL_LEN default to 131072 (128k),
  make max-num-seqs overridable via MAX_NUM_SEQS (default 4 for low
  concurrency / large KV cache). Echo concurrency in startup banner.
- 13_check_server.sh: new health check that polls /v1/models until ready,
  then sends a properly-sized test prompt and reports OK/failure.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
herzogflorian 2026-06-08 10:29:13 +02:00
parent 030d9f7935
commit b9eaf2df18
2 changed files with 136 additions and 3 deletions

View File

@ -13,10 +13,13 @@
# Environment variables (override defaults): # Environment variables (override defaults):
# MODEL_DIR - Path to model weights (default: ~/models/Qwen3.5-122B-A10B-FP8) # MODEL_DIR - Path to model weights (default: ~/models/Qwen3.5-122B-A10B-FP8)
# PORT - Server port (default: 7080) # PORT - Server port (default: 7080)
# MAX_MODEL_LEN - Maximum context length (default: 32768) # MAX_MODEL_LEN - Maximum context length (default: 131072 = 128k)
# GPU_MEM_UTIL - GPU memory utilization fraction (default: 0.92) # GPU_MEM_UTIL - GPU memory utilization fraction (default: 0.92)
# API_KEY - API key for authentication (default: none) # API_KEY - API key for authentication (default: none)
# TENSOR_PARALLEL - Number of GPUs for tensor parallelism (default: 4) # TENSOR_PARALLEL - Number of GPUs for tensor parallelism (default: 4)
# MAX_NUM_SEQS - Max concurrent sequences (default: 4). Raise this
# when more users need it AND the KV cache fits;
# lower it if 128k context runs out of memory.
# ------------------------------------------------------------------ # ------------------------------------------------------------------
set -euo pipefail set -euo pipefail
@ -25,10 +28,11 @@ SIF_FILE="${SCRIPT_DIR}/vllm_qwen.sif"
MODEL_DIR="${MODEL_DIR:-$HOME/models/Qwen3.5-122B-A10B-FP8}" MODEL_DIR="${MODEL_DIR:-$HOME/models/Qwen3.5-122B-A10B-FP8}"
PORT="${PORT:-7080}" PORT="${PORT:-7080}"
MAX_MODEL_LEN="${MAX_MODEL_LEN:-32768}" MAX_MODEL_LEN="${MAX_MODEL_LEN:-131072}"
GPU_MEM_UTIL="${GPU_MEM_UTIL:-0.92}" GPU_MEM_UTIL="${GPU_MEM_UTIL:-0.92}"
API_KEY="${API_KEY:-}" API_KEY="${API_KEY:-}"
TENSOR_PARALLEL="${TENSOR_PARALLEL:-4}" TENSOR_PARALLEL="${TENSOR_PARALLEL:-4}"
MAX_NUM_SEQS="${MAX_NUM_SEQS:-4}"
if [ ! -f "$SIF_FILE" ]; then if [ ! -f "$SIF_FILE" ]; then
echo "ERROR: Container image not found at ${SIF_FILE}" echo "ERROR: Container image not found at ${SIF_FILE}"
@ -56,7 +60,7 @@ VLLM_ARGS=(
--trust-remote-code --trust-remote-code
--reasoning-parser qwen3 --reasoning-parser qwen3
--served-model-name "qwen3.5-122b-a10b-fp8" --served-model-name "qwen3.5-122b-a10b-fp8"
--max-num-seqs 16 --max-num-seqs "$MAX_NUM_SEQS"
--enable-prefix-caching --enable-prefix-caching
) )
@ -73,6 +77,7 @@ echo " Port: ${PORT}"
echo " Context len: ${MAX_MODEL_LEN}" echo " Context len: ${MAX_MODEL_LEN}"
echo " GPU util: ${GPU_MEM_UTIL}" echo " GPU util: ${GPU_MEM_UTIL}"
echo " TP size: ${TENSOR_PARALLEL}" echo " TP size: ${TENSOR_PARALLEL}"
echo " Max seqs: ${MAX_NUM_SEQS}"
echo " dtype: auto (FP8)" echo " dtype: auto (FP8)"
echo " API key: ${API_KEY:-<none>}" echo " API key: ${API_KEY:-<none>}"
echo "==============================================" echo "=============================================="

128
13_check_server.sh Executable file
View File

@ -0,0 +1,128 @@
#!/usr/bin/env bash
# ------------------------------------------------------------------
# 13_check_server.sh
# Health-checks the vLLM server: polls /v1/models until the model is
# ready, then sends a properly-sized test prompt and prints the reply.
#
# Works whether you run it ON the server (localhost) or from another
# machine (use HOST=silicon.fhgr.ch).
#
# Usage:
# bash 13_check_server.sh
# HOST=silicon.fhgr.ch bash 13_check_server.sh
#
# Environment variables (override defaults):
# HOST - Server hostname (default: localhost)
# PORT - Server port (default: 7080)
# API_KEY - API key, if the server needs one (default: none)
# TIMEOUT - Seconds to wait for model (default: 600)
# MAX_TOKENS - Tokens for the test prompt (default: 512)
#
# NOTE: The model is a reasoning model — it spends tokens "thinking"
# before the final answer. MAX_TOKENS must be generous (>=256),
# or the reply ends up empty with finish_reason "length".
# ------------------------------------------------------------------
set -euo pipefail
HOST="${HOST:-localhost}"
PORT="${PORT:-7080}"
API_KEY="${API_KEY:-}"
TIMEOUT="${TIMEOUT:-600}"
MAX_TOKENS="${MAX_TOKENS:-512}"
BASE_URL="http://${HOST}:${PORT}/v1"
AUTH_ARGS=()
if [ -n "$API_KEY" ]; then
AUTH_ARGS=(-H "Authorization: Bearer ${API_KEY}")
fi
echo "=============================================="
echo " vLLM Server Health Check"
echo "=============================================="
echo " Endpoint: ${BASE_URL}"
echo " Timeout: ${TIMEOUT}s"
echo " Max tokens: ${MAX_TOKENS}"
echo "=============================================="
echo ""
# --- Step 1: poll /v1/models until ready -------------------------
echo "Waiting for server to respond at ${BASE_URL}/models ..."
DEADLINE=$(( $(date +%s) + TIMEOUT ))
MODELS_JSON=""
while true; do
if MODELS_JSON=$(curl -s -m 5 ${AUTH_ARGS[@]+"${AUTH_ARGS[@]}"} "${BASE_URL}/models" 2>/dev/null) \
&& echo "$MODELS_JSON" | grep -q '"data"'; then
break
fi
if [ "$(date +%s)" -ge "$DEADLINE" ]; then
echo "ERROR: Server did not become ready within ${TIMEOUT}s."
echo " Check the log: tail -f logs/vllm_server_122b_*.log"
exit 1
fi
printf '.'
sleep 5
done
echo ""
# Extract the served model id (first entry under data[]).
MODEL_ID=$(echo "$MODELS_JSON" | python3 -c \
"import sys, json; print(json.load(sys.stdin)['data'][0]['id'])" 2>/dev/null || true)
if [ -z "$MODEL_ID" ]; then
echo "ERROR: Could not parse model id from /v1/models response:"
echo "$MODELS_JSON"
exit 1
fi
echo "Server is up. Serving model: ${MODEL_ID}"
echo ""
# --- Step 2: send a real generation request ----------------------
echo "Sending test prompt..."
REQUEST=$(python3 -c "
import json, sys
print(json.dumps({
'model': sys.argv[1],
'messages': [{'role': 'user', 'content': 'Reply with exactly one word: hello'}],
'max_tokens': int(sys.argv[2]),
}))
" "$MODEL_ID" "$MAX_TOKENS")
RESPONSE=$(curl -s -m 120 ${AUTH_ARGS[@]+"${AUTH_ARGS[@]}"} \
-H "Content-Type: application/json" \
-d "$REQUEST" \
"${BASE_URL}/chat/completions")
echo ""
echo "$RESPONSE" | python3 -c "
import sys, json
try:
d = json.load(sys.stdin)
except Exception:
print('ERROR: Non-JSON response from server:')
print(sys.stdin.read() if not sys.stdin.closed else '<empty>')
sys.exit(1)
choice = d['choices'][0]
msg = choice.get('message', {})
content = msg.get('content')
finish = choice.get('finish_reason')
usage = d.get('usage', {})
print('Finish reason: %s' % finish)
print('Usage: %s' % usage)
print('Content: %r' % content)
print()
if content and content.strip():
print('RESULT: OK — model generated a reply. Server is working.')
elif finish == 'length':
print('RESULT: Model hit the token limit while reasoning and never')
print(' produced an answer. Re-run with a larger budget, e.g.:')
print(' MAX_TOKENS=1024 bash 13_check_server.sh')
sys.exit(2)
else:
print('RESULT: Empty content with finish_reason=%r. Investigate.' % finish)
sys.exit(2)
"