6/28/2026

setup-llama-linux.sh

#!/usr/bin/env bash

set -euo pipefail


# 国内环境默认使用 HuggingFace 镜像站,可通过环境变量覆盖

export HF_ENDPOINT="${HF_ENDPOINT:-https://hf-mirror.com}"


# GitHub 国内加速代理,可通过环境变量覆盖或置空

GITHUB_PROXY="${GITHUB_PROXY:-https://ghproxy.com/}"


# 用法:

# chmod +x setup-llama-linux.sh

# ./setup-llama-linux.sh [huggingface模型ID[:GGUF后缀]]

#

# 示例:

# ./setup-llama-linux.sh

# ./setup-llama-linux.sh Andycurrent/Qwen3.5-4B-Uncensored-HauhauCS-Aggressive:Q4_K_M

# ./setup-llama-linux.sh unsloth/Llama-3.2-1B-Instruct-GGUF:Q4_K_M


MODEL_SPEC="${1:-Andycurrent/Qwen3.5-4B-Uncensored-HauhauCS-Aggressive:Q4_K_M}"

MODEL_ID="${MODEL_SPEC%%:*}"

GGUF_SUFFIX="${MODEL_SPEC##*:}"


# 如果只给了模型 ID 没给后缀,默认 Q4_K_M

if [[ "$MODEL_ID" == "$MODEL_SPEC" ]]; then

GGUF_SUFFIX="${2:-Q4_K_M}"

fi


if [[ -z "$MODEL_ID" ]]; then

echo "错误: 请提供 Hugging Face 模型 ID"

echo "用法: $0 <huggingface模型ID>[:GGUF后缀]"

echo "示例: $0 Andycurrent/Qwen3.5-4B-Uncensored-HauhauCS-Aggressive:Q4_K_M"

exit 1

fi


MODEL_DIR="models"


# 1. 选择后端(三种模式都使用 llama.cpp 预编译 release)

echo ""

echo "请选择运行后端:"

echo " 1) CPU 模式 (默认,无需 GPU 驱动)"

echo " 2) Vulkan 模式 (推荐,兼容 AMD/Intel/NVIDIA 核显/独显)"

echo " 3) ROCm/HIP 模式 (AMD GPU 专用,性能通常最好)"

read -rp "输入 1/2/3 [默认 1]: " BACKEND

BACKEND="${BACKEND:-1}"


case "$BACKEND" in

1) BACKEND_NAME="cpu"; BACKEND_DIR="llama.cpp-cpu-bin" ;;

2) BACKEND_NAME="vulkan"; BACKEND_DIR="llama.cpp-vulkan-bin" ;;

3) BACKEND_NAME="rocm"; BACKEND_DIR="llama.cpp-rocm-bin" ;;

*) echo "错误: 无效选择"; exit 1 ;;

esac


# 2. 安装依赖(三种模式都只需要下载/解压工具)

echo "==> 安装下载/解压所需依赖..."

if command -v apt-get &>/dev/null; then

sudo apt-get update

sudo apt-get install -y python3-pip wget curl tar

else

echo "警告: 未检测到 apt-get,请手动安装 python3-pip、wget、curl、tar"

fi


# 3. 后端特定检查

if [[ "$BACKEND" == "2" ]]; then

echo "==> Vulkan 模式:安装 Vulkan 驱动..."

if command -v apt-get &>/dev/null; then

sudo apt-get install -y vulkan-tools mesa-vulkan-drivers

else

echo "警告: 未检测到 apt-get,请手动安装 vulkan-tools、mesa-vulkan-drivers"

fi


if command -v vulkaninfo &>/dev/null; then

echo "==> Vulkan 设备信息:"

vulkaninfo --summary 2>/dev/null || true

else

echo "提示: 未找到 vulkaninfo,安装完成后建议重启或重新登录以加载驱动。"

fi

elif [[ "$BACKEND" == "3" ]]; then

echo "==> ROCm/HIP 模式:检查 ROCm runtime..."

if ! command -v rocminfo &>/dev/null && ! command -v hipcc &>/dev/null; then

echo "错误: 未检测到 rocminfo / hipcc,请先安装 ROCm runtime。"

echo "参考命令:"

echo " sudo apt install rocm-dev hipblas rocblas amdgpu-install"

exit 1

fi


export HSA_OVERRIDE_GFX_VERSION="${HSA_OVERRIDE_GFX_VERSION:-11.0.3}"

export AMDGPU_TARGETS="${AMDGPU_TARGETS:-gfx1103}"

echo "==> HSA_OVERRIDE_GFX_VERSION=$HSA_OVERRIDE_GFX_VERSION"

echo "==> AMDGPU_TARGETS=$AMDGPU_TARGETS"

fi


# 4. 下载并解压 llama.cpp 预编译包

echo "==> 查询 llama.cpp 最新 ${BACKEND_NAME} 预编译包..."

RELEASE_JSON=$(mktemp)

trap 'rm -f "$RELEASE_JSON"' EXIT


if ! curl -fsSL -o "$RELEASE_JSON" "${GITHUB_PROXY}https://api.github.com/repos/ggml-org/llama.cpp/releases/latest"; then

echo "错误: 无法获取 llama.cpp release 信息,请检查网络或 GITHUB_PROXY 设置"

exit 1

fi


LATEST_TAG=$(python3 -c "import json; print(json.load(open('$RELEASE_JSON'))['tag_name'])")


ASSET=$(python3 -c "

import json

name = ''

for asset in json.load(open('$RELEASE_JSON'))['assets']:

n = asset['name']

if not n.endswith('.tar.gz'):

continue

if '$BACKEND_NAME' == 'cpu' and n.endswith('-bin-ubuntu-x64.tar.gz'):

name = n

break

elif '$BACKEND_NAME' == 'vulkan' and '-bin-ubuntu-vulkan-' in n:

name = n

break

elif '$BACKEND_NAME' == 'rocm' and '-bin-ubuntu-rocm-' in n:

name = n

break

print(name)

")


if [[ -z "$LATEST_TAG" || -z "$ASSET" ]]; then

echo "错误: 未找到 ${BACKEND_NAME} 预编译包"

exit 1

fi


echo "==> 最新版本: $LATEST_TAG"

echo "==> 下载包: $ASSET"


rm -rf "$BACKEND_DIR"

mkdir -p "$BACKEND_DIR"


DOWNLOAD_URL="${GITHUB_PROXY}https://github.com/ggml-org/llama.cpp/releases/download/${LATEST_TAG}/${ASSET}"

echo "==> 下载地址: $DOWNLOAD_URL"

wget -q --show-progress -O "$ASSET" "$DOWNLOAD_URL"


echo "==> 解压到 $BACKEND_DIR ..."

tar -xzf "$ASSET" -C "$BACKEND_DIR" --strip-components=1

rm -f "$ASSET"


# 确定可执行文件路径

find_llama_bin() {

local name="$1"

if [[ -f "$BACKEND_DIR/bin/$name" ]]; then

echo "$BACKEND_DIR/bin/$name"

elif [[ -f "$BACKEND_DIR/build/bin/$name" ]]; then

echo "$BACKEND_DIR/build/bin/$name"

else

echo ""

fi

}


CLI_BIN=$(find_llama_bin llama-cli)

SERVER_BIN=$(find_llama_bin llama-server)


if [[ -z "$CLI_BIN" || -z "$SERVER_BIN" ]]; then

echo "错误: 解压后未找到 llama-cli / llama-server"

exit 1

fi


# 5. 安装 huggingface-cli 用于下载模型

echo "==> 安装 huggingface-hub..."

pip3 install --user -U huggingface-hub


# 6. 下载模型

mkdir -p "$MODEL_DIR"

echo "==> 使用 HuggingFace 镜像: $HF_ENDPOINT"

echo "==> 下载模型 $MODEL_ID (后缀: $GGUF_SUFFIX)..."

huggingface-cli download "$MODEL_ID" \

--include "*.gguf" \

--local-dir "$MODEL_DIR/$MODEL_ID" \

--local-dir-use-symlinks False


# 尝试匹配对应后缀的 GGUF 文件

MODEL_FILE=$(find "$MODEL_DIR/$MODEL_ID" -maxdepth 1 -type f -name "*${GGUF_SUFFIX}*.gguf" | head -n 1)


# 如果没找到指定后缀,则任选第一个 GGUF

if [[ -z "$MODEL_FILE" ]]; then

MODEL_FILE=$(find "$MODEL_DIR/$MODEL_ID" -maxdepth 1 -type f -name "*.gguf" | head -n 1)

fi


if [[ -z "$MODEL_FILE" ]]; then

echo "错误: 未找到任何 .gguf 文件"

exit 1

fi


echo "==> 使用模型文件: $MODEL_FILE"


# 7. 选择运行模式并执行

echo ""

echo "请选择运行模式:"

echo " 1) cli 模式 (命令行交互)"

echo " 2) server 模式 (HTTP API 服务,默认端口 8080)"

read -rp "输入 1 或 2 [默认 1]: " MODE

MODE="${MODE:-1}"


# 公共参数

COMMON_ARGS=(

--model "$MODEL_FILE"

--ctx-size 512

--threads "$(nproc)"

--no-mmap

--cache-type-k q4_0

--cache-type-v q4_0

)


# 根据后端决定是否 GPU offload

if [[ "$BACKEND" == "1" ]]; then

COMMON_ARGS+=(-ngl 0)

else

COMMON_ARGS+=(-ngl 999)

fi


if [[ "$MODE" == "2" ]]; then

BIN="$SERVER_BIN"

RUN_ARGS=("${COMMON_ARGS[@]}" --host 127.0.0.1 --port 8080)

echo ""

echo "==> 准备以 server 模式启动..."

else

BIN="$CLI_BIN"

RUN_ARGS=("${COMMON_ARGS[@]}" --prompt "Hello, world!" --n-predict 64)

echo ""

echo "==> 准备以 cli 模式启动..."

fi


# 打印将要执行的完整命令

echo ""

echo "将要执行的命令:"

printf '%q ' "$BIN" "${RUN_ARGS[@]}"

echo ""

echo ""


# 执行

"$BIN" "${RUN_ARGS[@]}"