testzerogpu / installpi.sh
opencode
Sync with HelloSun/testzerogpu
c98a8c2
Raw History Blame Contribute Delete
20.8 kB
#!/usr/bin/env bash
set -euo pipefail
# ==============================================================================
# installpi.sh - 一键全自动安装 pi + llama.cpp (源码编译) + Qwen2.5 模型
# 特性:无 sudo、无互动、全自动、可断点续传、安装后自动验证
# 模型:unsloth/GLM-4.7-Flash-GGUF (GLM-4.7-Flash-Q4_K_M.gguf)
# 启动:taskset -c 0-14 llama-server ... -t 15 --jinja --load-mode mlock -c 65536 (64K上下文)
# ==============================================================================
HOME_DIR="$HOME"
# 脚本一开始就把之前安装的 node / pi / llama 路径放进 PATH,避免每次重复装 node
export PATH="${XDG_DATA_HOME:-$HOME/.local/share}/pi-node/current/bin:$HOME/.local/bin:$HOME/.pi/bin:$PATH"
LLAMA_SRC_DIR="$HOME_DIR/llama.cpp" # 源码目录
LLAMA_BIN="$LLAMA_SRC_DIR/build/bin" # 编译后二进制目录
MODEL_DIR="$HOME_DIR/models"
PI_MODELS_JSON="$HOME_DIR/.pi/agent/models.json"
LLAMA_PORT=8080
REPO="unsloth/GLM-4.7-Flash-GGUF"
MODEL_FILE="GLM-4.7-Flash-Q4_K_M.gguf"
MODEL_ID="glm-4.7-flash-q4_k_m"
PROVIDER_ID="llama-cpp-local"
CONTEXT_SIZE=65536 # 上下文 64K
# 基础输出函数
info() { echo -e "\033[36m[INFO]\033[0m $*"; }
ok() { echo -e "\033[32m[OK]\033[0m $*"; }
warn() { echo -e "\033[33m[WARN]\033[0m $*" >&2; }
error() { echo -e "\033[31m[ERROR]\033[0m $*" >&2; exit 1; }
# 确保必要目录
mkdir -p "$LLAMA_SRC_DIR" "$MODEL_DIR" "$(dirname "$PI_MODELS_JSON")" "$HOME_DIR/.local/bin"
# 检查必要工具(新增编译依赖)
for cmd in curl python3 tar git cmake g++; do
command -v "$cmd" >/dev/null 2>&1 || error "缺少必要工具: $cmd,请先安装"
done
# ==============================================================================
# 0. 确保 Node.js >=22.19.0 (pi 依赖)
# ==============================================================================
ensure_node() {
if command -v node >/dev/null 2>&1; then
if node -e 'const [maj,min,patch]=process.versions.node.split(".").map(Number); process.exit(maj>22||(maj===22&&(min>19||(min===19&&patch>=0)))?0:1)' >/dev/null 2>&1; then
ok "Node.js 已满足: $(node --version)"
return 0
else
warn "Node.js 版本过旧: $(node --version),将自动安装新版..."
fi
else
info "未检测到 Node.js,将自动安装..."
fi
info "自动安装 Node.js 22.x (standalone 模式)..."
NODE_DIST_BASE="https://nodejs.org/dist/latest-v22.x"
NODE_BASE_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/pi-node"
NODE_TMP_DIR="/tmp/pi-node-$$"
mkdir -p "$NODE_TMP_DIR" "$NODE_BASE_DIR"
OS="$(uname -s)"
ARCH="$(uname -m)"
case "$OS" in Linux) PLATFORM="linux" ;; Darwin) PLATFORM="darwin" ;; *) error "不支持的 OS: $OS" ;; esac
case "$ARCH" in x86_64|amd64) NODE_ARCH="x64" ;; aarch64|arm64) NODE_ARCH="arm64" ;; *) error "不支持的架构: $ARCH" ;; esac
info "解析 Node.js 下载链接 ($PLATFORM-$NODE_ARCH)..."
curl -fsSL --retry 3 --retry-delay 5 "$NODE_DIST_BASE/SHASUMS256.txt" -o "$NODE_TMP_DIR/SHASUMS256.txt" || error "下载 SHASUMS 失败"
NODE_FILE=$(awk -v suffix="-$PLATFORM-$NODE_ARCH.tar.xz" 'index($2,"node-v")==1 && substr($2,length($2)-length(suffix)+1)==suffix{print $2; exit}' "$NODE_TMP_DIR/SHASUMS256.txt")
[[ -n "$NODE_FILE" ]] || error "找不到对应平台的 Node.js 二进制"
info "下载 Node.js $NODE_FILE ..."
curl -fsSL --retry 3 --retry-delay 5 "$NODE_DIST_BASE/$NODE_FILE" -o "$NODE_TMP_DIR/$NODE_FILE" || error "Node.js 下载失败"
if command -v sha256sum >/dev/null 2>&1; then
(cd "$NODE_TMP_DIR" && grep -F "$NODE_FILE" SHASUMS256.txt > SHASUMS256.selected && sha256sum -c SHASUMS256.selected) || warn "SHA256 校验失败,继续安装..."
fi
if ! command -v xz >/dev/null 2>&1; then
warn "未找到 xz,将尝试使用 tar 自动解压 (若失败请手动安装 xz-utils)"
fi
NODE_EXTRACT_DIR="$NODE_BASE_DIR/${NODE_FILE%.tar.xz}"
rm -rf "$NODE_EXTRACT_DIR"
tar -xf "$NODE_TMP_DIR/$NODE_FILE" -C "$NODE_BASE_DIR" || error "解压 Node.js 失败"
rm -f "$NODE_BASE_DIR/current"
ln -s "$NODE_EXTRACT_DIR" "$NODE_BASE_DIR/current"
rm -rf "$NODE_TMP_DIR"
export PATH="$NODE_BASE_DIR/current/bin:$PATH"
for rc in "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.profile"; do
if [[ -f "$rc" ]] || [[ "$rc" == "$HOME/.bashrc" ]]; then
grep -q "pi-node/current/bin" "$rc" 2>/dev/null || echo "export PATH=\"$NODE_BASE_DIR/current/bin:\$PATH\"" >> "$rc"
fi
done
if command -v node >/dev/null 2>&1; then
ok "Node.js 安装完成: $(node --version) at $(command -v node)"
else
error "Node.js 安装后仍无法找到,请检查 PATH"
fi
}
ensure_node
command -v npm >/dev/null 2>&1 || error "npm 仍不可用,Node 安装可能失败"
info "npm 版本: $(npm --version)"
# ==============================================================================
# 1. 编译 llama.cpp (从源码)
# ==============================================================================
info "1) 编译 llama.cpp (源码)..."
if [[ "${LLAMA_FORCE_REBUILD:-0}" == "1" ]]; then
info "LLAMA_FORCE_REBUILD=1,清理旧 build 目录强制重编..."
rm -rf "$LLAMA_SRC_DIR/build"
fi
if [[ ! -x "$LLAMA_BIN/llama-server" ]]; then
info "克隆 llama.cpp 仓库 (深度1)..."
if [[ -d "$LLAMA_SRC_DIR/.git" ]]; then
info "源码目录已存在,更新..."
cd "$LLAMA_SRC_DIR"
git pull || warn "git pull 失败,继续使用现有源码"
else
git clone --depth 1 https://github.com/ggml-org/llama.cpp "$LLAMA_SRC_DIR"
fi
cd "$LLAMA_SRC_DIR"
info "执行 cmake 配置 (纯 CPU,不开 NATIVE/DL,避免 MoE/多变体后端在纯 CPU 上崩)..."
rm -rf build
cmake -B build \
-DGGML_NATIVE=OFF \
-DGGML_CPU=ON \
-DGGML_BACKEND_DL=OFF \
-DLLAMA_BUILD_TESTS=OFF \
-DCMAKE_BUILD_TYPE=Release
info "开始编译 (使用 -j16)..."
cmake --build build --config Release -j 16
# 验证编译产物
if [[ -x "$LLAMA_BIN/llama-server" ]]; then
ok "llama.cpp 编译完成: $LLAMA_BIN/llama-server"
else
error "编译失败,找不到 llama-server"
fi
else
ok "llama-server 已存在,跳过编译 (如需重编: LLAMA_FORCE_REBUILD=1 ./installpi.sh)"
fi
# 更新 PATH
export PATH="$LLAMA_BIN:$HOME_DIR/.local/bin:$PATH"
export LD_LIBRARY_PATH="$LLAMA_BIN:${LD_LIBRARY_PATH:-}"
for rc in "$HOME/.bashrc" "$HOME/.zshrc"; do
touch "$rc" 2>/dev/null || true
grep -q "llama.cpp/build/bin" "$rc" 2>/dev/null || echo "export PATH=\"$LLAMA_BIN:\$PATH\"" >> "$rc"
grep -q "LD_LIBRARY_PATH.*llama.cpp" "$rc" 2>/dev/null || echo "export LD_LIBRARY_PATH=\"$LLAMA_BIN:\$LD_LIBRARY_PATH\"" >> "$rc"
done
# ==============================================================================
# 2. 下载模型 (直接使用指定 URL)
# ==============================================================================
info "2) 下载模型 ${REPO} -> ${MODEL_FILE} ..."
MODEL_URL="https://huggingface.co/${REPO}/resolve/main/${MODEL_FILE}"
MODEL_PATH="$MODEL_DIR/${MODEL_FILE}"
if [[ ! -f "$MODEL_PATH" ]]; then
info "开始下载模型 (支持断点续传)..."
curl -L -C - --retry 3 --retry-delay 5 --progress-bar "$MODEL_URL" -o "$MODEL_PATH" || error "模型下载失败"
ok "模型下载完成: $MODEL_PATH"
else
SIZE=$(stat -c%s "$MODEL_PATH" 2>/dev/null || stat -f%z "$MODEL_PATH" 2>/dev/null || echo 0)
if [[ "$SIZE" -lt 1000000000 ]]; then
warn "模型文件过小 (${SIZE} bytes),可能下载不完整,将尝试续传..."
curl -L -C - --retry 3 --retry-delay 5 --progress-bar "$MODEL_URL" -o "$MODEL_PATH" || error "续传失败"
fi
ok "模型已存在,跳过下载: $MODEL_PATH ($SIZE bytes)"
fi
# ==============================================================================
# 3. 启动 llama-server (使用 taskset 和指定参数,上下文 64K)
# ==============================================================================
info "3) 启动 llama-server (port $LLAMA_PORT, taskset 0-14, context $CONTEXT_SIZE)..."
# 清理旧进程
if [[ -f "$HOME_DIR/llama-server.pid" ]]; then
OLD_PID=$(cat "$HOME_DIR/llama-server.pid" 2>/dev/null || echo "")
if [[ -n "$OLD_PID" ]] && kill -0 "$OLD_PID" 2>/dev/null; then
info "停止旧 llama-server (PID $OLD_PID)..."
kill "$OLD_PID" 2>/dev/null || true
sleep 2
kill -9 "$OLD_PID" 2>/dev/null || true
fi
fi
pkill -f "llama-server.*${LLAMA_PORT}" 2>/dev/null || true
sleep 1
# 按实际 CPU 数决定 taskset 范围 / 线程数 (避免机器核数不足时 taskset 报错)
NPROC=$(nproc 2>/dev/null || echo 16)
if [[ "$NPROC" -ge 15 ]]; then
TASKSET_ARGS=(-c 0-14)
NTHREADS=15
else
TASKSET_ARGS=(-c "0-$((NPROC-1))")
NTHREADS="$NPROC"
fi
if ! taskset "${TASKSET_ARGS[@]}" true 2>/dev/null; then
warn "taskset ${TASKSET_ARGS[*]} 不可用,改用不绑核启动"
TASKSET_ARGS=()
fi
# 构建命令(prlimit 限制内存 32GB;LD_LIBRARY_PATH 已在前面 export,prlimit 会继承)
CMD=(
taskset "${TASKSET_ARGS[@]}"
prlimit --as=34359738368
"$LLAMA_BIN/llama-server"
-m "$MODEL_PATH"
--alias "$MODEL_ID"
-t "$NTHREADS"
--jinja
--load-mode mlock
-c "$CONTEXT_SIZE"
--host 127.0.0.1
--port "$LLAMA_PORT"
)
# taskset 参数为空时去掉 taskset 本体
if [[ "${#TASKSET_ARGS[@]}" -eq 0 ]]; then
CMD=(prlimit --as=34359738368 "$LLAMA_BIN/llama-server" -m "$MODEL_PATH" --alias "$MODEL_ID" -t "$NTHREADS" --jinja --load-mode mlock -c "$CONTEXT_SIZE" --host 127.0.0.1 --port "$LLAMA_PORT")
fi
info "启动命令: ${CMD[*]}"
touch "$HOME_DIR/llama-server.log" 2>/dev/null || true
nohup "${CMD[@]}" > "$HOME_DIR/llama-server.log" 2>&1 &
echo $! > "$HOME_DIR/llama-server.pid"
info "llama-server PID: $(cat "$HOME_DIR/llama-server.pid")"
# 等待服务器就绪 (最长 5 分钟)
info "等待 llama-server 就绪 (最多 5 分钟)..."
READY=0
for i in {1..60}; do
if curl -sf "http://127.0.0.1:${LLAMA_PORT}/health" >/dev/null 2>&1; then
ok "llama-server 已就绪 (http://127.0.0.1:${LLAMA_PORT})"
READY=1
break
fi
if curl -sf "http://127.0.0.1:${LLAMA_PORT}/v1/models" >/dev/null 2>&1; then
ok "llama-server 已就绪 (via /v1/models)"
READY=1
break
fi
if ! kill -0 $(cat "$HOME_DIR/llama-server.pid" 2>/dev/null || echo 0) 2>/dev/null; then
error "llama-server 启动失败,请查看 ~/llama-server.log (最后 50 行):\n$(tail -n 50 "$HOME_DIR/llama-server.log" 2>/dev/null)"
fi
echo -n "."
sleep 5
done
echo ""
if [[ "$READY" -ne 1 ]]; then
error "llama-server 在 5 分钟内未就绪,请查看 ~/llama-server.log"
fi
# ==============================================================================
# 4. 安装 pi agent (全自动,无互动)
# ==============================================================================
info "4) 安装 pi agent (全自动)..."
NPM_PREFIX=$(npm prefix -g 2>/dev/null || npm config get prefix 2>/dev/null || echo "$HOME/.local")
info "npm 全局前缀: $NPM_PREFIX"
# 确保 PATH 包含本地 bin 目录
export PATH="$HOME/.local/bin:$HOME/.pi/bin:$NPM_PREFIX/bin:$PATH"
NEED_INSTALL=1
if command -v pi >/dev/null 2>&1; then
ok "pi 已安装: $(pi --version 2>&1 | head -n 1)"
NEED_INSTALL=0
if [[ "${PI_FORCE_REINSTALL:-0}" == "1" ]]; then
info "PI_FORCE_REINSTALL=1,强制重新安装..."
NEED_INSTALL=1
fi
fi
if [[ "$NEED_INSTALL" -eq 1 ]]; then
info "安装 pi (@earendil-works/pi-coding-agent)..."
PI_PACKAGE="@earendil-works/pi-coding-agent"
# 优先安装到 ~/.local (无需 sudo)
INSTALL_PREFIX="$HOME/.local"
info "安装到 $INSTALL_PREFIX (无需 sudo)"
set +e
npm install -g --ignore-scripts --no-fund --no-audit --progress=false --prefix "$INSTALL_PREFIX" "$PI_PACKAGE" 2>&1 | tee /tmp/pi-install.log
NPM_STATUS=${PIPESTATUS[0]}
set -e
if [[ "$NPM_STATUS" -ne 0 ]]; then
warn "npm 安装 pi 失败 (code $NPM_STATUS),尝试备用方法: curl 官方脚本..."
curl -fsSL https://pi.dev/install.sh | bash -s -- 2>&1 | tee -a /tmp/pi-install.log || true
fi
export PATH="$HOME/.local/bin:$HOME/.pi/bin:$NPM_PREFIX/bin:$PATH"
NODE_BIN_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/pi-node/current/bin"
export PATH="$NODE_BIN_DIR:$PATH"
hash -r 2>/dev/null || true
fi
PI_BIN=$(command -v pi 2>/dev/null || echo "")
if [[ -z "$PI_BIN" ]]; then
for cand in "$HOME/.local/bin/pi" "$HOME/.pi/bin/pi" "$NPM_PREFIX/bin/pi" "/usr/local/bin/pi"; do
if [[ -x "$cand" ]]; then
PI_BIN="$cand"
export PATH="$(dirname "$cand"):$PATH"
break
fi
done
fi
if [[ -z "$PI_BIN" ]] || [[ ! -x "$PI_BIN" ]]; then
error "pi 安装后仍找不到执行档,请查看 /tmp/pi-install.log"
fi
ok "pi 可用: $PI_BIN ($(pi --version 2>&1 | head -n 1))"
for rc in "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.profile"; do
touch "$rc" 2>/dev/null || true
PI_BIN_DIR="$(dirname "$PI_BIN")"
if [[ "$PI_BIN_DIR" != "" ]]; then
grep -qF "$PI_BIN_DIR" "$rc" 2>/dev/null || echo "export PATH=\"$PI_BIN_DIR:\$PATH\"" >> "$rc"
fi
grep -qF ".local/bin" "$rc" 2>/dev/null || echo "export PATH=\"\$HOME/.local/bin:\$PATH\"" >> "$rc"
done
# ==============================================================================
# 5. 配置 pi 使用本地模型 (上下文调至极限)
# ==============================================================================
info "5) 配置 pi models.json ($PI_MODELS_JSON)..."
mkdir -p "$(dirname "$PI_MODELS_JSON")"
python3 - "$PI_MODELS_JSON" "$LLAMA_PORT" "$MODEL_ID" "$PROVIDER_ID" "$CONTEXT_SIZE" << 'PY'
import json, os, sys
path, port, model_id, provider, ctx_size = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], int(sys.argv[5])
os.makedirs(os.path.dirname(path), exist_ok=True)
cfg = {"providers": {}}
if os.path.exists(path):
try:
with open(path) as f:
loaded = json.load(f)
if isinstance(loaded, dict):
cfg = loaded
if "providers" not in cfg:
cfg["providers"] = {}
except Exception as e:
print(f"[WARN] 无法解析旧 models.json,将覆盖: {e}")
cfg["providers"][provider] = {
"baseUrl": f"http://127.0.0.1:{port}/v1",
"api": "openai-completions",
"apiKey": "not-needed",
"compat": {"supportsDeveloperRole": True, "supportsReasoningEffort": False},
"models": [{
"id": model_id,
"name": "GLM-4.7-Flash Q4_K_M (Local)",
"reasoning": True,
"input": ["text"],
"contextWindow": ctx_size,
"maxTokens": ctx_size,
"cost": {"input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0}
}]
}
with open(path, "w") as f:
json.dump(cfg, f, indent=2)
print(f"[OK] 已写入 {path}")
print(json.dumps(cfg, indent=2))
PY
ok "pi 配置完成"
WRAPPER="$HOME/.local/bin/pi-local"
mkdir -p "$(dirname "$WRAPPER")"
cat > "$WRAPPER" << EOS
#!/usr/bin/env bash
exec pi --provider $PROVIDER_ID --model $MODEL_ID "\$@"
EOS
chmod +x "$WRAPPER"
ok "已建立 pi-local wrapper: $WRAPPER"
for rc in "$HOME/.bashrc" "$HOME/.zshrc"; do
touch "$rc" 2>/dev/null || true
grep -q "alias pi-local" "$rc" 2>/dev/null || echo "alias pi-local=\"pi --provider $PROVIDER_ID --model $MODEL_ID\"" >> "$rc"
done
# ==============================================================================
# 6. 安装后验证
# ==============================================================================
info "6) 安装后验证..."
VERIFICATION_FAILED=0
# 6.1 检查 llama-server 健康
info "[验证 1/4] 检查 llama-server 健康状态..."
if curl -sf "http://127.0.0.1:${LLAMA_PORT}/health" >/dev/null 2>&1; then
ok "llama-server 健康检查通过"
elif curl -sf "http://127.0.0.1:${LLAMA_PORT}/v1/models" >/dev/null 2>&1; then
ok "llama-server (via /v1/models) 健康检查通过"
else
warn "llama-server 健康检查失败"
VERIFICATION_FAILED=1
fi
# 6.2 测试 OpenAI API 推理
info "[验证 2/4] 测试 OpenAI 兼容 API 推理..."
API_TEST_RESPONSE=$(curl -sf "http://127.0.0.1:${LLAMA_PORT}/v1/chat/completions" \
-H "Content-Type: application/json" \
-d '{
"model": "'$MODEL_ID'",
"messages": [{"role": "user", "content": "用一句话介绍你自己,不要超过20字"}],
"max_tokens": 50,
"temperature": 0.7
}' 2>&1 || echo "CURL_FAILED")
if echo "$API_TEST_RESPONSE" | grep -q '"choices"' && echo "$API_TEST_RESPONSE" | grep -q '"content"'; then
ok "OpenAI API 推理测试通过"
echo "$API_TEST_RESPONSE" | python3 -m json.tool 2>/dev/null | head -n 30 || echo "$API_TEST_RESPONSE" | head -n 20
elif echo "$API_TEST_RESPONSE" | grep -q "CURL_FAILED"; then
warn "API 推理 curl 失败: $API_TEST_RESPONSE"
VERIFICATION_FAILED=1
else
warn "API 推理回应异常,可能是模型仍在加载中..."
echo "$API_TEST_RESPONSE" | head -n 50 >&2
fi
# 6.3 检查 pi 可用
info "[验证 3/4] 检查 pi 指令..."
if pi --version >/dev/null 2>&1; then
ok "pi --version: $(pi --version 2>&1 | head -n 1)"
else
warn "pi --version 执行失败"
VERIFICATION_FAILED=1
fi
if pi --help >/dev/null 2>&1; then
ok "pi --help 正常"
fi
if python3 -c "import json; d=json.load(open('$PI_MODELS_JSON')); assert '$PROVIDER_ID' in d.get('providers',{}); assert any(m['id']=='$MODEL_ID' for m in d['providers']['$PROVIDER_ID'].get('models',[]))" 2>/dev/null; then
ok "pi models.json 配置正确"
else
warn "pi models.json 配置检查失败"
cat "$PI_MODELS_JSON" 2>/dev/null || echo "文件不存在"
VERIFICATION_FAILED=1
fi
if [[ -x "$WRAPPER" ]]; then
ok "pi-local wrapper 存在且可执行"
else
warn "pi-local wrapper 缺失"
VERIFICATION_FAILED=1
fi
# 6.4 测试 pi-local 实际可用
info "[验证 4/4] 测试 pi-local 实际推理 (超时 120 秒)..."
export PATH="$HOME/.local/bin:$HOME/.pi/bin:$(dirname "$PI_BIN"):$PATH"
hash -r 2>/dev/null || true
set +e
PI_TEST_OUTPUT=$(timeout 120 pi --provider "$PROVIDER_ID" --model "$MODEL_ID" -p "用一句话介绍你自己,不超过20字" 2>&1)
PI_EXIT_CODE=$?
set -e
if [[ $PI_EXIT_CODE -eq 0 ]] && [[ -n "$PI_TEST_OUTPUT" ]]; then
ok "pi 推理测试通过 (exit 0)"
echo "--- pi 输出 ---"
echo "$PI_TEST_OUTPUT" | head -n 30
echo "----------------"
elif [[ $PI_EXIT_CODE -eq 124 ]]; then
warn "pi 测试超时 (120s),可能模型加载较慢或首次启动较久。请稍后手动重试: pi --provider $PROVIDER_ID --model $MODEL_ID -p \"你好\""
else
warn "pi 测试失败 (exit $PI_EXIT_CODE),输出:"
echo "$PI_TEST_OUTPUT" | head -n 100 >&2
VERIFICATION_FAILED=1
fi
# ==============================================================================
# 总结
# ==============================================================================
echo ""
echo "================================================================"
if [[ "$VERIFICATION_FAILED" -eq 0 ]]; then
echo -e "\033[32m✅ 安装完成且验证通过!\033[0m"
else
echo -e "\033[33m⚠️ 安装完成,但部分验证未通过,请查看上方警告\033[0m"
fi
echo "================================================================"
echo "- 模型: $REPO ($MODEL_FILE)"
echo " 模型文件: $MODEL_PATH"
echo "- 内存限制: 32GB"
echo "- llama-server (编译自源码): $LLAMA_BIN/llama-server"
echo " 启动参数: taskset -c 0-14 ... -t 15 --jinja --load-mode mlock -c $CONTEXT_SIZE --host 127.0.0.1 --port $LLAMA_PORT"
echo "- 服务: http://127.0.0.1:$LLAMA_PORT (log: ~/llama-server.log, pid: ~/llama-server.pid)"
echo "- pi: $PI_BIN ($(pi --version 2>&1 | head -n 1))"
echo "- pi 配置: $PI_MODELS_JSON (provider: $PROVIDER_ID, model: $MODEL_ID, context: $CONTEXT_SIZE)"
echo "- 快速使用:"
echo " source ~/.bashrc # 或 source ~/.zshrc"
echo " pi-local -p \"你好\""
echo " pi --provider $PROVIDER_ID --model $MODEL_ID -p \"你好\""
echo "- 停止服务器: kill \$(cat ~/llama-server.pid)"
echo "- 重新验证: curl http://127.0.0.1:$LLAMA_PORT/v1/models && pi-local -p \"测试\""
echo "================================================================"
if [[ "$VERIFICATION_FAILED" -ne 0 ]]; then
echo "请检查日志:"
echo " - llama-server: ~/llama-server.log (tail -n 100 ~/llama-server.log)"
echo " - pi 安装: /tmp/pi-install.log"
echo " - 模型: $MODEL_DIR/"
exit 1
fi
exit 0