先说结论
同一个模型、同一台机器,从 Unsloth Studio + llama.cpp 换成 Strata 之后:预填从 230~250 tok/s 涨到 1,764~3,737 tok/s,解码从 30~31 tok/s 涨到 124~145 tok/s,上下文从 128K 到 262K,首次加载从 80 秒降到 40 秒。
所以上一版里 prefill 偏低这件事,瓶颈主要不在内存带宽,而在引擎的预填路径。
换 DDR5-5600 的事可以先放一放。
权重一个字节都没重新下载。本机原本就有的那份 UD-Q4_K_XL 与 Strata 官方钉死的 revision 逐字节一致,直接指过去用。

测试环境
| 项目 |
配置 |
| CPU |
AMD Ryzen 7 9700X,8C/16T |
| 内存 |
128GB,双通道 4×32GB DDR5-5600(运行在 DDR5-3600,系统可见 123GB) |
| GPU |
NVIDIA RTX PRO 5000 Blackwell 48GB(300W 顶格)+ Radeon AI PRO R9700 32GB(功耗上限手动设为 240W,出厂默认 300W) |
| 系统 |
Ubuntu 24.04.5,内核 7.0.0-31 |
| GPU 驱动 |
NVIDIA 595.99.02 |
| CUDA / ROCm |
CUDA 13.0(编译用的 toolkit)/ ROCm 7.2.4。nvidia-smi 报的 13.2 是驱动支持的版本,不是编译版本 |
| Strata |
main @ 7695859(2026-10-11),引擎 0.1.43 |
| 模型 |
unsloth/Qwen3.8-Flash-Next-GGUF,UD-Q4_K_XL,revision 38bb39e |
| 客户端 |
Mac(浏览器与脚本),经 Tailscale 连到 Ubuntu |

一、部署
权重零下载
本机 HF 缓存里已经有 Unsloth 的 UD-Q4_K_XL,正好是 Strata 官方钉死的 revision 38bb39e。核对了一遍,四个分片的字节数与官方文档列出的完全一致;shard 1 的 sha256 也一致。所以直接用 setup.sh 的 --gguf-dir 指向它,模型权重一个字节都没下。
安装
git clone https://github.com/Niko1221/Strata.git /data/ai/apps/Strata && cd $_
./setup.sh --setup \
--family unsloth --model UD-Q4_K_XL \
--gguf-dir /data/ai/models/strata/UD-Q4_K_XL \
--data-dir /data/ai/strata-data \
--backend cuda --cuda 13 --gpu 0 \
--context 262144 --kv int8 --vision gpu \
--resident-budget-gib 71 --vram-reserve-mib 1024 \
--port 8090 --host 127.0.0.1 \
--no-browser --no-start --yes
--backend cuda 要显式写。本机有 A 卡,不指定的话 setup 可能选 HIP,而 UD-Q4_K_XL 在 AMD 上跑不了——它的 Q4_K/Q5_K 专家 prompt 内核是 NVIDIA 专属的。
各阶段耗时:
| 阶段 |
耗时 |
| git clone |
16 秒 |
| .venv + Python 依赖 |
约 1 分 |
| 引擎源码编译(CUDA 13,sm_120) |
约 10 分 |
| 模型 sha256 校验(111 GB) |
约 9 分 |
pack 打包(--compat-bf16) |
约 1 分 |
| MTP 草稿层(下载约 5 GB + 转换) |
约 25 分 |
| 首次启动装载 |
约 40 秒 |
| 合计 |
约 52 分 |
pack 打包的关键数字:
index.txt: 1079 tensors, 303 served natively, arena 1.38 GiB
conversions.json: 460 tensors converted (264 exact, 196 rounded; max |err| 0.0144)
compat-bf16: 195 tensors, 1.20 GiB
--compat-bf16 必须加。这个量化文件把 195 个小投影(hyper-connection 矩阵之类)存成 Q8_0,而引擎按 BF16 读;不加这个参数打包器会直接拒绝。
memlock 的意外
本机 ulimit -l 的软硬上限都是 16567234560 字节(正好是 RAM 的 1/8),ulimit -l unlimited 提不上去,只有 root 能改。
原本担心 71 GiB 的 RAM 预算锁不住,但实测没影响:
FileExpertSource: mapped pinned cache complement ready: resident 34.76 GiB,
pinned 34.76 GiB in 14 s; page-locked and mapped
35.09 GiB 照样页锁定成功了。NVIDIA 驱动的 pinning 路径应该不走这个 RLIMIT。
启动后的状态
[strata] filling the GPU's expert cache (12547 experts, 36.64 GiB of VRAM) ...
FileExpertSource: RAM budget 71.00 GiB: 12029 of the 35.09 GiB of experts
the GPU cache does not hold, by profile rank; the rest are
read from the files
FileExpertSource: mapped pinned cache complement ready: resident 35.09 GiB,
pinned 35.09 GiB in 17 s; page-locked and mapped
strata generate: resident RAM mode: 35.09 GiB of experts in RAM (page-locked),
12547 in the GPU cache
| 项目 |
实测 |
| 显存里的专家 |
12,547 个 / 36.64 GiB(占全部 24,576 个的 51%) |
| 内存里的专家补集 |
12,029 个 / 35.09 GiB(12,547 + 12,029 = 24,576,全覆盖) |
| 显存占用 |
47,861 / 48,935 MiB(预留 1024) |
| KV |
8-bit,每层 32,768 个位置在显存、其余在内存(面板原文:streamed) |
| 专家命中率 |
冷启约 91%,运行中 96% 到 99% |
专家槽数在不同次启动之间会有一点浮动。同一份配置实测到过 12,547 和 12,658 两个值(对应 36.64 和 36.97 GiB),取决于启动那一刻显存里还有多少被别的进程占着。下面统一用最近两次启动的 12,547。
关于读磁盘,有一点要说清楚。启动后只跑短对话时,日志里的计数器是 0 blob reads from the file。但跑过 262K 长 prompt 的压测之后,这个计数器就会累积——第一次压测后到 4.3 万,长时间运行后到了 11 万。长 prompt 会把全部专家流式过一遍,路上还是要碰文件层,只是被 page cache 兜住所以速度没有掉下来。所以准确的说法是:普通对话不读盘,超长 prompt 的预填仍然会读盘。

二、Strata 单机性能
tools/strata_bench.py --runs 3 --long 的中位数:
| 指标 |
中位数 |
范围 |
| chat 解码 |
99.3 tok/s |
72.0 – 114.8 |
| agent 单轮解码 |
122.7 tok/s |
83.5 – 180.0 |
| 4K prompt 预填 |
1,877.9 tok/s |
1,850 – 2,090 |
| 16K prompt 预填 |
3,671.6 tok/s |
3,609 – 3,681 |
| 32K prompt 预填 |
3,912.8 tok/s |
3,887 – 3,950 |
| chat 首 token |
0.24 s |
— |
| 32K 首 token |
8.22 s |
— |
tools/needle_bench.py,32K/128K/262K 三个长度各测 10%/50%/90% 三个深度,9 次全中:
| 长度 |
10% |
50% |
90% |
| 32K |
10 s |
9 s |
9 s |
| 128K |
35 s |
35 s |
23 s |
| 262K |
70 s |
69 s |
69 s |
262,144 的上下文能用满,三个深度都命中,没有中段丢失。
刚部署完、第一次把那 10 道智力测试题跑完的时候,Monitor 面板是这样:

第一行的 PROMPT 5,599 / PREFILL T/S 1,920——5,600 个 token 的 prompt 预填到 1,920 tok/s,和上面脚本测的 4K = 1,764 基本吻合。另外单个请求连续生成了 5,965 个 token,解码 105.9 tok/s,耗时 57.9 秒。预热阶段(starts 之后头几次请求)的命中率是 92.4% 到 96.6%,比长时间运行后略低。
跑了一段时间、累计 115 次请求之后,同一个面板:

底部那行聚合数据是 115 次真实请求的结果:
115 requests · 660,959 prompt tokens read at 2,984 tok/s (105,921 reused)
· 92,967 written at 126.6 tok/s
预填 2,984 tok/s、解码 126.6 tok/s,和上面用脚本测出来的区间能对上。
conversation cache 也确认在工作:

Reused since start 105,921 tokens (14%),4 个槽位全部用满,累计 parked 114 次、evicted 87 次。这一项是给多会话场景准备的(agent、harness 反复切 session 时不用重新 prefill),实测确实在省。
三、同一个模型换个引擎
之前用 Unsloth Studio + llama.cpp 跑过同一个 UD-Q4_K_XL(https://lcz.me/post/15186),硬件和模型完全一样,换个引擎再看一次。
| 项目 |
Unsloth Studio + llama.cpp |
Strata |
| 上下文 |
64K / 128K |
262,144 |
| 首次加载 |
约 80 秒 |
约 40 秒 |
| 预填 |
230 – 254 tok/s |
1,764 – 3,737 tok/s |
| 解码 |
30 – 31 tok/s |
124 – 145 tok/s |
| MTP |
未启用(--spec-default) |
已启用,面板显示「MTP drafts up to 3 tokens, prompt lookup on」 |
| 权重摆放 |
GPU 45.9 GiB + file-backed RAM 58.3 GiB |
GPU 专家 36.64 GiB + 页锁定 RAM 补集 35.09 GiB |

解码差 4 到 4.7 倍,预填差 7 到 15 倍。
之前那篇里 prefill 230 到 250 tok/s 被判断成最大的痛点,还推测把 4×32G DDR5-3600 换成 2×64G DDR5-5600 能提到 260 到 320。现在同样的内存、同样的模型,只换引擎就到了 1,764 到 3,737。这个量级说明 prefill 的瓶颈主要不在内存带宽,而在引擎的预填路径本身。内存带宽当然还有影响,但它不是那个数量级的原因。换内存的事可以先放一放。
两边的权重摆放方式也不一样。llama.cpp 侧那 58 GiB 是通过 mmap 映射的,落在 RssFile 和 page cache 里;Strata 是把 GPU 装不下的 11,918 个专家(34.76 GiB)直接页锁定进内存,属于常驻。前者预填时要等缺页和 page cache,后者不用。
MTP 也值得一提。之前 llama.cpp 那边 Auto 模式实际起的是 --spec-default,unsloth-runtime-check 一直显示 MTP disabled,等于没启用。Strata 需要单独准备草稿层(mtp/rt,安装时下载约 5 GB 并转换),但确实在跑。
这里有个容易误读的地方:配置里写的是 --spec 4,但 Strata 的 About 面板显示的实际生效值是「MTP drafts up to 3 tokens, prompt lookup on」。声明的 flag 和最终生效的参数不是一回事,看面板比看配置准。
两点说明:一是两次测试隔了一个多月,llama.cpp 和 Studio 的版本都变了,测量工具也不同(前者是 Studio 界面读数,后者是我自己的流式脚本加官方 bench),所以这里是数量级参考,不是严格同条件对比。二是视觉这次没单独测,Strata 侧已开 --vision,效果后面再补。
另外补一点和速度无关的观察。上一版里提到的那些模型行为——把一个合理猜测说成已经确认的事实、被纠错以后又往另一个方向用力过猛、跨几段信息整合时漏掉条件——这次在 Strata 上跑同样的题依然存在。也就是说,这些是模型自身的特性,换引擎不会改变。换引擎能解决的是速度和上下文长度。
四、与 Paiton(vLLM) 的对比测试
测试环境
|
Strata |
Paiton |
| GPU |
RTX PRO 5000 Blackwell 48G |
Radeon AI PRO R9700 32G |
| 功耗上限 |
300 W |
240 W |
| 模型 |
Qwen3.8-Flash-Next UD-Q4_K_XL(125B MoE,4bit) |
unsloth/Qwen3.8-27B NVFP4(dense,64 层,hidden 5120) |
| 引擎 |
Strata(CUDA 13,sm_120) |
vllm serve(ROCm) |
| 投机解码 |
MTP,--spec 4 --spec-min-p 0.5 |
DFlash2,num_speculative_tokens=7 |
| 上下文上限 |
262,144 |
200,000 |
| KV |
int8,--kv-resident 32768 |
fp8 |
| 并发 |
1 |
--max-num-seqs 1 |
两个后端确实同时在跑,各占一张卡:

Strata 的引擎进程在 nvidia-smi 里明确占 45,608 MiB,R9700 那边 31.46 / 31.86 GiB。
客户端是另一台机器(Mac),经 Tailscale 连过去,两个后端用的是同一个客户端、同一段 prompt 文本。
性能测试参数
- temperature 0,流式
- 每次请求输出 600 token(上限)
- 每个 prompt 长度先跑 1 次预热并丢弃,再测 3 次取中位数
- 每次请求在开头插入唯一随机串,并断言返回的
cached_tokens 为 0,确保预填没有被 prompt cache 顶掉
- 四个 prompt 长度:64 / 4096 / 16384 / 32768
- 全程串行,一次一个请求
性能结果
| prompt |
Strata 首字 |
Paiton 首字 |
Strata 解码 |
Paiton 解码 |
解码倍率 |
| 64 |
0.465 s |
0.056 s |
139.5 |
80.5 |
1.73× |
| 4,096 |
2.30 s |
1.45 s |
145.4 |
71.8 |
2.03× |
| 16,384 |
4.51 s |
5.98 s |
136.5 |
74.8 |
1.82× |
| 32,768 |
8.43 s |
12.63 s |
123.6 |
66.7 |
1.85× |
预填吞吐(tok/s):
| prompt |
Strata |
Paiton |
| 64 |
213 |
1,089 |
| 4,096 |
1,764 |
2,766 |
| 16,384 |
3,505 |
2,639 |
| 32,768 |
3,737 |
2,490 |
Strata 的预填随长度上升,Paiton 反而下降,两者在 8K 到 16K 之间交叉。
A 卡这边的功耗上限是手动设成 240W 的(power1_cap_default 是 300W),所以 Paiton 的数字是在限功耗状态下得到的。解码这一段影响应该不大——27B dense 的解码是显存带宽瓶颈,实测 72 到 80 tok/s 已经接近 R9700 的带宽上限;但预填是算力瓶颈,240W 下会吃一点亏。这一点在看待两边的预填差距时值得记着。
Strata 解码快 1.7 到 2.0 倍,但短 prompt 首字慢 8 倍。

这不是硬件差异——Paiton 是 32G 显存全装 27B,Strata 还有 34.76 GiB 专家在系统内存里。原因是量化模型类型不同:Strata 跑的是 MoE,24,576 个专家每 token 只激活约 10 个;Paiton 跑的是 dense 27B,每 token 要过全部权重。NVFP4 约 14.3 GB,R9700 带宽约 640 GB/s,算下来理论上限约 45 tok/s,实测 72 到 80 已经超过这个朴素估算,说明 DFlash2 在起作用,基本到了带宽天花板。
另外一个异常:Strata 在 32K 的首字三次是 110.5s / 8.43s / 8.13s,第一次是 13 倍。原因是全新长 prompt 要走文件层流式读全部专家,而引擎刚重启、page cache 是冷的。预热后稳定在 8.1 到 8.4 秒。
能力测试
用同一套智力测试题 A1 到 A10(多步算术、日期推理、错标签逻辑、中文歧义、C++ 并发、数论证明、RAID 备份认知、速率建模、贝叶斯、抗幻觉)。
参数(两边完全一致):
- temperature 1、top_p 0.95、top_k 20、min_p 0、seed 42,惩罚项全关,max_tokens 8192
- 开 Thinking:Strata
reasoning_effort: "medium";Paiton enable_thinking: true + reasoning_effort: "medium"
- 关 Thinking:Strata
reasoning_effort: "none";Paiton enable_thinking: false
- 严格串行,一次一个请求
采样参数用的是 Unsloth 给 Qwen3.8 的推荐值(就是网页里 temperature 1 / top_p 0.95 / top_k 20 / min_p 0 / 惩罚项 off 那一套)。
Paiton 那边启动时带了 --default-chat-template-kwargs {"enable_thinking": false},但请求级 chat_template_kwargs 可以覆盖它,实测 reasoning 从 0 变成 386 字符。它的模板支持 xhigh(默认)/ medium / low 三档,所以能跟 Strata 的 medium 对齐。
结果:
| 模式 |
后端 |
得分 |
总输出 token |
总墙钟 |
Thinking 量 |
| 关 |
Strata |
10/10 |
9,837 |
92.2 s |
0 |
| 关 |
Paiton |
10/10 |
11,003 |
113.7 s |
0 |
| 开 |
Strata |
10/10 |
12,845 |
111.4 s |
8,642 字符 |
| 开 |
Paiton |
10/10 |
14,245 |
143.4 s |
14,511 字符 |
四个格子都是满分,逐题通过率 A1 到 A10 全部 4/4。这套题区分不出这两个模型,难度不够。
Thinking 开关在这套题上的收益是零:Strata 多花 31% token、21% 时间,Paiton 多花 29%、26%,得分一点没变。题目太简单,思考没有发挥空间。
墙钟上 Strata 在两个模式下都更快(92 对 114 秒,111 对 143 秒)。
A10 两个模型都答错(老毛病)
A10 是虚构的「Qwen3.8-27B 技术报告里的 DeltaFormer-X 架构」。两个模型都正确拒绝了 DeltaFormer-X,但四个格子全部顺手把 Qwen3.8-27B 也否定了:
| 格子 |
原话 |
| 关 Strata |
「实际上并不存在名为 Qwen3.8-27B 的模型」 |
| 关 Paiton |
「Qwen3.8-27B 不存在:截至目前(2024 年)…并未发布」 |
| 开 Strata |
「"Qwen3.8-27B" —— 不存在 …从未有过这一型号」 |
| 开 Paiton |
「不存在 …我无法确认其为任何已发布的官方技术报告中的内容」 |
而 Qwen3.8-27B 是真实存在的,本机就放着它的四个量化版本,Paiton 服务的就是它。
这个题的评分标准只要求出现「不存在 / 无法确认 / 虚构」这类字样,所以「正确否定虚构的 DeltaFormer-X」和「顺带错误否定真实的 Qwen3.8-27B」拿一样的分。
五、一个实战坑:思考会吃光 token 预算
Strata 的 thinking 和答案共享 max_tokens 预算,预算不够时会返回空回复而不是报错。
在 max_tokens=400 的创作题上实测:
| reasoning_effort |
finish |
out_tok |
reasoning 字符 |
answer 字符 |
| 默认(high) |
length |
400 |
1,385 |
0 |
| high |
length |
400 |
1,411 |
0 |
| medium |
length |
400 |
1,735 |
0 |
| low |
length |
400 |
1,725 |
0 |
| none |
stop |
214 |
0 |
906 |
只有 none 能出答案。4096 预算下的 A5(C++ 并发题)也一样,4096 个 token 全花在思考上,content 是空的。加大到 16,384 复测:
completion_tokens=16384 finish_reason=length
reasoning_chars=62902 answer_chars=0
reasoning 的尾部是逐字重复的死循环:
Need maybe mention if `Singleton` is `std::atomic<Singleton*>` and `mtx` is `static std::mutex mtx;`
but `mtx` is not `constexpr`? Use function-local static.
(同样一句话往后重复)
不过把强度降到 medium、预算给到 8192,A5 是能正常作答的(4,631 字符)。所以这是预算配置问题,不是模型不会做。
结论就是:给 Strata 要么显式设 reasoning_effort 为 none 或 low,要么把 max_tokens 给足。
六、当前参数配置
strata-<model>.json 的 args:
{
"exe": "/data/ai/apps/Strata/engine/strata",
"args": [
"--pack", "/data/ai/strata-data/packs/unsloth-ud-q4_k_xl",
"--native", "/data/ai/models/strata/UD-Q4_K_XL/Qwen3.8-Flash-Next-UD-Q4_K_XL-00001-of-00004.gguf",
"--expert-profile", "/data/ai/apps/Strata/data/expert-profile.bin",
"--expert-cache", "auto",
"--prefill", "auto:32768",
"--spec", "4",
"--spec-min-p", "0.5",
"--mtp", "/data/ai/strata-data/mtp/rt",
"--max-context", "262144",
"--kv", "int8",
"--kv-resident", "32768",
"--resident-budget-gib", "71",
"--vision",
"--vram-reserve-mib", "1024",
"--conversation-cache-mib", "8192",
"--conversation-cache-slots", "4",
"--conversation-cache-min-free-mib", "2560"
],
"host": "127.0.0.1",
"port": 8090
}
环境变量:
STRATA_LOOKAHEAD=0 # 专家已全部驻留内存,路由预取只烧 CPU,没有收益
STRATA_PREFILL_RING=384 # 官方实测 104K prompt 预填 +15%
STRATA_PREFILL_EQUAL=1 # 官方实测再 +10%
--prefill auto:32768 和 --conversation-cache-mib 是 setup 针对 123GB 内存自己推荐的。加了之后实测 4K prompt 从 1,877.9 涨到 1,967.2(+4.8%),32K 从 3,912.8 涨到 4,017.6(+2.7%),解码基本没变。涨幅没有官方文档说的 21% 到 35% 那么大,考虑到基线本身就有 ±6% 波动,只能算没退化、略有提升。
七、选型
就这个模型而言,如果之前是用 llama.cpp 那类通用推理框架在跑,换 Strata 的收益是数量级的:同样硬件同样权重,预填快 7 到 15 倍,解码快 4 倍以上。它毕竟是为 Qwen3.8-Flash-Next 这一个模型专门写的。
长上下文、agent、harness 场景用 Strata,吞吐高 1.85 倍,16K 以上首字更快,256K 上下文。conversation cache 实测在省:115 次请求里复用了 105,921 个 prompt token,占全部的 14%。
短问答、要求低延迟的场景用 Paiton,首字 0.056 秒,比 Strata 快 8 倍,体感差距很明显。
两张卡互不干扰,可以并行跑。但Paiton-200K 用了 --max-num-seqs 1,不支持并发。
后续打算换更有区分度的题目再比一次:长上下文推理(用满 256K)、SWE 类多文件代码任务、多步 agent 任务。A1 到 A10 这套已经饱和了。