Tested in this article: Qwen3.8-Flash-Next-UD-Q4_K_XL, Qwen3.8-Flash-Next-NVFP4, Qwen3.8-Flash-Next-Swift1.5-NVFP4-FP8PLE_FP8PROJ Hardware: RTX 6000 Blackwell · 96 GB VRAM, 96 GB DDR4 OS: Debian 13 Engines: llama.cpp, vLLM, and Ninfer6000 Benchmarks: BFCL v4, MMLU-Pro, IFEval, Arena-Hard, HumanEval+, MBPP+, RULER, (+ Pelican)
📊 Expand Engine Config
  Qwen3.8-Flash-Next-UD-Q4_K_XL:
    ttl: 3000
    cmd: >
      /usr/local/bin/llama-server
      --port ${PORT}
      --model /models/qwen3.8-flash-next/UD-Q4_K_XL/Qwen3.8-Flash-Next-UD-Q4_K_XL-00001-of-00004.gguf
      --mmproj /models/qwen3.8-flash-next/mmproj-BF16.gguf
      --model-draft /models/qwen3.8-flash-next/mtp-Qwen3.8-Flash-Next-Q8_0.gguf
      --spec-type draft-mtp
      --spec-draft-n-max 3
      --ctx-size 262144
      --flash-attn on
      --cache-type-k q8_0
      --cache-type-v q8_0
      --ubatch-size 2048
      --main-gpu 0
      --split-mode none
      --parallel 2
      --temp 1.0 --top-p 0.95 --top-k 20 --min-p 0.0
  qwen3.8-flash-next-ninfer6000:
    ttl: 10000
    healthCheckTimeout: 900
    useModelName: Qwen/Qwen3.8-Flash-Next
    cmd: >
      /ninfer6000/build/apps/ninfer-serve /models/qwen3.8-flash-next/ninfer-conv/swift_1_5_qwen3_8_flash_next_nvfp4_fp8ple_fp8proj.ninfer
      --port ${PORT}
      --model-id Qwen/Qwen3.8-Flash-Next
      --max-context 262144
      --kv-capacity auto
      --kv-dtype bf16
      --max-concurrency 2
      --pending-timeout-ms 600000
      --device-state-slots 2
      --host-state-slots 8
      --host-kv-mib 16384
      --spec mtp
      --draft-tokens 3
      --lm-head-draft
      --vision
      --preserve-thinking
      --prefill-chunk 8192
  qwen3.8-flash-next-nvfp4:
    ttl: 10000
    healthCheckTimeout: 900
    env:
      - CUDA_VISIBLE_DEVICES=0
      - VLLM_PLE_CPU_OFFLOAD=1
      - MAX_JOBS=3
    cmd: >
      vllm serve /models/qwen3.8-flash-next/nvfp4
      --served-model-name qwen3.8-flash-next-nvfp4
      --port ${PORT}
      --quantization modelopt
      --trust-remote-code
      --max-model-len 262144
      --max-num-seqs 2
      --max-num-batched-tokens 8192
      --gpu-memory-utilization 0.95
      --enable-prefix-caching
      --async-scheduling
      --no-enable-flashinfer-autotune
      --reasoning-parser qwen3
      --enable-auto-tool-choice
      --tool-call-parser qwen3_coder
      --speculative-config '{"method":"mtp","num_speculative_tokens":2}'

Intro

It is abundantly clear we’ve entered the age of hyper-specific inference engines tuned to a specific model and specific hardware. I was scrolling Reddit when I came across a post regarding Ninfer6000, a fork of Ninfer specifically tuned for Qwen3.8-Flash-Next NVFP4 on RTX 6000 Blackwell. The reported speed numbers were incredible, so I HAD to grab it and benchmark it. If it really was going to bring me from ~150tok/s decode (vLLM + MTP) to well over 300, I needed to see it. More importantly I needed to see if it was lobotomized to achieve those speeds. To accomplish this I’ve run a host of traditional benchmarks to log the speed, size, accuracy, and long context behavior. I’ve also run a couple in-harness tests to compare how the models behave.

The Setup

I used llama-swap to run each one at a time through evalscope 1.8.1 for the scored suites, and a direct runner for RULER. I set concurrency 2 for all runs except one long context RULER test because that fit nicely into my hardware.

Ninfer6000vLLMllama.cpp
CheckpointSwift 1.5 NVFP4 + FP8 PLE/ProjNVFP4 (modelopt)UD-Q4_K_XL
KV cacheBF16BF16Q8_0
Context served262,144262,144131,072 (2 streams @ 262k)
Speculative decodeMTP, 3 draft tokensMTP, 2 tokensMTP, 3 draft tokens
Max concurrent requests222
Prefill / ubatch chunk8,1928,1922,048

UD-Q4_K_XL’s 131,072-token context is the one asymmetry amongst the trio. The two streams share the single 262,144 token pool in llama.cpp, but none of the tests came near this so the comparisons are still fair in that regard. The deep RULER ladder is the exception. To hit the 256,827 token prompt I dropped it to a single 262,144 token context stream for that benchmark.

Ninfer6000’s model is not perfectly apples to apples to the other two as it is based on a Swift1.5 fine tune geared toward reasoning brevity. That being said, it is the model Ninfer6000 recommends so it stands as how the engine is to be configured.

I first ran a greedy pass with a low max-token cap, then 3 repeats at temp 0.6 and a budget of 16k tokens. Everything going forward refers to the 3-repeat run unless the section says otherwise.

Speed & Size

The sweep: prefill, decode, time-to-first-token

First order of business was verifying the speed difference, with a note on RAM occupied. I measured the prefill, decode, and TTFT (time to first token) one engine at a time, single stream (no concurrency), the same synthetic prompt on all three, five prompt lengths from ~1k to 114k tokens, 512 tokens out, greedy, two reps per cell. I pulled the memory and load numbers from the logs. Prefill at 1k was noisy on each model (vLLM’s two reps were 2.3x apart for example), so treat sub-8k prefill as directional.

Decode: flat, and ~1.5-1.7x vLLM at every length

PromptNinfer6000vLLM nvfp4llama.cpp Q4_K_XLN vs vLLMN vs llama.cpp
~1k2321591381.46x1.68x
7.2k2411481291.63x1.87x
28.6k2271501121.51x2.02x
57.1k249149931.68x2.67x
114.1k240144651.66x3.70x
mean2381501081.59x2.21x

The most significant number here is presented by the purple line: Ninfer6000 averages 238 tok/s, stays consistent at any prompt size (unlike llama.cpp, though I’m sure this will be fixed at some point), and beats vLLM by ~60%. This says nothing of quality/accuracy of course but Ninfer6000’s advertised decode superiority checks out.

Prefill and TTFT: vLLM wins this one, decisively

PromptNinfer6000 prefillvLLM prefillllama.cpp prefillNinfer TTFTvLLM TTFTllama.cpp TTFT
~1k4,3156,9441,8230.23 s0.17 s0.56 s
7.2k7,99616,4842,9600.90 s0.44 s2.44 s
28.6k9,52116,7983,3203.00 s1.70 s8.61 s
57.1k9,91416,7003,2775.76 s3.42 s17.42 s
114.1k10,03716,2293,10811.37 s7.03 s36.70 s

vLLM is still the prefill champ: ~16.5k tok/s, flat from 8k to 114k, 1.6-2.1x Ninfer6000. The result is a first token that comes a few seconds earlier. 7.0 s versus 11.4 s on a 114k prompt. Ninfer6000 plateaus at ~10k tok/s, but only finds its stride in the longer prompts. llama.cpp never gets near either, capped at ~3.3k tok/s with a 36.7 second TTFT at 114k.

Quick note on the 1k row: vLLM’s two reps were 2.3x apart, attributable to cold-graph/prefix-cache noise. Not very valuable, better to focus on the 8k+ columns as the real prefill comparison.

End to end: the crossover is output length, not context length

If you consider a real-world use case, both prefill and decode impact the outcome notably. Wall time per request = measured TTFT + (output tokens / decode rate):

PromptOutputNinfer6000vLLM nvfp4llama.cpp Q4_K_XL
7.2k5123.0 s3.9 s6.4 s
7.2k2,0489.4 s14.2 s18.3 s
28.6k2,04812.0 s15.3 s26.9 s
57.1k8,19238.6 s58.5 s105.4 s
114.1k51213.5 s10.6 s44.6 s
114.1k2,04819.9 s21.2 s68.3 s
114.1k8,19245.5 s63.9 s162.9 s

Setting the two projections equal gives the crossover - the output length at which Ninfer6000’s decode lead repays its prefill debt:

Prompt~1k7.2k28.6k57.1k114.1k
Crossover, output tokens311795808631,567

So the nuanced conclusion of which is better would be “it depends”. Ask the model for a one-line answer on a huge prompt and vLLM cooks. Ask it for anything a human would call an answer (a paragraph, a diff, a tool trace) and Ninfer6000 wins at every prompt length, and the margin grows (1.4x faster end-to-end at 114k prompt / 8k output). Chat and agent traffic often sits on the long-output side of that line, so I’m personally inclined to lean toward the decode leader, but I also acknowledge prefill wins can be more perceivable to the end user in chat after a certain decode speed. llama.cpp is on the wrong side of both: 163 seconds for that same 114k/8k request. Oof.

Cold start, VRAM, and where the memory goes

Ninfer6000vLLM nvfp4llama.cpp Q4_K_XL
Artifactswift_1_5 _nvfp4 _fp8ple _fp8proj.ninfernvfp4 (modelopt)UD-Q4_K_XL + mmproj-BF16 + MTP draft Q8_0
Time to first ready request23 s290 s67 s
VRAM after load86.8 GiB90.3 GiB93.7 GiB
VRAM peak (131k prompt)86.8 GiB92.8 GiB94.4 GiB
Host RAM peak22.2 GiB70.1 GiB14.6 GiB
KV cache dtypeBF16BF16Q8_0

Three points of intrigue here.

First observation, all three fit on one 96 GB card.

Second, vLLM’s 290-second boot is a big price for that prefill lead. I do a lot of experimenting and model swapping on this rig, so startup time actually matters to me. It would be nice to have a whole machine dedicated to high availability vLLM multi-user serving, but this is real life. Ninfer6000 is serving traffic 23 seconds after a request cold-start and has probably finished its response by the time nvfp4 has even begun to prefill.

Third, memory fill varies greatly. vLLM sits at 70 GiB of RAM because I ran it with VLLM_PLE_CPU_OFFLOAD=1. The n-gram table state lives in system memory and streams in, which is also likely part of where that prefill efficiency comes from. llama.cpp memory-maps the GGUF and lets the page cache deal with the rest. Ninfer6000 actually uses the least VRAM of the three.

In action: what the benchmark runs themselves measured

The sweep above is single-stream and synthetic. The scored suites are the opposite and nonetheless agree on direction.

📊 Expand Speed Tables

Output tokens/s (mean per request)

BenchmarkRequestsNinfer6000vLLM nvfp4llama.cpp Q4_K_XL
BFCL v4~3,000176.9107.984.5
IFEval750169.8123.498.9
MMLU-Pro1,260219.0145.5114.0
HumanEval+492280.3162.5153.9
MBPP+1,134234.9144.3122.2
Arena-Hard (long-form)75137.959.250.6

End-to-end latency, seconds per request

BenchmarkNinfer6000 meanvLLM meanllama.cpp meanNinfer6000 p95vLLM p95llama.cpp p95
BFCL v40.921.922.54---
IFEval2.133.203.736.99.911.3
MMLU-Pro3.926.958.3610.719.423.5
HumanEval+0.771.451.401.63.72.6
MBPP+0.801.331.581.73.23.9
Arena-Hard45.96149.63171.22193551450
RULER (suite pass, 4k-64k)2.762.189.64---

Same ranking, wider spread. RULER is the one row where vLLM wins the wall clock as it was basically all prefill so that tracks. Both views support the Reddit post’s claims (even if they were a bit rounded-up and best-case focused).

Traditional Benchmarks

note these are not comparable to leaderboards - different sample size, different Arena Hard judge.

The scoreboard

BenchmarkSamplesNinfer6000vLLM nvfp4llama.cpp Q4_K_XLSpread
Tool calling (BFCL v4)30076.67 ± 5.2174.56 ± 0.9673.00 ± 2.963.7
Instruction following (IFEval, prompt-strict)25082.80 ± 1.0684.93 ± 0.6184.93 ± 0.612.1
Knowledge (MMLU-Pro)42084.13 ± 0.7783.65 ± 0.7384.92 ± 0.691.3
Code (HumanEval+)16493.29 ± 0.6194.92 ± 0.3593.90 ± 1.221.6
Code (MBPP+)37894.80 ± 0.3195.15 ± 1.0795.59 ± 0.760.8
Long-form (Arena-Hard)7581.4876.0777.425.41
Long context (RULER, 4k to 257k)29098.2899.1498.970.9

Five of seven results sit inside a 2.1-point band. These results support the conclusion that the engine swap mostly changes speed and not accuracy/capability. The exceptions were BFCL v4 (3.7, replicated direction) and Arena-Hard (4.7, single pass and mostly an answer-length effect). (RULER’s row is not a 3-repeat mean. It is the result from the deep ladder only run once, thus not in the chart below).

The noise floor

📊 Expand Noise Floor Table
BenchmarkSlotRun 1 / 2 / 3Mean ± SDRange
Tool callingNinfer600082.67 / 74.00 / 73.3376.67 ± 5.219.33
Tool callingvLLM nvfp475.67 / 74.00 / 74.0074.56 ± 0.961.67
Tool callingllama.cpp Q4_K_XL76.33 / 70.67 / 72.0073.00 ± 2.965.67
Instruction followingNinfer600082.40 / 82.00 / 84.0082.80 ± 1.062.00
Instruction followingvLLM nvfp484.80 / 85.60 / 84.4084.93 ± 0.611.20
Instruction followingllama.cpp Q4_K_XL84.40 / 84.80 / 85.6084.93 ± 0.611.20
KnowledgeNinfer600085.00 / 83.81 / 83.5784.13 ± 0.771.43
KnowledgevLLM nvfp483.81 / 82.86 / 84.2983.65 ± 0.731.43
Knowledgellama.cpp Q4_K_XL84.52 / 84.52 / 85.7184.92 ± 0.691.19
Code (HumanEval+)Ninfer600093.29 / 92.68 / 93.9093.29 ± 0.611.22
Code (HumanEval+)vLLM nvfp495.12 / 95.12 / 94.5194.92 ± 0.350.61
Code (HumanEval+)llama.cpp Q4_K_XL92.68 / 95.12 / 93.9093.90 ± 1.222.44
Code (MBPP+)Ninfer600094.44 / 94.97 / 94.9794.80 ± 0.310.53
Code (MBPP+)vLLM nvfp496.30 / 94.18 / 94.9795.15 ± 1.072.12
Code (MBPP+)llama.cpp Q4_K_XL96.03 / 94.71 / 96.0395.59 ± 0.761.32

Ninfer6000’s BFCL row swings 9.3 points across three repeats. N=300 clearly isn’t enough to separate them on its own, but we can still make directional observations and do per-sample pairing below.

📊 Expand Paired Significance Table

Exact McNemar on the paired samples, run per repeat, Holm-corrected within each benchmark. net is the discordant-pair count per repeat (arm vs base); p vote is the conservative majority-vote estimator across repeats.

BenchmarkPair (arm vs base)Δ pts (repeat 1)net per repeatpp Holmp voteSigReplicated
Tool callingvLLM vs Ninfer6000-7.00-21 / +0 / +2<0.001<0.0010.8145yesno
Tool callingNinfer6000 vs llama.cpp+6.33+19 / +10 / +40.00130.00260.5034yesyes
Tool callingvLLM vs llama.cpp-0.67-2 / +10 / +60.82380.82380.8238nodirection
Instruction followingvLLM vs Ninfer6000+2.40+6 / +9 / +10.36161.00.3018nodirection
Instruction followingNinfer6000 vs llama.cpp-2.00-5 / -7 / -40.45831.00.6072nodirection
Instruction followingvLLM vs llama.cpp+0.40+1 / +2 / -31.01.00.7539nodirection
KnowledgevLLM vs Ninfer6000-1.19-5 / -4 / +30.44211.01.0nodirection
KnowledgevLLM vs llama.cpp-0.71-3 / -7 / -60.71111.00.6072nodirection
KnowledgeNinfer6000 vs llama.cpp+0.48+2 / -3 / -90.85551.00.4545nodirection
Code (HumanEval+)vLLM vs llama.cpp+2.44+4 / +0 / +10.34381.00.25nodirection
Code (HumanEval+)vLLM vs Ninfer6000+1.83+3 / +4 / +10.45311.00.0625nodirection
Code (HumanEval+)Ninfer6000 vs llama.cpp+0.61+1 / -4 / +01.01.00.7266nono
Code (MBPP+)vLLM vs Ninfer6000+1.85+7 / -3 / +00.03910.11721.0nono
Code (MBPP+)Ninfer6000 vs llama.cpp-1.59-6 / +1 / -40.10940.21880.2891nodirection
Code (MBPP+)vLLM vs llama.cpp+0.26+1 / -2 / -41.01.00.2891nodirection

Two rows hold up to Holm correction, and all both are BFCL rows involving Ninfer6000. The Ninfer6000-vs-vLLM row is exactly the trap this layout exists to catch while Ninfer6000-vs-llama.cpp is real. +19 / +10 / +4, same sign all three times, Holm p=0.0026.

BFCL v4

Details: 50 samples, 6 subsets → 300 samples, 3 repeats

📊 Expand Data Tables

Overall (3 repeats)

SlotAccuracySDRepeats
Ninfer600076.67%5.2182.67 / 74.00 / 73.33
vLLM nvfp474.56%0.9675.67 / 74.00 / 74.00
llama.cpp Q4_K_XL73.00%2.9676.33 / 70.67 / 72.00

By Subset (n=50, mean ± SD over 3 repeats)

SubsetNinfer6000vLLM nvfp4llama.cpp Q4_K_XLBest
Simple Python97.3 ± 0.998.0 ± 0.095.3 ± 2.5vLLM
Multiple92.7 ± 0.989.3 ± 0.989.3 ± 0.9Ninfer6000
Parallel87.3 ± 0.986.0 ± 0.083.3 ± 1.9Ninfer6000
Live Multiple73.3 ± 2.574.0 ± 8.566.7 ± 5.2vLLM
Irrelevance82.7 ± 1.978.0 ± 1.681.3 ± 3.4Ninfer6000
Multi-Turn Base26.7 ± 23.622.0 ± 14.122.0 ± 14.1Ninfer6000

Most categories had an insignificant gap, but multi_turn_base stood out quite a bit. The greedy first run scored it 54 / 42 / 42 and ended up with a massive band. Treat BFCL’s direction as real and its magnitude as multi-turn luck. Ninfer6000 is ahead on tool calling, somewhere between +2 and +4 points on the mean.

IFEval

Details: 250 samples, 3 repeats, all four metrics

📊 Expand Data Tables
IFEval metric (mean of 3 repeats)Ninfer6000vLLM nvfp4llama.cpp Q4_K_XLBest
Prompt-level strict82.8084.9384.93vLLM / llama.cpp
Instruction-level strict89.0990.2990.31llama.cpp
Prompt-level loose86.1388.1387.73vLLM
Instruction-level loose91.6792.9192.60vLLM

Ninfer6000 is behind on every metric in all three repeats for instruction following. Directionally consistent, small magnitude. Interestingly the initial greedy run gap was greater, at -6.0 points. Roughly two thirds of it was decoding conditions.

MMLU-Pro

Details: 30 samples, 14 categories → 420 samples, 3 repeats

📊 Expand Data Tables

Overall

SlotAccuracySDRepeats
Ninfer600084.13%0.7785.00 / 83.81 / 83.57
vLLM nvfp483.65%0.7383.81 / 82.86 / 84.29
llama.cpp Q4_K_XL84.92%0.6984.52 / 84.52 / 85.71

By Category (mean of 3 repeats, 30 samples each)

CategoryNinfer6000vLLM nvfp4llama.cpp Q4_K_XL
Math96.7%96.7%96.7%
Computer Science94.4%92.2%94.4%
Biology94.4%92.2%93.3%
Physics94.4%96.7%96.7%
Chemistry94.4%90.0%92.2%
Business90.0%88.9%92.2%
Economics88.9%90.0%90.0%
Engineering83.3%81.1%82.2%
Psychology83.3%78.9%78.9%
Philosophy80.0%78.9%84.4%
Health77.8%78.9%82.2%
Law70.0%73.3%78.9%
Other67.8%66.7%64.4%
History62.2%66.7%62.2%

This is a shuffle. Quantization format and serving stack seemingly do not move this model’s capabilities on closed-book QA.

HumanEval+ & MBPP+

Details: 164 and 378 problems, 3 repeats

📊 Expand Data Tables
BenchmarkNinfer6000vLLM nvfp4llama.cpp Q4_K_XLSpread
HumanEval+ pass@193.29 ± 0.6194.92 ± 0.3593.90 ± 1.221.6
MBPP+ pass@194.80 ± 0.3195.15 ± 1.0795.59 ± 0.760.8

MBPP+ is saturated on all three. Insignificant gaps, and in the one signficant spot the sign flips per result. HumanEval+ vLLM beats Ninfer6000 on all three repeats with a directional (but insignificant) gap and beats llama.cpp on two of three.

Arena-Hard

Details: 500 prompts, 75 judged, single pass, temp 0.6, 16,384 token cap

📊 Expand Data Tables
SlotJudge winrate vs baselinePaired win rateMedian answer (tok)Answers at capLatency p95
Ninfer600081.48%73.33%4,71714/75 (18.7%)193 s
vLLM nvfp476.07%69.17%7,32324/75 (32.0%)551 s
llama.cpp Q4_K_XL77.42%68.67%7,23220/75 (26.7%)450 s

Without scrutiny Ninfer6000 looks to be superior here, but this mostly comes down to answer-brevity. With Ninfer6000 running a Swift1.5 tuned model it leans toward concise answers, resulting in fewer cutoffs and greater scoring. That isn’t to say this means nothing though. The latency would feel very different in real world applications.

RULER

Details: 290 items per slot, haystack tiers from 4,096 to 224,000 tokens, 9 tasks, seed 69, greedy, 128-token answers, one stream, one pass.

The RULER pass inside the scored suites stopped at 64k and could not separate these engines, so I re-ran the ladder all the way to the edge of the context slot. 30,134,410 prompt tokens per engine and the same haystacks on all three. Tier names are just haystack tokens. The chat template plus re-tokenisation inflates the prompt by ~15%, so the “224k” tier is really a 256,827-token prompt inside a 262,144-token slot with 4,885 tokens left for the answer.

HaystackActual prompt tokensNinfer6000vLLM nvfp4llama.cpp Q4_K_XLSpreadItems
4,0964,82098.89100.0098.891.1145
16,38418,91098.89100.0098.891.1145
32,76837,75498.75100.00100.001.2540
65,53675,29498.7598.7598.750.0040
131,072150,37197.5098.7598.751.2540
180,000206,41897.5097.5098.751.2540
224,000256,82797.5098.7598.751.2540
all 290-98.2899.1498.970.86290

Retrieval does not fall apart. Across the range no engine drops more than 2.50 points off its own best tier. Long context doesn’t cost answer-correctness, just varied wall time per model/engine.

Every loss came from one task

All 21 imperfect items out of 870 scored are solely from variable_tracking. The other eight tasks are 100.00 at every depth on all three engines. Every miss is a half-credit, because vt asks for two variables and the model gets one of them right.

TaskItems per engineNinfer6000vLLM nvfp4llama.cpp Q4_K_XL
c3 (classification)10100.00100.00100.00
cw (common words extraction)10100.00100.00100.00
niah_single_1 and niah_single_310 + 10100.00100.00100.00
niah_multikey60100.00100.00100.00
niah_multivalue60100.00100.00100.00
niah_multiquery60100.00100.00100.00
passkey10100.00100.00100.00
vt (variable tracking)6091.6795.8395.00

Of 870 items, 18 misses are two haystacks returning the same wrong value on every engine that trips on them, and 3 are the grader choking on leading zeros. That leaves no miss that is attributable to depth, and none by more than 2 items.

📊 Every imperfect item (all 21, raw)
SlotHaystack tierNeedle depthExpectedReturnedWhat went wrong
Ninfer60004,096100%508815, 406806398270, 406806reported a different variable’s value
llama.cpp Q4_K_XL4,096100%508815, 406806398270, 406806reported a different variable’s value
Ninfer600016,384100%508815, 406806398270, 406806reported a different variable’s value
llama.cpp Q4_K_XL16,384100%508815, 406806398270, 406806reported a different variable’s value
Ninfer600032,7680%581390, 004819581390, 4819found it, printed it without the leading zeros
Ninfer600065,53650%508815, 406806398270, 406806reported a different variable’s value
vLLM nvfp465,53650%508815, 406806398270, 406806reported a different variable’s value
llama.cpp Q4_K_XL65,53650%508815, 406806398270, 406806reported a different variable’s value
Ninfer6000131,0720%581390, 004819145962, 004819reported a different variable’s value
Ninfer6000131,07250%508815, 406806398270, 406806reported a different variable’s value
vLLM nvfp4131,07250%508815, 406806398270, 406806reported a different variable’s value
llama.cpp Q4_K_XL131,07250%508815, 406806398270, 406806reported a different variable’s value
Ninfer6000180,0000%581390, 004819581390, 4819found it, printed it without the leading zeros
Ninfer6000180,00050%508815, 406806398270, 406806reported a different variable’s value
vLLM nvfp4180,00050%508815, 406806398270, 406806reported a different variable’s value
vLLM nvfp4180,000100%061004, 72429661004, 724296found it, printed it without the leading zeros
llama.cpp Q4_K_XL180,00050%508815, 406806398270, 406806reported a different variable’s value
Ninfer6000224,0000%581390, 004819145962, 004819reported a different variable’s value
Ninfer6000224,00050%508815, 406806398270, 406806reported a different variable’s value
llama.cpp Q4_K_XL224,00050%508815, 406806398270, 406806reported a different variable’s value
vLLM nvfp4224,0000%581390, 004819145962, 004819reported a different variable’s value

Tier names are the haystack name; the prepared prompt averages ~1.15x that. Nothing here scored 0.00 - every miss is one of two variables wrong.

Unstructured / Personal Tests

Open-WebUI Chat - Search, Reasoning, Function Calling

I primarily use Open-WebUI for my LLM chat needs. This test is set up to see how well the model fares in my harness. Can it obey the system prompt and follow the user prompt? Can it properly assess available tools, format the calls, and handle errors?

  1. Can you find a few recently released unified memory systems with 128gb+ ram and compare their prices/availability/pros and cons?
  2. Can you format that information into a single page pdf so i can share it?
📊 Sys Prompt
You are an autonomous deep research assistant. You excel at interleaved thinking, tool use, and thorough investigation. Follow these operational rules on every request:

## Absolute Temporal Grounding
- The current date is {{CURRENT_DATE}} and the local time is {{CURRENT_TIME}}.
- **Override Cutoff Bias:** Your internal training data is frozen in the past. Trust this system date implicitly. If an event, software release, or milestone occurs prior to {{CURRENT_DATE}}, it has already happened. Never refer to past or current real-world data as "upcoming," "future," or "incorrect" based on your training cutoff.
- **Relative Calculations:** Always calculate relative time expressions (e.g., "last year," "three months ago," "next quarter") using this exact system anchor as day zero.
- **Search Analysis:** When interpreting results from `search_web`, evaluate the timelines of articles relative to the current system year.

## Planning & Task Tracking
- Before acting, think through a concise plan of steps.
- Use "create_tasks" (plural) to publish that plan as a checklist immediately.
- Use "update_task" (singular) after completing each step — including the final one. Never skip the last "update_task" call.

## Web Research Strategy
- When using search_web, set the count parameter (1–5) proportional to query complexity:
  • 1: Simple facts, definitions, single-entity lookups
  • 2-3: Moderately complex topics requiring multiple angles
  • 4-5: Deep/niche subjects, current events, or highly specific technical queries
- After search_web, if the required detail isn't in the snippets, select the most promising result and call fetch_url to extract deeper context. Do not guess or truncate your research.

## Tool Usage
- Use any available tools (file access, knowledge bases, memory, calculations, etc.) to best solve or research the query. Be proactive — don't wait for permission to use a tool if it would help.
- When multiple tools could apply, chain them intelligently rather than making redundant calls.

## Output
- Synthesize findings into a clear, well-structured report once research is complete.
- Cite sources where relevant. Be concise but thorough.

I’m expecting to see:

  • information about Nvidia RTX/DGX spark, existing and upcoming M# Ultra Mac Studios, and some of the various Ryzen AI Max 395 mini pcs.
  • MSRP, but would love to see a model identify how much prices have increased.
  • pros and cons discussing availability, memory size, memory bandwidth, and compute.
  • these models to be able to find and call the PDF creation tools present in the harness easily.

I’m expecting this test to be trivial for all 3 models, but it’s a good place to start.

Results

Ninfer6000 (Swift1.5 NVFP4)

Open PDF ↗

Did a great job setting the search count, bigger count (5) at first, down to 3 as it became more specific. Great variety of info, misc Strix Halo boxes, GB10, new 192gb framework, M5 Ultra and Max. Created all the tasks, but cluster-closed them all right before generating output. Gave a malformed tool call when asked to create the one-pager. Used the wrong tool name format.

📊 Expand Report Comparison Table
Ninfer6000vLLM nvfp4llama.cpp Q4_K_XL
Pages2 (single-page asked)11
PaperLetterA4Letter
Systems in the table76 (+1 honorable mention)6
Price movement called outcategory-wide, ~30-75%per-SKU, “was $4,699 up $2,251”, “up 73%+ from launch”per-SKU, $4,699 to $6,950
Found the Surface RTX Spark Dev Boxnoyes, only oneno
Per-box tok/s in the pros/consyesyesno
Layout defectsources footer spilled to page 2A4 instead of Letter, very densetable overruns the page by ~7mm, Availability column clipped

Turns out it wasn’t trivial. None of the three were perfect.

The notable failure is Ninfer6000’s because it is a tool failure rather than a writing/reasoning failure. It noticed its own 2-page output, planned the fix, and then emitted the fix as text. A tool-call block printed into the message instead of dispatched, so the harness never ran it. I prompted the model to fix its malformed tool calling and try again, and it succeeded.

This is interesting because 300 curated tool-calling samples in the benchmark did not predict it. All that, and yet a messy two-turn job in my harness did. I’ve actually been using (or trying to use) Ninfer6000 while writing/formatting this blog entry and I’ve encountered this same behavior in Cline. Almost every request has required manual input to get it to fix a failed tool call. It has pushed me back to NVFP4 as my primary driver, despite the slower decode. It remains to be seen if this is caused by the Swift1.5 based model itself, its conversion to Ninfer, or the engine itself.

The call that printed instead of running — click to expand ninfer6000_failed_tool_1.txt
<tool_call> <function=replace_file_to_fix_fontsize> <parameter=path> /home/user/unified_memory_128gb_onepager.html </parameter> <parameter=replacements> [{"target": "@page { size: Letter; margin: 13mm 13mm 11mm 13mm; }", "replacement": "@page { size: Letter; margin: 10mm 10mm 9mm 10mm; }"}, {"target": "body { font-family: \"DejaVu Sans\", Helvetica, Arial, sans-serif; color: #1a1a2e; font-size: 8.2pt; line-height: 1.32; }", "replacement": "body { font-family: \"DejaVu Sans\", Helvetica, Arial, sans-serif; color: #1a1a2e; font-size: 7.5pt; line-height: 1.22; }"}, {"target": "h1 { font-size: 15pt;", "replacement": "h1 { font-size: 13pt;"}, {"target": "h2 { font-size: 9.5pt; color: #0d1b3e; border-bottom: 1.2pt solid #2c4a8a; padding-bottom: 1.5pt; margin: 7pt 0 4pt 0; }", "replacement": "h2 { font-size: 8.8pt; color: #0d1b3e; border-bottom: 1pt solid #2c4a8a; padding-bottom: 1pt; margin: 5pt 0 3pt 0; }"}, {"target": "table { width: 100%; border-collapse: collapse; font-size: 7.6pt; }", "replacement": "table { width: 100%; border-collapse: collapse; font-size: 6.9pt; }"}, {"target": "th { background: #0d1b3e; color: #fff; text-align: left; padding: 3pt 4pt; font-weight: bold; }", "replacement": "th { background: #0d1b3e; color: #fff; text-align: left; padding: 2.2pt 3.5pt; font-weight: bold; }"}, {"target": "td { padding: 2.8pt 4pt;", "replacement": "td { padding: 2pt 3.5pt;"}, {"target": ".card { border: 0.6pt solid #c4cdda; border-left: 2.5pt solid #2c4a8a; border-radius: 2pt; padding: 4pt 5pt; margin-bottom: 5pt; break-inside: avoid; }", "replacement": ".card { border: 0.6pt solid #c4cdda; border-left: 2.5pt solid #2c4a8a; border-radius: 2pt; padding: 3pt 4pt; margin-bottom: 4pt; break-inside: avoid; }"}, {"target": ".card h3 { font-size: 8.4pt; color: #0d1b3e; margin-bottom: 1.5pt; }", "replacement": ".card h3 { font-size: 7.8pt; color: #0d1b3e; margin-bottom: 1pt; }"}, {"target": ".card .tag { font-size: 7pt;", "replacement": ".card .tag { font-size: 6.5pt;"}, {"target": "li { margin-bottom: 1.2pt; }", "replacement": "li { margin-bottom: 0.8pt; }"}, {"target": ".tldr { background: #eef3fb; border: 0.8pt solid #2c4a8a; border-radius: 2pt; padding: 5pt 6pt; font-size: 8pt; }", "replacement": ".tldr { background: #eef3fb; border: 0.8pt solid #2c4a8a; border-radius: 2pt; padding: 4pt 5pt; font-size: 7.4pt; }"}, {"target": ".foot { margin-top: 5pt; font-size: 6.6pt;", "replacement": ".foot { margin-top: 3.5pt; font-size: 6pt;"}, {"target": ".sub { color: #5a6478; font-size: 8pt; margin-bottom: 7pt; }", "replacement": ".sub { color: #5a6478; font-size: 7.3pt; margin-bottom: 5pt; }"}] </parameter> </function> </tool_call>

Pelican on a Bicycle

Same harness, silly pelican benchmark:

Generate an SVG of a pelican riding a bicycle

Ninfer6000 (Swift1.5 NVFP4)

Open SVG ↗

Took 29 seconds to fail another tool call. 1:05 total to create the pelican after prompting it to fix the call. Overall well put together pelican.

SVG generated by Ninfer6000

All three wrote a real file and all three files render. All three are identifiable as a pelican. The Ninfer6000* and vLLM outputs are great, the llama.cpp model was a little less put together and took so much longer. My personal ranking would be Ninfer6000, closely followed by vLLM, with UD_Q4_K_XL trailing behind.

*Ninfer6000 misfired again on the way there, just like with the pdf report. Its first write_file call streamed 7.2kB of SVG and then died mid-attribute inside the wing feathers. The closing tag never emitted and the call printed instead of running. The retry once again was successful. The drawing above is that second attempt. The last thing the first one managed to emit was:

<path d="M318 194 C 350 196, 386 210, 418 24

The whole attempt is saved raw if you want to see how far it got before the framing fell apart. Two turns, two malformed calls.

Conclusion

tl;dr

  • The speed benefit is real. The massive decode gap makes tasks extremely rapid. Prefill falls short of vLLM but still WAY faster than llama.cpp.
  • Benchmarks are mostly a wash with the one surprising inverted result of Ninfer6000 topping BFCL and failing tool calls in real world applications consistently.
  • The knowledge and accuracy differences didn’t move beyond the noise floor in most spots and suggest the models are interchangeable for my needs.

If the tool calling issue is solved, Ninfer6000 will be the obvious choice for me. Until then I’ll eat the vLLM startup time/decode reduction and benefit from prefill gains (even though total wall time will be worse).