Ollama-style server for PrismML ternary Bonsai 2 LLMs + any HF GGUF. CUDA & CPU, OpenAI API
520
Ships the pllama command-line tool, so commands below read pllama pull, pllama run and so on.
Run PrismML's ternary Bonsai 2 LLMs, or any GGUF from Hugging Face, with an Ollama-style CLI and an OpenAI-compatible API.
Bonsai 2 packs its weights into about 1.75–2.13 bits each, so Bonsai 2 27B is 6–7 GB instead of ~54 GB. It fits
on an 8 GB GPU with vision, tool calling and thinking intact. pllama wraps
PrismML's llama.cpp fork, which is needed for the PQ2_0 / PTQ1_0
packings, in llama-server router mode. One endpoint serves many models, loads them on demand,
evicts the least recently used one, and keeps models in memory forever or unloads them when idle.
| tag | for | size |
|---|---|---|
latest, cuda, 0.2.0-cuda | NVIDIA GPUs, Turing → Blackwell (RTX 20xx–50xx), CUDA 12.8 | 3.7 GB |
cpu, 0.2.0-cpu | any x86-64 CPU (picks AVX/AVX2/AVX-512 kernels at runtime) | 170 MB |
0.2.0 bundles llama.cpp fork release prism-b10777-e3de715.
Requirements: NVIDIA driver ≥ 570 (the image is built on CUDA 12.8), plus the NVIDIA Container Toolkit.
docker run -d --name pllama --gpus all --restart unless-stopped \
-p 127.0.0.1:11435:8080 -v pllama-models:/models \
emmaylots/prismml-llama-bonsai:cuda
docker exec pllama pllama pull bonsai2:27b # picks the packing that fits your VRAM
docker exec -it pllama pllama run bonsai2:27b # interactive chat
CPU only: use emmaylots/prismml-llama-bonsai:cpu and drop --gpus all.
API: http://localhost:11435/v1 (OpenAI-compatible: chat, completions, tool calls, image input).
Web UI: http://localhost:11435/. Open WebUI: add an OpenAI connection with that /v1 URL.
curl http://localhost:11435/v1/chat/completions -H 'Content-Type: application/json' -d '{
"model": "bonsai2:27b",
"messages": [{"role": "user", "content": "Explain ternary weights in two sentences."}]
}'
services:
pllama:
image: emmaylots/prismml-llama-bonsai:cuda
container_name: pllama
networks: [pllama]
restart: unless-stopped
ports: ["127.0.0.1:11435:8080"] # "0.0.0.0:11435:8080" to expose on your LAN (set an API key!)
volumes: ["./models:/models"]
ulimits: { memlock: { soft: -1, hard: -1 } }
env_file: .env # HF_TOKEN=..., PLLAMA_API_KEY=..., etc.
environment:
PLLAMA_PRELOAD: bonsai2:27b # pull + load at startup
PLLAMA_KEEP_ALIVE: "-1" # keep in VRAM forever
deploy:
resources:
reservations:
devices: [{ driver: nvidia, count: all, capabilities: [gpu] }]
networks:
pllama:
name: pllama # fixed name other projects can join (see below)
The compose files put pllama on a Docker network with the fixed name pllama.
Containers on that network reach it by name, on the container port:
http://pllama:8080/v1 # not 11435: that port only exists on the host
The 127.0.0.1:11435 host binding has no effect on this; it only controls access from the host.
Containers not on the network can't resolve pllama, and host.docker.internal:11435 fails
too, because the host port listens on 127.0.0.1 only.
To connect a container from another compose project, join the network as external. For example, Open WebUI:
# open-webui/docker-compose.yml
services:
open-webui:
image: ghcr.io/open-webui/open-webui:main
ports: ["127.0.0.1:3000:8080"]
volumes: ["open-webui:/app/backend/data"]
environment:
OPENAI_API_BASE_URL: http://pllama:8080/v1
OPENAI_API_KEY: ${PLLAMA_API_KEY:-none} # match PLLAMA_API_KEY if you set one
ENABLE_OLLAMA_API: "false"
networks: [default, pllama]
volumes:
open-webui:
networks:
pllama:
external: true # start pllama first: it creates the network
From a plain docker run: docker run --network pllama ....
Every container on the network can call pllama without logging in unless PLLAMA_API_KEY is set.
| command | does |
|---|---|
pllama catalog | list known short names |
pllama pull NAME | download from Hugging Face (resumable, multi-shard, vision projector included) |
pllama list / pllama ps | installed models / models in memory |
pllama run NAME [prompt] | chat; --no-think, --hidethinking, --verbose (timings) |
pllama load / unload NAME | pin into memory / free it |
pllama rm NAME | delete |
pllama show NAME | effective llama-server settings |
pllama config NAME key=value | per-model overrides, e.g. ctx-size=40960 |
pllama bench NAME | prompt and generation tok/s |
| name | what you get |
|---|---|
bonsai2:2b :4b :9b :27b | best packing for your GPU: PQ2_0 if it fits in VRAM, else PTQ1_0 |
bonsai2:27b-pq2, bonsai2:27b-ptq1 … | a specific packing, always |
bonsai2:9b-mtp | 9B with a multi-token-prediction head: +24% generation speed, same output |
hf.co/<user>/<repo>:<QUANT> | any GGUF repo, e.g. hf.co/unsloth/gemma-3-4b-it-GGUF:Q4_K_M |
Bonsai models come from prism-ml on Hugging Face (Apache 2.0).
q8_0 KV cache, 32K context, 233-token prompt, 128 tokens generated:
| model | VRAM | prompt | generation |
|---|---|---|---|
| bonsai2:4b | 2.6 GB | 2,169 tok/s | 141 tok/s |
| bonsai2:9b | 3.9 GB | 1,479 tok/s | 88 tok/s |
| bonsai2:9b-mtp | 4.7 GB | 1,200 tok/s | 108 tok/s |
| bonsai2:27b (PTQ1_0) | 7.0 GB | 487 tok/s | 41 tok/s |
The 27B runs at full speed up to about 40K context on 8 GB.
All settings are environment variables. The defaults are tuned for a single GPU.
| variable | default | meaning |
|---|---|---|
PLLAMA_KEEP_ALIVE | -1 | -1 keeps models loaded forever; 300, 5m, 2h unload after that much idle time |
PLLAMA_MAX_LOADED | 1 | models resident at once; the least recently used is evicted |
PLLAMA_PRELOAD | – | comma list, pulled and loaded at startup |
PLLAMA_CTX | 32768 | context per model (Bonsai 2 supports up to 262144) |
PLLAMA_KV_CACHE | q8_0 | KV cache type: f16, q8_0, q4_0 (q8_0 = half the memory of f16, about the same speed) |
PLLAMA_PARALLEL | 1 | concurrent request slots per model |
PLLAMA_NGL | auto (GPU) | layers on the GPU; auto fits as many as VRAM allows |
PLLAMA_FIT_TARGET | 256 | MiB of VRAM the auto-fit leaves free (raise it if a desktop shares the GPU) |
PLLAMA_AUTO_QUANT | 1 | 0 = bare names always use PQ2_0 |
PLLAMA_VRAM_GB | detected | VRAM to plan the packing choice for |
PLLAMA_MLOCK | 0 | lock weights in RAM (needs --ulimit memlock=-1:-1) |
PLLAMA_THINKING | 1 | 0 disables thinking server-wide |
PLLAMA_REASONING_EFFORT | – | medium for shorter reasoning |
PLLAMA_MMPROJ_OFFLOAD | auto | vision projector in VRAM; moved to RAM automatically for models over 60% of VRAM |
PLLAMA_API_KEY | – | require Authorization: Bearer <key> |
PLLAMA_EXTRA_ARGS | – | extra llama-server flags for every model |
HF_TOKEN | – | for gated or private Hugging Face repos |
Sampling defaults follow each model card. Any field sent in a request overrides them.
pllama, the container and network are pllama, and settings are PLLAMA_*.
Old XOLLAMA_* variables are not read; a startup warning names each one to rename. Models need no migration.ps prints (bonsai2/4b as well as bonsai2:4b).The server has no authentication unless you set PLLAMA_API_KEY. Keep the port on 127.0.0.1
or set a key before you publish it to a network.
Content type
Image
Digest
sha256:6d7638626…
Size
2.2 GB
Last updated
8 days ago
docker pull emmaylots/prismml-llama-bonsai