BetterWright-4b — GGUF
Three quantisations (Q4_K_M, Q5_K_M, Q8_0) of ProCreations/BetterWright-4b.
GGUF conversion of ProCreations/BetterWright-4b — a full-parameter fine-tune of XHToken/Spark-X2.5-4B specialised for driving a real browser through BetterWright (a persistent, policy-guarded Playwright browser for AI agents).
Read the upstream card first. This repository is a format conversion only — no fine-tuning, no re-training, no behavioural changes. The architecture, benchmark results, training recipe and limitations are all inherited from the BF16 original. For the full story and benchmark caveats, see ProCreations/BetterWright-4b.
Available quantisations
Three quants of the same weights, all converted from the upstream BF16 release with llama-quantize (llama.cpp 0.5.0-dev, commit eae11d221):
| File | Size | file_type | BPW | Tensor mix | SHA256 |
|---|---|---|---|---|---|
BetterWright-4b-Q4_K_M.gguf | 2.60 GB | 15 | 4.85 | 180 Q4_K, 37 Q6_K, 73 F32 | 2a758e504db8da48… |
BetterWright-4b-Q5_K_M.gguf | 2.98 GB | 17 | 5.66 | 180 Q5_K, 37 Q6_K, 73 F32 | 3b4fc2307b9ae4bb… |
BetterWright-4b-Q8_0.gguf | 4.38 GB | 7 | 8.50 | 217 Q8_0, 73 F32 | b6c9706b6faaf7ac… |
All three carry the spark2_5 architecture, 290 tensors, the full 131,072-token vocabulary, and an embedded chat template. The embedding table and output head stay at the higher Q6_K in the K-quants.
Which to pick: Q5_K_M is the default balance and the one recommended unless you have a reason otherwise. Q8_0 is the closest to BF16 — use it when tool-call argument fidelity matters more than download size, or if you have VRAM to spare. Q4_K_M is for tight VRAM or bandwidth-limited setups; it still produces valid tool calls but is the most likely to drift on long, exacting browser code.
The upstream BF16 safetensors are 8.22 GB; these three are 32%, 36% and 53% of that respectively.
Requirements
llama.cpp ≥ build 3ad1ba7336 (2026-09-06, PR #27868 "[Model] Support for Spark2_5ForCausalLM"). Before that commit spark2_5 was an unknown architecture and loading failed.
docker pull ghcr.io/ggml-org/llama.cpp:server-vulkan # verified working
The GGUF embeds its own chat template and tokenizer (131,072-token BPE vocab), so no extra files are needed.
Usage
llama.cpp server
Download the quant you want, then:
docker run --rm --gpus all --ipc=host -p 8080:8080 \
-v /path/to/models:/models:ro \
ghcr.io/ggml-org/llama.cpp:server-vulkan \
-m /models/BetterWright-4b-Q5_K_M.gguf \
-ngl 999 -fa on -c 262144 --host 0.0.0.0 --port 8080
# or, without a GPU
docker run --rm -p 8080:8080 \
-v /path/to/models:/models:ro \
ghcr.io/ggml-org/llama.cpp:server \
-m /models/BetterWright-4b-Q4_K_M.gguf -c 32768 --host 0.0.0.0 --port 8080
Or natively:
llama-server -m BetterWright-4b-Q5_K_M.gguf -ngl 999 -c 262144
llama.cpp CLI
llama-cli -m BetterWright-4b-Q8_0.gguf -ngl 999 -c 262144 \
-p "What is 84 * 3 / 2?"
Drive a browser with BetterWright
npm install -g betterwright && betterwright setup
betterwright exec "find the top Hacker News story and give me its title and points" \
--base-url http://127.0.0.1:8080/v1 --model betterwright-4b
Transformers / SGLang / vLLM
For BF16 accuracy and the reference benchmark numbers, use the upstream BF16 repo. Serving GGUF with vLLM requires its experimental GGUF loader and SGLang requires the Spark plugin; neither was used for the upstream numbers, so treat GGUF serving as unbenchmarked.
Tool calling and sampling
The GGUF preserves the Spark-X2.5 chat template, so llama.cpp's built-in parser handles tool calls natively — no manual regex or parser wiring needed.
- Tool format:
<tool_call>name<arg_key>k</arg_key><arg_value>v</arg_value></tool_call>, thinking in<think>…</think>. - Sampling defaults baked into the GGUF:
temperature 1.0,top_p 0.95,top_k -1,repeat_penalty 1.0— these match the upstream recommendation, so the defaults are already correct. - Target harness:
betterwright exec/ the interactivebetterwrightconsole (toolsbrowser,done, pluslogin/ask/handoffwhen the host exposes them). Also works from the BetterWright MCP server and the Pi extension.
Verified behaviour
All three quants were loaded in llama.cpp 0.5.0-dev (build 11277, commit eae11d221) on Vulkan with full GPU offload and exercised against the same prompts:
| Quant | Loads | Chat + reasoning_content | browser tool call parsed | Completion tokens |
|---|---|---|---|---|
Q4_K_M | ✅ | ✅ | ✅ finish_reason: tool_calls, valid page.goto(...) in code + note | 144 |
Q5_K_M | ✅ | ✅ | ✅ same | 158 |
Q8_0 | ✅ | ✅ | ✅ same | 158 |
Responses differed slightly in phrasing across quants (expected), but all three produced well-formed tool calls with both required arguments. That is a functional smoke test, not a quality comparison — see the caveats below.
Architecture reference
From the GGUF metadata:
| Key | Value |
|---|---|
block_count | 36 layers (27 sliding + 9 full attention) |
context_length | 1,048,576 (native) |
embedding_length | 2560 |
feed_forward_length | 10240 |
attention.head_count | 16 heads, 4 KV heads (GQA) |
attention.key_length / value_length | 256 |
sliding_window | 512 |
vocab_size | 131,072 |
rope.dimension_count | 64 full-attention / 256 sliding-window |
rope.freq_base | 5,000,000 full / 10,000 sliding |
attention.sliding_window_pattern | [1,1,1,0] repeating (3 sliding per 1 full) |
Recommended serving window: 262,144 tokens. The architecture's native positions extend to 1M, but the model was trained on sequences up to ~96k.
Memory at 262k context
KV cache dominates at long context: ~9.05 GiB in f16 at 262k tokens (9.0 GiB in the nine full-attention layers, only 0.05 GiB in the 27 sliding-window layers, since their window is only 512).
| Component | Q4_K_M | Q5_K_M | Q8_0 |
|---|---|---|---|
| Model weights | 2.60 GB | 2.98 GB | 4.38 GB |
| KV cache, f16 @ 262k | 9.05 GiB | 9.05 GiB | 9.05 GiB |
| KV cache, q8_0 @ 262k | ~6.8 GiB | ~6.8 GiB | ~6.8 GiB |
| Compute buffer | ~1–2 GB | ~1–2 GB | ~1–2 GB |
| Total (f16 cache) | ~13 GB | ~14 GB | ~15 GB |
| Total (q8_0 cache) | ~11 GB | ~11 GB | ~13 GB |
Use --cache-type-k q8_0 --cache-type-v q8_0 to cut the KV cache by about 25% (q8_0 is not half of f16 — it keeps a scale per 32-element block) if VRAM is tight. At 262k the KV cache is by far the largest term, so quantising the cache is usually a bigger lever than stepping down the model quant. At more typical contexts (8k–32k) the KV cache shrinks proportionally and all three quants fit comfortably in 6–8 GB.
Other quantisations
Only the three above are published here. To build others from the upstream BF16 repo:
# 1. convert the BF16 safetensors to GGUF (needs a llama.cpp build new enough for spark2_5)
python llama.cpp/convert_hf_to_gguf.py ProCreations/BetterWright-4b --outfile bw-f16.gguf --outtype f16
# 2. quantise
docker run --rm -v "$PWD":/work ghcr.io/ggml-org/llama.cpp:full \
/work/bw-f16.gguf /work/BetterWright-4b-Q6_K.gguf Q6_K
Quality ordering, largest to smallest: BF16 → Q8_0 → Q6_K → Q5_K_M → Q5_K_S → Q4_K_M → Q4_0.
Notes and caveats
- This is a community conversion, not an official ProCreations release. The upstream project publishes BF16 safetensors; if you need an authoritative GGUF, please ask them. All three files were verified by SHA256 against the source and by live inference, but not perplexity-benchmarked.
- Quantisation is unbenchmarked for this model. The upstream benchmark (judge mean score 1.21 → 2.40, grounding 22% → 40%) was run on BF16. Each quant will differ somewhat, and tool-call argument accuracy is the most likely place to notice. We have not ranked these quants against each other on quality — treat
Q5_K_Mas a well-tested default, not a measured optimum. If fidelity to BF16 matters more than size, useQ8_0; it is the least lossy of the three. - Benchmark numbers on the upstream card refer to BF16, not this file. Please don't quote them as GGUF results.
- Text-only: the model never sees screenshots; it relies on BetterWright's accessibility snapshots, DOM text and JSON results.
- Authenticated flows: trained on public, login-free sites and sandbox/demo sites for write actions; not trained on authenticated flows with real credentials.
- 4B parameters: strong at operating the browser, weaker than large models at open-ended reasoning about page content.
Acknowledgements
This is a format conversion of ProCreations/BetterWright-4b by the ProCreations / BetterWright Project. Base model by XHToken (Spark-X2.5-4B, Apache-2.0). Harness, benchmarks and browser: The BetterWright Project (MIT). Task sources: Online-Mind2Web (OSU NLP) and Odysseys (Jang et al., 2026, MIT-licensed task data).
The underlying weights, training recipe and benchmark results are the work of the upstream authors; this repository only repackages them in GGUF form for llama.cpp.