欢迎光临
我们一直在努力

我的32G小主机实测-5个大模型自由切换-llama.cpp路由模式

llama.cpp 多模型路由实测:一个进程管理 5 个 GGUF,按需加载 + LRU 驱逐,附完整配置与源码级排障

摘要

摘要:本文记录在 5700U + 32G 内存(无独显)的迷你主机上,用 llama.cpp 原生 router mode + models preset 实现 5 个 GGUF 模型自由切换的完整实测。核心思路是"一个常驻 llama-server 进程 + INI 模型登记表":前端按模型名点名,进程自动装载对应模型,内存满自动按 LRU 驱逐最久未用的模型,彻底告别"换模型五分钟,聊天两分钟"的旧玩法。文章包含完整可抄作业的 INI 配置与启动脚本、32G 内存的容量账本,以及一个反直觉参数坑(–no-models-autoload 实为"禁止按请求装载"而非"不预热")的源码级定位与修复,并对比了与 Ollama 的取舍。

结论先行:

  • llama.cpp 的 –models-preset 路由模式 = 单个常驻 llama-server 进程 + INI 模型登记表,前端按模型名点名,自动装载/驱逐。
  • 架构分工:sh 只做开关运维,ini 声明模型与参数(键 = 命令行参数去横线,写错键名会导致整个 preset 解析失败)。
  • 核心坑:–no-models-autoload 的真实语义是"禁止按请求装载"(server-models.cpp:1813),而非"不预热"。加了这个参数,前端点名未加载模型必然报 model is not loaded。
  • MAXMODELS=1 下行为完美:不预热、按需装载、LRU 驱逐、请求排队等装载。

  • 1. 环境与模型清单

    项值
    CPU AMD 5700U(8 物理核,纯 CPU 推理)
    内存 32G(可用约 28G,系统留 4G)
    系统 Ubuntu 24.04
    llama.cpp b10472 构建(需支持 –models-preset)
    前端 Cherry Studio(OpenAI 兼容 API)

    5 个模型(均为社区 GGUF 量化版):

    段名模型权重占用定位
    qwen30b-rp Huihui-Qwen3-30B-A3B-Instruct-2507-abliterated.i1-Q4_K_M ~17-18G RP 主力(快一档)
    qwen35b-rp Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q4_K_M ~20G 质量档
    agent-lfm2 LFM2-24B-A2B-Abliterated-Q4_K_M ~15G Agent 备胎
    agent-ling Ling-3.0-tiny-UD-Q8_K_XL ~5-6G Agent 轻量(KDA+MLA 混合架构,加载失败属预期)
    code-ornith Ornith-1.5-9B-Q5_K_M ~5G 代码,48K 长上下文

    2. 方案:为什么是"ini + sh"而不是纯 shell

    "路由模式"是 llama.cpp server 内置能力,不是 shell 实现的:一个常驻 llama-server 进程内部自带路由器,前端请求带什么 model 名,进程内自动装载对应模型,内存满自动卸载最久未用(LRU)。因此模型清单必须以 server 原生可读的 INI(preset)声明,shell 只剩薄薄一层开关职责。

    文件角色
    start-llama-router.sh 启停、健康检查、预热/卸载、状态查询、构建能力自检
    llama-routers.ini 模型登记表(每个 [段名] 就是一个对外 API 模型名)

    3. 完整配置

    3.1 llama-routers.ini

    [*]
    threads = 8 # 5700U 物理核数(超线程反而降速)
    parallel = 1 # 并发 slot,纯 CPU 单人用
    mmap = 1 # 系统页缓存管内存,切模型后旧权重自动换出
    rea = off # 关闭思考链输出
    ctk = q8_0 # KV cache 量化 K
    ctv = q8_0 # KV cache 量化 V
    ctx-size = 16384 # 默认上下文
    ============ 角色扮演 ============
    [qwen30b-rp]
    model = /home/ligui/models/Huihui-Qwen3-30B-A3B-Instruct-2507-abliterated.i1-Q4_K_M.gguf
    temp = 0.85
    top-p = 0.8
    top-k = 20
    min-p = 0.0
    [qwen35b-rp]
    model = /home/ligui/models/Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q4_K_M.gguf
    ctx-size = 12288 # 权重大,上下文收着点防挤压系统内存
    temp = 0.85
    top-p = 0.8
    top-k = 20
    min-p = 0.0
    ============ Agent 备胎 ============
    [agent-lfm2]
    model = /home/ligui/models/LFM2-24B-A2B-Abliterated-Q4_K_M.gguf
    [agent-ling]
    model = /home/ligui/models/Ling-3.0-tiny-UD-Q8_K_XL.gguf
    ctx-size = 8192
    ============ 代码备胎 ============
    [code-ornith]
    model = /home/ligui/models/Ornith-1.5-9B-Q5_K_M.gguf
    ctx-size = 49152
    temp = 1.0
    top-p = 0.95
    top-k = 20
    min-p = 0.0
    presence-penalty = 1.5

    关键规则:preset 的键 = llama-server 命令行参数去掉横线(-ctk → ctk)。解析器遇到不认识的键会抛错拒绝整个配置,不存在静默忽略。已知易错点:kv-type-k/v 是错误键名(正确为 ctk/ctv);reasoning 同理,正确为 rea。

    3.2 start-llama-router.sh

    #!/bin/bash
    set -u
    LLAMA_BIN="${LLAMA_BIN:-/home/ligui/llama-b10472/llama-b10472}"
    PRESET="${PRESET:-/home/ligui/models/llama-routers.ini}"
    HOST="${HOST:-0.0.0.0}"
    PORT="${PORT:-8080}"
    MAXMODELS="${MAXMODELS:-1}" # 同时在线模型数上限,32G 默认 1 绝对安全
    LOG="${LOG:-/tmp/llama-router.log}"
    BASE="http://127.0.0.1:$PORT"
    do_start() {
    [ -x "$LLAMA_BIN/llama-server" ] || { echo "✗ 找不到 llama-server"; exit 1; }
    [ -f "$PRESET" ] || { echo "✗ 找不到 preset: $PRESET"; exit 1; }
    构建能力自检
    if ! "$LLAMA_BIN/llama-server" –help 2>&1 | grep -q — "–models-preset"; then
    echo "✗ 当前构建不支持 –models-preset,请升级 llama.cpp"; exit 1
    fi
    清残留进程(32G 上双 server 并存 = swap 地狱)
    if pgrep -f llama-server >/dev/null 2>&1; then
    pkill -f llama-server; sleep 2; pkill -9 -f llama-server 2>/dev/null
    fi
    ⚠️ 不要加 –no-models-autoload:它禁止按请求装载,
    导致前端点名未加载模型时报 "model is not loaded"(见第 5 节)
    nohup "$LLAMA_BIN/llama-server"

    –host "$HOST" –port "$PORT"

    –models-preset "$PRESET"

    –models-max "$MAXMODELS"

    >"$LOG" 2>&1 &
    60 秒健康检查
    for _ in $(seq 1 60); do
    sleep 1
    curl -sf "$BASE/health" >/dev/null 2>&1 && { echo "✓ 路由器就绪"; exit 0; }
    done
    echo "✗ 健康检查未通过:"; tail -20 "$LOG"; exit 1
    }
    case "${1:-start}" in
    start) do_start ;;
    stop) pkill -f llama-server ;;
    status) curl -s "$BASE/models" | python3 -m json.tool ;;
    warm) curl -s -X POST "$BASE/models/load" -H 'Content-Type: application/json'

    -d "{"model":"$2"}"; echo ;;
    unload) curl -s -X POST "$BASE/models/unload" -H 'Content-Type: application/json'

    -d "{"model":"$2"}"; echo ;;
    log) tail -n 80 -f "$LOG" ;;
    *) echo "用法: $0 {start|stop|status|log|warm <模型名>|unload <模型名>}" ;;
    esac

    注:Windows 编辑过的文件传到 Ubuntu 后务必 sed -i 's/\\r$//' start-llama-router.sh llama-routers.ini && chmod +x start-llama-router.sh,否则 \\r 会导致解析错误。

    3.3 部署与使用

    # 传文件到 Ubuntu 后
    sed -i 's/\\r$//' start-llama-router.sh llama-routers.ini && chmod +x start-llama-router.sh
    cp llama-routers.ini ~/models/
    ./start-llama-router.sh # 启动并显示模型清单
    ./start-llama-router.sh warm qwen30b-rp # 手动预热
    ./start-llama-router.sh unload agent-lfm2 # 手动卸载释放内存

    前端(Cherry Studio / SillyTavern / Open WebUI 等)设置 API 地址 http://<小主机IP>:8080/v1,模型名填 ini 段名:qwen30b-rp / qwen35b-rp / agent-lfm2 / agent-ling / code-ornith。

    4. 内存账本(32G 的数学)

    模型权重占用(Q4)可同时在线
    Qwen3.6-35B ~20G 与 30B 不可共存
    Huihui-Qwen3-30B ~17-18G 与 35B 不可共存
    LFM2-24B ~15G 可与小模型共存
    Ornith-9B / Ling-tiny ~5-6G 轻松
    • 默认 MAXMODELS=1:任何时刻只有一个模型在线,绝对安全。
    • MAXMODELS=2:仅限"小+小"或"大+小";两个 Qwen 大模型同在线(合计 ~38G)必炸。
    • router 模式下模型按需加载,不会真同时占内存;切换约十几秒(从盘装载)。

    5. 排障实录:model is not loaded 的源码级根因

    现象

    • Cherry Studio 报错:AI_APICallError: model is not loaded
    • 服务端日志完全正常:

      starting server in router mode. models will be automatically loaded on-demand
      listening on http://0.0.0.0:8080

    • 即:路由器正常监听,但前端点名后没有任何装载动作。

    排查

    直接查源码 server-models.cpp:1813:

    if (!models_autoload && !meta->is_running()) {
    res_err(res, "model is not loaded"); // ← 报错来源
    }

    根因:启动脚本中加了 –no-models-autoload 参数。这个标志的真实语义是"禁止按请求自动装载"——当请求点名的模型未加载时,直接报错拒绝,而不是去装载它。此前加它是想"开机不预热模型省内存",但源码显示 load_models() 启动时只把 5 个模型登记为"未加载",并不会实际装载任何东西,所以那个内存担忧根本不存在,该开关纯属自缚手脚。

    修复

    sed -i '/–no-models-autoload/d' start-llama-router.sh
    ./start-llama-router.sh stop && ./start-llama-router.sh

    前端无需改动(连接和模型名本来就没错)。

    顺带确认的三个行为(源码佐证)

  • 不预热:load_models() 只登记状态,不装载。
  • LRU 自动驱逐:server-models.cpp:1409 存在 evicting idle LRU … to make room,达到 –models-max 上限时自动卸载最久未用模型、装入新点名的。
  • 请求排队:切模型后的第一条请求不会失败,等服务端装载完成再开始生成。
  • 验证

    日志出现以下行即按需装载生效:

    ensure_model: model name=qwen30b-rp is not loaded, loading…

    实测行为:

  • 点未装载模型 → 从盘装载,第一条消息多等十几秒到几分钟(取决于磁盘),之后正常流式;
  • 切换模型 → 旧模型被自动驱逐、新模型装载,仅切换后第一条消息有额外等待;
  • 持续使用同一模型 → 常驻内存,无额外延迟。
  • 6. 与 Ollama 的取舍

    • Ollama:托管式开箱即用,多模型管理省心,但模型文件/服务由它接管,调参自由度受限。
    • llama.cpp router:在原有技术栈内升级,保留全部命令行级调参(KV 量化、采样、上下文逐模型覆盖),资源开销低(无转发层)。
    • 结论:追求省事选 Ollama;有既有 llama.cpp 工作流、需要细粒度参数控制者,选 router 模式。

    7. 备注与免责

    • 模型均为社区第三方量化版本(含 abliterated/uncensored 变体),非官方发布;仅供本地技术验证,请遵守所在地区法律法规与平台规则。
    • agent-ling(KDA+MLA 混合架构)在部分 llama.cpp 构建上可能加载失败,属预期情况,可先用 agent-lfm2 顶替。
    • –models-preset 仅近期 llama.cpp 构建支持,脚本已内置能力自检。

    更多交流信息及实测、免费API信息请关注同名公众号获取。

    赞(0)
    未经允许不得转载:171主机测评 » 我的32G小主机实测-5个大模型自由切换-llama.cpp路由模式
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址