Model Descriptor reference
The model descriptor is the YAML applied by akka models apply to an inference cluster. It declares model deployments, the accelerators they run on, the secrets they need, and the hostnames that expose them. See Serving models for the tasks these resources support.
Two commands check a descriptor without deploying it:
akka models validate -f models.yaml
akka models apply -f models.yaml --dry-run
validate checks the file alone. --dry-run also checks it against the cluster and persists nothing.
Document envelope
A descriptor is a multi-document YAML file. Documents are separated by a line starting with ---, and every document carries the same four top-level fields.
| Field | Type | Description |
|---|---|---|
resource |
string required |
One of |
resourceVersion |
string required |
Must be |
metadata.name |
string required |
Resource name. See Naming rules. |
spec |
object required |
Shape depends on |
Specs are parsed strictly. An unrecognized field is an error rather than a value that is silently ignored, so a mistyped field name fails the file instead of quietly changing behavior.
Validation reports every problem it finds, not only the first.
Naming rules
metadata.name, served model names, adapter names, and accelerator references all follow the same rules:
-
lowercase alphanumeric characters and dashes, matching
[a-z0-9]([-a-z0-9]*[a-z0-9])? -
42 characters maximum
The cap is lower than the DNS label limit of 63 because the operator derives object names from yours by adding suffixes, and those derived names have to fit.
Apply order
Applying a descriptor writes resources in dependency order, so nothing refers to an object that does not exist yet:
-
Secrets
-
Accelerators
-
Cache volume claims, then model deployments
-
Inference routes
Routes come last because a route names deployments. A route applied before its models still works, because exposure resolves continuously rather than only at apply time.
Apply is authoritative for what it names. An existing resource has its spec set from the descriptor. Labels and annotations added by other tools are preserved, and the values in the descriptor win where both set the same key.
Two resources are never mutated once they exist:
-
Accelerators, whose shape is immutable on the server.
-
Cache volume claims, which may hold a pre-warmed cache. Most of a claim’s spec is immutable in any case.
Secret
Creates a secret on the inference cluster. Values are written as plain strings, which keeps the YAML readable.
resource: Secret
resourceVersion: v1
metadata:
name: hf-token
spec:
type: generic
data:
token: hf_xxxxxxxxxxxxxxxxxxxx
| Field | Type | Description |
|---|---|---|
spec.type |
string required |
Only |
spec.data |
map required |
At least one key. Keys match |
akka models export masks secret values with NOT EXPORTED. Applying an exported file unedited fails validation rather than overwriting a live secret with the mask. Replace the value, or delete the document and create the secret ahead of time.
Accelerator
An accelerator carves the platform’s device inventory into capacity a model deployment can be placed on. Devices are platform inventory, and an accelerator is how a project claims a slice of it. Run akka models devices list to see the devices available in a region.
resource: Accelerator
resourceVersion: v1
metadata:
name: l4-dedicated
spec:
device: l4
tenancy: dedicated
| Field | Type | Description |
|---|---|---|
spec.device |
string required |
Device kind from platform inventory, for example |
spec.tenancy |
string |
|
spec.devicesPerReplica |
integer |
Devices each replica claims. Defaults to |
spec.shared.maxModels |
integer |
How many models split one device. Required when tenancy is |
Dedicated tenancy
Each model gets whole devices. This is the default.
Setting devicesPerReplica above 1 requires a node holding that many devices, and the deployment’s parallelism factors have to multiply to exactly that number.
Shared tenancy
Several models split one device’s memory. Every model placed on a shared accelerator has to state its engine.memoryPercent. A member that does not declare its share is sized against the whole card and runs out of memory after a full weight download.
spec.shared is only valid when tenancy is shared, and maxModels has to be at least 2. One model per device is dedicated tenancy, not shared.
A shared accelerator cannot set devicesPerReplica above 1. It splits one device between models rather than claiming several.
resource: Accelerator
resourceVersion: v1
metadata:
name: l4-shared
spec:
device: l4
tenancy: shared
shared:
maxModels: 3
ModelDeployment
One serving engine running one model.
resource: ModelDeployment
resourceVersion: v1
metadata:
name: agent
spec:
model: google/gemma-3-4b-it
servedModelName: agent
replicas: 1
placement:
accelerator: l4-dedicated
engine:
maxModelLen: 16384
memoryPercent: 90
| Field | Type | Description |
|---|---|---|
spec.model |
string required |
Checkpoint to serve, for example |
spec.servedModelName |
string |
Name clients send in the OpenAI |
spec.replicas |
integer |
Engine count, minimum 1. Each replica needs its own device. |
spec.placement.accelerator |
string required |
Accelerator to run on. |
There is no path that lets the scheduler pick the hardware. placement.accelerator is required because the hardware a model runs on is part of how it behaves, and a model that lands on whatever device is free has its performance decided by the scheduler. The first sign of that is a latency change nobody asked for.
spec.engine
| Field | Type | Description |
|---|---|---|
maxModelLen |
integer |
Maximum context length, prompt and output combined. |
memoryPercent |
integer |
Share of device memory the engine may use, 1 to 100. |
quantization |
string |
|
textOnly |
boolean |
Drop the vision tower on a multimodal checkpoint. |
checkpointFormat |
string |
|
toolCalling.enabled |
boolean |
Enable function calling. |
toolCalling.parser |
string |
Parser for the model’s tool-call syntax. |
Always set maxModelLen explicitly. Some checkpoints declare a default of 262144, and the engine sizes a KV cache for it.
memoryPercent is required when the deployment is placed on a shared accelerator, where it has to fit inside the model’s share of the device.
textOnly returns the vision tower’s memory to the KV cache. The engine then cannot accept images at all, so it is only correct for a multimodal checkpoint used for text.
checkpointFormat: mistral selects the Mistral-native tokenizer, config, and weight formats. Without it, a Mistral-native checkpoint is read along the standard path and its files are parsed incorrectly. It is never inferred from the model name.
toolCalling.parser is required when enabled is true, and cannot be set when it is false. Valid names come from the serving engine the platform pins rather than from the CLI, so the value is only checked for shape: lowercase alphanumeric with dashes or underscores. Common values are pythonic, mistral, and hermes.
Choose the parser deliberately. The engine does not verify that a parser matches the model, and the wrong one starts healthy and returns tool calls as prose.
spec.parallelism
| Field | Type | Description |
|---|---|---|
tensor |
integer |
Splits the model across devices on one node. |
pipeline |
integer |
Splits layers, and may cross nodes. |
data |
integer |
Runs independent copies of the tensor-parallel group. |
The factors multiply to the number of devices one replica uses. Unset factors count as 1. When the accelerator sets devicesPerReplica above 1, the product has to equal it exactly.
spec.adapters
LoRA adapters served from the base model. Each adapter is addressable as its own model name, so one deployment can answer to several names.
adapters:
- name: agent-support
path: s3://acme-adapters/support/
| Field | Type | Description |
|---|---|---|
name |
string required |
Model name clients use. Must be unique and must not collide with |
path |
string required |
URI with a scheme, for example |
Which schemes can be fetched is the operator’s decision, so the CLI only checks that a scheme is present.
spec.source
Where weights come from and how they are cached.
source:
huggingFaceTokenSecret: hf-token/token
cache:
enabled: true
size: 100Gi
| Field | Type | Description |
|---|---|---|
huggingFaceTokenSecret |
string |
Reference in |
cache.enabled |
boolean |
Persist weights and compiled artifacts across restarts. |
cache.size |
string |
Volume size, required when the cache is enabled. |
cache.size is a Kubernetes quantity, for example 100Gi. An ephemeral cache pays the compilation cost on every restart.
The referenced secret has to be declared in the same descriptor or already exist in the namespace. Apply checks this before writing anything.
InferenceRoute
Exposes model deployments on a hostname.
The unit is the hostname, not the deployment. One host serves many models, and clients choose between them with the model field of the request body, so a single base URL works with any OpenAI SDK.
resource: InferenceRoute
resourceVersion: v1
metadata:
name: acme
spec:
host: models.acme.example.com
models:
- name: agent
- name: docs
client = OpenAI(base_url="https://models.acme.example.com/v1")
client.chat.completions.create(model="agent", ...)
client.chat.completions.create(model="docs", ...)
| Field | Type | Description |
|---|---|---|
spec.host |
string required |
Hostname already registered on the project. |
spec.models[].name |
string required |
Name of a |
Two projects may both serve a model called agent. Their hostnames differ, so served names do not need to be globally unique.
The names clients send are the deployments' own served names, adapters included, so one models entry can answer to several names.
Registering a hostname is a separate step, with DNS verified and a certificate issued. The CLI checks only that spec.host looks like a hostname. Whether the project owns it is the platform’s answer, so a descriptor that validates locally can still be refused on the cluster with host is not configured on project.
A hostname the platform generated needs nothing further. A hostname you supplied carries its own certificate and gets its own listener.
Cross-document rules
Checked across the whole file:
-
Names must not repeat within a resource kind.
-
Served model names must not collide across deployments, counting adapter names. Requests for a duplicated name would be ambiguous.
-
A deployment placed on a shared accelerator declared in the same file has to set
engine.memoryPercent. -
A deployment’s parallelism factors have to multiply to the accelerator’s
devicesPerReplicawhen that is above 1.
Placement rules are only checked in the file when the accelerator is declared there too. An accelerator that exists only on the cluster is checked at apply time.
What apply checks against the cluster
Before writing anything, apply verifies:
-
Served model names do not collide with deployments already in the namespace that are not part of this descriptor.
-
Every referenced secret is declared in the descriptor or already exists.
-
Every referenced accelerator is declared in the descriptor or already exists.
These need the cluster, so akka models validate cannot do them. Use --dry-run to run them without persisting.
Complete example
resource: Secret
resourceVersion: v1
metadata:
name: hf-token
spec:
type: generic
data:
token: hf_xxxxxxxxxxxxxxxxxxxx
---
resource: Accelerator
resourceVersion: v1
metadata:
name: l4-dedicated
spec:
device: l4
tenancy: dedicated
---
resource: ModelDeployment
resourceVersion: v1
metadata:
name: agent
spec:
model: google/gemma-3-4b-it
servedModelName: agent
replicas: 1
placement:
accelerator: l4-dedicated
engine:
maxModelLen: 16384
memoryPercent: 90
toolCalling:
enabled: true
parser: pythonic
source:
huggingFaceTokenSecret: hf-token/token
cache:
enabled: true
size: 100Gi
---
resource: InferenceRoute
resourceVersion: v1
metadata:
name: acme
spec:
host: models.acme.example.com
models:
- name: agent
Resources that belong elsewhere
Devices cannot be created from a descriptor. They are platform inventory. See Reviewing available hardware.
|
The features described in this section are an add-on to Akka Automated Operations. They are not included in the base product. |