Model family← Models
Spark-X2.6-4B
XHToken's retrained successor to Spark-X2.5-4B. It turned evidence into answers far more often than its predecessor, but on our tool test it still never reached for a tool on its own.
- Files tested
- 1
- Scored runs
- 15
Made by XHToken · Apache 2.0 · released 19 Oct 2026
How this page was made. The tests run automatically on our Mac Studio, and every score here comes straight from those runs. This overview was written by Claude, an AI model, from the lab's own records: the run log, notes kept at the time, and the working sessions where each decision was made. Quotes are Alan's words, with spelling fixed. How these pages are made.
Why we tested it
XHToken released Spark-X2.6-4B on 19 October as the successor to Spark-X2.5-4B, which we had tested in September. Alan, on 24 October: "ok, there's a new spark model, we tested the previous one but it's now the same model with different training."
XHToken says the design is unchanged and the gains come from improved training. So the question was whether that training fixed X2.5's two failures: it never reached for a tool on its own, and it held answers back.
What it took
Nothing unusual: XHToken's own file on standard llama.cpp. We took its Q4_K_M to match the file X2.5 was tested on, but XHToken built this one differently: it keeps some parts at higher precision, and is 3.54 GB against X2.5's 2.60 GB. To compare like with like, we re-ran X2.5 the same day in the same way: one conversation at a time, 64K of context, the same llama.cpp build.
What happened
- It still never reached for a tool on its own: 0% (0 of 60), even when the prompt said a tool was available or gave a rule for when to use one. When the task was to pick a tool, it did well: 95% (38 of 40) at choosing the right tool from a growing list, and 86.7% (13 of 15) at picking and chaining tools for a request.
- It held back far less. Against X2.5 run the same way, it scored 81.7% (49 of 60) at turning tool results into an answer, against 28.3% (17 of 60). It was also better at answering from the document rather than from what it already knew, 95.8% (46 of 48) against 72.9% (35 of 48), and at finding a fact planted in up to 32,000 tokens of conversation, 87.3% (96 of 110) against 63.6% (70 of 110). On weighing sources it rose to 40% (16 of 40) from 20% (8 of 40), a gap that could be chance on 40 cases.
- It was mixed where a value could be missing. It was better at saying "I don't know" when the answer wasn't there, 63.9% (46 of 72) against 48.6% (35 of 72), but it slipped at tagging with empty fields allowed, 71.7% (172 of 240) against 88.8% (213 of 240). Plain tagging was level, 87.9% (211 of 240) against 87.5% (210 of 240).
- Against two much bigger files run the same way, Flint (26 GB) and LFM2.5-24B-A2B (13.6 GB), it scored highest of the three at tagging and at finding planted facts. It matched Flint at judging whether a value pulled from a document is right, 98.3% (59 of 60), and at answering from the document. It trailed both at weighing sources, at reaching for tools, and at following a convention it had to go and fetch, 29.2% (14 of 48).
- It was slower and hungrier than we expected. With our other models loaded, it wrote 57.8 tokens a second, about the same as X2.5, where we had expected over 100. It peaked at 7.8 GB of memory with 64K of context allocated; we had expected under 6 GB.
What it taught us
- X2.6 improved on one failure and not the other. It answered far more often, but still never reached for a tool in our test. Tool perception is mostly all-or-nothing.
- Re-run the old model before crediting the new one. Run the same way, X2.5 matched its September scores exactly, with word for word the same answer in 270 of 272 cases, so the gains aren't down to our setup.
- The gains mix training with a different file. Even the base model changed, not only the later training XHToken describes: its base files for the two versions are the same size but hold different weights. And the new file keeps more at higher precision. We can't yet say which did the work.
Should you use it?
For checking values pulled from documents, tagging, or finding facts in long conversations, it did well here in a small file. Check it where an empty field matters, since it was mixed there against X2.5. Don't count on it to reach for a tool on its own: for that, K2-Horizon-3.7B scored 100% (60 of 60) on the same tool test. We ran it with thinking off, though XHToken's template turns thinking on by default.
- Spark-X2.6-4B
XHToken's own Q4_K_M, which keeps some parts at higher precision. The only file, tested on 24 October.
Benched 24 Oct 2026 · 3.5 GB · 15 scored runs · smallest Mac 16 GB
Decisions, in order
- 2026-10-24 — bench X2.6 under the runbook procedure. Alan: "ok, there's a new spark model, we tested the previous one but it's now the same model with different training." Procedure: the lab's benchmarking runbook. One model at a time.
- 2026-10-24 — quant: the vendor's Q4_K_M, not Q4_0 (Claude). The runbook prefers Q4_0 on the M1, but this bench's question is training, and X2.5 was measured on its vendor Q4_K_M. Matching the format removes the quantisation variable. Speed isn't the question for a 4B. The vendor ships no Q4_0.
- Noted: X2.6's Q4_K_M is 3.54 GB against X2.5's 2.60 GB, with identical tensor shapes. The vendor quantised differently this time. The header (variant doc) confirms BF16 embeddings and Q8_0 attn-output, so "same format" doesn't mean identical bits.
- 2026-10-24 — pre-registered (Claude, before any run).
- Server:
llama.cpp-b11846/build/bin/llama-server -m Spark-X2.6-4B-Q4_K_M.gguf -np 1 -c 65536 -fa on -ngl 999 --cache-ram 0 --jinja, KV default f16. Beside the full fleet (VACATE=0; 3.5 GB). - Benches: the coherence gate, then the gauntlet (15 suites,
PAR=1, extraction profile), then the context ladder, 8K to the 1M native window, stopping at the budget or swap guard. - Comparators:
- X2.5 (
spark-x25-4b, 2026-09-10) is the training comparison, but it ran a different configuration:-c 32768, q8_0 KV, b10893. Any difference mixes training with configuration, so it's a hypothesis until X2.5 is re-run under this procedure. - k2-3.7b holds the tool-dispatch seat (toolcall/toolscale 100/100).
- Flint and LFM2.5 single-slot 64K are the only like-for-like procedure comparators.
- Expectations, each falsifiable:
- toolcall rises from 0/60 to at least 12/60. At minimum, the availability arm, where the prompt says a tool exists, should pass. The vendor's agentic-training claim is aimed squarely at this. If it's still 0/60, the training didn't reach tool perception.
- need and unmentioned arms stay low (≤ 3/12 each). Finding Tool perception is mostly all-or-nothing and tracks the checkpoint, not size or vendor claims: detecting an unannounced tool is a separate capability, and the vendor's "agentic" means harnesses that announce their tools.
- worldview > 20% and synthesis > 28.3%, i.e. the "no value" disposition is reduced. Expected movement is uncertain; this is the training question that needs the X2.5 re-run to settle.
- Coherence COHERENT and thinking-off verified on every suite. The template supports
enable_thinking: false. - Peak RSS under 6 GB at 64K, and single-stream decode above 100 t/s (a 4B; LFM2.5 at 2.45B active ran 102.5, contended).
- What would change the plan: a thinking-off precondition failure (then a harness incident, not a score), or a load failure on b11846.
- 2026-10-24 ~12:24Z — complete; the pre-registered expectations, scored (kept beside the plan above).
- toolcall ≥ 12/60: missed. 0/60, 0/12 in every arm including availability. The training didn't reach tool perception.
- need and unmentioned ≤ 3/12: met (0/12 each), but vacuously, since every arm is 0.
- worldview > 20% and synthesis > 28.3%: met. worldview 40.0, synthesis 81.7, with the configuration and quantisation caveat above. (Settled 2026-10-24 by the X2.5 re-run: configuration is ruled out; synthesis is beyond the intervals, worldview isn't.)
- Coherent and thinking-off: met. COHERENT, and thinking-off verified on every suite.
- RSS under 6 GB, decode above 100 t/s: both missed.
- Peak RSS was 7.8 GB in the gauntlet, though the ladder's 64K rung, with no prompt load, read 5.78.
- Decode was 57.8 t/s. My reasoning was wrong: I compared a 4.4B dense model with a 2.45B-active MoE, but decode here is bandwidth-bound on the bytes read per token, and a dense model reads all of them. 57.8 × 3.54 GB ≈ 205 GB/s.
- Plan deviation: the ladder climbed to 256K, not the 1M native window, because
eval/ctx_ladder.pytops out at 262,144. - 2026-10-24 17:51Z — X2.5 re-run under the same procedure. It settles the training-vs-configuration question above; see "Against X2.5, same procedure" under What we learned.
What we learned, in the lab's words
From the gauntlet of record (single slot, 64K, f16 KV, b11846, 15 suites; coherence COHERENT) and the context ladder. Bundles 2026-10-24-4174a46f and -743cfeb3.
Against X2.5, same procedure (re-run 2026-10-24, spark-x2.5-4b-q4km-np1-c64k-b11846, bundle 2026-10-24-0b6bf0e3). The re-run reproduces X2.5's 2026-09-10 run case for case (272/272 outcomes, 270/272 identical answers), so configuration is ruled out. The differences are training (base and post-training both changed) plus the vendor's different quantisation mix.
| suite | X2.6 | X2.5 (re-run) |
|---|---|---|
| synthesis | 81.7 | 28.3 |
| epistemics | 95.8 | 72.9 |
| needle | 87.3 | 63.6 |
| nullschema | 63.9 | 48.6 |
| worldview | 40.0 | 20.0 (intervals overlap) |
| enrichment | 85.2 | 77.8 |
| tagger_nullable | 71.7 | 88.8 |
| tagger | 87.9 | 87.5 |
| grounding | 72.0 | 72.8 |
| screening | 98.3 | 96.7 |
| tools | 86.7 | 80.0 |
| toolscale | 95.0 | 95.0 |
| contract | 29.2 | 25.0 |
| toolcall | 0.0 | 0.0 |
| toolcall/2 fetch / restraint / honesty | 25/48, 37/48, 69/120 | 0/48, 41/48, 91/120 |
Like for like (single slot, 64K, b11846; Flint and LFM2.5 from their bundles):
| suite | Spark-X2.6 (4.4B dense) | Flint (2.5B active) | LFM2.5 (2.45B active) |
|---|---|---|---|
| screening | 98.3 | 98.3 | 25.0 |
| epistemics | 95.8 | 95.8 | 70.8 |
| tagger | 87.9 | 82.1 | 62.1 |
| needle (all 110) | 87.3 | 60.0 | 54.5 |
| enrichment | 85.2 | 77.8 | 51.9 |
| synthesis | 81.7 | 78.3 | 75.0 |
| grounding | 72.0 | 77.6 | 72.8 |
| tagger_nullable | 71.7 | 60.8 | 50.0 |
| nullschema | 63.9 | 70.8 | 44.4 |
| worldview | 40.0 | 75.0 | 55.0 |
| toolscale | 95.0 | 95.0 | 100.0 |
| tools | 86.7 | 100.0 | 86.7 |
| contract | 29.2 | 60.4 | 75.0 |
| toolcall | 0.0 | 55.0 | 100.0 |
- The retraining didn't reach tool perception under toolcall/1. It is still 0/60, and 0/12 even in the availability and conditional arms, where the prompt states the tool exists or gives a rule. It calls tools in toolscale and tools, so the failure is in deciding to call one from a toolcall-style prompt, not in calling one at all.
- toolcall/2 shows what training did change: X2.6 fetches when asked directly (24/24, against X2.5's 0/24), and X2.5 never makes a parsed call at all.
- It did reduce the "no value" disposition, and that is training, not configuration (the re-run above): synthesis +53, epistemics +23, needle +24, nullschema +15. Worldview +20 is within the intervals.
- The cost: it makes things up more. toolcall/2 honesty fell from 76% to 58%, and tagger_nullable (leaving a field empty when the value is absent) from 88.8 to 71.7. X2.5 says "not there"; X2.6 more often supplies a value.
- The strongest 4B-class judge and tagger benched here. It ties Flint on screening (98.3) and epistemics (95.8), and leads all three models on tagger, needle, enrichment and synthesis, at 3.5 GB of weights.
- Weak on contract (29.2) and worldview (40.0) against Flint.
- Speed: dense, so bandwidth-bound. Decode is 57.8 t/s (contended), slower than the 2.5B-active MoEs (Flint 74.2, LFM2.5 102.5), because every token reads all 3.54 GB of weights. Prefill is 465 t/s. X2.5 (2.60 GB) decodes at 58.4, so the larger file costs nothing measurable here.
- Memory: 3.8 GB at 8K to 12.5 GB at 256K (≈ 34.4 KB/token f16); peak RSS 7.8 GB in the 64K gauntlet.
- Read (Claude, one run each): a strong candidate for screening, tagging and long-context recall at a small footprint, but check its abstention where an empty field matters. Not a tool dispatcher: k2-3.7b (toolcall 100) keeps that job, the seat X2.5 was once tested against.
Why it was tested, in the lab's words
Alan, 2026-10-24: "ok, there's a new spark model, we tested the previous one but it's now the same model with different training." The question: did X2.6's training fix what X2.5 failed? From X2.5's record (2026-09-10):
- toolcall/1 0/60, every case
answered_directly, against toolscale 38/40; - worldview 20% and synthesis 28.3%, a "no value" disposition.
Open questions
- Training or quantisation? Configuration is ruled out (X2.5 re-run). The two vendor files still differ in precision (BF16 embeddings and a Q8_0 output head on X2.6), so a Q8_0 of both, or the BF16 weights, would separate training from quantisation. That's Alan's call.
- Why does toolcall stay 0/12 even in the availability arm, when toolscale and tools show it calling tools, and toolcall/2's direct_ask shows it fetching 24/24? Comparing the toolcall prompt shape with toolscale's would answer it.
- What changed in the base checkpoint? The vendor describes post-training only.
- The memory and quality of the full 1M window are unmeasured.
- decide/1 and edgefill are still to run.
The model in detail
| field | value |
|---|---|
| vendor | XHToken |
| upstream repos | XHToken/Spark-X2.6-4B (BF16 safetensors, revision 66e3ae7bee), XHToken/Spark-X2.6-4B-GGUF (revision fe31f8d64890302cc3a1d365d700357b4b75ba77), base XHToken/Spark-X2.6-4B-Base |
| licence | Apache-2.0 |
| released | 2026-10-19 (weights and GGUF repos created; GGUF last modified 2026-10-21) |
| architecture | spark2_5 (GGUF header), 36 blocks, 4 KV heads, 4,447,623,680 parameters (GGUF total), native context 1,048,576. The card says it's identical to X2.5: hybrid attention, one full-attention layer per three sliding-window layers |
| base checkpoint | Not X2.5's base. Spark-X2.6-4B-Base and Spark-X2.5-4B-Base have 5 safetensors shards with identical byte sizes but different sha256 on every shard (e.g. shard 1: 39cef19f… vs 2408e76b…). Same shapes, different weights, so the base was re-trained as well, not only the post-training the card describes |
| thinking control | the chat template defaults enable_thinking to true; "enable_thinking": false turns it off; with thinking on, reasoning_effort is high (default) or low |
| vendor serving advice | temperature 1.0, top_p 0.95, top_k 0/−1; SGLang/vLLM spark25 tool parser; llama.cpp b10828 or later for spark2_5 |
| vendor claims | "substantial improvements in coding, agent, long-context, multilingual, reasoning". Charts only; no X2.5-vs-X2.6 numbers in text |