2026年10月3日
cover_7900xtx_125b_1789563895884

48G 显存挑战 125B 大模型!双 7900 XTX 实测 Qwen3.8 Flash:日常 38 tok/s、48K 长文本稳定 28 速度

导读与事实基底声明(SSOT)
本文的参数、显存读数与性能数字来自 2026-09-16 的同一台测试主机:Ryzen 7 3700X、RX 7900 XTX 24GB × 2、96GB 物理内存(系统显示约 94.2GiB)、Ubuntu 24.04、Linux 6.14、TheRock ROCm 7.14,以及 nasone32/llama.cpp-RDNA3-7900xtx-opt commit 15995a12d1d530645a4f34c72afdaa30fa680149。
以下结果只代表这套硬件、这份模型量化、这次软件构建和这组测试负载;不是所有双 7900 XTX 的理论上限,更不是对其他模型的性能承诺。

部署状态说明
FAST-50K 是本文的性能基线,STABLE-64K 是已验证的按需配置。本文更新时,测试机临时保留 ctx-size=32768 供客户端跑日常 API 扫描;这不改变 50K / 64K 的历史 A/B 结果,也不代表已经上线多 Profile 自动路由。

64GB 内存适用范围
本文的性能数据来自 96GB 测试机,不能改写成“64GB 实测成绩”。但在 --parallel 1、--load-mode none、--lazy-mode on-direct、不运行其他重内存模型服务的前提下,64GB 可作为 FAST-50K / 32K 的部署起点。64K 则应视为 96GB 推荐、64GB 必须单独验收的配置。

📺 本文配套真机实测与视频讲解:

两张 24GB 的 7900 XTX,能不能把 90GB 级别的 Qwen3.8 Flash Next GGUF 跑成一个真正可用的本地服务?可以。但这里没有把 90GB 权重硬塞进 48GB 显存:这是一个 双卡分层 + 主机内存 + Lazy Loading 的 MoE 部署。

先说明标题中的速度:它说的是读者实际等待的 输出生成速度(TG),不是预填充(PP)。当前 32K API 扫描在 512–8,192-token 提示词范围内,TG P50 为 38.32 tok/s;固定 48,009-token 输入、固定输出 512 token 的严格压力测试中,FAST-50K 的 TG 为 27.98 tok/s。两者分别对应日常使用与长上下文重负载。

本文的 FAST-50K 性能基线使用 50,144-token 上下文、Q8 KV、MTP draft n-max=2。在完全相同的 48,009-token 输入加 512-token 输出下,三轮平均预填充为 467.03 tok/s,生成速度为 27.98 tok/s。

64K 参数也已完成 48K 严格 A/B 验收:预填充 424.75 tok/s、生成 24.49 tok/s。它是“已验证的按需长上下文 Profile”,不是当前常驻的第二个生产服务,更不是已经由网关自动分流的双实例。

核心技术栈选型一览

核心组件 本文配置 选择理由
推理核心 nasone32/llama.cpp-RDNA3-7900xtx-opt,15995a12… 文章中的全部参数与成绩均绑定这次 RDNA3 构建。
运行时 TheRock ROCm 7.14,gfx1100 独立于系统 ROCm,避免破坏已有工作负载。
主模型 Qwen3.8-Flash-Next-UD-Q3_K_XL 主模型分三卷;显存、系统内存与 lazy loading 共同承担运行负载。
投机解码 shared Q8_0 MTP draft,n-max=2 本机实测的默认折中点。
KV Cache q8_0 / q8_0 以较小精度代价换取更大的上下文和显存余量。
性能基线 Profile FAST-50K,ctx-size=50144 48K 严格 A/B 中 PP / TG 都优于 64K。
长上下文 Profile STABLE-64K,按需启动 已完成 48K 严格验收,但不是常驻路由后端。
OpenAI 兼容客户端
        │
        ▼
鉴权网关(完成安全加固后才开放)
        │
        ▼
FAST-50K · llama-server :8082
        │
        ▼
RX 7900 XTX × 2(layer split) + Host RAM + Lazy Loading

超过约 48K 的任务:受控停止 FAST-50K → 启动 STABLE-64K → 验收 → 恢复

⚡ 一、这台机器实际跑出了什么

项目 FAST-50K:性能基线 STABLE-64K:按需验证
ctx-size 50,144 65,536
batch-size / ubatch-size 4096 / 1024 4096 / 1024
KV Cache Q8_0 / Q8_0 Q8_0 / Q8_0
MTP adaptive,最大 2 token adaptive,最大 2 token
fit-target 3800,1024 5000,2048
48,009-token PP,3 轮平均 467.03 ± 1.32 tok/s 424.75 ± 1.66 tok/s
512-token TG,3 轮平均 27.98 ± 0.20 tok/s 24.49 ± 1.99 tok/s
三轮平均总耗时 121.08s 134.06s

这组 A/B 的输入 Token ID、采样种子和输出长度一致,且关闭 Prefix Cache:prompt_n=48009、predicted_n=512、cache_n=0、truncated=false。因此它能说明两个 Profile 在 48K 实际工作负载 下的差异。

但它不能替代近窗口上限的容量验收。65,536 是总上下文窗口,输入还必须为系统提示词、模板和输出预留空间;它不等于“百万汉字”或“百万字文档”。

同一服务的 0.5K–8K API 扫描:不要和 48K A/B 混比

另一次单并发 OpenAI API 扫描把提示词从 512 token 递增到 8,192 token。请求自然结束,实际输出只有 119–155 token;它不是固定 512-token 输出的压力测试。界面报告的数据如下:

测试口径 Prompt 范围 输出长度 PP 吞吐 TG 吞吐
API 扫描,单并发 512–8,192 119–155,自然结束 平均 544.11;P50 583.64 tok/s 平均 36.07;P50 34.73 tok/s
严格 A/B,FAST-50K 48,009 512,固定输出 467.03 tok/s 27.98 tok/s

图 1:FAST-50K 下的单并发 OpenAI API 扫描;提示词从 512 递增至 8,192 token。

图 1|FAST-50K(50,144 context)日常 API 扫描。PP 平均 544.11 tok/s、P50 583.64 tok/s;TG 平均 36.07 tok/s、P50 34.73 tok/s。每轮输出自然结束在 119–155 token,不是固定 512-token 压测。

图 2:32K 上下文下的单并发 OpenAI API 扫描;提示词从 512 递增至 8,192 token。

图 2|将服务切为 32,768 context 后,以同一界面和单并发口径复测。PP 平均 536.45 tok/s、P50 593.12 tok/s;TG 平均 38.05 tok/s、P50 38.32 tok/s。相较图 1,P50 PP 小幅提高,TG 指标更高;但每轮自然输出长度不同,不能将这两张 API 扫描图当成严格的因果性能结论。

更严格的 24,576-token + 固定 256-token、cache_prompt=false 对照显示,32K 相比 50K 的平均 PP 从 526.54 提升到 534.68 tok/s(约 +1.5%),TG 从 29.53 提升到 30.39 tok/s(约 +2.9%)。这才是判断“缩短 context 是否更快”的主要依据。

两行数据并不矛盾。随着 prompt 变长,attention 与 KV 访问成本会提高,新的 token 需要关注更长的历史;所以 48K 的 Prefill、尤其 Decode,低于 8K 内的中位数是正常现象。反过来,短扫首轮还会包含 lazy loading、图捕获或后台干扰,截图中 512-token 的 191.39 tok/s 与 1,536-token 的 361.13 tok/s 就不适合被当作模型上限。

以后引用速度时,必须同时写出:prompt token 数、固定或自然结束的输出长度、并发数、是否命中 Prefix Cache,以及 PP / TG 的统计方式。只写一个“tokens/s”没有可比性。

💡 架构边界先说清楚:FAST-50K 是本文常驻基线,64K 脚本已通过严格 A/B,但尚未由独立 systemd 服务常驻,也没有在网关中按模型名自动路由。把两者写成“已上线双 Profile 集群”是不准确的。


🛠️ 二、硬件与软件基线

组件 实测配置 为什么重要
GPU RX 7900 XTX 24GB × 2,gfx1100 双卡层切分,共同承载模型与 KV / scratch。
内存 验证平台为 96GB 物理内存(约 94.2GiB) 这是性能数据的实测环境,不是宣称的最低要求。
推理核心 RDNA3 优化分支,commit 15995a12… 本文所有参数都绑定该构建,不能直接照搬到任意 upstream 版本。
独立运行时 TheRock ROCm 7.14 不改动既有系统 ROCm;AMD 官方提供 gfx110X tarball。
主模型 Qwen3.8-Flash-Next-UD-Q3_K_XL 主模型分三卷;显存、系统内存与 lazy loading 共同承担运行负载。
Draft 模型 mtp-Qwen3.8-Flash-Next-shared-Q8_0.gguf 复用主模型部分权重,用于投机解码。

先确认系统和两张卡:

uname -a
free -h
df -h /
rocminfo | grep -E 'Name:.*gfx1100'
rocm-smi

两张卡应显示为 gfx1100。如果设备编号中还混有核显,不要假设 0,1 必然是两张 7900 XTX;先执行 llama-server --list-devices 再设 HIP_VISIBLE_DEVICES。

64GB 还是 96GB?按目标选择

主机内存 适合的目标 使用边界
64GB 32K;FAST-50K 单并发 关闭其他大模型服务,保持 --parallel 1,用真实 24K–48K 请求验收且持续观察 Swap。
96GB FAST-50K 的推荐配置;64K 验证环境 为 host-resident experts、模型文件页缓存和长请求波动留出更大余量。
128GB+ 64K 长会话、多并发或更多后台服务 适合将长上下文服务作为长期基础设施使用。

模型文件约 90GB,不代表它会把 90GB 全部常驻进 RAM。这里依赖 mmap、host-resident experts 与 lazy loading;但空闲时能启动,不等于长 Prompt 下就一定稳定。64GB 主机首次部署后至少完成一次 24K 和一次接近目标上限的冷请求,并确认:

free -h
swapon --show

验收期间不应出现持续增长的 Swap、OOM 或请求结束后无法回落的可用内存。若目标是 64K,不要把 64GB 当作已验证配置;先完成该机器自身的长请求验收,再决定是否长期使用。


🚀 三、独立安装 ROCm 7.14,不碰系统 ROCm

TheRock 的 gfx110X 包是 AMD 官方提供的安装方式,下载地址与文件名以 ROCm 官方文档为准:

mkdir -p ~/rocm714-download
cd ~/rocm714-download

wget https://repo.amd.com/rocm/tarball-multi-arch/therock-dist-linux-gfx110X-all-7.14.0.tar.gz

sudo mkdir -p /opt/qwen38/rocm-7.14
sudo chown "$USER":"$USER" /opt/qwen38/rocm-7.14
tar -xf therock-dist-linux-gfx110X-all-7.14.0.tar.gz -C /opt/qwen38/rocm-7.14

运行时环境统一写进启动脚本和 systemd,不依赖登录 shell:

export ROCM_PATH=/opt/qwen38/rocm-7.14
export PATH="$ROCM_PATH/bin:$ROCM_PATH/lib/llvm/bin:$PATH"
export LD_LIBRARY_PATH="$ROCM_PATH/lib:$ROCM_PATH/lib/llvm/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"

不要只在普通 shell 中直接执行 ldd llama-server 来判断是否串库。它可能没有带入服务的 LD_LIBRARY_PATH。更可靠的验收是:

# 启动前:在与服务相同的环境下检查
env LD_LIBRARY_PATH=/opt/qwen38/rocm-7.14/lib:/opt/qwen38/rocm-7.14/lib/llvm/lib   ldd /opt/qwen38/src/llama.cpp-RDNA3-7900xtx-opt/build-rocm-gfx1100-portable/bin/llama-server   | grep -Ei 'hip|hsa|rocblas|hipblas'

# 启动后:以实际进程映射为准
grep -E '/opt/qwen38/rocm-7\.14/.*(libhip|libhsa|libroc|libamd)' /proc/<LLAMA_PID>/maps

🔧 四、构建 RDNA3 版本 llama.cpp

sudo apt update
sudo apt install -y git cmake ninja-build build-essential pkg-config curl wget python3 python3-pip libssl-dev

sudo mkdir -p /opt/qwen38/{models,src,logs,benchmarks,conf,bin}
sudo chown -R "$USER":"$USER" /opt/qwen38

cd /opt/qwen38/src
git clone https://github.com/nasone32/llama.cpp-RDNA3-7900xtx-opt.git
cd llama.cpp-RDNA3-7900xtx-opt
git checkout 15995a12d1d530645a4f34c72afdaa30fa680149

cmake -S . -B build-rocm-gfx1100-portable -G Ninja   -DCMAKE_BUILD_TYPE=Release   -DCMAKE_C_COMPILER="$ROCM_PATH/lib/llvm/bin/clang"   -DCMAKE_CXX_COMPILER="$ROCM_PATH/lib/llvm/bin/clang++"   -DCMAKE_HIP_COMPILER="$ROCM_PATH/lib/llvm/bin/clang"   -DCMAKE_HIP_FLAGS='-mllvm --amdgpu-unroll-threshold-local=600'   -DGGML_HIP=ON   -DGGML_HIP_GRAPHS=ON   -DAMDGPU_TARGETS=gfx1100   -DLLAMA_BUILD_TESTS=ON

cmake --build build-rocm-gfx1100-portable -j "$(nproc)"

📦 五、下载主模型与 MTP Draft

python3 -m venv ~/hf-cli
source ~/hf-cli/bin/activate
pip install -U huggingface_hub

mkdir -p /opt/qwen38/models/Qwen3.8-Flash-Next-GGUF/{UD-Q3_K_XL,MTP}

hf download unsloth/Qwen3.8-Flash-Next-GGUF   UD-Q3_K_XL/Qwen3.8-Flash-Next-UD-Q3_K_XL-00001-of-00003.gguf   UD-Q3_K_XL/Qwen3.8-Flash-Next-UD-Q3_K_XL-00002-of-00003.gguf   UD-Q3_K_XL/Qwen3.8-Flash-Next-UD-Q3_K_XL-00003-of-00003.gguf   --local-dir /opt/qwen38/models/Qwen3.8-Flash-Next-GGUF

hf download unsloth/Qwen3.8-Flash-Next-GGUF   MTP/mtp-Qwen3.8-Flash-Next-shared-Q8_0.gguf   --local-dir /opt/qwen38/models/Qwen3.8-Flash-Next-GGUF

deactivate

模型只指定第一分卷即可,llama.cpp 会发现后续分卷。


⚙️ 六、FAST-50K:性能基线参数

先把核心命令跑通,再交给 systemd。下面保留了实际验证过的推理参数;示例刻意绑定 127.0.0.1,避免把未加固后端直接暴露到局域网。

#!/usr/bin/env bash
set -euo pipefail

ROCM_PATH=/opt/qwen38/rocm-7.14
ROOT=/opt/qwen38/src/llama.cpp-RDNA3-7900xtx-opt
SERVER="$ROOT/build-rocm-gfx1100-portable/bin/llama-server"
MODEL=/opt/qwen38/models/Qwen3.8-Flash-Next-GGUF/UD-Q3_K_XL/Qwen3.8-Flash-Next-UD-Q3_K_XL-00001-of-00003.gguf
DRAFT=/opt/qwen38/models/Qwen3.8-Flash-Next-GGUF/MTP/mtp-Qwen3.8-Flash-Next-shared-Q8_0.gguf

export PATH="$ROCM_PATH/bin:$ROCM_PATH/lib/llvm/bin:$PATH"
export LD_LIBRARY_PATH="$ROCM_PATH/lib:$ROCM_PATH/lib/llvm/lib"
export HIP_VISIBLE_DEVICES=0,1
export GGML_CUDA_ALLREDUCE=internal
export GGML_CUDA_AR_WIRE=q8_0
export GGML_CUDA_AR_Q8_THRESHOLD=1048576
export GGML_CUDA_AR_FUSED_RESIDUAL=1
export GGML_CUDA_GDN_CHUNKED_BF16=1
export GGML_CUDA_AR_P2P=0

exec "$SERVER"   --model "$MODEL"   --model-draft "$DRAFT"   --alias qwen3.8-flash-next-fast50k,qwen3.8-default,qwen3.8   --api-key-file /opt/qwen38/conf/api_keys.txt   --metrics   --host 127.0.0.1 --port 8082   --ctx-size 50144   --spec-type draft-mtp-adaptive   --spec-draft-n-min 1   --spec-draft-n-min-adaptive 1   --spec-draft-n-max 2   --device-draft ROCm0   --split-mode layer   --flash-attn on   --batch-size 4096 --ubatch-size 1024   --moe-expert-cache 0   --cache-type-k q8_0 --cache-type-v q8_0   --parallel 1   --fit on --fit-target 3800,1024   --load-mode none --lazy-mode on-direct   --temp 0.0 --top-p 0.95 --top-k 20 --min-p 0.0   --presence-penalty 0.0   --reasoning on --reasoning-effort medium

为什么默认是 50K?
同一测试中,FAST-50K 的 48K Prefill 比 64K 快约 9%,生成快约 12.5%。日常编码、问答和中长任务选择它,性价比更高。


🧪 七、STABLE-64K:已验证,但按需切换

64K 不是把 ctx-size 改大就结束。此机型在维持 ubatch=1024 时,需要将 layer placement 调整为:

--ctx-size 65536
--fit-target 5000,2048

其他核心参数与 FAST-50K 保持一致。这样能给一次较大的 ggml_gallocr scratch 分配留出空间,而不是粗暴把 ubatch 从 1024 降到 512。

但请不要直接编辑常驻 FAST 脚本再重启来“切换 Profile”。正确做法是保留独立的 start-q3-stable64k.sh,并在每次切换前完成:停止 FAST、启动 64K、健康检查、执行长上下文验收、完成后恢复 FAST。要做到无人值守再为它创建独立 service 和受控切换脚本。


🔐 八、API、网关与安全:先完成加固,再开放 LAN

llama-server 的 OpenAI 兼容接口可直接验证:

export QWEN38_API_KEY='从安全的环境变量或密码管理器读取'

curl http://127.0.0.1:8082/v1/models   -H "Authorization: Bearer $QWEN38_API_KEY"

后端 API Key 并不等于已安全开放局域网。以下三条必须同时满足:

  1. 后端只监听 localhost,或防火墙精确放行可信网段与 VPN;绝不直接面向公网开放。
  2. 网关必须验证客户端身份。不能让任意 LAN 请求自动获得后端 Bearer Key。
  3. 流式验收必须通过:stream=true 的响应最终必须收到 data: [DONE]。HTTP/1.1 代理不能丢掉 chunked 编码或结束标记,否则 Cherry、OpenAI SDK 等客户端会显示正文后永久“处理中”。

发布前应实测:

curl -N http://<gateway>/v1/chat/completions   -H 'Content-Type: application/json'   -H 'Authorization: Bearer <client-key>'   -d '{"model":"qwen3.8","messages":[{"role":"user","content":"只回复 OK"}],"stream":true,"max_tokens":32}'

输出末尾必须是:

data: [DONE]

🧰 九、systemd:守护 FAST-50K,也要守护网关

模型进程应由 systemd 管理,启动脚本末尾必须使用 exec。最小单元如下:

[Unit]
Description=Qwen3.8 Flash Next FAST-50K
After=network-online.target
Wants=network-online.target

[Service]
Type=exec
User=xin
Group=xin
SupplementaryGroups=render video
WorkingDirectory=/opt/qwen38
ExecStartPre=/opt/qwen38/bin/preflight-check.sh
ExecStart=/opt/qwen38/start-q3-fast50k.sh
ExecStartPost=/opt/qwen38/bin/wait-health.sh
Restart=on-failure
RestartSec=10
TimeoutStartSec=300
LimitNOFILE=65535
LimitMEMLOCK=infinity

[Install]
WantedBy=multi-user.target

网关是另一项服务,不能依赖 nohup python router.py &。它也应有独立 unit、依赖后端 health check、使用受限运行用户,并在进程退出时自动重启。否则“模型服务已自动恢复”只覆盖模型,不覆盖客户端真正访问的入口。


✅ 十、发布前验收清单

[ ] 实际运行进程加载的是独立 ROCm 7.14 库
[ ] FAST-50K 的 systemd 服务 enabled + active
[ ] /health、/v1/models 与一次非流式调用通过
[ ] 流式调用收到 data: [DONE]
[ ] 网关要求客户端 API Key;后端密钥不对 LAN 自动注入
[ ] 防火墙规则已按实际网段验收,而不是只写在文档里
[ ] 64K Profile 有近窗口上限的独立验收,且结果归档
[ ] 若声称“双 Profile 路由”,已实际部署第二服务和模型名分流

结论

这套双 7900 XTX 的价值不在于把所有参数推到极限,而在于把一台可重复验证的本地推理机跑稳:默认 50K 获得更好的交互性能;真正需要更长上下文时,再受控切到已验证的 64K 配置。

性能数据已经有原始三轮 A/B 支撑。下一步优先级不是继续追 1–2 tok/s,而是把网关鉴权、systemd 托管、64K 自动切换和近上限验收补齐。完成这些之后,它才是一套可以放心交给多个开发工具使用的本地推理基础设施。


参考资料

About The Author

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注