Community-maintained llama.cpp SYCL Docker optimized for Intel Arc Pro B70 (Battlemage). Latest oneAPI/compute-runtime/IGC, B70-specific AOT build, all features enabled (Flash Attention, MTP, reorder kernels, no GGML_SYCL_DISABLE_OPT).
2
stars
20
commits
C++
primary language
Sep 5, 2026
updated
A maintained, up-to-date Docker image + guidance for running llama.cpp with SYCL on the Intel Arc Pro B70 (32 GB, BMG-G31 / Xe2) and other Battlemage B-series cards.
The official ghcr.io/ggml-org/llama.cpp:* -intel images often lag on oneAPI / compute-runtime / IGC. This community effort keeps the stack current for B70 while keeping every feature enabled — Flash Attention, speculative decoding / MTP, reorder kernels, and dynamic backends. No GGML_SYCL_DISABLE_OPT.
GGML_SYCL_FA_ONEDNN=1) ≈ prefill 392 t/s / decode 26.2 t/s, draft acceptance 0.573. ~1.85× prefill over the q8_0 no-DNN baseline; full suite (T1–T5 + V1–V3) passes, 0 crashes.Q8 (not BF16) MTP draft is required on the upgrade stack at 128k — the BF16 draft's speculative buffer reserve crashes the 32 GB card; Q8 frees ~1.5 GB with no acceptance loss.
GGML_SYCL_DNN=ON) does (prefill 392+ t/s). See docs/B70-SYCL-KNOWLEDGE.md §7.From the repo root (contains .devops/intel.Dockerfile):
# Convenience script
./scripts/build-b70-image.sh server
# ...or directly
docker build \
--target server \
-t llama.cpp-sycl-b70:server \
-f .devops/intel.Dockerfile \
--build-arg ONEAPI_VERSION=2026.1.2-devel-ubuntu26.04 \
--build-arg GGML_SYCL_F16=ON \
--build-arg GGML_SYCL_DEVICE_ARCH=bmg-g31 \
.
Build targets: server (recommended), light, full. Override any Intel dependency pin at build time via --build-arg (IGC_VERSION, COMPUTE_RUNTIME_VERSION, LEVEL_ZERO_VERSION, …).
DNN / XMX: the image built above is oneDNN-enabled — the Dockerfile installs
intel-oneapi-dnnl-devel(build) +intel-oneapi-dnnl(runtime) and configures-DGGML_SYCL_DNN=ON(default ON for llama.cpp v0.3.0). This unlocks the XMX flash-attention SDPA path on the B70 (deep-context prefill ≈2×, up to 4–5×). To use it at runtime setGGML_SYCL_FA_ONEDNN=1and use F16 KV--cache-type-k/v f16, see §Run) — XMX SDPA only fires on native F16, BF16 is explicitly excluded by the oneDNN kernel.After a build-config change (e.g. base image, oneDNN, or any Dockerfile edit): the GHCR dedup fingerprint (
server-c<CR>-<llama>-) does not include build config, so CI treats the current combo as already built and skips it. Run the Build Stable workflow from the Actions UI withforce: trueto rebuild this combo under the new config (the fresh candidate then satisfies dedup).
Find your render device first:
ls -l /dev/dri # typically /dev/dri/renderD128 or renderD129 for the dGPU
Docker run (with the mandatory environment inside or via -e):
docker run --rm -it \
--device /dev/dri \
-v /path/to/models:/models \
-p 8080:8080 \
-e ONEAPI_DEVICE_SELECTOR=level_zero:0 \
-e SYCL_CACHE_PERSISTENT=0 \
-e ZES_ENABLE_SYSMAN=1 \
llama.cpp-sycl-b70:server \
-m /models/Qwen3.8-27B-Q4_K_M.gguf \
--n-gpu-layers 999 \
--flash-attn on \
--ctx-size 98304 \
--cache-type-k q8_0 --cache-type-v q8_0 \
--port 8080 --host 0.0.0.0
Mandatory environment (never set GGML_SYCL_DISABLE_OPT):
ONEAPI_DEVICE_SELECTOR=level_zero:0 # select the GPU
SYCL_CACHE_PERSISTENT=0 # =1 SIGSEGVs on Xe2 during first JIT
ZES_ENABLE_SYSMAN=1
A docker-compose.yml and a ready-made launcher for the Qwen3.8-27B MTP stack are included (examples/qwen27b-server.sh).
| Config | Context | KV | MTP draft | When |
|---|---|---|---|---|
| MTP3 + Q4/F16/96k (recommended) | 96k | f16 | Q4_0 MTP, n=3 | Default / production (v0.3.0 + oneDNN/XMX, GGML_SYCL_FA_ONEDNN=1) |
| MTP4 + Q8/128k | 128k | q8_0 | Q8_0 MTP, n=4 | Prior production (full 128k); superseded by DNN/XMX |
| MTP3 + Q8/128k (v0.2.0) | 128k | q8_0 | Q8_0 MTP, n=3 | Prior production (superseded by MTP4) |
| MTP3 + 96k (legacy) | 96k | q8_0 | BF16 MTP, n=3 | Pre-upgrade safe config |
| MTP4 + 128k (max, old stack) | 128k | q8_0 | BF16 MTP, n=4 | When the full 128k window was required pre-upgrade |
| no-draft + 128k | 128k | f16 | none | The stable agent "workhorse" when speculation isn't worth it |
Full details and memory footprints in benchmark/configs/. Also:
--n-gpu-layers 999 (offload everything).--flash-attn on (SYCL backend supports it).Source: the official Qwen3.8-27B HF model card (Recommended Inference Parameters). Two modes:
| Mode | temperature | top_p | top_k | min_p | presence_penalty | repetition_penalty |
|---|---|---|---|---|---|---|
| Thinking | 1.0 | 0.95 | 20 | 0.0 | 0.0 | 1.0 |
| Instruct (non-thinking) — use for agents | 0.7 | 0.80 | 20 | 0.0 | 1.5 | 1.0 |
The textbook fix for Qwen3.8 verbosity/rambling in non-thinking mode is
presence_penalty=1.5(penalizes already-seen tokens), not a manually-lowered temperature. With--temp 0.7 --top-p 0.80 --top-k 20 --min-p 0.0 --presence-penalty 1.5 --frequency-penalty 0.0 --repeat-penalty 1.0the model answers crisply with no thinking leakage into the visible channel and intact function-calling.
Add these to the llama-server invocation when serving Qwen3.8-27B in non-thinking mode (verify with GET /v1/... /props → default_generation_settings.params):
--temp 0.7 --top-p 0.80 --top-k 20 --min-p 0.0 \
--presence-penalty 1.5 --frequency-penalty 0.0 --repeat-penalty 1.0
Chat template note: the GGUF bakes in the official native Qwen3.8-27B template (8952 chars, full enable_thinking / reasoning_effort VL + XML tool logic). A log line like Using specialized template: Qwen3-Coder is just llama.cpp's name for the arch=qwen35 built-in — the in-GGUF template is loaded in preference (example_format: '<|im_start|>system). Disable thinking per-request with chat_template_kwargs.enable_thinking:false (or reasoning_effort:"none"); a bare top-level enable_thinking is ignored by this build.
.
├── README.md ← you are here
├── STATUS.md ← current pin versions & known-working state
├── CONTRIBUTING.md ← how to contribute (benchmarks welcome)
├── docs/
│ ├── B70-SYCL-KNOWLEDGE.md ← all field knowledge & the "why" behind the config
│ └── B70-TUNING.md ← hands-on flags, pitfalls, PCIe stability
├── benchmark/
│ ├── METHODOLOGY.md ← the 5-task test suite + metric definitions
│ ├── configs/ ← one file per reproducible server config
│ ├── results/ ← one file per dated test run
│ └── incidents/ ← stability / dropout incident logs
├── examples/
│ └── qwen27b-server.sh ← recommended launcher (Q4 MTP + Q8 mmproj, MTP3/96k + XMX)
├── scripts/
│ └── build-b70-image.sh ← convenience build script
├── .devops/intel.Dockerfile ← the build pipeline (all version pins)
├── docker-compose.yml
├── .github/workflows/ ← CI auto-build (stable / dev)
└── llama.cpp/ ← upstream llama.cpp vendored via git subtree
mul_mat kernels for Q4_K etc.GGML_BACKEND_DL).We explicitly do not set GGML_SYCL_DISABLE_OPT.
benchmark/ holds the full test methodology and all measured runs. Start with benchmark/METHODOLOGY.md for the 5-task suite and metric conventions, then browse:
2026-08-25-v030-f16-96k-dnn-mtp3-q4.md; the Q8 tagging-gate is 2026-08-25-mtp3-q8-128k.md).Testing methodology matters. Always verify cards with a real
/v1/chat/completions→finish_reason=stop, keep thinking off for artifact tasks, use q8_0 KV for MTP+large context, and never trust llama.cpp's batchedeval timefigures as the real throughput (see methodology).
source /opt/intel/oneapi/setvars.sh
# oneDNN/libdnnl is required for the XMX SDPA path (GGML_SYCL_DNN=ON):
# apt-get install intel-oneapi-dnnl-devel (Intel oneAPI repo) OR libdnnl-dev
cmake -B build \
-DGGML_SYCL=ON \
-DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx \
-DGGML_SYCL_DEVICE_ARCH=bmg-g31 \
-DGGML_SYCL_F16=ON \
-DGGML_SYCL_DNN=ON \
-DDNNL_ROOT=/opt/intel/oneapi/dnnl/latest \
-DGGML_BACKEND_DL=ON
cmake --build build --config Release -j$(nproc)
Then run with the env vars above. GGML_SYCL_DNN=ON enables the oneDNN/XMX
flash-attention path (run with GGML_SYCL_FA_ONEDNN=1 + F16 KV). Note: a
bare-metal build may hit the Intel driver "version triangle" and fail to initialize
at runtime — the prebuilt container is the reliable path (see docs/B70-SYCL-KNOWLEDGE.md §2).
SYCL_USE_XMX is a misnomer). Recheck on each llama.cpp update.bmg-g31 sharply reduces cold-start JIT cost / SIGSEGV risk.See benchmark/ for measured numbers.
Two dedicated workflows keep pins fresh without manual work:
| Workflow | Branch | Schedule | What it tracks |
|---|---|---|---|
build-stable.yml | main | Every 4 hours | llama.cpp v* tags + all Intel deps (compute-runtime, IGC, Level Zero, oneAPI base) |
build-dev.yml | dev | Saturdays 00:00 UTC | llama.cpp + latest deps (skips when the newest tag is a release, else builds latest b*) |
When a change is detected, CI builds a temporary tag (server-vX.Y-YYYYMMDD-HHMM / server-dev-…) and opens a GitHub Issue with diffs. The maintainer then pulls it to real B70 hardware, tests, and only then creates a proper named tag. Manual pins in the Dockerfile are still supported.
Contributions that keep the B-series current and high-performance are very welcome — see CONTRIBUTING.md. Especially valuable: verified version-pin updates and before/after benchmarks on real B70 hardware.
This is a community effort. Use at your own risk. Test thoroughly with your workloads and report issues so the pins stay fresh for B70.
20 commits
C++
55.2%
C
15.5%
Python
8.0%
Cuda
5.3%
TypeScript
4.2%
Svelte
2.2%
HTML
2.1%
Metal
1.4%
Jinja
1.2%
Community-maintained llama.cpp SYCL Docker optimized for Intel Arc Pro B70 (Battlemage). Latest oneAPI/compute-runtime/IGC, B70-specific AOT build, all features enabled (Flash Attention, MTP, reorder kernels, no GGML_SYCL_DISABLE_OPT).
2
stars
20
commits
C++
primary language
Sep 5, 2026
updated
A maintained, up-to-date Docker image + guidance for running llama.cpp with SYCL on the Intel Arc Pro B70 (32 GB, BMG-G31 / Xe2) and other Battlemage B-series cards.
The official ghcr.io/ggml-org/llama.cpp:* -intel images often lag on oneAPI / compute-runtime / IGC. This community effort keeps the stack current for B70 while keeping every feature enabled — Flash Attention, speculative decoding / MTP, reorder kernels, and dynamic backends. No GGML_SYCL_DISABLE_OPT.
GGML_SYCL_FA_ONEDNN=1) ≈ prefill 392 t/s / decode 26.2 t/s, draft acceptance 0.573. ~1.85× prefill over the q8_0 no-DNN baseline; full suite (T1–T5 + V1–V3) passes, 0 crashes.Q8 (not BF16) MTP draft is required on the upgrade stack at 128k — the BF16 draft's speculative buffer reserve crashes the 32 GB card; Q8 frees ~1.5 GB with no acceptance loss.
GGML_SYCL_DNN=ON) does (prefill 392+ t/s). See docs/B70-SYCL-KNOWLEDGE.md §7.From the repo root (contains .devops/intel.Dockerfile):
# Convenience script
./scripts/build-b70-image.sh server
# ...or directly
docker build \
--target server \
-t llama.cpp-sycl-b70:server \
-f .devops/intel.Dockerfile \
--build-arg ONEAPI_VERSION=2026.1.2-devel-ubuntu26.04 \
--build-arg GGML_SYCL_F16=ON \
--build-arg GGML_SYCL_DEVICE_ARCH=bmg-g31 \
.
Build targets: server (recommended), light, full. Override any Intel dependency pin at build time via --build-arg (IGC_VERSION, COMPUTE_RUNTIME_VERSION, LEVEL_ZERO_VERSION, …).
DNN / XMX: the image built above is oneDNN-enabled — the Dockerfile installs
intel-oneapi-dnnl-devel(build) +intel-oneapi-dnnl(runtime) and configures-DGGML_SYCL_DNN=ON(default ON for llama.cpp v0.3.0). This unlocks the XMX flash-attention SDPA path on the B70 (deep-context prefill ≈2×, up to 4–5×). To use it at runtime setGGML_SYCL_FA_ONEDNN=1and use F16 KV--cache-type-k/v f16, see §Run) — XMX SDPA only fires on native F16, BF16 is explicitly excluded by the oneDNN kernel.After a build-config change (e.g. base image, oneDNN, or any Dockerfile edit): the GHCR dedup fingerprint (
server-c<CR>-<llama>-) does not include build config, so CI treats the current combo as already built and skips it. Run the Build Stable workflow from the Actions UI withforce: trueto rebuild this combo under the new config (the fresh candidate then satisfies dedup).
Find your render device first:
ls -l /dev/dri # typically /dev/dri/renderD128 or renderD129 for the dGPU
Docker run (with the mandatory environment inside or via -e):
docker run --rm -it \
--device /dev/dri \
-v /path/to/models:/models \
-p 8080:8080 \
-e ONEAPI_DEVICE_SELECTOR=level_zero:0 \
-e SYCL_CACHE_PERSISTENT=0 \
-e ZES_ENABLE_SYSMAN=1 \
llama.cpp-sycl-b70:server \
-m /models/Qwen3.8-27B-Q4_K_M.gguf \
--n-gpu-layers 999 \
--flash-attn on \
--ctx-size 98304 \
--cache-type-k q8_0 --cache-type-v q8_0 \
--port 8080 --host 0.0.0.0
Mandatory environment (never set GGML_SYCL_DISABLE_OPT):
ONEAPI_DEVICE_SELECTOR=level_zero:0 # select the GPU
SYCL_CACHE_PERSISTENT=0 # =1 SIGSEGVs on Xe2 during first JIT
ZES_ENABLE_SYSMAN=1
A docker-compose.yml and a ready-made launcher for the Qwen3.8-27B MTP stack are included (examples/qwen27b-server.sh).
| Config | Context | KV | MTP draft | When |
|---|---|---|---|---|
| MTP3 + Q4/F16/96k (recommended) | 96k | f16 | Q4_0 MTP, n=3 | Default / production (v0.3.0 + oneDNN/XMX, GGML_SYCL_FA_ONEDNN=1) |
| MTP4 + Q8/128k | 128k | q8_0 | Q8_0 MTP, n=4 | Prior production (full 128k); superseded by DNN/XMX |
| MTP3 + Q8/128k (v0.2.0) | 128k | q8_0 | Q8_0 MTP, n=3 | Prior production (superseded by MTP4) |
| MTP3 + 96k (legacy) | 96k | q8_0 | BF16 MTP, n=3 | Pre-upgrade safe config |
| MTP4 + 128k (max, old stack) | 128k | q8_0 | BF16 MTP, n=4 | When the full 128k window was required pre-upgrade |
| no-draft + 128k | 128k | f16 | none | The stable agent "workhorse" when speculation isn't worth it |
Full details and memory footprints in benchmark/configs/. Also:
--n-gpu-layers 999 (offload everything).--flash-attn on (SYCL backend supports it).Source: the official Qwen3.8-27B HF model card (Recommended Inference Parameters). Two modes:
| Mode | temperature | top_p | top_k | min_p | presence_penalty | repetition_penalty |
|---|---|---|---|---|---|---|
| Thinking | 1.0 | 0.95 | 20 | 0.0 | 0.0 | 1.0 |
| Instruct (non-thinking) — use for agents | 0.7 | 0.80 | 20 | 0.0 | 1.5 | 1.0 |
The textbook fix for Qwen3.8 verbosity/rambling in non-thinking mode is
presence_penalty=1.5(penalizes already-seen tokens), not a manually-lowered temperature. With--temp 0.7 --top-p 0.80 --top-k 20 --min-p 0.0 --presence-penalty 1.5 --frequency-penalty 0.0 --repeat-penalty 1.0the model answers crisply with no thinking leakage into the visible channel and intact function-calling.
Add these to the llama-server invocation when serving Qwen3.8-27B in non-thinking mode (verify with GET /v1/... /props → default_generation_settings.params):
--temp 0.7 --top-p 0.80 --top-k 20 --min-p 0.0 \
--presence-penalty 1.5 --frequency-penalty 0.0 --repeat-penalty 1.0
Chat template note: the GGUF bakes in the official native Qwen3.8-27B template (8952 chars, full enable_thinking / reasoning_effort VL + XML tool logic). A log line like Using specialized template: Qwen3-Coder is just llama.cpp's name for the arch=qwen35 built-in — the in-GGUF template is loaded in preference (example_format: '<|im_start|>system). Disable thinking per-request with chat_template_kwargs.enable_thinking:false (or reasoning_effort:"none"); a bare top-level enable_thinking is ignored by this build.
.
├── README.md ← you are here
├── STATUS.md ← current pin versions & known-working state
├── CONTRIBUTING.md ← how to contribute (benchmarks welcome)
├── docs/
│ ├── B70-SYCL-KNOWLEDGE.md ← all field knowledge & the "why" behind the config
│ └── B70-TUNING.md ← hands-on flags, pitfalls, PCIe stability
├── benchmark/
│ ├── METHODOLOGY.md ← the 5-task test suite + metric definitions
│ ├── configs/ ← one file per reproducible server config
│ ├── results/ ← one file per dated test run
│ └── incidents/ ← stability / dropout incident logs
├── examples/
│ └── qwen27b-server.sh ← recommended launcher (Q4 MTP + Q8 mmproj, MTP3/96k + XMX)
├── scripts/
│ └── build-b70-image.sh ← convenience build script
├── .devops/intel.Dockerfile ← the build pipeline (all version pins)
├── docker-compose.yml
├── .github/workflows/ ← CI auto-build (stable / dev)
└── llama.cpp/ ← upstream llama.cpp vendored via git subtree
mul_mat kernels for Q4_K etc.GGML_BACKEND_DL).We explicitly do not set GGML_SYCL_DISABLE_OPT.
benchmark/ holds the full test methodology and all measured runs. Start with benchmark/METHODOLOGY.md for the 5-task suite and metric conventions, then browse:
2026-08-25-v030-f16-96k-dnn-mtp3-q4.md; the Q8 tagging-gate is 2026-08-25-mtp3-q8-128k.md).Testing methodology matters. Always verify cards with a real
/v1/chat/completions→finish_reason=stop, keep thinking off for artifact tasks, use q8_0 KV for MTP+large context, and never trust llama.cpp's batchedeval timefigures as the real throughput (see methodology).
source /opt/intel/oneapi/setvars.sh
# oneDNN/libdnnl is required for the XMX SDPA path (GGML_SYCL_DNN=ON):
# apt-get install intel-oneapi-dnnl-devel (Intel oneAPI repo) OR libdnnl-dev
cmake -B build \
-DGGML_SYCL=ON \
-DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx \
-DGGML_SYCL_DEVICE_ARCH=bmg-g31 \
-DGGML_SYCL_F16=ON \
-DGGML_SYCL_DNN=ON \
-DDNNL_ROOT=/opt/intel/oneapi/dnnl/latest \
-DGGML_BACKEND_DL=ON
cmake --build build --config Release -j$(nproc)
Then run with the env vars above. GGML_SYCL_DNN=ON enables the oneDNN/XMX
flash-attention path (run with GGML_SYCL_FA_ONEDNN=1 + F16 KV). Note: a
bare-metal build may hit the Intel driver "version triangle" and fail to initialize
at runtime — the prebuilt container is the reliable path (see docs/B70-SYCL-KNOWLEDGE.md §2).
SYCL_USE_XMX is a misnomer). Recheck on each llama.cpp update.bmg-g31 sharply reduces cold-start JIT cost / SIGSEGV risk.See benchmark/ for measured numbers.
Two dedicated workflows keep pins fresh without manual work:
| Workflow | Branch | Schedule | What it tracks |
|---|---|---|---|
build-stable.yml | main | Every 4 hours | llama.cpp v* tags + all Intel deps (compute-runtime, IGC, Level Zero, oneAPI base) |
build-dev.yml | dev | Saturdays 00:00 UTC | llama.cpp + latest deps (skips when the newest tag is a release, else builds latest b*) |
When a change is detected, CI builds a temporary tag (server-vX.Y-YYYYMMDD-HHMM / server-dev-…) and opens a GitHub Issue with diffs. The maintainer then pulls it to real B70 hardware, tests, and only then creates a proper named tag. Manual pins in the Dockerfile are still supported.
Contributions that keep the B-series current and high-performance are very welcome — see CONTRIBUTING.md. Especially valuable: verified version-pin updates and before/after benchmarks on real B70 hardware.
This is a community effort. Use at your own risk. Test thoroughly with your workloads and report issues so the pins stay fresh for B70.
20 commits
C++
55.2%
C
15.5%
Python
8.0%
Cuda
5.3%
TypeScript
4.2%
Svelte
2.2%
HTML
2.1%
Metal
1.4%
Jinja
1.2%