Showcase: serving MiniCPM5-1B¶
This walkthrough takes one real model — openbmb/MiniCPM5-1B,
quantized to Q8_0 — and serves it as a running inference server on a GPU
using nothing but a docker login selector and a docker pull.
This is model-centric pull: you pull a model (models/qnib/minicpm5:q8-0)
under a hardware profile, and MetaHub composes a ready-to-run image server-side —
the right runtime for your GPU, the model weights, and a per-profile serving
config, stacked into one image. The model is the image; there is no base
image to choose and nothing to assemble by hand.
The model here was served on a Strix Halo box (AMD Ryzen AI MAX+ 395 /
Radeon 8060S, gfx1151, 124 GB usable VRAM) via a ROCm llama.cpp runtime — but
nothing in the user flow is hardware-specific: the same pull + run composes
the model for whatever profile asked for it.
What makes up the showcase¶
| Piece | Identity | Role |
|---|---|---|
| Model | models/qnib/minicpm5:q8-0 |
pulled directly; composed per requesting profile |
| Runtime | collection qnib/llama-server |
resolves the vendor image (rocm / cuda / …) for the profile |
| Weights | q8-0 GGUF |
the model-layer image, stacked in as a layer |
| Config | serve.json |
per-profile serving config (llama-server flags) |
| Profile | frame |
the Strix Halo tier; selected at login as meta/frame |
1. How it was made available (operator)¶
A one-time setup wires the model into MetaHub. The GGUF is brought in as an ORAS
artefact, then repackage turns it into a model-layer image and wires it under
the frame profile, bound to the qnib/llama-server runtime collection (which
resolves the ROCm image for frame):
# 1. bring the GGUF into MetaHub as an ORAS artefact
oras cp harbor.lab.hvk/library/models/minicpm5:q8-0 \
"metahub-registry.org/models/minicpm5:q8-0"
# 2. repackage it into a model-layer image + wire it under the `frame` profile,
# bound to the qnib/llama-server runtime collection
metahub-admin --config ./config.yaml repackage \
--artifact-repo models/minicpm5 \
--artifact-type application/vnd.qnib.model.artifact \
--name qnib/minicpm5 \
--quant-tag q8-0 \
--profile frame \
--runtime qnib/llama-server
Note
The runtime is a profile-resolved collection now (collections/qnib/llama-server),
not a registered runtime — there is no runtime register step. The collection
picks the vendor image (rocm for frame, cuda for an NVIDIA tier, …) at serve
time. In the community edition the model and collection are declared as files
(models/qnib/minicpm5 + collections/qnib/llama-server) and seeded by parse.
2. Pull the model under your profile (user)¶
As with every MetaHub feature, the profile comes from the login credential —
meta/frame (password hub) selects the frame (Strix Halo) profile. Pulling
the model tag returns the image MetaHub composed for that profile:
$ docker login -u 'meta/frame' metahub-registry.org
Password: hub
Login Succeeded
$ docker pull metahub-registry.org/models/qnib/minicpm5:q8-0
$ docker inspect metahub-registry.org/models/qnib/minicpm5:q8-0
"RootFS": {
"Layers": [
"sha256:1a2b3c...", // runtime base (ROCm llama.cpp) — resolved from the qnib/llama-server collection for `frame`
"sha256:c0ffee...", // model layer → /model/qnib/minicpm5/minicpm5-1b-Q8_0.gguf
"sha256:c02f19..." // config layer → /model/qnib/minicpm5/config/serve.json
]
}
MetaHub composed this image server-side for the frame profile: the ROCm
runtime + the q8-0 weights + the per-profile config, stacked additively.
Pull under a plain meta login (no profile) and there is nothing runnable — the
model only resolves under a profile whose hardware can serve it.
3. Run it — the runtime serves the model on the GPU¶
The composed image's entrypoint discovers the GGUF under /model/<org>/<name>/,
reads the injected config dir ($QNIB_MODEL_CONFIG_DIR), and serves an
OpenAI-compatible API on port 8080. The runtime is already baked into the image
MetaHub composed for your profile — ROCm for frame, CUDA for bazzite — so only
the GPU-passthrough flags differ per host:
Pulled under meta/frame; the AMD GPU is handed in with the KFD/DRI devices:
$ docker run --rm -p 8080:8080 \
--device /dev/kfd --device /dev/dri \
metahub-registry.org/models/qnib/minicpm5:q8-0
>> MetaHub runtime: serving injected model /model/qnib/minicpm5/minicpm5-1b-Q8_0.gguf
>> injected config dir: /model/qnib/minicpm5/config
ggml_cuda_init: found 1 ROCm device: Radeon 8060S Graphics (gfx1151)
llama_model_loader: loaded meta data ... general.name = MiniCPM5 1B
main: server listening on http://0.0.0.0:8080
The same q8-0 tag, pulled under meta/bazzite — MetaHub composed the
CUDA llama.cpp runtime (sm_86, 12 GiB tier) instead of ROCm. The NVIDIA GPU
is handed in with --gpus all:
$ docker run --rm -p 8080:8080 \
--gpus all \
metahub-registry.org/models/qnib/minicpm5:q8-0
>> MetaHub runtime: serving injected model /model/qnib/minicpm5/minicpm5-1b-Q8_0.gguf
>> injected config dir: /model/qnib/minicpm5/config
ggml_cuda_init: found 1 CUDA device: NVIDIA GeForce RTX 3060 (sm_86)
llama_model_loader: loaded meta data ... general.name = MiniCPM5 1B
main: server listening on http://0.0.0.0:8080
The model path, GPU offload (-ngl 99), host and port are all set by the
runtime's entrypoint — the user supplies none of them. The one model tag resolves
to a different runtime image per profile: each vendor image is pinned to its
profile in the qnib/llama-server collection, so frame gets the ROCm build and
bazzite gets the CUDA build — never the other way round.
4. Query the endpoint¶
Once healthy, hit the completion endpoint:
$ curl -s localhost:8080/health
{"status":"ok"}
$ curl -s localhost:8080/completion \
-H 'Content-Type: application/json' \
-d '{"prompt":"Q: What is the capital of France? A:","n_predict":24,"temperature":0.1}'
{
"content": " Paris",
"model": "/model/qnib/minicpm5/minicpm5-1b-Q8_0.gguf",
"stop": true,
"tokens_predicted": 18
}
The same server answers the OpenAI-style route too, so existing clients work unchanged:
curl -s localhost:8080/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{"messages":[{"role":"user","content":"Name three primary colors."}]}'
5. Confirm it ran on the GPU¶
The server log names the backend it loaded — for the Strix Halo box, the ROCm
device and gfx1151 architecture:
$ docker logs <container> | grep -iE 'gfx1151|ROCm|radeon'
ggml_cuda_init: found 1 ROCm device: Radeon 8060S Graphics (gfx1151)
With all layers offloaded (-ngl 99), MiniCPM5-1B-Q8_0 serves at interactive
speed — on the order of ~140 tokens/second on the Radeon 8060S.
What you see in the UI¶
| Concept | Where it shows up |
|---|---|
| The model | the Models tab — a qnib/minicpm5 card with its q8-0 variant and the frame profile |
| Its compositions | the card's compositions — the runnable qnib/llama-server + q8-0 + config bundle, derived from the model's referrers |
| The source artefact | Artefacts, as models/qnib/minicpm5, linked from the card via its OCI subject reference |
| The composed layers | expand models/qnib/minicpm5 under the frame profile — runtime base + the model layer + the config layer |
Note
The GGUF is stored once and shared across every profile that composes it — serving MiniCPM5 for two different profiles does not duplicate the weights in object storage.
Recap¶
# operator (once)
oras cp … models/minicpm5:q8-0
metahub-admin repackage --name qnib/minicpm5 --quant-tag q8-0 --profile frame --runtime qnib/llama-server
────────────────────
# user
docker login -u 'meta/frame' # select the profile
docker pull …/models/qnib/minicpm5:q8-0 # composed for your profile
docker run --device /dev/kfd --device /dev/dri -p 8080:8080 …/models/qnib/minicpm5:q8-0
curl localhost:8080/completion … # served on the GPU
One pull under your profile, and the model lands — sized, composed, and served — on whatever host asked for it.