Auto-detect Scout/Maverick from config.json and add verify script

This commit is contained in:
2026-10-26 16:59:44 +08:00
parent 13f14a12e9
commit 738d9f80e4
10 changed files with 816 additions and 235 deletions

128
run.sh
View File

@@ -1,17 +1,24 @@
#!/usr/bin/env bash
#
# Llama 4 Scout / Maverick 一键构建 + 启动(Iluvatar BI-V150)
# Llama 4 统一构建 + 启动(Iluvatar BI-V150)
#
# ./run.sh scout
# ./run.sh maverick
# 自动读取模型目录下的 config.json,判断是 Scout 还是 Maverick,然后选择:
# Scout : TP8 / PP1 / 8 卡 / 8091 / llama4-scout
# Maverick : TP8 / PP2 / 16 卡 / 8092 / llama4-maverick
#
# 用法:
# ./run.sh /mnt/disk0/models/LLM-Research/Llama-4-Scout-17B-16E-Instruct
# ./run.sh /mnt/disk0/models/LLM-Research/Llama-4-Maverick-17B-128E-Instruct-FP8
# MODEL_HOST_DIR=/path/to/model ./run.sh
# ./run.sh # 依次尝试两个默认模型目录
#
# 常用覆盖项:
# GPUS=8,9,10,11,12,13,14,15 ./run.sh scout
# MODEL_HOST_DIR=/path/to/model ./run.sh maverick
# EXTRA_ARGS="--max-model-len 8192" ./run.sh scout
# EXTRA_DOCKER_ARGS="-v /mnt/disk1:/data:ro" ./run.sh scout
# BUILD=0 ./run.sh scout # 使用已有镜像,不重新构建
# DRY_RUN=1 ./run.sh scout # 只打印 docker run 命令
# GPUS=8,9,10,11,12,13,14,15 ./run.sh /path/to/scout
# EXTRA_DOCKER_ARGS="-v /mnt/disk1:/data:ro" ./run.sh /path/to/model
# EXTRA_ARGS="--max-model-len 8192" ./run.sh /path/to/model
# TP=8 PP=1 PORT=8095 SERVED_NAME=my-llama4 ./run.sh /path/to/model
# BUILD=0 ./run.sh /path/to/model # 使用已有镜像
# DRY_RUN=1 ./run.sh /path/to/model # 只打印 docker run 命令
#
set -euo pipefail
@@ -19,67 +26,91 @@ cd "$(dirname "$0")"
usage() {
cat >&2 <<'EOF'
用法: ./run.sh <scout|maverick>
用法: ./run.sh [MODEL_DIR]
预设默认值在 presets/<name>.env 中,所有值都可以用环境变量覆盖:
IMAGE NAME PORT MODEL_HOST_DIR MODEL_MOUNT SERVED_NAME
不传 MODEL_DIR 时,按顺序尝试:
/mnt/disk0/models/LLM-Research/Llama-4-Scout-17B-16E-Instruct
/mnt/disk0/models/LLM-Research/Llama-4-Maverick-17B-128E-Instruct-FP8
模型类型由 MODEL_DIR/config.json 自动判断,不需要 scout/maverick 参数。
环境变量覆盖:
IMAGE NAME MODEL_HOST_DIR MODEL_MOUNT PORT SERVED_NAME
TP PP GPUS MAX_MODEL_LEN MAX_NUM_SEQS GPU_MEM_UTIL
ENFORCE_EAGER EXTRA_ARGS EXTRA_DOCKER_ARGS
ENFORCE_EAGER AUTO_DETECT EXTRA_ARGS EXTRA_DOCKER_ARGS
BUILD=0/1 DRY_RUN=0/1
EOF
}
VARIANT="${1:-}"
if [[ -z "${VARIANT}" || "${VARIANT}" == "-h" || "${VARIANT}" == "--help" ]]; then
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage
exit 0
fi
MODEL_HOST_DIR="${1:-${MODEL_HOST_DIR:-}}"
if [[ -z "${MODEL_HOST_DIR}" ]]; then
for candidate in \
"/mnt/disk0/models/LLM-Research/Llama-4-Scout-17B-16E-Instruct" \
"/mnt/disk0/models/LLM-Research/Llama-4-Maverick-17B-128E-Instruct-FP8"; do
if [[ -f "${candidate}/config.json" ]]; then
MODEL_HOST_DIR="${candidate}"
break
fi
done
fi
if [[ -z "${MODEL_HOST_DIR}" ]]; then
echo "ERROR: 未指定模型目录,也没有找到默认模型目录。" >&2
usage
exit 2
fi
PRESET="presets/${VARIANT}.env"
if [[ ! -f "${PRESET}" ]]; then
echo "ERROR: 未知预设: ${VARIANT}" >&2
usage
exit 2
if [[ ! -f "${MODEL_HOST_DIR}/config.json" ]]; then
echo "ERROR: 模型目录不完整: ${MODEL_HOST_DIR}/config.json" >&2
echo "请先下载模型,或把 MODEL_DIR 指向正确目录。" >&2
exit 1
fi
# shellcheck disable=SC1090
source "${PRESET}"
DETECT_OUTPUT="$(python3 detect_model.py "${MODEL_HOST_DIR}")" || exit 1
eval "${DETECT_OUTPUT}"
IMAGE="${IMAGE:-${DEFAULT_IMAGE}}"
NAME="${NAME:-${DEFAULT_NAME}}"
PORT="${PORT:-${DEFAULT_PORT}}"
MODEL_HOST_DIR="${MODEL_HOST_DIR:-${DEFAULT_MODEL_HOST_DIR}}"
MODEL_KIND="${DETECTED_MODEL_KIND}"
IMAGE="${IMAGE:-llama4-bi150:2026-10-26}"
NAME="${NAME:-llama4-${MODEL_KIND}}"
PORT="${PORT:-${DETECTED_PORT}}"
MODEL_MOUNT="${MODEL_MOUNT:-/models/llama4}"
SERVED_NAME="${SERVED_NAME:-${DEFAULT_SERVED_NAME}}"
TP="${TP:-${DEFAULT_TP}}"
PP="${PP:-${DEFAULT_PP}}"
GPUS="${GPUS:-${CUDA_VISIBLE_DEVICES:-${DEFAULT_GPUS}}}"
MAX_MODEL_LEN="${MAX_MODEL_LEN:-${DEFAULT_MAX_MODEL_LEN}}"
MAX_NUM_SEQS="${MAX_NUM_SEQS:-${DEFAULT_MAX_NUM_SEQS}}"
GPU_MEM_UTIL="${GPU_MEM_UTIL:-${DEFAULT_GPU_MEM_UTIL}}"
SERVED_NAME="${SERVED_NAME:-${DETECTED_SERVED_NAME}}"
TP="${TP:-${DETECTED_TP}}"
PP="${PP:-${DETECTED_PP}}"
MAX_MODEL_LEN="${MAX_MODEL_LEN:-4096}"
MAX_NUM_SEQS="${MAX_NUM_SEQS:-1}"
GPU_MEM_UTIL="${GPU_MEM_UTIL:-0.90}"
ENFORCE_EAGER="${ENFORCE_EAGER:-1}"
AUTO_DETECT="${AUTO_DETECT:-1}"
EXTRA_ARGS="${EXTRA_ARGS:-}"
EXTRA_DOCKER_ARGS="${EXTRA_DOCKER_ARGS:-}"
BUILD="${BUILD:-1}"
DRY_RUN="${DRY_RUN:-0}"
GPU_COUNT=$((TP * PP))
if [[ -n "${GPUS:-}" ]]; then
GPUS="${GPUS}"
elif [[ -n "${CUDA_VISIBLE_DEVICES:-}" ]]; then
GPUS="${CUDA_VISIBLE_DEVICES}"
else
GPUS="$(seq -s, 0 $((GPU_COUNT - 1)))"
fi
GPUS="${GPUS// /}"
if [[ ! -f "${MODEL_HOST_DIR}/config.json" ]]; then
echo "ERROR: 模型目录不完整: ${MODEL_HOST_DIR}/config.json" >&2
echo "请先下载模型,或设置 MODEL_HOST_DIR 指向正确目录。" >&2
exit 1
fi
EXPECTED_GPUS=$((TP * PP))
if [[ -n "${GPUS}" ]]; then
IFS=',' read -r -a GPU_LIST <<< "${GPUS}"
if (( ${#GPU_LIST[@]} < EXPECTED_GPUS )); then
echo "ERROR: TP*PP=${EXPECTED_GPUS},但 GPUS 只给了 ${#GPU_LIST[@]} 张: ${GPUS}" >&2
if (( ${#GPU_LIST[@]} < GPU_COUNT )); then
echo "ERROR: ${MODEL_KIND} 需要 TP*PP=${GPU_COUNT} 张卡,但 GPUS 只给了 ${#GPU_LIST[@]} 张: ${GPUS}" >&2
exit 1
fi
if (( ${#GPU_LIST[@]} > EXPECTED_GPUS )); then
echo "WARN: TP*PP=${EXPECTED_GPUS},但 GPUS 给了 ${#GPU_LIST[@]} 张;vLLM 只会使用其中 ${EXPECTED_GPUS} 张。" >&2
if (( ${#GPU_LIST[@]} > GPU_COUNT )); then
echo "WARN: TP*PP=${GPU_COUNT},但 GPUS 给了 ${#GPU_LIST[@]} 张;vLLM 只会使用其中 ${GPU_COUNT} 张。" >&2
fi
fi
@@ -101,6 +132,8 @@ DOCKER_RUN=(
--ulimit stack=67108864
-e CUDA_VISIBLE_DEVICES="${GPUS}"
-e MODEL_PATH="${MODEL_MOUNT}"
-e AUTO_DETECT="${AUTO_DETECT}"
-e MODEL_KIND="${MODEL_KIND}"
-e SERVED_NAME="${SERVED_NAME}"
-e PORT="${PORT}"
-e TP="${TP}"
@@ -115,6 +148,11 @@ DOCKER_RUN=(
"${IMAGE}"
)
echo "==> detected ${MODEL_KIND}: ${DETECTED_DESCRIPTION}"
echo " model : ${MODEL_HOST_DIR}"
echo " TP/PP : ${TP}/${PP} (${GPU_COUNT} GPUs), port=${PORT}, name=${SERVED_NAME}"
echo " GPUs : ${GPUS}"
if [[ "${DRY_RUN}" == "1" ]]; then
printf '%q ' "${DOCKER_RUN[@]}"
printf '\n'
@@ -131,7 +169,7 @@ fi
echo "==> recreate ${NAME}"
docker rm -f "${NAME}" 2>/dev/null || true
echo "==> run ${VARIANT}: GPUs=${GPUS}, TP=${TP}, PP=${PP}, model=${MODEL_HOST_DIR}"
echo "==> run ${MODEL_KIND}"
"${DOCKER_RUN[@]}"
echo "==> wait for http://127.0.0.1:${PORT}/health"