标签: 大模型

  • Tesla V100 32G + llama.cpp 本地部署 Qwen3.6 27B:从驱动到 138K 长上下文的完整方案

    Tesla V100 32G + llama.cpp 本地部署 Qwen3.6 27B:从驱动到 138K 长上下文的完整方案

    这篇记录 Qwen3.6 27B 大模型全本地跑通的完整过程。目标一句话:27B 参数模型,全本地,长上下文,暴露 OpenAI 兼容 API,任何前端(包括 DeepSeek Harness 本身)直接对接。

    最终结果:

    • Qwen3.6-27B UD-Q5_K_XL(18.95 GB)+ 138K 上下文 + KV 缓存量化 → 32GB 显存刚好装下
    • 同一条流水线后来延伸到 Qwen3.8-27B:Q4_K_XL + MTP 投机解码 + 256K 上下文,实测占用 26077 / 32768 MiB

    下面就是完整搭建流程。所有参数都来自实际在跑的脚本,不是理论最优值。

    一、硬件与驱动

    实际值
    GPU Tesla V100-PCIE-32GB(TCC 模式)
    驱动 573.96(Data Center Tesla 桌面版)
    CUDA 12.8(cuda_12.8.0_571.96_windows)
    系统 Windows 10/11

    两个坑:

    1. V100 不能用 GeForce 消费级驱动。 要用数据中心分支,安装包文件名里带 data-center-tesla(我本地留了份:573.96-data-center-tesla-desktop-win10-win11-64bit-dch-international.exe)。

    2. TCC 模式没有桌面显示输出。 V100 是纯计算卡,看屏幕靠核显,状态全靠 nvidia-smi。写这篇时的实况(节选):

    | 0  Tesla V100-PCIE-32GB   TCC    75C    51W / 250W
    | 26077MiB / 32768MiB
    | 进程: llama-server.exe  26066MiB
    

    二、编译 CUDA 版 llama.cpp

    我保留两套 llama.cpp:

    • F:\AI\llama.cpp-CUDA\ — CUDA 后端(给 V100)
    • F:\AI\llama.cpp\ — Vulkan 后端(更早的 AMD RX 590 8G 在用)

    CUDA 版用 VS2022(MSVC 19.44)+ CUDA 12.8 工具链编译,当前在产 build:

    version: 0.1.0-dev (build 10415, commit 1d2869c6e)
    built with MSVC 19.44.35228.0 for x64
    

    CMake 关键参数:

    cmake -B build -G "Visual Studio 17 2022" -A x64 ^
      -DGGML_CUDA=ON ^
      -DCMAKE_BUILD_TYPE=Release
    cmake --build build --config Release -j
    

    所有启动脚本都会先检查 Release\llama-server.exe 是否存在,缺了就直接提示先编译,避免"启动失败但不知道为什么"。

    三、模型选择:27B 为什么"装得下"

    手头的模型文件(实测大小):

    模型 大小 备注
    Qwen3.6-27B-Q4_K_M.gguf 15.93 GB 常规 K 量化
    Qwen3.6-27B-UD-Q5_K_XL.gguf 18.95 GB Unsloth 动态量化(本文主角)
    Qwen3.8-27B-UD-Q4_K_XL.gguf 16.69 GB 当前生产主模型
    Qwen3.8-27B-Q5_K_M.gguf 18.47 GB
    Qwen3.8-27B-UD-Q6_K_XL.gguf 23.56 GB 高质量档(偏重)
    mtp-Qwen3.8-27B-Q4_0.gguf 1.28 GB MTP 投机解码草稿

    3.6 为什么选 UD-Q5_K_XL:UD(Unsloth Dynamic)量化用 imatrix 校准数据动态分配 bit,关键张量多给、不重要的少给,同等名义 5 bit 下质量比固定 Q5_K_M 好。imatrix 校准文件(imatrix_unsloth.gguf)就放在模型目录里。

    但 27B 长上下文能上 32G 的关键不是量化,是架构。 我写了个小脚本解析 GGUF v3 元数据(解析器在 novel-project/tools/gguf-meta.py,顺带解决了 v3 格式 KV 区紧跟文件头、字符串长度用 u64 编码的坑),结果有点意外:

    general.architecture = qwen35
    qwen35.block_count = 65
    qwen35.full_attention_interval = 4      # 每 4 层才 1 层全注意力
    qwen35.attention.head_count_kv = 4      # GQA,4 个 KV 头
    qwen35.attention.key_length = 256       # head 维度
    qwen35.context_length = 262144          # 原生 256K
    qwen35.nextn_predict_layers = 1         # 内置 MTP 层
    qwen35.ssm.state_size = 128             # 线性注意力/SSM 状态
    

    也就是说 Qwen3.x-27B 系列是混合架构:65 个 block 里只有 1/4 是全注意力(约 17 层),其余是线性注意力/SSM,状态大小固定、不随上下文增长。KV 缓存只给那 17 层全注意力层分配——这是 256K 上下文能塞进 32GB 的根本原因。

    四、显存预算(全部真实数字)

    KV 缓存容量公式(q4_0 量化约 4.5 bit/元素,0.5625 B/元素):

    KV = 2(K+V) × ctx × 4(KV头) × 256(head维) × 0.5625B × 17(全注意力层)
    

    256K 代入:单层 KV ≈ 288 MiB,17 层合计 ≈ 4.8 GB;若不做 KV 量化(fp16),同样 256K 要 17 GB

    Q3.8 Q4_K_XL @256K(实测) Q3.6 Q5_K_XL @138K(估算)
    模型权重 16.69 GB 18.95 GB
    KV 缓存(q4_0) ≈4.8 GB ≈2.6 GB
    SSM 状态 + 激活 + 计算缓冲 ≈4.0 GB(实测余量) ≈4.0 GB(参照)
    合计 ≈25.5 GB → 实测 26077 MiB ≈25.6 GB,还能开 –parallel 2

    实测与估算吻合,这套预算方法是可信的。两个结论:

    1. --flash-attn on + --cache-type-k q4_0 --cache-type-v q4_0 是长上下文的两个必选项,缺一个 256K 都悬。
    2. Q6 + 256K 不成立:光权重就 23.56 GB,我的 Q6 脚本 batch 只能压到 256。要质量降上下文,要上下文降量化,二选一。

    五、启动脚本(真实演进过程)

    早期是 Vulkan 时代(RX 590 8G),部分层卸载到 GPU:

    :: 历史配置:RX 590 8G Vulkan 版
    llama-server -m Qwen3.6-27B-Q4_0.gguf -ngl 24 --n-cpu-moe 999 ^
      -c 4096 -b 1024 -ub 512 -t 6 --device Vulkan0 --cache-ram 2048 --mlock
    

    -ngl 24 只把 24 层推 GPU,其余吃 CPU;--n-cpu-moe 999 是 35B-A3B MoE 模型时代抄过来的,对稠密 27B 实际不生效——无害但误导,后来删掉了。

    V100 到位后配置重写:99 层全上 GPU,上下文从 4K 拉到 138K

    :: start_Qwen3.6-27b-Q5-MTP_v01.bat(核心部分)
    set MODEL_PATH=F:\AI\models\Qwen3.6-27B-UD-Q5_K_XL.gguf
    set CTX_LEN=141072
    
    Release\llama-server.exe -m "%MODEL_PATH%" ^
      -ngl 99 -c 141072 -b 512 -t 8 ^
      --host 0.0.0.0 --port 8080 ^
      --flash-attn on --cache-type-k q4_0 --cache-type-v q4_0 ^
      --parallel 2 --mlock --metrics
    

    参数解释:

    • -ngl 99:全部层上 GPU(32G 够放,不用抠)
    • -c 141072:算过能装下的上下文长度(138K)。Q5 权重比 Q4 重约 2GB,256K 装不下
    • --parallel 2:2 个并发请求槽位(KV 缓存翻倍,预算表里已留了余量)
    • --mlock:锁定内存防换页
    • -t 8:CPU 线程数,服务残留的 CPU 部分

    注意 141072 不是整数规格——是"算到刚好装下"的结果,不是官方档位。

    当前生产版已升级到 Qwen3.8-27B,并加了 MTP 投机解码

    :: 当前生产配置
    Release\llama-server.exe -m "D:\Models\Qwen3.8-27B\Qwen3.8-27B-UD-Q4_K_XL.gguf" ^
      --model-draft "D:\Models\Qwen3.8-27B\mtp-Qwen3.8-27B-Q4_0.gguf" ^
      -ngl 99 -np 1 -c 262144 -b 512 -t 8 ^
      --host 0.0.0.0 --port 8080 ^
      --flash-attn on --cache-type-k q4_0 --cache-type-v q4_0 ^
      --spec-type draft-mtp --spec-draft-n-max 2
    

    元数据里 nextn_predict_layers = 1 说明模型自带 1 层 MTP(Multi-Token Prediction),3.8 配套了独立的 1.28GB Q4_0 草稿文件。--spec-draft-n-max 2 让草稿层一次多预测 2 个 token、主模型一次性验证,中文文本接受率不低,白捡的速度。注意 Q3.6 配置里没有这一项(3.6 没有独立 MTP 草稿文件),别照抄。

    六、前端接入

    llama-server 原生 OpenAI 兼容:

    • API:http://127.0.0.1:8080/v1(chat/completions、models 都通)
    • Web:http://127.0.0.1:8080 自带 playground

    对 DeepSeek Harness(运行本文的工具),把模型服务指向 8080 即可:

    :: D:\Dev\start-harness.bat(简化)
    dsh web --port 3080
    

    然后打开 http://127.0.0.1:3080。现在正在服务这段对话的模型,就是本文这台 V100 上跑的——某种意义上是自我验证。

    服务监听 0.0.0.0,内网其他机器也能用;如果机器走 VPN 或暴露公网,记得加认证和限流(llama-server 没有内置鉴权,建议套一层反代)。

    七、踩坑清单

    1. V100 要 Data Center 驱动,GeForce 驱动装不上/不识别。
    2. Q6 + 256K 直接别想,光权重 23.56GB。
    3. KV 缓存量化是长上下文的必选项:q4_0 把 256K 的 KV 从 17GB 压到约 4.8GB。
    4. --n-cpu-moe 对稠密模型无效,MoE 时代的残留,删掉免得误导。
    5. MTP 要配套草稿文件:3.6 没有 mtp 文件,--spec-type draft-mtp 加了也白加。
    6. 别重复起服务:8080 端口被 llama-server 占着,脚本里有存在性检查,手动启动前先 nvidia-smi 看一眼。

    八、速查表

    场景 推荐组合
    质量优先 Q3.8 UD-Q6_K_XL + ctx 32K~64K
    均衡(3.6 主选) Q3.6 UD-Q5_K_XL + ctx 138K + –parallel 2
    长上下文优先 Q3.8 UD-Q4_K_XL + ctx 256K + MTP 投机解码
    小模型快速验证 Qwen3.5-9B-Q4_K_M(5.29 GB,8G 显存即可)

    脚本、模型都在这台机器上,GGUF 元数据解析器在 novel-project/tools/gguf-meta.py。下一篇想写 imatrix 校准与 UD 量化的制作流程。