Remote
llama.cppworkbench for GGUF models with direct runtime control, persistent chats, RAG knowledge base, RPC split serving, and hardware-aware tuning from RK3588 boards to Windows CUDA systems.
llama-webui is a standalone local web interface for llama.cpp with no Ollama dependency. Ollama was removed after CVE-2026-7482 (CVSS 9.1) exposed a critical RCE vulnerability. The serving stack is compiled llama.cpp, so KV cache quantization, context length, batch sizing, CPU affinity, GPU layer offload, and model-specific flags remain fully controllable.
This repository started as a board-local control surface for testing REAP-pruned Mixture-of-Experts models on a Radxa ROCK 5B+ with Rockchip RK3588. It now serves three purposes:
- A practical remote web UI for loading and serving local GGUF models with
llama.cpp - A documented benchmark and tuning harness for constrained ARM boards and more capable desktop machines
- A serious-workload control plane for Windows CUDA hosts, including Windows-to-Windows
llama.cppRPC split serving across a LAN
The main point is simple: keep the convenience of a web UI without giving up the flags that decide whether local inference is actually usable.
Many local-AI UIs optimize for convenience first and runtime visibility second. llama-webui is deliberately built the other way around.
- It talks to compiled
llama.cppdirectly — no Ollama dependency (removed after CVE-2026-7482). - It preserves the flags that actually decide whether a host feels usable:
- KV cache type
- context window
- batch and ubatch sizing
- CPU affinity
- GPU offload depth
- reasoning / no-thinking mode
- It treats benchmark-backed hardware tuning as a feature, not background trivia.
- It is intentionally credible on small ARM systems, especially the
Radxa ROCK 5B+withRK3588, not only on desktop GPUs. - It supports
llama.cppRPC split serving, so one coordinator can combine local and remote compute instead of being limited to a single box.
If you just want a generic chat shell, other tools already cover that. This repo is for people who want a usable web UI without giving up the runtime knobs that explain real behavior.
- engineers benchmarking GGUF models on
llama.cpp - people serving models on ARM SBCs, headless Linux hosts, or mixed desktop hardware
- developers who want a remote control plane for model switching and runtime tuning
- anyone who needs to compare presets, flags, and model behavior with less guesswork
- Ollama removed after CVE-2026-7482 (CVSS 9.1 critical RCE)
- more direct control over
llama.cppstartup flags - easier to reason about model-specific tuning and failure modes
- better fit for benchmarking, profiling, and constrained-hardware tuning
- no hidden abstraction layer between you and the runtime knobs
- less GPU-desktop assumption baked into the defaults
- friendlier to SBC and remote-host workflows
- clearer path to RK3588 and CPU-first tuning
- persistent chats
- browser control plane
- model inventory and presets
- easier inspection of runtime state and configuration
Most local-AI tools talk about ARM boards as a novelty. This repo does not.
- It was shaped around real tuning work on a
Radxa ROCK 5B+. - It exposes the settings that matter on RK3588: context, KV cache quantization, threads, affinity, and no-thinking mode.
- It carries benchmark-backed presets instead of pretending the same defaults work equally well on laptops, workstations, and SBCs.
- It is useful when the goal is stable, private local inference on constrained hardware, not just desktop demos.
llama.cpponly — Ollama removed after CVE-2026-7482 (CVSS 9.1)- Browser-driven model loading and runtime config editing
- GPU auto-detection for CUDA, ROCm, Metal, and CPU-first profiles
- Streaming responses via Server-Sent Events
- Persistent chat history in SQLite
- Model discovery from configurable GGUF directories
- Cross-platform support for ARM SBCs, Linux desktops, NVIDIA GPUs, and Windows CUDA hosts
llama.cppRPC split mode for LAN-connected worker machines- Knowledge Base / RAG: index and search AI conversation history (Pi, Claude Code, Codex, Factory, Qwen Code, OpenCode) with hybrid BM25 + vector retrieval
- Knowledge-augmented chat: inject retrieved context into model prompts with one toggle
- RK3588-tested presets for fast daytime use and stronger overnight use
- explicit no-thinking defaults for interactive serving, plus visible-response sanitation when models leak empty think wrappers anyway
llama-webui/
├── README.md
├── AGENTS.md
├── CONTRIBUTING.md
├── REAP_RK3588_NOTES.md
├── WINDOWS_SETUP_GUIDE.md
├── SETUP_MISSING_COMPONENTS.md
├── .env.example
├── pyproject.toml
├── docs/
│ ├── architecture.md
│ ├── hardware-portability.md
│ ├── openapi.json
│ ├── reap-roadmap.md
│ └── rk3588-benchmarks.md
├── models/
│ └── .gitkeep
├── data/
│ └── .gitkeep
├── scripts/
│ ├── build_llama_cuda.sh
│ ├── build_llama_cuda.ps1
│ ├── configure_env.ps1
│ ├── reap_bakeoff.py
│ ├── reap_benchmark.py
│ ├── reap_status.sh
│ ├── run_reap_pipeline.sh
│ └── setup_windows.ps1
├── src/llama_webui/
│ ├── knowledge/ # RAG pipeline (DB, chunker, embedder, retriever, ingest)
│ └── ...
└── static/
Runtime artifacts under data/, downloaded models under models/, and local virtual environments are intentionally ignored by git.
- Clone the repo and enter it.
- Build
llama.cpp. - Download at least one GGUF into
./models,~/models, or a path listed inLLAMA_WEBUI_MODEL_DIRS. - Install and run:
git clone https://github.com/SergiioB/llamacpp-workbench.git
cd llamacpp-workbench
./scripts/build_llama_cuda.sh
uv venv
source .venv/bin/activate
uv pip install -e .
llama-webui- Run the setup script:
# Build from source
.\scripts\setup_windows.ps1
# Or use prebuilt binaries
.\scripts\setup_windows.ps1 -UsePrebuilt- Configure environment variables if needed:
.\scripts\configure_env.ps1 -CreateEnvFile- Start the app:
.venv\Scripts\Activate.ps1
llama-webuiSee WINDOWS_SETUP_GUIDE.md and SETUP_MISSING_COMPONENTS.md for the Windows flow and dependency troubleshooting.
Open http://<host>:8095.
For the exact Windows-to-Windows launch checklist and PowerShell helpers, use docs/rpc-remote-host-runbook.md.
The WebUI can start llama-server either on one machine or with llama.cpp RPC
offload to another reachable device. In this mode there are two roles:
- Coordinator host: runs
llama-webuiand startsllama-server. - RPC worker host: runs
rpc-serverand exposes one accelerator or CPU backend over TCP.
The worker must already be running before the coordinator starts or loads a
model. The coordinator passes --rpc <host>:<port>, --split-mode layer, and
optionally --tensor-split to llama-server.
This mode has been validated for real Windows-to-Windows local workloads: a Windows desktop coordinator can drive a Windows laptop RPC worker on the same LAN, combining CUDA devices while keeping the WebUI as the single control surface.
Install or copy a compatible llama.cpp build onto the worker. Use the same llama.cpp build as the coordinator when possible; protocol mismatches can fail during model load.
On Windows, open PowerShell on the worker:
cd C:\path\to\llama.cpp\bin
.\rpc-server.exe -H 0.0.0.0 -p 50052 -cOn Linux, start the equivalent binary from the build directory:
cd /path/to/llama.cpp/build/bin
./rpc-server -H 0.0.0.0 -p 50052 -cThe worker log should print the endpoint, transport, and visible devices. For a CUDA worker, also check:
nvidia-smiIf the worker has a firewall enabled, allow inbound TCP on the selected port
(50052 in the examples). On Windows, the rule can be added from an elevated
PowerShell:
New-NetFirewallRule -DisplayName "llama.cpp RPC 50052" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 50052Only expose this port on a trusted LAN. llama.cpp RPC is an experimental internal transport, not an authenticated public API.
Open Settings in the WebUI and set:
Runtime -> Mode:RPC SplitRPC Host: the worker IP or DNS name, for example192.168.1.146Port: the worker port, for example50052Tensor Split: a comma-separated model-weight ratio, for example34,66
Then click Check in the RPC panel. This verifies TCP reachability before any
model is loaded.
After the RPC check passes, select a scanned model or preset and press Start
or Load Preset. During load, llama-server uploads tensors to the worker.
That upload can take a while and the worker may refuse extra TCP probes while
the active coordinator connection owns the RPC server. The WebUI treats a
managed healthy llama-server as authoritative instead of re-probing the busy
RPC port.
Tensor Split is a comma-separated ratio that controls how much model weight is
placed on each backend. It must match the coordinator device plus each RPC
device in order.
Examples:
50,50: roughly even split between local GPU and one RPC worker.34,66: keep less model weight on a 12 GB display GPU and more on the remote worker.70,30: keep more weight local when the worker has less available VRAM.
Tune the split against actual load success, free memory, prompt throughput, and
token throughput. If the worker OOMs or disconnects during set_tensor, reduce
the worker share or close competing GPU processes on the worker.
RPC mode uses --split-mode layer. Layer offload moves activations across the
network at layer boundaries and is the practical default for normal LAN links.
The default KV cache policy remains --flash-attn on --cache-type-k q8_0 --cache-type-v q8_0 so long-context serving keeps VRAM use predictable.
If Check RPC fails before model load, verify:
- the remote
rpc-serverprocess is running - the host/IP and port match the WebUI fields
- the firewall allows inbound TCP on the RPC port
- both devices are on the same network or otherwise routable
- the remote accelerator is visible to its local runtime, for example through
nvidia-smi,rocminfo,clinfo, or the vendor tool for that device
If the model starts loading but then the worker logs recv failed, restart the
worker rpc-server, stop the local llama-server, and try a smaller or more
conservative split. A half-loaded local llama-server can hold VRAM even after
the RPC worker died; use the WebUI Stop button or terminate that process
before relaunching.
If the model is already loaded and chat works, a direct TCP probe to the worker
may fail because the active llama-server connection is using the RPC server.
In that state, trust /api/server/status or the WebUI server indicator over a
standalone port probe.
For a Radxa ROCK 5B+ or other RK3588 board, the practical interactive baseline is:
Qwen3.5-2Bfor the fast tierQwen3.5-4Bwhen quality matters more than latency- explicit no-thinking flags for chat-style serving
rk-llama.cppwhere available for the better CPU path
The tracked board notes live in REAP_RK3588_NOTES.md.
┌─────────────────────────────────────────────────────────────┐
│ Browser (Client) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ llama-webui │ Chat UI │ Model Settings │ Logs │ │
│ └───────────────┴───────────┴──────────────────┴──────┘ │
└────────────────────────────┬────────────────────────────────┘
│ HTTP / SSE
┌────────────────────────────▼────────────────────────────────┐
│ FastAPI Server │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ Chat Router │ │Model Manager │ │Download Manager │ │
│ │ (SSE) │ │ │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ App State │ │ Settings │ │ Model Inventory │ │
│ │ (SQLite) │ │ (.env) │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
└────────────────────────────┬────────────────────────────────┘
│ Subprocess / IPC
┌────────────────────────────▼────────────────────────────────┐
│ llama.cpp (Binary) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │llama-server │ │ llama-cli │ │ Custom Flags │ │
│ │ (HTTP API) │ │ (Interactive)│ │ gpu_layers, ctx, │ │
│ │ │ │ │ │ threads, etc. │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────────────┘
The app is path-portable. Machine-specific paths are handled through environment-driven defaults.
Supported variables:
LLAMA_WEBUI_DATA_DIRLLAMA_WEBUI_MODEL_DIRSLLAMA_WEBUI_DEFAULT_DOWNLOAD_DIRLLAMA_WEBUI_LLAMA_SERVERLLAMA_WEBUI_LLAMA_CLILLAMA_WEBUI_KNOWLEDGE_SOURCES
See .env.example for concrete examples.
Default behavior without overrides:
- Data directory:
./data - Model search roots:
./modelsand~/models - Default download target: first existing model root, otherwise
./models llama-serverandllama-cli: resolved from env, thenPATH, then common local build locations underthird_party/llama.cpp- Knowledge source paths: auto-discovered from
~/.pi,~/.claude,~/.codex,~/.factory,~/.local/share/opencode,~/.qwen/projects
./scripts/build_llama_cuda.sh
# Manual fallback
git clone https://github.com/ggerganov/llama.cpp.git third_party/llama.cpp
cd third_party/llama.cpp
mkdir build-cuda && cd build-cuda
cmake .. -DGGML_CUDA=ON -DCMAKE_BUILD_TYPE=Release -DLLAMA_BUILD_SERVER=ON -DLLAMA_BUILD_CLI=ON
cmake --build . --config Release -j$(nproc)# Recommended
.\scripts\setup_windows.ps1
# Build-only path
.\scripts\build_llama_cuda.ps1
# Prebuilt binaries
.\scripts\setup_windows.ps1 -UsePrebuilt -CudaVersion 12.4Prerequisites for Windows CUDA builds:
- Visual Studio 2022 Build Tools with the C++ desktop workload
- CUDA Toolkit 12.4 or later, with 12.8+ recommended for RTX 50-series
- CMake 3.18+
Tested on Ubuntu 24.04 with ROCm 6.4.4 and an RX 7800 XT (gfx1101).
# Prerequisites: ROCm 6.4+ installed and HSA_OVERRIDE_GFX_VERSION set if needed
git clone https://github.com/ggerganov/llama.cpp.git third_party/llama.cpp
cd third_party/llama.cpp
mkdir build-hip && cd build-hip
cmake .. \
-DGGML_HIP=ON \
-DAMDGPU_TARGETS=gfx1101 \
-DCMAKE_BUILD_TYPE=Release \
-DGGML_HIP_ROCWMMA_FATTN=ON \
-DGGML_HIP_GRAPHS=ON \
-DGGML_HIP_MMQ_MFMA=ON \
-DGGML_HIP_NO_VMM=ON
cmake --build . --config Release -j$(nproc)Key build flags explained:
GGML_HIP_ROCWMMA_FATTN=ON— FlashAttention via AMD matrix coresGGML_HIP_GRAPHS=ON— HIP graph capture for reduced launch overheadGGML_HIP_MMQ_MFMA=ON— RDNA3 MFMA matrix multiply kernelsGGML_HIP_NO_VMM=ON— Avoids virtual memory overhead on RDNA3
The binary resolves automatically from third_party/llama.cpp/build-hip/bin/ when ROCm is detected.
cd third_party/llama.cpp
mkdir build-rk-opt && cd build-rk-opt
cmake .. -DGGML_CPU_VULKAN=ON -DGGML_CPU_BLAS=ON -DCMAKE_BUILD_TYPE=Release -march=armv8.2a+dotprod
cmake --build . --config Release -j$(nproc)TurboQuant enables 3.5-bit quantization to fit larger models on 16GB GPUs with a better size-to-quality tradeoff than plain Q4 variants.
git clone https://github.com/turbo-tan/llama.cpp-tq3.git third_party/llama.cpp-tq3
cd third_party/llama.cpp-tq3
mkdir build && cd build
cmake .. -DGGML_CUDA=ON -DCMAKE_BUILD_TYPE=Release
cmake --build . --config Release -j$(nproc)| Backend | Detection | Default Settings |
|---|---|---|
| CUDA | nvidia-smi available |
gpu_layers=99, parallel=4, batch_size=512 |
| ROCm | AMD GPU vendor ID (0x1002) or rocm-smi |
gpu_layers=99, flash_attn=on, parallel=1, kv=q8_0/q8_0 |
| Metal | Apple Silicon | Managed by llama.cpp |
| CPU | Fallback | gpu_layers=0, parallel=1, batch_size=128 |
The detected backend affects default gpu_layers, parallel, batch_size, ubatch_size, model presets, and build-path priority for llama-server. ROCm detection checks /sys/class/drm/card*/device/vendor for the AMD vendor ID (0x1002), with a rocm-smi fallback.
- Board:
Radxa ROCK 5B+ - SoC:
Rockchip RK3588 - Architecture:
aarch64 - Total cores:
8 - RAM class: about
24 GiB - Tested models:
GLM-4.7-Flash-REAP-23B-A3B,Qwen3.5-2B,Qwen3.5-4B,Qwen3.5-9B
- OS: Windows 11
- CPU: Intel Core Ultra 9 285H
- GPU: NVIDIA GeForce RTX 5060 Laptop GPU plus Intel Arc 140T
- RAM: 32 GB
- CUDA: 12.8+ for Blackwell-class support
- OS: Ubuntu 24.04 LTS (headless)
- CPU: AMD Ryzen 7 3800X
- GPU: Sapphire RX 7800 XT 16GB (gfx1101, RDNA3)
- RAM: 16 GB DDR4
- ROCm: 6.4.4
- Access: Tailscale, sleeps 01:00-07:30
- Tested models:
Qwen3.6-35B-A3B(IQ3_XXS),GLM-4.7-REAP-23B(IQ4_XS),Qwen3-27B(Q4_K_M)
- Coordinator: Windows desktop running
llama-webuiandllama-server - Worker: Windows laptop running
rpc-server - Transport: trusted LAN TCP with
--rpc,--split-mode layer, and tuned--tensor-split - Workload class: serious interactive local inference, not only toy demos
See docs/rk3588-benchmarks.md and docs/hardware-portability.md.
Although validation is strongest on the ROCK 5B+, the project is not ARM-only. The UI works anywhere llama.cpp works, including:
- ARM SBCs running CPU-only inference
- Desktop Linux CPU-only systems
- NVIDIA CUDA hosts using GPU offload
- AMD ROCm hosts
- Apple Silicon systems
- Windows CUDA laptops and desktops
What changes per machine is not the app architecture, but the runtime tuning: gpu_layers, ctx_size, threads, parallel, batch_size, ubatch_size, and custom llama.cpp flags.
Model:
GLM-4.7-Flash-REAP-23B-A3B-Q3_K_M.gguf
Validated settings:
- CPU affinity:
4-7 - Threads:
4 - Parallel:
1 - Context:
202752 - Batch size:
128 - KV cache quantization:
--cache-type-k q8_0 --cache-type-v q4_0 - Thinking disabled:
--reasoning off --reasoning-budget 0 --reasoning-format none
Qwen3.5-2B-Q4_K_M.gguf
Reason:
- Best measured latency / throughput balance for interactive RK3588 CPU use
- Strong enough for chat, light coding, and day-to-day local work
Qwen3.5-4B-Q4_K_M.gguf
Reason:
- Slower than 2B on RK3588, but structurally better on harder prompts
- Better treated as a quality tier than as the universal default
Model:
Qwen3.6-35B-A3B-UD-IQ3_XXS.gguf(13 GB)- MoE: 35B total / 3B active per token
- IQ3_XXS — most aggressive quant that stays coherent; anything larger loses KV cache headroom for 128K
Validated settings:
- GPU layers:
99(full offload) - Flash attention:
ON(mandatory for 128K) - Context:
131072(128K) - Batch size:
512 - Micro batch:
128 - KV cache:
--cache-type-k q8_0 --cache-type-v q8_0(halves VRAM vs FP16) - Reasoning:
--reasoning off(10x fewer output tokens, higher benchmark scores) - Throughput: ~60 tok/s
Why it works:
- IQ quants crush K-quants on RDNA3: same model in Q3_K_L (14 GB) → 17 tok/s vs IQ4_XS (12.6 GB) → 60 tok/s
- MoE is bandwidth-bound, not compute-bound — power cap from 190W to 80W shows near-zero throughput loss
- GPU draws 56-81W during inference
Model:
Qwen3-27B-Q4_K_M.ggufor similar dense 27B
Validated settings:
- GPU layers:
99 - Flash attention:
ON - Context:
163840(160K) - Batch size:
512 - Micro batch:
128 - KV cache:
--cache-type-k q8_0 --cache-type-v q8_0
Context ceiling on 16GB:
- Dense 27B: 160K max (192K OOMs by only 505MB)
- MoE 35B/3B: comfortable at 128K
- MoE 26B/A4B (e.g. Gemma-4-26B-A4B): 256K possible with IQ2_M + Q4_0 KV
- IQ quants massively outperform K-quants on gfx1101 — the IQ decompression kernels are significantly better optimized for this architecture
- MoE inference is bandwidth-bound, not compute-bound — cutting power cap by >50% barely changes throughput
- Flash attention is mandatory for any context above ~32K on 16GB VRAM
--reasoning offon Qwen3.6 MoE gives 10x fewer output tokens for the same quality — worth it for always-on inference- KV cache q8_0/q8_0 is the sweet spot: halves VRAM vs FP16, better coherence than q4_0
- REAP-pruned MoE models deliver strong quality-per-size on constrained hardware
- Disabling reasoning scratchpad improved interactive latency materially on RK3588
- KV cache quantization mattered enough to keep enabled by default
- On this board, the best interactive profile came from better runtime tuning, not from enabling more model thinking
- Even with reasoning disabled server-side, some models can still leak empty
<think>wrappers, so user-visible response sanitation is still worth keeping
| Feature | Status |
|---|---|
| Web UI | ✅ Production-ready |
| Persistent chats | ✅ Production-ready |
| Model scanning/loading | ✅ Production-ready |
| Streaming responses | ✅ Production-ready |
| Benchmark helpers | ✅ Production-ready |
| Windows-to-Windows RPC split serving | ✅ Validated |
| RK3588-tuned presets | ✅ Production-ready |
| ROCm/RX 7800 XT presets | ✅ Production-ready |
| Windows setup flow | ✅ Available |
| Knowledge Base / RAG | ✅ Available |
| Knowledge-augmented chat | ✅ Available |
| Corpus ingestion (multi-source) | ✅ Available |
| Retrieval / memory pages | 🔜 Planned |
| Personalized REAP build | 🔜 Planned |
Contributions are welcome.
- Fork the repo
- Create a feature branch
- Run
ruff check . && mypy src/ - Submit a PR
See CONTRIBUTING.md for contribution guidance.
MIT