Skip to content

After the Fix: Qwen-Coder vLLM BF16 vs Ollama Q4_K_M, Side by Side

896 milliseconds. That was the smoke test after I patched runner.py — the first clean response from the vLLM endpoint since I accidentally broke it by adding min-P sampling to every provider without checking whether vLLM actually supported it alongside speculative decoding. It doesn't. Every request came back HTTP 400, all 28 tests errored out, and I shipped yesterday's post with that whole column missing.

The fix was 15 lines. Gate min-P behind a per-profile send_min_p flag, default it off for the openai_compat provider since min-P isn't even part of the OpenAI spec, leave Ollama unchanged. I could rant about how "add a parameter to every provider" is never as safe as it sounds, but the short version is: different upstreams have different feature gates, and the right pattern is per-profile opt-in.

Same model, two stacks, one run

Rows 7 and 9 in the leaderboard below are the same model. Qwen2.5-Coder-32B-Instruct, same weights, same temperature. One copy served by vLLM at BF16 with speculative decoding and prefix caching. The other served by Ollama at Q4_K_M, the way every other local model in this benchmark has been running for the past week. Same 28 prompts. Same dual judge.

MetricvLLM BF16Ollama Q4_K_M
Wins (out of 28)21
Average rank7.378.04
Response time1.9s3.6s
Output tokens3842
VRAM~22 GB~18 GB

vLLM wins on everything except VRAM footprint. The speed gap is the real headline — 1.9× faster, and that's not noise, that's hardware-limited by spec decode and prefix caching. The +1 win and +0.67 rank improvement could be variance. The latency cannot.

This is the second time I've seen this pattern. Yesterday's coding-suite A/B showed vLLM BF16 winning 4 of 5 tasks at 38.8/50 vs Ollama's 34.6/50 — a 12% quality lift on completely different prompts. Two independent confirmations now. BF16 with a real serving stack just produces better output than Q4 through Ollama, even on a kid-tutor task suite that shouldn't care about quantization artifacts.

What it actually won

blip-math-001. A math drill prompt where a kid says the wrong answer and the model has to correct gently. vLLM beat all 16 other models on that one test. Worth pausing on: math has been the weakest local category in every single benchmark run this series. A local model winning a math test outright? First time.

blip-voice-003. Voice quality — short, TTS-friendly, no markdown. vLLM averaged rank 2.67 across all three voice tests, which is the best of any model in the entire benchmark for that category. And at 1.9 seconds per response, the kid hears Blip answer almost immediately. How many of the cloud models can say that?

The numbers I don't trust yet

Sonnet jumped from 3 wins to 6 in this run. That's a 3-win swing on the same 28 tests. Opus dropped from 4 to 2. The Claude family total stayed at 7 — they just swapped which tests each one won. I'm calling that noise until a third run says otherwise.

The blip-edu family collapsed from 7 wins to 2. I had just written a whole post about blip-edu-coder being the new primary local model, and now it's at zero wins. Honestly? I shouldn't have committed to a routing change based on a single run. I knew the variance floor was ±2-3 wins. I did it anyway. Lesson re-learned.

One thing that has never moved across any run in this series: the opus-distilled Qwen variants sit at the bottom. Zero wins, worst average ranks, every time. That's the only finding I'd bet money on at this point.

17 models, full table

#ModelWinsAvg rankAvg timeAvg tok
1Claude Sonnet 4.665.592.9s45
2GLM-5 (cloud)34.488.1s130
3DeepSeek-V3-032436.564.4s37
4GLM-Z1-32B (local)38.267.8s240
5Claude Opus 4.626.262.9s49
6Qwen3-32B (local)26.374.1s41
7qwen-coder-32b-fp8 (vLLM BF16)27.371.9s38
8blip-edu (mine)210.411.2s45
9qwen-coder-32b (Ollama Q4)18.043.6s42
10DeepSeek-R1:32b18.963.3s36
11qwen3.5-abliterated19.227.9s58
12Hermes3:8b111.891.6s56
13MiniMax-M2.507.935.6s144
14blip-edu-coder010.191.2s44
15blip-edu:v2010.410.3s45
16qwen3.5-35b opus-distilled014.5213.0s468
17qwen3.5-27b opus-distilled016.5613.4s495

So what actually changes

I'm adding the vLLM entry to Blip's router for voice-quality turns. Rank 2.67 average on voice, 1.9-second latency, runs on my own hardware. That's a better fit than anything else in the lineup for the "kid hears the response read aloud" use case.

The Ollama Q4 version becomes the fallback for when vLLM is down. Same weights, slower and slightly worse, but it doesn't need a second serving process to be healthy. I'm not touching the FP8/NVFP4 Docker upgrade yet — BF16 is already winning the A/B, and the throughput gain from real quantized serving isn't blocking anything I'm currently doing.

The blip-edu routing decision from yesterday? Shelved. I'm running a third round before I commit to anything based on win counts that swing by ±3 between runs. The variance protocol from earlier in this series exists for exactly this kind of situation and I should have followed it the first time.

Total spend on this whole benchmarking series so far: about $24 over four days. Twelve runs, eight posts, three trained models, one validated A/B between serving stacks. Not bad for a few evenings of GPU time and some cloud judging credits.