跳转至内容
  • 版块
  • 最新
  • 标签
  • 热门
  • 用户
  • 群组
皮肤
  • 浅色
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • 深色
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • 默认(LCZ-Blue)
  • 不使用皮肤
  • LCZ-Green
  • LCZ-Blue
  • LCZ-Black
折叠
品牌标识

抡锤者

首页 版块 标签
硬件
装备秀
AI 广场 App
L

LearningAI

@LearningAI
取消关注 关注
关于
帖子
12
主题
2
分享
0
群组
0
粉丝
0
关注
0

帖子

最新 最佳 有争议的

  • AI Pro R9700 单卡 SGlang qwen3.8 27b
    L LearningAI
    LLM讨论区 r9700 sg-lang qwen-27b

    @fcme 谢谢,我又折腾一整天,没成功,再上网看看有没有别的启发信息😅


  • AI Pro R9700 单卡 SGlang qwen3.8 27b
    L LearningAI
    LLM讨论区 r9700 sg-lang qwen-27b

    @terry 啊? 英文帖子有风险?不明白啊。能解释一下吗?我平常都是用英文跟AI聊的。要是需要,以后发帖就让AI翻译成中文


  • AI Pro R9700 单卡 SGlang qwen3.8 27b
    L LearningAI
    LLM讨论区 r9700 sg-lang qwen-27b

    @paul-hou 今天走通了我也很高兴,赶紧让Hermes把配置和过程给总结下来,跟大家分享一下。具体测试我有空再做,或者其他有r9700的朋友们有空也可以测一下


  • AI Pro R9700 单卡 SGlang qwen3.8 27b
    L LearningAI
    LLM讨论区 r9700 sg-lang qwen-27b

    @fcme 好像是因为不支持WMMA影响了prefill 的速度。 但是我搞不定,因为都是让Hermes + Deepseek V4.1 flash抄作业的😅


  • AI Pro R9700 单卡 SGlang qwen3.8 27b
    L LearningAI
    LLM讨论区 r9700 sg-lang qwen-27b

    说明:本文原为英文,已按原文逐段译为中文——技术内容一字未改,命令、路径、参数、代码块全部原样保留。译文由小特整理。

    今天让Hermes抄flyer666的作业,单卡r9700跑SGlang 成功了,跟大家分享一下,同时感谢Terry建立这个环境供大家一起学习,也感谢各位高手分享AI知识。

    在 AMD Radeon R9700 (gfx1201) 上用 SGLang 运行 Qwen3.8-27B(W4A16 GPTQ,4-bit)

    一份完整、可复现的构建与运维指南。它是为了能在另一台机器上(带 R9700)照着执行而写的
    ——无论是人还是 agent——每个阶段之后都设有一个校验点,这样失败会在它发生的地方
    被发现,而不是等到三个阶段之后。

    这里的一切都是在参考机器上凭经验确立的,实测数字都是真实的,不是估算出来的。凡是
    属于估算、或从未测试过的内容,都会明确标注出来。

    约定。 把 $HOME 换成你的家目录(/home/<user>)。
    像 <API-KEY>、<BOT-TOKEN>、<server-ip> 这样的占位符需要你自己填写。
    命令面向 Ubuntu 24.04 + Bash。


    0. 这套方案能达成什么

    模型 Qwen3.8-27B(mamba/attention 混合 VL 模型,arch Qwen3_5ForConditionalGeneration),4-bit GPTQ W4A16
    GPU 1× Radeon AI PRO R9700,32 GB,gfx1201 (RDNA4)
    引擎 Docker 中的 SGLang 0.5.13.post1(rocm/sgl-dev),TP=1
    Decode 27 t/s(普通)· 43–62 t/s(使用 NEXTN/MTP 投机)
    Prefill @4K 244–247 t/s(scalar GPTQ 路径——原因见 §5.4)
    KV pool 仅 device 295,902 tokens (fp8_e4m3) · 带 HiCache host pool 时 887,707 tokens
    上下文 每请求 131,072
    视觉 支持——vision tower 常驻
    权重占用显存 17.95 GB

    24 GB 的卡不行:checkpoint 约 18.6 GiB,而你还需要实实在在的余量留给 KV、
    graph buffer 和 workspace。


    1. 前置条件

    1.1 硬件 / 操作系统

    • 1× Radeon R9700 (gfx1201),32 GB——或任意 32 GB 以上的 gfx1201 显卡
    • 如果想要 HiCache(longctx)档,系统内存 ≥ 62 GB。其中 21 GB
      被 pinned host pool 吃掉。speed 档不需要 host pool。
    • 约 120 GB 可用磁盘:Docker 镜像约 71 GB + 模型约 19 GB + 构建树约 1–3 GB
    • Ubuntu 24.04(或类似版本),使用内核自带的 amdgpu 驱动。宿主机侧不需要安装
      ROCm
      ——容器镜像自带 userland;宿主机只需要内核驱动,再加上暴露出来的
      /dev/kfd 与 /dev/dri/*。

    1.2 Docker + GPU 访问

    sudo apt-get update
    sudo apt-get install -y docker.io
    sudo systemctl enable --now docker
    sudo usermod -aG docker "$USER"     # then LOG OUT and back in
    

    校验点 1 — 确认 GPU 设备节点存在且守护进程可用:

    ls -l /dev/kfd /dev/dri/                 # expect /dev/kfd + renderD128.. cards
    docker info >/dev/null && echo "docker OK"
    

    ⚠️ 两个会白白浪费时间的坑:

    • 组成员身份只对新会话生效。在已经打开的 shell 里,
      给 Docker 命令加上 sg docker -c "..." 前缀即可,不必重新登录。
    • 后面会看到,systemd user unit 无法把自己排在系统级
      docker.service 之后。应改用就绪循环等待守护进程(§9.1)。

    1.3 识别你的 render 节点并确认架构

    for c in /sys/class/drm/card*/device/uevent; do
      echo "$c $(grep -o 'PCI_ID=.*' $c)"
    done
    cat /sys/class/drm/card*/device/mem_info_vram_total   # bytes
    

    记下属于 R9700 的那个 renderDxxx 节点——下面每条命令都会用到它。在多卡机器上,
    只把这一个节点传进容器,才能让另一张卡保持空闲。

    校验点 2 — 在容器内,架构必须读出 gfx1201:

    IMG=rocm/sgl-dev:v0.5.13.post1-ubuntu24.04-py3.14-rocm7.14.1
    docker run --rm --device /dev/kfd --device /dev/dri/renderD129 \
      --group-add=video --security-opt seccomp=unconfined \
      -e HIP_VISIBLE_DEVICES=0 -e ROCR_VISIBLE_DEVICES=0 \
      $IMG bash -lc 'rocminfo | grep -m1 gfx'
    # expected: gfx1201
    

    这一步要是失败,就停下来——后面任何东西都不会工作。


    2. 拉取镜像

    docker pull rocm/sgl-dev:v0.5.13.post1-ubuntu24.04-py3.14-rocm7.14.1
    

    约 71 GB。镜像内含:Python 3.14、HIPCC/ROCm 7.14、Triton 以及 SGLang wheel。
    请固定这个 tag——§5 的补丁集针对的正是这个确切版本。


    3. 获取模型

    3.1 用哪个 checkpoint,以及为什么

    使用 Vishva007/Qwen3.8-27B-W4A16-AutoRound-GPTQ(约 19 GB)。

    为什么偏偏用这一个:它是货真价实的 GPTQ W4A16 打包(4-bit 权重、
    16-bit 激活),并且有意把它的 MTP/NEXTN head 留在 bf16,这样投机解码仍然能用。
    这个模型上所有打着 "AWQ" 招牌的 checkpoint 实际上都是 Quark 或 compressed-tensors
    格式,SGLang 在 RDNA 上跑不了(见附录 C)。

    mkdir -p "$HOME/models/sglang"
    hf download Vishva007/Qwen3.8-27B-W4A16-AutoRound-GPTQ \
      --local-dir "$HOME/models/sglang/qwen3.8-27b-w4a16-gptq"
    

    预期是 5 个权重分片 + model_extra_tensors.safetensors + 常规的那些配置文件。

    3.2 硬卡点 #1 — checkpoint 的 config.json 会让 loader 挂掉

    该 checkpoint 自带两条动态量化规则,把 MTP tensor 纳入了量化:

    "+:.*mtp.*":      {...},
    "+:.*mtp\\.fc.*": {...}
    

    但那些 tensor 是以 bf16 存储的,所以 GPTQ loader 会去反量化未量化的数据然后炸掉。
    把这两条替换成一条排除(exclusion)规则。

    #!/usr/bin/env python3
    """Fix the MTP dynamic-quant rules. Idempotent; keeps a one-time .orig backup."""
    import json, os, shutil, sys
    
    path = sys.argv[1] if len(sys.argv) > 1 else \
        os.path.expanduser("~/models/sglang/qwen3.8-27b-w4a16-gptq/config.json")
    
    cfg = json.load(open(path))
    qc  = cfg.get("quantization_config", {})
    dyn = qc.setdefault("dynamic", {})
    
    removed = [k for k in list(dyn) if k.startswith("+") and "mtp" in k.lower()]
    for k in removed:
        del dyn[k]
    
    added = False
    if not any(k.startswith("-") and "mtp" in k.lower() for k in dyn):
        dyn["-:.*mtp.*"] = {"bits": 16, "group_size": 128}
        added = True
    
    if removed or added:
        bak = path + ".orig"
        if not os.path.exists(bak):
            shutil.copy(path, bak)
        json.dump(cfg, open(path, "w"), indent=2)
        print(f"patched: removed {len(removed)} include-rule(s), added exclusion: {added}")
    else:
        print("already patched (nothing to do)")
    print("mtp rules now:", {k: v for k, v in dyn.items() if "mtp" in k.lower()})
    print("quant:", qc.get("quant_method"), qc.get("bits"), "group", qc.get("group_size"))
    

    校验点 3 — 运行之后,quantization_config 必须显示
    gptq / bits 4 / group_size 64,而且唯一的 MTP 规则必须是
    -:.*mtp.*,带 bits: 16。未量化的 tensor(embeddings、MTP head、
    mamba/conv 参数)是 bf16 → 它决定了 §6 中的 dtype 选择。


    4. 构建之前先理解差距

    有两个事实使得自建成为必须——请自行验证它们,以确认在你所用的版本上
    是否仍然需要这个 fork:

    # (a) The prebuilt wheel ships NO GPTQ ops
    docker run --rm $IMG bash -lc 'python3 -c "
    import torch, sgl_kernel as s
    print([x for x in dir(s) if \"gptq\" in x.lower()])"'
    # expect: [] (empty)
    
    # (b) Upstream has no ROCm W4A16 int4 quant *scheme* beyond these:
    docker run --rm $IMG bash -lc \
      'grep -rhoE "quark_w4[a-z0-9_]+" /sgl-workspace/sglang/python/sglang/srt/layers/quantization/quark/ | sort -u'
    # quark_w4a4_mxfp4 / _moe / quark_w4a8_mxfp4_moe — MXFP4 is CDNA+AITER only.
    

    所以:RDNA 上的 GPTQ 支持必须自己编译进去。


    5. 为 gfx1201 构建 GPTQ kernel

    5.1 获取 fork

    mkdir -p "$HOME/sglang-sandbox/src" && cd "$HOME/sglang-sandbox/src"
    git clone -b gfx1100-support https://github.com/StevenChenSE/sglang.git sglang-gfx1100
    cd sglang-gfx1100 && git log -1 --format='%H %s'
    # reference: f84475ccf593087df3d1da13c9e675eadee12352
    

    这个分支带有 RDNA3 的 GPTQ kernel(csrc/gemm/gptq/q_gemm_rdna3*.{hip,cu}、
    q_gemm_rdna3_wmma.*、moe_q_gemm_rdna3.hip),一个 ROCm 版 setup_rocm.py,
    以及它自己的 tests/test_gptq_rdna3_smoke.py。

    5.2 为什么原样无法为 gfx1201 构建

    三道各自独立的关卡,全都只认 gfx1100:

    1. scalar 反量化 GEMM 主体被 defined(__gfx1100__) 守护;
    2. 一处运行期 TORCH_CHECK 断言架构是 gfx1100;
    3. WMMA translation unit 使用了 wmma-256b-insts builtin——只有 RDNA3 才有
      的指令
      。Clang 拒绝为 gfx1201 编译它们,而强行开启该 feature 会让
      clang-23 段错误。没有绕法;这个 TU 必须去掉。

    关键在于,在 RDNA 上通用的 gptq_gemm op 会直接路由进
    gptq_gemm_rdna3,所以 scalar 路径就是全部实现——WMMA
    TU 是一个独立的、可选的 op。

    5.3 硬卡点 #2 — 跨 4 个文件的 5 处修改

    把这些改动应用到 fork 上(§12 的脚本会替你完成;这里说的是它们改了什么、以及为什么)。
    请以源码文本作为锚点,不要依赖行号。

    (1)+(2) csrc/gemm/gptq/q_gemm_rdna3.hip 和 q_gemm_rdna3.cu —— 放宽
    架构守护,让 scalar 主体能为 RDNA4 编译:

    // before
    #if defined(__HIPCC__) && defined(__gfx1100__)
    // after
    #if defined(__HIPCC__) && (defined(__gfx1100__) || defined(__gfx1201__))
    

    (3) 同样这两个文件 —— 当 WMMA 被排除时,WMMA dispatch 和只在 gfx1100 成立的
    运行期断言都不得被编译:

    #ifndef SGL_GPTQ_NO_WMMA
      ... existing WMMA dispatch + TORCH_CHECK(arch == gfx1100) ...
    #endif
    

    (4) csrc/common_extension_rocm.cc —— gptq_gemm_rdna3_wmma 的 extern
    声明以及它的 m.def/m.impl 注册也必须加上守护,否则
    链接时会出现未定义符号:

    #ifndef SGL_GPTQ_NO_WMMA
      ... extern decl + m.def/m.impl for gptq_gemm_rdna3_wmma ...
    #endif
    

    (5) python/sglang/kernels/aot/setup_rocm.py —— 对于非 gfx1100 的 RDNA
    目标:去掉 WMMA 源文件,并为两个编译器都定义该宏:

    hipcc_flags.append("-DSGL_GPTQ_NO_WMMA")
    cxx_flags.append("-DSGL_GPTQ_NO_WMMA")
    

    setup_rocm.py 里还有一个 RDNA_TARGETS = {gfx1100, gfx1151, gfx1201} 集合,
    如果你的卡是别的 RDNA4 SKU,就需要扩展它。

    5.4 构建

    DEV=/dev/dri/renderD129 TARGET=gfx1201 JOBS=16 \
      bash "$HOME/sglang-sandbox/build-gptq-kernels.sh"
    

    脚本在镜像内运行 setup_rocm.py build_ext --inplace,只暴露一个 DRM 节点,
    并把 AMDGPU_TARGET 钉死,这样架构探测不会漂移。

    产物:python/sglang/kernels/aot/python/sgl_kernel/common_ops.cpython-314-x86_64-linux-gnu.so
    (约 25 MB,32 个 gfx1201 code object,约 86 个 gptq 符号)。

    如果构建因为删不掉上一次尝试留下的 root 所属对象而失败,就通过容器删除
    build 目录(容器是以 root 运行的):
    docker run --rm -v <src>:/src $IMG bash -lc 'rm -rf /src/python/sglang/kernels/aot/build; chown -R 1000:1000 /src'

    校验点 4 — 用数值验证,而不是凭感觉。改造 fork 自带的 smoke
    test(constant-nibble 技巧 → 解析上已知的结果),要求
    在 R9700 上 35/35 项检查通过,maxdiff = 0,覆盖 fp16 和 bf16、M=1→128、
    GPTQ v1 与 v2、gptq_shuffle,以及生产场景(bf16 激活 + fp16
    scale)。只有那个 WMMA op 可以跳过,因为你是刻意不构建它的。

    放弃 WMMA 的实际代价在 prefill,不在 decode:

    scalar 路径(本方案) 带 WMMA 的 gfx1100 构建(参考)
    decode 27.2 t/s 2×7900XTX TP=2 上约 80 t/s
    prefill @4K 246 t/s 每卡约 934 t/s

    Decode 受带宽限制,因此不受影响(27.2 t/s ≈ 640 GB/s ÷ 18.6 GB 上限的
    80 %)。真正的牺牲品是 prefill——大约 3.8×。 要想把它找回来,
    需要一个原生的 W4A8/FP8 RDNA4 kernel。


    6. 硬卡点 #3 — dtype 必须是 bf16,而 SGLang 禁止它

    上游 SGLang 把 GPTQ 限制为 fp16:

    torch.bfloat16 is not supported for quantization method gptq
    

    但 checkpoint 里未量化的 tensor 是 bf16,而这个模型是 mamba/attention
    混合架构,它的 causal_conv1d Triton kernel 在 bf16/fp16 混用时会硬失败
    (Mismatched type for col0)。所以你必须跑 bf16——也就必须
    给 SGLang 打补丁以允许它。

    把镜像里的
    sglang/srt/layers/quantization/gptq/gptq.py 复制出来,然后在 GPTQConfig 中:

    @classmethod
    def get_supported_act_dtypes(cls) -> List[torch.dtype]:
        return [torch.half, torch.bfloat16]     # upstream is [torch.half] only
    

    依据:§5 构建的 kernel 能处理 bf16 激活——35/35 的 smoke test 证明的正是这一点
    (bf16 激活 + fp16 scale)。运行时把打过补丁的文件挂载覆盖镜像里的副本(§7)。


    7. 启动脚本

    标准调用方式。保存为 $HOME/sglang-sandbox/run-sglang.sh,并修改
    顶部的路径。

    #!/bin/bash
    set -euo pipefail
    
    IMG=${IMG:-rocm/sgl-dev:v0.5.13.post1-ubuntu24.04-py3.14-rocm7.14.1}
    MODELS_DIR=${MODELS_DIR:-$HOME/models/sglang}
    MODEL_SUBDIR=${MODEL_SUBDIR:-qwen3.8-27b-w4a16-gptq}
    PORT=${PORT:-30001}
    CTX=${CTX:-131072}
    PAGE=${PAGE:-64}
    MEMFRAC=${MEMFRAC:-0.78}
    KV=${KV:-fp8_e4m3}
    DTYPE=${DTYPE:-bfloat16}
    CTR=${CTR:-sglang-gptq}
    RENDER_NODE=${RENDER_NODE:-/dev/dri/renderD129}
    
    # bf16 GPTQ allowance (see §6)
    GPTQ_PY=${GPTQ_PY:-$HOME/sglang-sandbox/patches/gptq.py}
    PY_MOUNT=""
    [ -f "$GPTQ_PY" ] && PY_MOUNT="-v $GPTQ_PY:/sgl-workspace/sglang/python/sglang/srt/layers/quantization/gptq/gptq.py"
    
    # self-built sgl_kernel with the GPTQ ops (see §5)
    GPTQ_SO=${GPTQ_SO:-$HOME/sglang-sandbox/src/sglang-gfx1100/python/sglang/kernels/aot/python/sgl_kernel/common_ops.cpython-314-x86_64-linux-gnu.so}
    SO_MOUNT=""
    if [ -f "$GPTQ_SO" ]; then
      SO_MOUNT="-v $GPTQ_SO:/opt/venv/lib/python3.14/site-packages/sgl_kernel/common_ops.cpython-314-x86_64-linux-gnu.so"
    else
      echo "[!] built sgl_kernel NOT found at $GPTQ_SO — GPTQ ops will be missing"; exit 1
    fi
    
    SPEC_FLAGS=""
    [ "${SPEC:-1}" = "1" ] && SPEC_FLAGS="--speculative-algorithm NEXTN --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4"
    
    HICACHE_FLAGS=""
    [ "${HICACHE:-0}" = "1" ] && HICACHE_FLAGS="--enable-hierarchical-cache --hicache-ratio 2 --hicache-io-backend direct --hicache-write-policy write_through"
    
    # a crashed container stays "Up" and holds the port + GPU
    sg docker -c "docker rm -f $CTR" >/dev/null 2>&1 || true
    
    exec sg docker -c "docker run --rm --name $CTR \
      --device /dev/kfd \
      --device $RENDER_NODE \
      --network=host \
      --ipc=host \
      --group-add=video \
      --cap-add=SYS_PTRACE \
      --security-opt seccomp=unconfined \
      -e HF_HOME=/app/models \
      -e SGLANG_USE_AITER=0 \
      -e SGLANG_ROCM_FUSED_DECODE_MLA=0 \
      -e HIP_VISIBLE_DEVICES=0 \
      -e ROCR_VISIBLE_DEVICES=0 \
      -e PYTORCH_HIP_ALLOC_CONF=expandable_segments:True \
      -e PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True \
      -v $MODELS_DIR:/app/models \
      $SO_MOUNT $PY_MOUNT \
      $IMG \
      python3 -m sglang.launch_server \
        --model-path /app/models/$MODEL_SUBDIR \
        --quantization gptq \
        --dtype $DTYPE \
        --tp-size 1 \
        --mamba-ssm-dtype bfloat16 \
        --attention-backend triton \
        --triton-attention-num-kv-splits 16 \
        --context-length $CTX \
        --kv-cache-dtype $KV \
        --mem-fraction-static $MEMFRAC \
        --max-running-requests 4 \
        --max-mamba-cache-size 20 \
        --chunked-prefill-size 2048 \
        --page-size $PAGE \
        --schedule-policy lpm \
        --reasoning-parser qwen3 \
        --tool-call-parser qwen3_coder \
        --enable-metrics \
        --chat-template /app/models/$MODEL_SUBDIR/chat_template-fixed.jinja \
        --host 0.0.0.0 --port $PORT \
        $SPEC_FLAGS $HICACHE_FLAGS"
    

    为什么用这些参数

    参数 原因
    --tp-size 1 单卡;跨混合架构做 TP=2 不可行(附录 C)
    --quantization gptq + 挂载的 .so 这些 op 在上游并不存在
    --dtype bfloat16 + --mamba-ssm-dtype bfloat16 checkpoint 的 tensor 是 bf16;mamba kernel 不接受混合 dtype
    --attention-backend triton 这些 kernel 所需的组合
    --triton-attention-num-kv-splits 16 RDNA 上的吞吐
    --kv-cache-dtype fp8_e4m3 在速度和效果完全相同的前提下 KV pool 翻倍(295,902 对 148,271 tokens)
    --page-size 64 只要 radix cache 处于启用状态就会被忽略/强制为 1(§8)
    --schedule-policy lpm longest-prefix-match 调度
    --chunked-prefill-size 2048 prefill 调度粒度
    --max-mamba-cache-size 20 混合 SSM 状态槽位(48 个 Gated-DeltaNet + 16 个 full-attention 层)
    --max-running-requests 4 并发上限;让 KV 余量保持在合理范围
    --mamba-ssm-dtype 见 dtype 那一行
    --enable-metrics 暴露 /metrics——§8 的 HiCache + spec 计数器需要它
    --chat-template .../chat_template-fixed.jinja §7.2

    有两种 dtype 值得一说:fp8_e5m2 会被 CLI 接受,但分配器实际创建的
    仍然是 E4M3
    ——在这个目标平台上 AMD FP8 只有 E4M3,所以实际上
    并不存在 e5m2 这个选项。

    校验点 5 — 首次成功启动。留意以下四行:

    KV Cache is allocated. dtype: torch.float8_e4m3fn, #tokens: 295902, ...
    The server is fired up and ready to roll!
    

    并做端到端确认:

    curl -s localhost:30001/v1/models | jq -r '.data[].id'
    curl -s localhost:30001/v1/chat/completions -H 'Content-Type: application/json' \
      -d '{"model":"any-alias","messages":[{"role":"user","content":"say OK"}],"max_tokens":8}' | jq -r '.choices[0].message.content'
    

    服务器接受任意 model 字符串,作为这个已加载模型的别名——
    所以你可以给客户端编一个好记的名字(§10)。

    7.2 硬卡点 #4 — 模型自带的 chat template 会拒绝标准客户端

    这一条让一个符合标准的客户端(DeepSeek Harness)在每个请求上都吃到
    HTTP 400,而 curl 却一切正常。这两个错误都来自模型自带的
    chat_template.jinja——不是 SGLang 的问题:

    Unexpected message role.                                    # chat_template.jinja
    Unexpected reasoning effort high. Supported types are
      xhigh (default), medium, and low.                         # chat_template.jinja
    

    两处不匹配:

    1. role: "developer" —— OpenAI 规范中 system 的继任者,由
      现代 SDK/harness 发出。而模板只处理 system/user/assistant/tool。
    2. reasoning_effort 词表夹击。 OpenAI 的字段(以及 SGLang
      为它定义的 pydantic schema)接受 none|low|medium|high|max,而模板
      只认得 xhigh|medium|low。于是 high/max 通过了校验、随后
      死在模板里,而 xhigh 在模板看到它之前就已经死在 SGLang 的 schema 里。
      过去只有 none|low|medium 能同时穿过这两层。

    在服务端修复,让所有客户端都受益——补丁打在模板上,而不是
    逐个客户端去改:

    {#- 1. normalise the OpenAI effort vocabulary onto the template's three levels -#}
    {%- set resolved_reasoning_effort = reasoning_effort|default('xhigh') %}
    {%- if resolved_reasoning_effort in ('high', 'max') %}
        {%- set resolved_reasoning_effort = 'xhigh' %}
    {%- elif resolved_reasoning_effort in ('none', 'minimal') %}
        {%- set resolved_reasoning_effort = 'low' %}
    {%- endif %}
    
    {#- 2. treat the developer role exactly like system -#}
    {%- if messages[0].role in ('system', 'developer') %}
    {%- if message.role in ("system", "developer") %}
    

    把它写到与原文件并列的 chat_template-fixed.jinja(原文件保持不动),
    再用 --chat-template 让服务器指向它。

    校验点 6 — 完整矩阵必须全部返回 HTTP 200:

    请求 预期
    role: developer 200
    reasoning_effort: none 200,0 个 reasoning 字符(证明禁用路径生效)
    reasoning_effort: low / medium / high / max 200
    chat_template_kwargs: {reasoning_effort: xhigh} 200

    8. 两套运行档,因为在 ROCm 上它们互斥

    只要 speculative decoding 开着,SGLang 就会自动禁用 radix cache:

    Speculative decoding for Qwen3_5ForConditionalGeneration is not compatible
    with radix cache on ROCm devices. Automatically disabling radix cache.
    

    而 HiCache 就是 radix cache 的一个扩展 —— 所以 --enable-hierarchical-cache
    加上 speculation 会在启动时直接中止,报
    enable-hierarchical-cache and disable-radix-cache are mutually exclusive。

    与其跟它较劲,不如把两者都做成具名运行档:

    运行档 Flags 设备池 有效容量 Decode 最适合
    speed SPEC=1 HICACHE=0 MEMFRAC=0.78 KV=fp8_e4m3 PAGE=64 133,791 tok 133,791 tok 43–62 t/s 交互式、写代码
    longctx SPEC=0 HICACHE=1 MEMFRAC=0.90 KV=fp8_e4m3 PAGE=1 295,902 tok 887,707 tok(device + 2× host) 27 t/s 长 agent 会话、大文档

    这些数字背后的实测支撑

    配置 KV pool Decode Prefill @4K
    bf16 KV,无 spec 148,271 27.2 t/s 246 t/s
    fp8_e4m3 KV,无 spec 296,542 27.1 t/s 244 t/s
    fp8_e4m3 + NEXTN 133,791 43.0 / 62.0 t/s 247 t/s
    • NEXTN/MTP speculation:accept_length 3.1、accept_rate 0.70(对
      greedy 无损 —— 输出与非 spec 运行逐字节相同)。Decode 之所以能突破
      约 34 t/s 的带宽天花板,是因为现在每次权重遍历返回的是约 3 个被接受的
      token,而不是 1 个。
    • 代价:eagle worker 的缓冲区位于 mem-fraction-static 之外,
      所以 spec 会强制把 pool 压低。带 spec 时可用值是 MEMFRAC=0.78 ——
      0.90 / 0.85 / 0.80 都会把 draft worker 撑到 OOM(分别差 2.37 GiB / 2.37 GiB / 152 MiB)。
      没有 spec 时,0.90 没问题。
    • HiCache:--hicache-ratio 2 给出的 host pool 恰好是 591,805 tokens
      (通过 hicache_host_total_tokens 实测),即 887,707 有效容量。代价约
      22.6 GB 的 pinned host RAM(19.4 GB KV + 3.2 GB mamba)。已验证可用:
      使用后 hicache_host_used_tokens > 0,并且在 4k prompt 上 warm-prefix TTFT
      16.67 s → 0.74 s(22.5×)。
    • radix cache 生效时 --page-size 64 会被静默强制成 1
      (这个模型在 no_buffer mamba 调度下需要如此)—— 因此两套运行档
      用了不同的 page size。
    • 注意:warm-prefix 测试测的是 radix 复用。host pool 自己的职责 ——
      把从 device 逐出的条目重新水化 —— 需要把 pool 灌过 296k tokens 才能测,
      这一点没有尝试。

    内存占用(longctx,实测)

    Device (R9700):  weights 17.95 GB · KV 9.03 GB (K 4.52 + V 4.52) · graph 0.25 GB
                     → 30.50 / 31.86 GiB used  (~1.4 GiB free)
    Host RAM:        HiCache KV 19.39 GB + mamba 3.22 GB ≈ 21.1 GiB pinned/shared
    

    不要把 --mem-fraction-static 调得比运行档里的值更高 —— 这点余量是
    刻意留得很薄的(仅 device 时 0.90,带 spec 时 0.78)。


    9. 自启动与启动顺序

    9.1 systemd user unit

    # ~/.config/systemd/user/sglang.service
    [Unit]
    Description=SGLang GPTQ server (R9700)
    After=network-online.target
    Wants=network-online.target
    
    [Service]
    Type=simple
    # A *user* unit cannot order against the system-level docker.service — wait for it.
    ExecStartPre=/bin/bash -c 'for i in $(seq 1 90); do (docker info >/dev/null 2>&1 || sg docker -c "docker info" >/dev/null 2>&1) && exit 0; sleep 2; done; exit 1'
    ExecStart=/bin/bash %h/sglang-sandbox/sglang.sh longctx
    # READINESS GATE — see below. Blocks the start job (and every After= dependent)
    # until the model actually answers. "-" = degrade to "started anyway" on timeout.
    ExecStartPost=-/bin/bash -c 'for i in $(seq 1 100); do curl -sf -o /dev/null --max-time 4 http://127.0.0.1:30001/v1/models && exit 0; sleep 6; done; exit 1'
    Restart=on-failure
    RestartSec=30
    TimeoutStartSec=1200
    TimeoutStopSec=120
    KillMode=mixed
    
    [Install]
    WantedBy=default.target
    
    systemctl --user daemon-reload
    systemctl --user enable --now sglang.service
    

    9.2 为什么就绪门(readiness gate)是必需项,而不是可选项

    模型加载要花约 4 分钟。该 unit 是 Type=simple,所以容器一启动 systemd 就把它标为
    started —— 远早于端口开始响应。因此仅凭 After= 并不能阻止客户端与加载过程抢跑。
    真正让 After= 变得有意义的是 ExecStartPost 里的探针。(在这台机器上做过实验验证:
    一个 Type=simple 的 unit,其服务 15 s 后才开始响应,再配一个带 After=/Wants= 的
    依赖单元 → 该依赖单元的 start job 正好耗时 15 s。)

    9.3 每个依赖单元上的顺序

    给每个要跟模型通信的 unit 都放一个 drop-in:

    # ~/.config/systemd/user/<unit>.service.d/wait-for-sglang.conf
    [Unit]
    Wants=sglang.service      # not Requires= — a broken model must never block boot
    After=sglang.service
    

    需要意识到的后果:Wants= 意味着在模型没起来时启动这样一个 unit,也会启动
    模型并等它就绪。

    ⚠️ % 在 unit 文件里是 systemd specifier。 ExecStart 里的 date +%s 会
    静默变成用户的 shell 路径(%s → shell),产出一堆乱东西
    (例如一个内容为 /bin/bash 的文件)。请改用 $(( ... )) 算术,或转义为
    %%。刻意使用的 specifier 没问题 —— 上面用的 %h(家目录)就是有意为之。
    用 grep -c '%' <unit> 审计。


    10. 接入 OpenAI 兼容客户端

    任何 OpenAI 兼容客户端都能用:

    base_url   http://127.0.0.1:30001/v1
    api_key    any non-empty placeholder (the server ignores auth)
    model      any alias — e.g. qwen3.8-27b-gptq-r9700
    

    上下文长度: 服务端的每请求上限是 --context-length(这里是 131,072)。
    客户端上声明 128,000,给输出留出空间。

    ⚠️ Hermes Agent 特别强制要求最小 64,000 tokens 的上下文窗口
    (agent 初始化时的 MINIMUM_CONTEXT_LENGTH)。声明得比这更少,
    每一个请求都会失败并报
    ValueError: Model X has a context window of N tokens, which is below the minimum 64,000
    —— 在它抵达服务端之前就失败了。

    自定义 provider 配置示例:

    custom_providers:
      - name: sglang
        base_url: http://127.0.0.1:30001/v1
        api_key: 'local-no-auth'
        model: qwen3.8-27b-gptq-r9700
        models:
          qwen3.8-27b-gptq-r9700:
            context_length: 128000     # >= 64000 required by Hermes
            supports_vision: true      # vision tower is resident — verified
    

    Reasoning effort —— 打上 §7.2 的模板补丁后,标准 OpenAI
    词表就能直接被接受(none|low|medium|high|max;high/max 都
    表示模型的最大值 xhigh)。如果客户端支持显式 body 透传,也可以用
    chat_template_kwargs: {reasoning_effort: xhigh} 来直接控制模板。

    Vision 已验证可用(一张图片 → 期望的文本)。不需要
    mmproj 文件 —— SGLang 用的是 HF checkpoint 里的 vision tower
    (enable_multimodal 会自动检测到它)。

    调试客户端集成

    客户端侧的 400 是常态;服务端日志往往只记录状态码,不记录
    消息体。两个辅助手段:

    • 透传日志代理 —— 在另一个端口上跑一个极小的代理,把每个请求体
      都 dump 出来,把客户端的 base_url 临时指向它,然后用 curl
      重放捕获到的 body 来读真正的错误。§7.2 里的
      developer role 和 reasoning_effort 问题就是这样找到的。
    • Payload 形状探针 —— 先发基线请求,然后一次加一个字段
      (role: developer、max_completion_tokens 与 max_tokens、store、
      tools、顶层的 effort 与 chat_template_kwargs 里的 effort),并把每个 HTTP 状态
      连同它的响应体打印出来。

    11. 运维

    sglang.sh speed       # NEXTN speculation: 43-62 t/s, 133k pool
    sglang.sh longctx     # HiCache: ~888k effective, 27 t/s        <- autostart default
    sglang.sh status      # kernels, pool, VRAM/RAM breakdown
    sglang.sh stop
    

    运行时健康检查:

    curl -s localhost:30001/get_server_info | jq '{
      ctx: .context_length, tokens: .max_total_num_tokens, kv: .kv_cache_dtype }'
    curl -s localhost:30001/metrics | grep -E 'hicache_(host_used|host_total)_tokens'
    curl -s localhost:30001/metrics | grep -E 'spec_accept|accept_length'   # speed profile
    

    切换运行档需要完整重新加载模型(约 3–4 分钟)。


    12. 故障排查对照表

    症状 原因 修复
    torch.bfloat16 is not supported for quantization method gptq 上游 dtype 限制 §6 补丁;确认它确实被挂载上了
    Mismatched type for col0(Triton) mamba kernel 里混用了 bf16/fp16 --dtype 和 --mamba-ssm-dtype 都跑 bf16
    GPTQ loader 在 MTP 张量上炸掉 checkpoint 的 +:.*mtp.* 规则 §3.2
    torch.ops.sgl_kernel 为空 / 没有 gptq 符号 预编译 wheel 不带 GPTQ ops §5 构建并挂载那个 .so
    clang-23 segfault 为 gfx1201 强行开启 wmma-256b-insts 永远不要开;去掉 WMMA TU(§5.2)
    链接时出现 Undefined symbol common_extension_rocm.cc 的注册没有被 guard §5.3 的编辑(4)
    崩溃后容器显示 "Up" 但端口已死 崩掉的 scheduler 占着端口 + GPU 先 docker rm -f(launcher 会做)
    构建在删除 root 所属文件时失败 容器以 root 运行 通过容器去删构建目录
    enable-hierarchical-cache and disable-radix-cache are mutually exclusive spec 与 HiCache 同时开 只用一套运行档(§8)
    eagle worker 里 spec OOM draft 缓冲区在 mem-fraction-static 之外 MEMFRAC=0.78
    Unexpected message role. / Unexpected reasoning effort high. 原生 chat template §7.2 模板补丁
    Model X has a context window of N tokens, below the minimum 64,000 客户端声明 <64k 声明 ≥64k(用 128,000)
    start job 在模型就绪之前就返回 Type=simple 且没有门 §9.2 就绪门
    unit 输出里出现 %s/%n 乱码 % 是 systemd specifier $(( )) 或 %%

    附录 A —— 实测参考数字

    参考机器:1× R9700(gfx1201,32 GB,31.86 GiB 可用)+ 62 GB RAM,Ubuntu
    24.04,rocm/sgl-dev:v0.5.13.post1-ubuntu24.04-py3.14-rocm7.14.1。

    load time          12.2 s (weights 17.95 GB, quant=gptq bits=4)
    architecture       Qwen3_5ForConditionalGeneration (hybrid: 48 GatedDeltaNet + 16 full attention)
    KV, bf16           148,271 tokens
    KV, fp8_e4m3       296,542 tokens (device pool at MEMFRAC=0.90)
    KV, fp8_e4m3+spec  133,791 tokens (device) at MEMFRAC=0.78
    HiCache host pool  591,805 tokens (--hicache-ratio 2), + 3.22 GB mamba pool
    effective total    887,707 tokens
    decode             27.2 t/s plain · 43.0 t/s prose with NEXTN · 62.0 t/s predictable text
    prefill @4K        246 t/s (TTFT ~17 s cold)
    accept_length      3.1   accept_rate 0.70
    quality            5/5 deterministic prompts, identical with fp8 KV and with spec
    warm-prefix TTFT   16.67 s → 0.74 s (22.5×)
    

    附录 B —— 复现清单

    [ ] docker present, user in docker group, /dev/kfd + /dev/dri visible
    [ ] rocminfo inside the image reports gfx1201
    [ ] checkpoint downloaded; config.json MTP rules fixed (§3.2)
    [ ] fork cloned at the pinned commit; 5 edits applied across 4 files
    [ ] kernel build completes; smoke test 35/35 maxdiff=0 on THIS card
    [ ] patched gptq.py in place (bf16 allowed)
    [ ] chat_template-fixed.jinja generated; role+effort matrix all 200
    [ ] launcher boots: "server is fired up and ready to roll!"
    [ ] /v1/models + a chat completion both answer
    [ ] systemd unit enabled with the readiness gate; dependents ordered After=
    [ ] clients configured: alias, context_length >= 64000, vision if wanted
    

    附录 C —— 在 RDNA 上不可行的事(死路,附原因)

    帮你省下它们耗掉的那几天:

    • Quark / compressed-tensors int4 —— SGLang 只实现了
      quark_w4a4_mxfp4、..._moe、quark_w4a8_mxfp4_moe、w8a8_fp8、
      w8a8_fp8_moe。没有 W4A16 方案;Quark 会抛
      NotImplementedError,compressed-tensors 则反量化到 bf16(约 54 GB)→ OOM。
      这个模型所有打着 "AWQ" 幌子宣传的 checkpoint 都是 Quark/CT-pack,而不是
      AWQ-pack。
    • MXFP4 —— 仅限 CDNA3/4 + AITER。RDNA 没有 FP4 硬件。
    • 单张 32 GB 卡上的 FP8 27B —— 权重 28.70 GiB 对 31.86 GiB 可用,
      只剩约 3 GiB 给 KV + workspace。不可行。
    • 跨不匹配 AMD 架构的 --tp-size 2(例如 gfx1100 + gfx1201)—— FP8/4-bit
      kernel 逐架构不同,混合架构的 RCCL 很脆弱。
    • 这个 fork 的 WMMA GPTQ 路径在 gfx1201 上 —— clang-23 segfault(§5.2)。
    • vLLM (ROCm) int4 —— 未继续追的线索。AMD 的文档提到 AWQ 保持 INT4,而一个
      ROCm vLLM fork 记录了 VLLM_ROCM_USE_RDNA_W4A16(镜像
      vllm/vllm-openai-rocm)。用 Quark checkpoint 时预计会看到
      AttributeError: 'dict' object has no attribute 'endswith'。
      如果你需要把 prefill 吞吐拿回来,值得一试。

  • X99-AD4运行7900XTX黑屏,求助
    L LearningAI
    AI硬件 7900xtx x99

    @terry Terry 好,我的两张卡不一样,AI pro r9700 和 7900xtx. 我查了一下sglang只支持tenser parallel ,我感觉我这两个肯定不行。 我现在只是用llama.cpp tensor split. 显存可以叠加,速度好像跟单卡一样。你设置好的4090 48g 跑sglang时比llama.cpp 快多少? 有定量的测试吗?


  • SGLANG跑RTX4090D-48G-QWEN3.6-27B-FP8配置
    L LearningAI
    LLM讨论区 sg-lang qwen-27b rtx4090

    请问大家在用本地模型驱动Hermes agent的时候怎么检测/记录/统计模型的pp/tg 速度? 有特定的工具或者特定的设置吗?


  • X99-AD4运行7900XTX黑屏,求助
    L LearningAI
    AI硬件 7900xtx x99

    感谢大家的帮助,我的问题解决了。我买了一块GT710做亮机卡,插在第一pcie. 一开始还是不能点亮,后来根据AI提示把HDMI线换成VGA就可以点亮进入bios了。 然后关了CSM, 打开Above 4G等等设置。用GT710显示安装了Ubuntu 24.04和rocm 7.15.

    再把显示器插回7900xtx的HDMI后显示器不亮。AI提示说X99只要选择了第一插槽做显示输出就不容易改动了。我就把GT710换成r9700,然后正常开机了。

    装上Hermes+deepseek flash,配置llama-server, qwen3.6 27B Q8_0 双卡启动Hermes正常。

    后续测试结果我会发到论坛和大家分享。

    再次感谢🙏


  • X99-AD4运行7900XTX黑屏,求助
    L LearningAI
    AI硬件 7900xtx x99

    @abaalei 谢谢,看到您的使用效果我更有信心了😄。请问您的bios版本是哪一年的? 还有您的bios关于pcie部分是怎么设置的?🙏


  • X99-AD4运行7900XTX黑屏,求助
    L LearningAI
    AI硬件 7900xtx x99

    @Xiaote 谢谢😄,关闭 Above 4G Decoding会影响显存调用效果吗?


  • X99-AD4运行7900XTX黑屏,求助
    L LearningAI
    AI硬件 7900xtx x99

    @williamlouis 谢谢! 我打算买个便宜的GTX710先把机器点亮再说。 我的bios里没有pcie lane设置选项,需要刷老版本的bios吗?您是用的pcie3.0x16设置吗?N卡还是A卡?


  • X99-AD4运行7900XTX黑屏,求助
    L LearningAI
    AI硬件 7900xtx x99

    大家好,我刚刚在华南金牌买了一套X99-AD4, 配E5-2686V4 CPU,双DDR4 32G 内存。我自己买了一块华擎的7900XTX和一块xfx radeon ai pro r9700,还有一块NVME 2T SSD.

    我先安装了7900XTX。 昨天可以进bios, 我按照网上推荐的设置改了一下bios. 改完后能启动,本打算安装Ubuntu 24.04。但是时间有点晚了,我就关机了。今天打算装系统,发现无法启动。显示器黑屏。我试着插拔显卡,无效。 我尝试把显卡从第二pcie挪到第一个pcie,仍然无效。但是挪完后我能看到主板上的led显示67。 网上查了一下说有可能是内存接触不良。我根据AI网上的建议插拔内存并清除了CMOS. 之后加点仍然黑屏,但是显卡风扇照转。错误码显示AD. 我问了一下Copilot, 说是pcie初始化失败。它还说X99对7900xtx兼容不好。 推荐我找一块旧的NVIDIA显卡先进入bios然后把pcie改成gen2.

    请问大家遇到过类似情况吗? 必须要降pcie速度吗? 我是打算双卡Vulkan在llama.cpp跑qwen3.6 27B的,pcie降到gen2 对速度损失太大了吧。

    我昨天注意到我bios的版本日期好像是2025年的。

    麻烦高手给指点迷津。多谢啦!

  • 登录

  • 登录或注册以进行搜索。
  • 第一个帖子
    最后一个帖子
0
  • 版块
  • 最新
  • 标签
  • 热门
  • 用户
  • 群组