An empty launch_mode meant ray: a Ray head and joins on every node, a dependency to install, and a path never checked against a real cluster. It now means mp - every node runs vllm serve with its rank and the leader's address, the workers headless - which is how vLLM documents a multi-node launch today and needs nothing but vLLM. ray is still there for a vLLM too old for mp's flags. The example agent configuration, doctor and the reference say so. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1368 lines
32 KiB
Markdown
1368 lines
32 KiB
Markdown
# Configuration reference
|
|
|
|
Every setting llmgw reads from a file, with the type it takes and what it is
|
|
for.
|
|
|
|
**Generated from the source.** The descriptions are the comments on the fields
|
|
themselves, so this cannot describe a setting that does not exist or miss one
|
|
that does — and a test fails when it has drifted. Do not edit it; edit the
|
|
comment and run `go generate ./...`.
|
|
|
|
Where a setting takes another block, the block is listed under its own heading
|
|
rather than repeated.
|
|
|
|
## Every key
|
|
|
|
| Key | Type | In |
|
|
|---|---|---|
|
|
| `enabled` | `bool` | [Admission](#admission) |
|
|
| `bands` | `[]Band` | [Admission](#admission) |
|
|
| `default_band` | `string` | [Admission](#admission) |
|
|
| `band_header` | `string` | [Admission](#admission) |
|
|
| `queue_ttl` | `time.Duration` | [Admission](#admission) |
|
|
| `queue_capacity_per_band` | `int` | [Admission](#admission) |
|
|
| `interval` | `time.Duration` | [Admission](#admission) |
|
|
| `enabled` | `bool` | [Auth](#auth) |
|
|
| `store` | `string` | [Auth](#auth) |
|
|
| `cache_ttl` | `time.Duration` | [Auth](#auth) |
|
|
| `negative_ttl` | `time.Duration` | [Auth](#auth) |
|
|
| `default_rpm` | `int` | [Auth](#auth) |
|
|
| `default_tpm` | `int` | [Auth](#auth) |
|
|
| `signup_open` | `bool` | [Auth](#auth) |
|
|
| `personal` | `Personal` | [Auth](#auth) |
|
|
| `pricing` | `map[string]Price` | [Auth](#auth) |
|
|
| `default_price` | `Price` | [Auth](#auth) |
|
|
| `flush_interval` | `time.Duration` | [Auth](#auth) |
|
|
| `batch_size` | `int` | [Auth](#auth) |
|
|
| `buffer_size` | `int` | [Auth](#auth) |
|
|
| `name` | `string` | [Band](#band) |
|
|
| `priority` | `int` | [Band](#band) |
|
|
| `saturation_ceiling` | `float64` | [Band](#band) |
|
|
| `tools` | `bool` | [Capabilities](#capabilities) |
|
|
| `vision` | `bool` | [Capabilities](#capabilities) |
|
|
| `embeddings` | `bool` | [Capabilities](#capabilities) |
|
|
| `node_id` | `string` | [Config](#config) |
|
|
| `server` | `string` | [Config](#config) |
|
|
| `servers` | `[]string` | [Config](#config) |
|
|
| `hostname` | `string` | [Config](#config) |
|
|
| `mgmt_addr` | `string` | [Config](#config) |
|
|
| `labels` | `map[string]string` | [Config](#config) |
|
|
| `mgmt_interface` | `string` | [Config](#config) |
|
|
| `fabrics` | `[]inventory.FabricAttachment` | [Config](#config) |
|
|
| `heartbeat_interval` | `time.Duration` | [Config](#config) |
|
|
| `reconnect_base` | `time.Duration` | [Config](#config) |
|
|
| `reconnect_max` | `time.Duration` | [Config](#config) |
|
|
| `adopt_ready_timeout` | `time.Duration` | [Config](#config) |
|
|
| `tls` | `tlsconf.Config` | [Config](#config) |
|
|
| `model_dirs` | `[]string` | [Config](#config) |
|
|
| `engines_dir` | `string` | [Config](#config) |
|
|
| `weights_cache` | `string` | [Config](#config) |
|
|
| `discovery` | `discovery.Options` | [Config](#config) |
|
|
| `engines` | `engines.Config` | [Config](#config) |
|
|
| `supervisor` | `supervisor.Config` | [Config](#config) |
|
|
| `interval` | `time.Duration` | [Control](#control) |
|
|
| `base_backoff` | `time.Duration` | [Control](#control) |
|
|
| `max_backoff` | `time.Duration` | [Control](#control) |
|
|
| `unreachable_after` | `time.Duration` | [Control](#control) |
|
|
| `lost_after` | `time.Duration` | [Control](#control) |
|
|
| `port_range` | `[]int` | [Control](#control) |
|
|
| `mgmt_interface` | `string` | [Control](#control) |
|
|
| `enabled` | `bool` | [Control](#control) |
|
|
| `lease_ttl` | `time.Duration` | [Control](#control) |
|
|
| `id` | `string` | [Endpoint](#endpoint) |
|
|
| `url` | `string` | [Endpoint](#endpoint) |
|
|
| `models` | `[]string` | [Endpoint](#endpoint) |
|
|
| `engine` | `string` | [Endpoint](#endpoint) |
|
|
| `pool` | `string` | [Endpoint](#endpoint) |
|
|
| `weight` | `float64` | [Endpoint](#endpoint) |
|
|
| `priority` | `int` | [Endpoint](#endpoint) |
|
|
| `contact` | `string` | [Landing](#landing) |
|
|
| `notice` | `string` | [Landing](#landing) |
|
|
| `bin` | `string` | [LlamaCppConfig](#llamacppconfig) |
|
|
| `parallel` | `int` | [LlamaCppConfig](#llamacppconfig) |
|
|
| `api` | `string` | [Mirror](#mirror) |
|
|
| `tls` | `tlsconf.Config` | [Mirror](#mirror) |
|
|
| `registry` | `string` | [Mirror](#mirror) |
|
|
| `timeout` | `time.Duration` | [Mirror](#mirror) |
|
|
| `name` | `string` | [Model](#model) |
|
|
| `aliases` | `[]string` | [Model](#model) |
|
|
| `description` | `string` | [Model](#model) |
|
|
| `source` | `string` | [Model](#model) |
|
|
| `profiles` | `[]Profile` | [Model](#model) |
|
|
| `scaling` | `Scaling` | [Model](#model) |
|
|
| `fallbacks` | `[]string` | [Model](#model) |
|
|
| `routing_profile` | `string` | [Model](#model) |
|
|
| `slo` | `SLO` | [Model](#model) |
|
|
| `context_length` | `int` | [Model](#model) |
|
|
| `max_output` | `int` | [Model](#model) |
|
|
| `capabilities` | `Capabilities` | [Model](#model) |
|
|
| `prometheus` | `string` | [Monitoring](#monitoring) |
|
|
| `window` | `time.Duration` | [Monitoring](#monitoring) |
|
|
| `timeout` | `time.Duration` | [Monitoring](#monitoring) |
|
|
| `nvidia_smi` | `string` | [Options](#options) |
|
|
| `ib_root` | `string` | [Options](#options) |
|
|
| `prefer_nvml` | `bool` | [Options](#options) |
|
|
| `skip_gpus` | `bool` | [Options](#options) |
|
|
| `disabled` | `bool` | [Personal](#personal) |
|
|
| `rpm` | `int` | [Personal](#personal) |
|
|
| `tpm` | `int` | [Personal](#personal) |
|
|
| `budget` | `float64` | [Personal](#personal) |
|
|
| `period` | `string` | [Personal](#personal) |
|
|
| `enabled` | `bool` | [Prefix](#prefix) |
|
|
| `max_nodes` | `int` | [Prefix](#prefix) |
|
|
| `min_match` | `int` | [Prefix](#prefix) |
|
|
| `ttl` | `time.Duration` | [Prefix](#prefix) |
|
|
| `match_ratio` | `float64` | [Prefix](#prefix) |
|
|
| `balance_abs` | `float64` | [Prefix](#prefix) |
|
|
| `balance_rel` | `float64` | [Prefix](#prefix) |
|
|
| `prompt_per_1k` | `int64` | [Price](#price) |
|
|
| `completion_per_1k` | `int64` | [Price](#price) |
|
|
| `name` | `string` | [Profile](#profile) |
|
|
| `engine` | `string` | [Profile](#profile) |
|
|
| `gpu_class` | `string` | [Profile](#profile) |
|
|
| `tp` | `int` | [Profile](#profile) |
|
|
| `pp` | `int` | [Profile](#profile) |
|
|
| `gpus_per_node` | `int` | [Profile](#profile) |
|
|
| `nodes` | `int` | [Profile](#profile) |
|
|
| `args` | `[]string` | [Profile](#profile) |
|
|
| `env` | `map[string]string` | [Profile](#profile) |
|
|
| `min_memory_gb` | `int` | [Profile](#profile) |
|
|
| `min_disk_gb` | `int` | [Profile](#profile) |
|
|
| `node_selector` | `map[string]string` | [Profile](#profile) |
|
|
| `weight` | `float64` | [Profile](#profile) |
|
|
| `priority` | `int` | [Profile](#profile) |
|
|
| `startup_timeout` | `time.Duration` | [Profile](#profile) |
|
|
| `activation_wait` | `time.Duration` | [Router](#router) |
|
|
| `scrape_interval` | `time.Duration` | [Router](#router) |
|
|
| `scrape_timeout` | `time.Duration` | [Router](#router) |
|
|
| `stale_after` | `time.Duration` | [Router](#router) |
|
|
| `retries` | `int` | [Router](#router) |
|
|
| `cooldown` | `time.Duration` | [Router](#router) |
|
|
| `failure_threshold` | `int` | [Router](#router) |
|
|
| `default_profile` | `string` | [Router](#router) |
|
|
| `prefix` | `Prefix` | [Router](#router) |
|
|
| `session_header` | `string` | [Router](#router) |
|
|
| `inject_usage` | `bool` | [Router](#router) |
|
|
| `max_body_bytes` | `int64` | [Router](#router) |
|
|
| `timeouts` | `Timeouts` | [Router](#router) |
|
|
| `scoring` | `Scoring` | [Router](#router) |
|
|
| `admission` | `Admission` | [Router](#router) |
|
|
| `python` | `string` | [SGLangConfig](#sglangconfig) |
|
|
| `ttft_p99` | `time.Duration` | [SLO](#slo) |
|
|
| `tpot_p99` | `time.Duration` | [SLO](#slo) |
|
|
| `min` | `int` | [Scaling](#scaling) |
|
|
| `max` | `int` | [Scaling](#scaling) |
|
|
| `idle_timeout` | `time.Duration` | [Scaling](#scaling) |
|
|
| `target_waiting` | `float64` | [Scoring](#scoring) |
|
|
| `target_inflight` | `float64` | [Scoring](#scoring) |
|
|
| `kv_ceiling` | `float64` | [Scoring](#scoring) |
|
|
| `session_load_factor` | `float64` | [Scoring](#scoring) |
|
|
| `listen` | `string` | [Server](#server) |
|
|
| `admin_listen` | `string` | [Server](#server) |
|
|
| `metrics_listen` | `string` | [Server](#server) |
|
|
| `agent_listen` | `string` | [Server](#server) |
|
|
| `auth` | `Auth` | [Server](#server) |
|
|
| `threads` | `Threads` | [Server](#server) |
|
|
| `landing` | `Landing` | [Server](#server) |
|
|
| `agent_tls` | `tlsconf.Config` | [Server](#server) |
|
|
| `monitoring` | `Monitoring` | [Server](#server) |
|
|
| `mirror` | `Mirror` | [Server](#server) |
|
|
| `engines` | `map[string]string` | [Server](#server) |
|
|
| `router` | `Router` | [Server](#server) |
|
|
| `control` | `Control` | [Server](#server) |
|
|
| `models` | `[]catalog.Model` | [Server](#server) |
|
|
| `endpoints` | `[]Endpoint` | [Server](#server) |
|
|
| `bin` | `string` | [SimConfig](#simconfig) |
|
|
| `store` | `string` | [Threads](#threads) |
|
|
| `retain_hours` | `int` | [Threads](#threads) |
|
|
| `dial` | `time.Duration` | [Timeouts](#timeouts) |
|
|
| `response_header` | `time.Duration` | [Timeouts](#timeouts) |
|
|
| `generation` | `time.Duration` | [Timeouts](#timeouts) |
|
|
| `first_token` | `time.Duration` | [Timeouts](#timeouts) |
|
|
| `idle` | `time.Duration` | [Timeouts](#timeouts) |
|
|
| `total` | `time.Duration` | [Timeouts](#timeouts) |
|
|
| `bin` | `string` | [VLLMConfig](#vllmconfig) |
|
|
| `launch_mode` | `string` | [VLLMConfig](#vllmconfig) |
|
|
| `ray_bin` | `string` | [VLLMConfig](#vllmconfig) |
|
|
|
|
## Admission
|
|
|
|
### `enabled`
|
|
|
|
`bool`
|
|
|
|
Enabled turns the layer on. Off, every request goes straight through,
|
|
which is the v0.2.0 behaviour.
|
|
|
|
### `bands`
|
|
|
|
`[]Band`
|
|
|
|
### `default_band`
|
|
|
|
`string`
|
|
|
|
### `band_header`
|
|
|
|
`string`
|
|
|
|
BandHeader lets a client declare its band. Until authentication lands in
|
|
v1.0.0 this is trusted, so the port must not be exposed to callers who
|
|
should not be able to promote themselves.
|
|
|
|
### `queue_ttl`
|
|
|
|
`time.Duration`
|
|
|
|
### `queue_capacity_per_band`
|
|
|
|
`int`
|
|
|
|
### `interval`
|
|
|
|
`time.Duration`
|
|
|
|
## Auth
|
|
|
|
### `enabled`
|
|
|
|
`bool`
|
|
|
|
### `store`
|
|
|
|
`string`
|
|
|
|
Store is the SQLite file holding keys, tenancy and usage.
|
|
|
|
### `cache_ttl`
|
|
|
|
`time.Duration`
|
|
|
|
CacheTTL bounds how long a revoked key keeps working, traded against a
|
|
database read per key per TTL.
|
|
|
|
### `negative_ttl`
|
|
|
|
`time.Duration`
|
|
|
|
NegativeTTL is how long a rejected key is remembered as rejected, so a
|
|
client looping with a bad key cannot become a database read per request.
|
|
|
|
### `default_rpm`
|
|
|
|
`int`
|
|
|
|
DefaultRPM and DefaultTPM apply to a key that no scope gives a limit to.
|
|
|
|
Unlimited used to be the default, and a project created without limits is
|
|
the easy path — the "default" project on this cluster still is one. The
|
|
first sign of that is the bill or the outage. Zero keeps the old
|
|
behaviour for anyone who wants it, but it should be a choice rather than
|
|
an omission. A fallback, not a ceiling: an explicit limit at any scope
|
|
wins, above or below.
|
|
|
|
### `default_tpm`
|
|
|
|
`int`
|
|
|
|
### `signup_open`
|
|
|
|
`bool`
|
|
|
|
SignupOpen serves the signup form. Accounts it creates are pending until
|
|
an operator approves them, so this is not a way in — but turning it off
|
|
means accounts are made with `llmgw users create` instead.
|
|
|
|
### `personal`
|
|
|
|
`Personal`
|
|
|
|
Personal is what a person may do on their own, outside any project: make
|
|
personal keys and use the chat page personally, within these limits.
|
|
|
|
Takes a [Personal](#personal) block.
|
|
|
|
### `pricing`
|
|
|
|
`map[string]Price`
|
|
|
|
Pricing is what each model costs, for budgets. A model absent from the
|
|
table costs whatever DefaultPrice says, which is nothing unless set.
|
|
|
|
### `default_price`
|
|
|
|
`Price`
|
|
|
|
Takes a [Price](#price) block.
|
|
|
|
### `flush_interval`
|
|
|
|
`time.Duration`
|
|
|
|
FlushInterval and BatchSize decide when usage records are written.
|
|
|
|
### `batch_size`
|
|
|
|
`int`
|
|
|
|
### `buffer_size`
|
|
|
|
`int`
|
|
|
|
BufferSize bounds the queue. Beyond it records are dropped rather than
|
|
blocking a request: losing accounting is bad, turning a stalled database
|
|
into an outage is worse.
|
|
|
|
## Band
|
|
|
|
### `name`
|
|
|
|
`string`
|
|
|
|
### `priority`
|
|
|
|
`int`
|
|
|
|
### `saturation_ceiling`
|
|
|
|
`float64`
|
|
|
|
## Capabilities
|
|
|
|
### `tools`
|
|
|
|
`bool`
|
|
|
|
### `vision`
|
|
|
|
`bool`
|
|
|
|
### `embeddings`
|
|
|
|
`bool`
|
|
|
|
## Config
|
|
|
|
### `node_id`
|
|
|
|
`string`
|
|
|
|
NodeID defaults to the hostname. It must equal the common name of the
|
|
agent's certificate, so set it only where the two differ.
|
|
|
|
### `server`
|
|
|
|
`string`
|
|
|
|
Server is the control plane, and Servers is the same thing when there is
|
|
more than one. Both are accepted: every configuration written before
|
|
there could be a second control plane names one address, and none of
|
|
them should have to change.
|
|
|
|
The order is tried in order, and a refusal moves to the next. Only the
|
|
leader accepts an agent, so a standby is skipped in the time it takes to
|
|
be told so — which is what makes failover a reconnect rather than an
|
|
edit to every node's configuration.
|
|
|
|
### `servers`
|
|
|
|
`[]string`
|
|
|
|
### `hostname`
|
|
|
|
`string`
|
|
|
|
Hostname defaults to the machine's.
|
|
|
|
### `mgmt_addr`
|
|
|
|
`string`
|
|
|
|
MgmtAddr is the address engines are reached on. It defaults to this
|
|
machine's address on the route to the control plane, which is the one
|
|
the control plane and the router can reach.
|
|
|
|
### `labels`
|
|
|
|
`map[string]string`
|
|
|
|
Labels are free-form facts about a node for a profile's node_selector.
|
|
Nothing needs them: memory, GPUs, engines and disk are measured, and a
|
|
label restating one of those goes stale the day the machine changes.
|
|
|
|
### `mgmt_interface`
|
|
|
|
`string`
|
|
|
|
MgmtInterface is the ethernet interface NCCL bootstraps over. It
|
|
defaults to the interface holding MgmtAddr, then eth0.
|
|
|
|
### `fabrics`
|
|
|
|
`[]inventory.FabricAttachment`
|
|
|
|
Fabrics labels this node's HCAs. It is explicit on purpose: OpenSM's
|
|
default subnet prefix is the same on every fabric, so nothing can be
|
|
inferred from the wire (plan §5.2).
|
|
|
|
### `heartbeat_interval`
|
|
|
|
`time.Duration`
|
|
|
|
### `reconnect_base`
|
|
|
|
`time.Duration`
|
|
|
|
ReconnectBase is the first reconnect delay; it backs off from there.
|
|
|
|
### `reconnect_max`
|
|
|
|
`time.Duration`
|
|
|
|
### `adopt_ready_timeout`
|
|
|
|
`time.Duration`
|
|
|
|
AdoptReadyTimeout bounds how long an adopted engine is given to answer a
|
|
health check before the agent stops waiting on it.
|
|
|
|
Shorter than a startup timeout on purpose: this engine is already
|
|
running, so it is not loading a model, it is either serving or it is not.
|
|
|
|
### `tls`
|
|
|
|
`tlsconf.Config`
|
|
|
|
TLS authenticates both ends of the control-plane stream. Leaving it unset
|
|
keeps the plaintext behaviour, which only belongs on a trusted network.
|
|
|
|
Takes a [Config](#config) block.
|
|
|
|
### `model_dirs`
|
|
|
|
`[]string`
|
|
|
|
ModelDirs are the directories this node keeps model weights in, beyond
|
|
WeightsCache, which is always looked in. Storage differs at every installation,
|
|
so llmgw observes it rather than owning it: a Lustre mount, an image
|
|
exported over the fabric, local NVMe and a copy made by hand all look
|
|
identical from here, and placement only needs to know whether the file
|
|
is present.
|
|
|
|
### `engines_dir`
|
|
|
|
`string`
|
|
|
|
EnginesDir is where the agent installs engines, one directory per
|
|
build. Defaults to /opt/llmgw/engines.
|
|
|
|
### `weights_cache`
|
|
|
|
`string`
|
|
|
|
WeightsCache is where a remote source is downloaded to. Defaults to the
|
|
first entry of ModelDirs, because a node that says where its models live
|
|
has already answered this question, and otherwise to
|
|
/var/lib/llmgw-weights.
|
|
|
|
Fetching is the simple arrangement: every node keeps its own copy. The
|
|
exotic ones need no code — weights on a shared filer or an image exported
|
|
over the fabric are simply present, and present means nothing is fetched.
|
|
|
|
### `discovery`
|
|
|
|
`discovery.Options`
|
|
|
|
Takes a [Options](#options) block.
|
|
|
|
### `engines`
|
|
|
|
`engines.Config`
|
|
|
|
Takes a [Config](#config) block.
|
|
|
|
### `supervisor`
|
|
|
|
`supervisor.Config`
|
|
|
|
Takes a [Config](#config) block.
|
|
|
|
## Control
|
|
|
|
### `interval`
|
|
|
|
`time.Duration`
|
|
|
|
Interval is how often desired and actual state are compared.
|
|
|
|
### `base_backoff`
|
|
|
|
`time.Duration`
|
|
|
|
BaseBackoff and MaxBackoff bound how fast a failing model is retried.
|
|
|
|
### `max_backoff`
|
|
|
|
`time.Duration`
|
|
|
|
### `unreachable_after`
|
|
|
|
`time.Duration`
|
|
|
|
UnreachableAfter and LostAfter stage node expiry. They are deliberately
|
|
far apart: a network blip must not tear down replicas that still serve,
|
|
and rebuilding a multi-node replica costs tens of minutes of loading.
|
|
|
|
### `lost_after`
|
|
|
|
`time.Duration`
|
|
|
|
### `port_range`
|
|
|
|
`[]int`
|
|
|
|
PortRange is the per-node range for engine HTTP and dist-init ports.
|
|
|
|
### `mgmt_interface`
|
|
|
|
`string`
|
|
|
|
MgmtInterface is the ethernet interface NCCL bootstraps over.
|
|
|
|
### `enabled`
|
|
|
|
`bool`
|
|
|
|
Enabled runs the control plane even when configuration declares no
|
|
models.
|
|
|
|
Without it, a deployment whose catalog lives entirely in the database
|
|
cannot start: control plane mode is inferred from the config file, so an
|
|
empty models block means "router only", the process refuses to start for
|
|
want of anything to serve, and the models it would have loaded are never
|
|
read. That is a cluster that cannot be managed at runtime because it is
|
|
managed at runtime. AgentListen cannot carry this signal — it has a
|
|
default, so every deployment would become a control plane.
|
|
|
|
### `lease_ttl`
|
|
|
|
`time.Duration`
|
|
|
|
LeaseTTL is how long this control plane's claim to be the one placing
|
|
work stands without being renewed.
|
|
|
|
Only meaningful with a shared store, where a second control plane can
|
|
see the claim. Long enough to survive a slow query or a brief network
|
|
stall, short enough that a standby takes over before anyone has finished
|
|
reading the alert. Zero takes the default.
|
|
|
|
## Endpoint
|
|
|
|
### `id`
|
|
|
|
`string`
|
|
|
|
### `url`
|
|
|
|
`string`
|
|
|
|
### `models`
|
|
|
|
`[]string`
|
|
|
|
### `engine`
|
|
|
|
`string`
|
|
|
|
Engine names the inference engine, which decides what its metrics are
|
|
called. Empty means vLLM's names.
|
|
|
|
### `pool`
|
|
|
|
`string`
|
|
|
|
### `weight`
|
|
|
|
`float64`
|
|
|
|
### `priority`
|
|
|
|
`int`
|
|
|
|
## Landing
|
|
|
|
### `contact`
|
|
|
|
`string`
|
|
|
|
Contact is where someone without a key should go — an address, a URL, a
|
|
channel name. Rendered as a link when it is one, as text otherwise.
|
|
|
|
### `notice`
|
|
|
|
`string`
|
|
|
|
Notice is an optional line of your own, for whatever the reader needs to
|
|
know that this page cannot guess.
|
|
|
|
## LlamaCppConfig
|
|
|
|
### `bin`
|
|
|
|
`string`
|
|
|
|
Bin is the llama-server binary. It is the server, not the CLI: the
|
|
gateway talks OpenAI over HTTP and needs the one that serves it.
|
|
Empty means the agent installs llama.cpp itself, at the version the
|
|
control plane asks for. Setting it opts out of that.
|
|
|
|
### `parallel`
|
|
|
|
`int`
|
|
|
|
Parallel is how many requests a server handles at once, when a profile
|
|
does not say. llama.cpp defaults to one, which would make every second
|
|
request wait behind the first no matter what the router decided.
|
|
|
|
## Mirror
|
|
|
|
### `api`
|
|
|
|
`string`
|
|
|
|
API is the mirror's management address, scheme included, for example
|
|
https://models.internal:8082. Empty means no mirror is configured.
|
|
|
|
The management port, not the one nodes fetch bytes from. Those are two
|
|
listeners on the mirror precisely so this one can be locked down without
|
|
re-certifying every agent's fetcher.
|
|
|
|
### `tls`
|
|
|
|
`tlsconf.Config`
|
|
|
|
TLS authenticates to the mirror's management API, with the same CA the
|
|
agents use. Empty leaves the connection in plain HTTP, which is only
|
|
acceptable on a network where nothing untrusted can reach that port —
|
|
the mirror says as much in its own log when it starts that way.
|
|
|
|
Takes a [Config](#config) block.
|
|
|
|
### `registry`
|
|
|
|
`string`
|
|
|
|
Registry is the model registry the mirror page browses, empty for the
|
|
public Hugging Face. Set it to an internal mirror of the registry where
|
|
the control plane cannot reach the internet — or leave the whole mirror
|
|
block out, which turns the explorer off rather than giving it a search
|
|
box that can only time out.
|
|
|
|
### `timeout`
|
|
|
|
`time.Duration`
|
|
|
|
Timeout bounds a management call. It does not bound a download: the
|
|
mirror answers a fetch as soon as it has started one, and the bytes keep
|
|
arriving long after this deadline has passed.
|
|
|
|
## Model
|
|
|
|
### `name`
|
|
|
|
`string`
|
|
|
|
### `aliases`
|
|
|
|
`[]string`
|
|
|
|
### `description`
|
|
|
|
`string`
|
|
|
|
Description is what this model is for, in a line.
|
|
|
|
Written by whoever added it, because nobody else can say it. A registry
|
|
offers a pipeline tag and a wall of README, and neither answers the
|
|
question a person picking from a list is asking: which of these nine
|
|
names should I send this request to.
|
|
|
|
It reaches clients through /v1/models, which is the only view most of
|
|
them ever see. A gateway serving nine models by name alone makes that
|
|
choice by guesswork.
|
|
|
|
### `source`
|
|
|
|
`string`
|
|
|
|
Source is the weights path or a HuggingFace id.
|
|
|
|
### `profiles`
|
|
|
|
`[]Profile`
|
|
|
|
### `scaling`
|
|
|
|
`Scaling`
|
|
|
|
Takes a [Scaling](#scaling) block.
|
|
|
|
### `fallbacks`
|
|
|
|
`[]string`
|
|
|
|
### `routing_profile`
|
|
|
|
`string`
|
|
|
|
RoutingProfile selects how the router scores endpoints for this model.
|
|
|
|
### `slo`
|
|
|
|
`SLO`
|
|
|
|
Takes a [SLO](#slo) block.
|
|
|
|
### `context_length`
|
|
|
|
`int`
|
|
|
|
ContextLength is how many tokens one request may use, prompt and
|
|
completion together, and MaxOutput bounds the completion alone. Zero
|
|
means unknown, which is what every model was until now.
|
|
|
|
The gateway knew neither, so an over-long prompt was not refused: it was
|
|
admitted, given a replica, and failed at the engine, and a client sizing
|
|
its prompts from /v1/models had nothing to read. Worse, the number is not
|
|
the one an operator writes in the engine's arguments — llama.cpp divides
|
|
--ctx-size across its parallel slots, so a pool of 8192 across four slots
|
|
is 2048 a request, and nothing said so.
|
|
|
|
### `max_output`
|
|
|
|
`int`
|
|
|
|
### `capabilities`
|
|
|
|
`Capabilities`
|
|
|
|
Capabilities is what this model can do beyond plain completion.
|
|
|
|
Takes a [Capabilities](#capabilities) block.
|
|
|
|
## Monitoring
|
|
|
|
### `prometheus`
|
|
|
|
`string`
|
|
|
|
Prometheus is the server's address, for example
|
|
http://monitoring.internal:9090. Empty leaves the charts off the
|
|
dashboard rather than showing an error where one should be.
|
|
|
|
### `window`
|
|
|
|
`time.Duration`
|
|
|
|
Window is how far back the charts look. Zero takes an hour.
|
|
|
|
### `timeout`
|
|
|
|
`time.Duration`
|
|
|
|
Timeout bounds one query. It runs while somebody waits for a page, so a
|
|
monitoring system that is slow today is skipped rather than waited for.
|
|
|
|
## Options
|
|
|
|
### `nvidia_smi`
|
|
|
|
`string`
|
|
|
|
NvidiaSMI is the path to nvidia-smi; empty means look it up on PATH.
|
|
Worth configuring on nodes where the driver lives outside the default
|
|
paths, which containerized driver installs often do.
|
|
|
|
### `ib_root`
|
|
|
|
`string`
|
|
|
|
IBRoot is the sysfs InfiniBand directory.
|
|
|
|
### `prefer_nvml`
|
|
|
|
`bool`
|
|
|
|
PreferNVML uses the NVML backend when this binary has one. It is the only
|
|
source of NVLink topology.
|
|
|
|
### `skip_gpus`
|
|
|
|
`bool`
|
|
|
|
SkipGPUs omits GPU discovery. A node without nvidia-smi is already
|
|
found to have none, so this is for one whose driver is broken.
|
|
|
|
## Personal
|
|
|
|
### `disabled`
|
|
|
|
`bool`
|
|
|
|
Disabled refuses personal keys and personal chat; people then use the
|
|
gateway only through projects they are members of.
|
|
|
|
### `rpm`
|
|
|
|
`int`
|
|
|
|
### `tpm`
|
|
|
|
`int`
|
|
|
|
### `budget`
|
|
|
|
`float64`
|
|
|
|
Budget is in whole units per Period ("day" or "month").
|
|
|
|
### `period`
|
|
|
|
`string`
|
|
|
|
## Prefix
|
|
|
|
### `enabled`
|
|
|
|
`bool`
|
|
|
|
### `max_nodes`
|
|
|
|
`int`
|
|
|
|
MaxNodes bounds the tree, MinMatch is the shortest match worth acting on
|
|
in bytes, and TTL is how long an entry is believed — an engine evicts on
|
|
its own schedule, so an old record may describe a cache that is gone.
|
|
|
|
### `min_match`
|
|
|
|
`int`
|
|
|
|
### `ttl`
|
|
|
|
`time.Duration`
|
|
|
|
### `match_ratio`
|
|
|
|
`float64`
|
|
|
|
MatchRatio is the share of the prompt that must match to be worth acting
|
|
on. BalanceAbs and BalanceRel are the imbalance guard, and both must trip
|
|
before affinity is abandoned.
|
|
|
|
### `balance_abs`
|
|
|
|
`float64`
|
|
|
|
### `balance_rel`
|
|
|
|
`float64`
|
|
|
|
## Price
|
|
|
|
### `prompt_per_1k`
|
|
|
|
`int64`
|
|
|
|
### `completion_per_1k`
|
|
|
|
`int64`
|
|
|
|
## Profile
|
|
|
|
### `name`
|
|
|
|
`string`
|
|
|
|
### `engine`
|
|
|
|
`string`
|
|
|
|
### `gpu_class`
|
|
|
|
`string`
|
|
|
|
### `tp`
|
|
|
|
`int`
|
|
|
|
### `pp`
|
|
|
|
`int`
|
|
|
|
### `gpus_per_node`
|
|
|
|
`int`
|
|
|
|
GPUsPerNode defaults to TP for a single-node profile.
|
|
|
|
### `nodes`
|
|
|
|
`int`
|
|
|
|
Nodes above 1 makes this a multi-node profile, which requires a fabric.
|
|
|
|
### `args`
|
|
|
|
`[]string`
|
|
|
|
### `env`
|
|
|
|
`map[string]string`
|
|
|
|
### `min_memory_gb`
|
|
|
|
`int`
|
|
|
|
MinMemoryGB is the host RAM this profile needs to run.
|
|
|
|
The number that matters is the model's working set: the weights, plus the
|
|
KV cache for the whole context pool, plus the engine's own overhead. For
|
|
a GPU profile that lives in the cards and this is small; for a CPU
|
|
profile it is the whole thing, and getting it wrong means an OOM on a
|
|
node that reported itself healthy.
|
|
|
|
Zero means unconstrained, which is every profile that existed before
|
|
this. A node that does not report its memory is not excluded either —
|
|
an older agent must not have its nodes quietly emptied by an upgrade of
|
|
the control plane.
|
|
|
|
### `min_disk_gb`
|
|
|
|
`int`
|
|
|
|
MinDiskGB is the free space a node needs before it can hold these
|
|
weights.
|
|
|
|
Only checked when the node does not already have them: a node holding
|
|
the file needs no room for it, and requiring the space twice would keep
|
|
a model off the one node best placed to run it.
|
|
|
|
Declared rather than derived, because the size of a model that has never
|
|
been fetched anywhere is not knowable from here — and a wrong guess
|
|
fails late, halfway through a download, which is the failure this exists
|
|
to prevent. Zero means unconstrained, and a node that reports no storage
|
|
is not excluded: unknown is not full.
|
|
|
|
### `node_selector`
|
|
|
|
`map[string]string`
|
|
|
|
NodeSelector restricts this profile to nodes carrying every one of these
|
|
labels, with these values.
|
|
|
|
A CPU profile otherwise fits everywhere, because there is no card to be
|
|
free — which is right for a 0.5B model and wrong for a 14B one. Nothing
|
|
in the inventory says how much memory a node has, so the operator says
|
|
which nodes are meant for a model instead of the scheduler inferring it.
|
|
Agents have reported labels since the beginning; this is what reads them.
|
|
|
|
### `weight`
|
|
|
|
`float64`
|
|
|
|
Weight is the router's capacity weight. It should come from ctl bench
|
|
rather than a guess (plan §6.2.1).
|
|
|
|
### `priority`
|
|
|
|
`int`
|
|
|
|
Priority orders profiles during placement; highest that fits wins.
|
|
|
|
### `startup_timeout`
|
|
|
|
`time.Duration`
|
|
|
|
StartupTimeout bounds model loading. A 70B model across two nodes takes
|
|
tens of minutes, so this is per profile rather than global.
|
|
|
|
## Router
|
|
|
|
### `activation_wait`
|
|
|
|
`time.Duration`
|
|
|
|
ActivationWait is how long a request waits for an on-demand model to
|
|
load before the client is told to come back. Zero takes the default.
|
|
|
|
The one real decision in on-demand loading. Refusing outright makes the
|
|
feature useless, since the first request for every model would fail;
|
|
waiting without a bound turns a request into a job, and a client that
|
|
budgeted thirty seconds ends up holding a connection for ten minutes.
|
|
|
|
### `scrape_interval`
|
|
|
|
`time.Duration`
|
|
|
|
### `scrape_timeout`
|
|
|
|
`time.Duration`
|
|
|
|
### `stale_after`
|
|
|
|
`time.Duration`
|
|
|
|
StaleAfter is how long an endpoint may go unscraped before being scored
|
|
down (plan §7.6).
|
|
|
|
### `retries`
|
|
|
|
`int`
|
|
|
|
Retries is how many *additional* endpoints may be tried after a failure,
|
|
and only while nothing has been written to the client (plan §7.7).
|
|
|
|
### `cooldown`
|
|
|
|
`time.Duration`
|
|
|
|
Cooldown is how long a failing endpoint leaves the candidate pool.
|
|
|
|
### `failure_threshold`
|
|
|
|
`int`
|
|
|
|
FailureThreshold is the consecutive failure count that opens a breaker.
|
|
1 turns the breaker into a pure cooldown.
|
|
|
|
### `default_profile`
|
|
|
|
`string`
|
|
|
|
DefaultProfile names the routing profile used when a model picks none.
|
|
|
|
### `prefix`
|
|
|
|
`Prefix`
|
|
|
|
Prefix turns on the approximate prefix tree (plan §7.5 tier 1). Off, the
|
|
router uses session affinity alone, which is tier 0 and already most of
|
|
the win for multi-turn traffic.
|
|
|
|
Takes a [Prefix](#prefix) block.
|
|
|
|
### `session_header`
|
|
|
|
`string`
|
|
|
|
SessionHeader carries the session id for affinity (plan §7.5 tier 0).
|
|
|
|
### `inject_usage`
|
|
|
|
`bool`
|
|
|
|
InjectUsage asks engines for usage even when the client did not, so token
|
|
accounting works regardless of client behaviour.
|
|
|
|
### `max_body_bytes`
|
|
|
|
`int64`
|
|
|
|
MaxBodyBytes bounds the request body the router will read.
|
|
|
|
### `timeouts`
|
|
|
|
`Timeouts`
|
|
|
|
Takes a [Timeouts](#timeouts) block.
|
|
|
|
### `scoring`
|
|
|
|
`Scoring`
|
|
|
|
Takes a [Scoring](#scoring) block.
|
|
|
|
### `admission`
|
|
|
|
`Admission`
|
|
|
|
Takes a [Admission](#admission) block.
|
|
|
|
## SGLangConfig
|
|
|
|
### `python`
|
|
|
|
`string`
|
|
|
|
Python is the interpreter of the SGLang virtualenv. SGLang is launched as
|
|
a module rather than a console script, which is the documented entry
|
|
point and avoids depending on the script being on PATH.
|
|
|
|
## SLO
|
|
|
|
### `ttft_p99`
|
|
|
|
`time.Duration`
|
|
|
|
### `tpot_p99`
|
|
|
|
`time.Duration`
|
|
|
|
## Scaling
|
|
|
|
### `min`
|
|
|
|
`int`
|
|
|
|
### `max`
|
|
|
|
`int`
|
|
|
|
### `idle_timeout`
|
|
|
|
`time.Duration`
|
|
|
|
IdleTimeout is how long an on-demand model may go unasked-for before its
|
|
replicas are stopped. Zero takes the cluster default.
|
|
|
|
Minutes rather than seconds, always. Stopping a replica throws away the
|
|
KV cache prefix routing spent its effort filling, and a model that flaps
|
|
in and out loses that entirely — so the saving has to be worth more than
|
|
the cache, which it only is over a real idle period.
|
|
|
|
## Scoring
|
|
|
|
### `target_waiting`
|
|
|
|
`float64`
|
|
|
|
### `target_inflight`
|
|
|
|
`float64`
|
|
|
|
### `kv_ceiling`
|
|
|
|
`float64`
|
|
|
|
### `session_load_factor`
|
|
|
|
`float64`
|
|
|
|
## Server
|
|
|
|
### `listen`
|
|
|
|
`string`
|
|
|
|
Listen is the client-facing OpenAI API address.
|
|
|
|
### `admin_listen`
|
|
|
|
`string`
|
|
|
|
AdminListen serves the dashboard, the management API, health and pprof.
|
|
|
|
Loopback by default, and it should stay there: pprof can dump the process
|
|
heap, and API keys are in that heap in plaintext. Every comment beside
|
|
this setting has always said not to expose it, while the default bound
|
|
every interface — a default that contradicts its own documentation is a
|
|
footgun, so the default now matches the advice.
|
|
|
|
### `metrics_listen`
|
|
|
|
`string`
|
|
|
|
MetricsListen serves Prometheus metrics and nothing else.
|
|
|
|
Separate from AdminListen because the reason that one is loopback is
|
|
pprof, not metrics — and metrics are the one thing on it that something
|
|
else genuinely needs to reach. Sharing a listener meant a fleet could
|
|
either be monitored or keep its heap private, which is not a choice
|
|
anybody should have to make.
|
|
|
|
Empty means off, and metrics remain available on AdminListen either way,
|
|
so nothing that scrapes it today has to change.
|
|
|
|
### `agent_listen`
|
|
|
|
`string`
|
|
|
|
AgentListen is where node agents connect. Separate from the client port
|
|
so the fleet-facing surface can be firewalled independently.
|
|
|
|
### `auth`
|
|
|
|
`Auth`
|
|
|
|
Auth turns on API keys on the client-facing port.
|
|
|
|
Takes a [Auth](#auth) block.
|
|
|
|
### `threads`
|
|
|
|
`Threads`
|
|
|
|
Threads keeps conversations and agent memory without API keys, for a
|
|
gateway on one trusted machine. With auth on they live in the auth store,
|
|
per project, and this block is ignored.
|
|
|
|
Takes a [Threads](#threads) block.
|
|
|
|
### `landing`
|
|
|
|
`Landing`
|
|
|
|
Landing configures the page served at "/".
|
|
|
|
Takes a [Landing](#landing) block.
|
|
|
|
### `agent_tls`
|
|
|
|
`tlsconf.Config`
|
|
|
|
AgentTLS authenticates the fleet-facing port. It deliberately does not
|
|
cover the client-facing one: that surface is fronted by a publicly
|
|
trusted certificate, while this one is mutual and private.
|
|
|
|
Takes a [Config](#config) block.
|
|
|
|
### `monitoring`
|
|
|
|
`Monitoring`
|
|
|
|
Monitoring is where the dashboard reads its history from.
|
|
|
|
Takes a [Monitoring](#monitoring) block.
|
|
|
|
### `mirror`
|
|
|
|
`Mirror`
|
|
|
|
Mirror points the control plane at a model mirror it can administer.
|
|
Empty means there is none, and /admin/mirror stays unmounted.
|
|
|
|
Takes a [Mirror](#mirror) block.
|
|
|
|
### `engines`
|
|
|
|
`map[string]string`
|
|
|
|
Engines are the engines every node installs, and at which version. The
|
|
agents install them themselves — the right build for their hardware,
|
|
checked against its publisher's checksum and seen to run — so a node is
|
|
never trusted to already have what somebody once put there.
|
|
|
|
Unset keeps DefaultEngines. A version replaces the default; an empty
|
|
one leaves that engine to be installed by hand.
|
|
|
|
### `router`
|
|
|
|
`Router`
|
|
|
|
Takes a [Router](#router) block.
|
|
|
|
### `control`
|
|
|
|
`Control`
|
|
|
|
Takes a [Control](#control) block.
|
|
|
|
### `models`
|
|
|
|
`[]catalog.Model`
|
|
|
|
### `endpoints`
|
|
|
|
`[]Endpoint`
|
|
|
|
Endpoints is the phase-1 static replica list. It is only consulted when
|
|
no model declares a profile, which is what makes a router-only smoke test
|
|
against sim-engines possible without a control plane.
|
|
|
|
## SimConfig
|
|
|
|
### `bin`
|
|
|
|
`string`
|
|
|
|
Bin is the llmgw binary itself; the engine is one of its subcommands.
|
|
Empty means whatever started this agent, which is right almost always.
|
|
|
|
## Threads
|
|
|
|
### `store`
|
|
|
|
`string`
|
|
|
|
Store is the SQLite file. Empty means nothing is kept.
|
|
|
|
### `retain_hours`
|
|
|
|
`int`
|
|
|
|
RetainHours is how long idle conversations and notes are kept. Required
|
|
with Store: a store with no expiry keeps everything anyone typed, by
|
|
omission.
|
|
|
|
## Timeouts
|
|
|
|
### `dial`
|
|
|
|
`time.Duration`
|
|
|
|
### `response_header`
|
|
|
|
`time.Duration`
|
|
|
|
ResponseHeader bounds the wait for headers on a streaming request. It is
|
|
a liveness check there, because headers arrive before generation starts.
|
|
|
|
### `generation`
|
|
|
|
`time.Duration`
|
|
|
|
Generation bounds a non-streaming request, where the engine sends no
|
|
headers until the completion is done. Setting response_header alone used
|
|
to cap both, so 60s read as a liveness guard and behaved as a limit of
|
|
about a hundred tokens on a slow model.
|
|
|
|
### `first_token`
|
|
|
|
`time.Duration`
|
|
|
|
### `idle`
|
|
|
|
`time.Duration`
|
|
|
|
### `total`
|
|
|
|
`time.Duration`
|
|
|
|
## VLLMConfig
|
|
|
|
### `bin`
|
|
|
|
`string`
|
|
|
|
Bin is the vllm executable.
|
|
|
|
### `launch_mode`
|
|
|
|
`string`
|
|
|
|
LaunchMode selects the multi-node mechanism: "mp", the default, or
|
|
"ray".
|
|
|
|
mp is what vLLM documents today — every node runs serve with its rank,
|
|
the workers headless — and needs nothing but vLLM. ray is the older way,
|
|
kept for a vLLM too old for mp's multi-node flags; it needs Ray on every
|
|
node and has not been checked against a real cluster.
|
|
|
|
### `ray_bin`
|
|
|
|
`string`
|
|
|
|
RayBin is used when LaunchMode is "ray".
|
|
|