Serve source-defined models¶
loom-serve runs text, image, embedding, decision and speech models in one HTTP server.
Models are runtime inputs: a JSON deployment document, Loom programs and assets.
Registering a compatible package does not require rebuilding the executable.
The process can start empty and keep serving while models are added or removed.
This walkthrough produces an independently checkable embedding response on an
x86 CPU. The example performs arithmetic, not learned inference; it exercises
the real JIT, device execution, batching and HTTP path without downloading weights.
It requires an installed loom-serve with the CPU target and task HAL enabled,
plus curl and jq. Acquiring Loom
describes obtaining the tools.
Start with no models¶
Leave this process running and use another terminal for the requests below.
The JSON ready record on stderr reports the bound address. It means the HTTP
server is accepting connections, not that any model has finished preparation.
curl --fail --silent --show-error http://127.0.0.1:8080/readyz
curl --fail --silent --show-error http://127.0.0.1:8080/v1/models
The first response is {"status":"ready"}; the second has an empty data
array. Device selection is explicit. task executes native x86 kernels using
the shared CPU workers; it does not emulate a GPU. This example uses fixed
retained backing. The command reference
describes device and memory choices, including the distinction between HAL VMM
support and serving's elastic-pool integration.
Obtain the example package¶
The maintained embedding example contains six files. Download them into a new directory on the server machine:
mkdir vectors
source_url=https://raw.githubusercontent.com/ROCm/hrx-system/main/loom/src/loom/serve/fixture/embedding
for name in model.json prepare.loom control.loom config.loom embed.loom tokenizer.json; do
curl --fail --silent --show-error --location "$source_url/$name" --output "vectors/$name"
done
model.json gives the deployment the public name vectors. It names the cold
preparation program, warm control program, native source providers and asset
directory. The tokenizer recognizes a, b and x; the example's output is
deliberately simple enough to check without another inference framework.
Register and execute¶
Registration takes the same model document
accepted by --model. An HTTP document needs an absolute base_directory for
relative file references. That directory is on the server, not the client.
jq --arg directory "$(pwd)/vectors" '. + {base_directory: $directory}' vectors/model.json |
curl --fail --silent --show-error http://127.0.0.1:8080/v1/models/register \
-H 'Content-Type: application/json' --data-binary @-
curl --fail --silent --show-error http://127.0.0.1:8080/v1/embeddings \
-H 'Content-Type: application/json' \
-d '{"model":"vectors","input":["a","bbb"],"dimensions":2}' |
jq '{data: [.data[] | {index, embedding}], usage}'
Registration returns HTTP 202 for accepted intent. Preparation and JIT run asynchronously; the inference request can wait for readiness within the server's bounded admission capacity. The response contains these vectors, in input order, and accounts for four prompt tokens:
{
"data": [
{"index": 0, "embedding": [1, 1]},
{"index": 1, "embedding": [6, 3]}
],
"usage": {"prompt_tokens": 4, "total_tokens": 4}
}
The two components are the sum of token_id + 1 and the token count.
a has ID 0 and b has ID 1. The package executes two native kernels and
restores the request's row ordering after producing rows in reverse order.
Inspect and remove¶
curl --fail --silent --show-error http://127.0.0.1:8080/v1/status
curl --fail --silent --show-error http://127.0.0.1:8080/metrics
curl --fail --silent --show-error http://127.0.0.1:8080/logz \
-H 'X-Loom-Model: vectors'
curl --fail --silent --show-error http://127.0.0.1:8080/v1/models/drain \
-H 'Content-Type: application/json' -d '{"model":"vectors"}'
curl --fail --silent --show-error http://127.0.0.1:8080/v1/models/unregister \
-H 'Content-Type: application/json' -d '{"model":"vectors","mode":"drain"}'
Drain closes admission while accepted requests finish. New inference waits
within the holding budget until undrain, or fails if that budget is full.
Unregister is different: it removes the registration after accepted work and
resource borrowers retire. Its HTTP 202 acknowledges the removal request;
/v1/status shows progress until the name disappears. Other models and the
server remain alive. Ctrl-C in the server terminal stops admission and joins
accepted work before process teardown.
Use your own package¶
An existing package can be registered at startup instead:
loom-serve --device=task --pool_backing=fixed \
--model=/srv/models/vectors/model.json \
--model=/srv/models/scout/model.json
Each package must provide programs for the chosen device and the source
interface of the installed server. A checkpoint alone is not a model package.
Text and portable bytecode (.loom and .loombc) can be mixed; both still JIT
for the selected live device. Provider dependencies are resolved by Loom's
symbol linker, not by a native list of model layers.
The model-document reference explains path binding, source roles and modality capacities. The command reference covers device groups, multiple TCP/Unix listeners and process limits. Operation and observation cover model swapping, pressure, counters and log streams. HTTP administration and model loading assume trusted clients and programs; deployment-owned isolation or tunnels supply any access-control boundary.
HTTP profiles enumerate the supported request fields, raw tokenizer utilities and retained-text checkpoint controls. Connect model clients configures Pi, Oh My Pi and Open WebUI against the mixed catalog without changing those clients. Stream speech demonstrates incremental audio, concurrent voices and playback through the speech profile. Author serving model packages traces the source, parameter and result ownership needed to replace the example's math. Develop models on a live server connects kernel checks and benchmarks to source uploads, retained-checkpoint comparisons and native executable selection without reloading weights.