Sign inSign up

emmaylots/prismml-llama-bonsai

By emmaylots

•Updated 8 days ago

Ollama-style server for PrismML ternary Bonsai 2 LLMs + any HF GGUF. CUDA & CPU, OpenAI API

Image
Machine learning & AI
0

520

emmaylots/prismml-llama-bonsai repository overview

⁠prismml-llama-bonsai

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.

⁠Tags

tagforsize
latest, cuda, 0.2.0-cudaNVIDIA GPUs, Turing → Blackwell (RTX 20xx–50xx), CUDA 12.83.7 GB
cpu, 0.2.0-cpuany x86-64 CPU (picks AVX/AVX2/AVX-512 kernels at runtime)170 MB

0.2.0 bundles llama.cpp fork release prism-b10777-e3de715.

⁠Quick start (NVIDIA)

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."}]
}'

⁠docker compose

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)

⁠Using pllama from other containers

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.

⁠Commands

commanddoes
pllama cataloglist known short names
pllama pull NAMEdownload from Hugging Face (resumable, multi-shard, vision projector included)
pllama list / pllama psinstalled models / models in memory
pllama run NAME [prompt]chat; --no-think, --hidethinking, --verbose (timings)
pllama load / unload NAMEpin into memory / free it
pllama rm NAMEdelete
pllama show NAMEeffective llama-server settings
pllama config NAME key=valueper-model overrides, e.g. ctx-size=40960
pllama bench NAMEprompt and generation tok/s

⁠Models

namewhat you get
bonsai2:2b :4b :9b :27bbest 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-mtp9B 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).

⁠Measured on an RTX 5050 (8 GB)

q8_0 KV cache, 32K context, 233-token prompt, 128 tokens generated:

modelVRAMpromptgeneration
bonsai2:4b2.6 GB2,169 tok/s141 tok/s
bonsai2:9b3.9 GB1,479 tok/s88 tok/s
bonsai2:9b-mtp4.7 GB1,200 tok/s108 tok/s
bonsai2:27b (PTQ1_0)7.0 GB487 tok/s41 tok/s

The 27B runs at full speed up to about 40K context on 8 GB.

⁠Configuration

All settings are environment variables. The defaults are tuned for a single GPU.

variabledefaultmeaning
PLLAMA_KEEP_ALIVE-1-1 keeps models loaded forever; 300, 5m, 2h unload after that much idle time
PLLAMA_MAX_LOADED1models resident at once; the least recently used is evicted
PLLAMA_PRELOAD–comma list, pulled and loaded at startup
PLLAMA_CTX32768context per model (Bonsai 2 supports up to 262144)
PLLAMA_KV_CACHEq8_0KV cache type: f16, q8_0, q4_0 (q8_0 = half the memory of f16, about the same speed)
PLLAMA_PARALLEL1concurrent request slots per model
PLLAMA_NGLauto (GPU)layers on the GPU; auto fits as many as VRAM allows
PLLAMA_FIT_TARGET256MiB of VRAM the auto-fit leaves free (raise it if a desktop shares the GPU)
PLLAMA_AUTO_QUANT10 = bare names always use PQ2_0
PLLAMA_VRAM_GBdetectedVRAM to plan the packing choice for
PLLAMA_MLOCK0lock weights in RAM (needs --ulimit memlock=-1:-1)
PLLAMA_THINKING10 disables thinking server-wide
PLLAMA_REASONING_EFFORT–medium for shorter reasoning
PLLAMA_MMPROJ_OFFLOADautovision 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.

⁠Changelog

  • 0.2.0: renamed: the command is now 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.
  • 0.1.1: model commands accept the IDs ps prints (bonsai2/4b as well as bonsai2:4b).
  • 0.1.0: first release.

⁠Security

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.

Tag summary

Content type

Image

Digest

sha256:6d7638626…

Size

2.2 GB

Last updated

8 days ago

docker pull emmaylots/prismml-llama-bonsai