OBLETHdocs

Capacity auto-tune

Measure how many requests a self-hosted model serves at once with a short load probe, then apply the result as its pool size.

3 min readUpdated for v2.4.0Edit on GitHub

Applies toChat and embedding models on servers you run
Run itA model's page › Capacity › Auto-tune capacity
It costsUp to 60 seconds of real load and its tokens
It changesNothing until you apply the result

Run a probe

  1. 1

    Open the dialog

    On the model's page, under Capacity, choose Auto-tune capacity. Run it in a quiet window: the probe sends real concurrent load to the model's backend.

  2. 2

    Describe the backend

    Set Replicas running, the copies of the model serving now; Latency tolerance, how much slower than one idle request you accept at peak (Tight 2×, Balanced 4×, Relaxed 8×); and the Workload: short chat turns, or coding with a large context and longer replies.

  3. 3

    Run and apply

    Choose Run probe. The dialog shows the recommended slots, the throughput there, the latency budget, why the ramp stopped, and a row per step. Apply sets the model's pool to the recommendation and switches it to the tuned capacity mode.

Keep a model on a metered cloud API on a fixed pool instead: the probe would spend real money, and a fixed number bounds your spend. If the backend's replica count changes on its own, use the discovered mode, with the tuned value divided by the replicas as the per-replica concurrency.

How the probe works

The probe runs in the Management API and sends requests straight to the model's API base, bypassing obleth's own admission, so it measures the backend rather than the current pool. It carries the model's upstream headers.

  1. It steps concurrency up 1, 2, 4, 8 and so on to a ceiling, holding each step for 2.5 seconds and recording throughput and p50 and p99 latency.
  2. It sets a latency budget from the concurrency-1 baseline: the baseline p99 × the tolerance, never below 100 ms.
  3. It always runs the whole ladder, so the result is reproducible; only the safety limits below, or a step where every request failed, cut it short.
  4. It recommends the highest concurrency that stayed within the budget and still added throughput.
Why it stoppedMeaning
latency_degradedA step's p99 went past the budget
plateauThroughput gained less than about 7% over the step before
max_concurrencyIt reached the ceiling with no knee; the real one may be higher
no_dataNo step produced usable samples: the upstream is unreachable

The ceiling is max_concurrency if you give it (at most 512), otherwise 32 × Replicas running, otherwise 64.

WorkloadPromptReply
chat (default)about 512 tokens128 tokens
codingabout 6,000 tokens512 tokens

Capacity modes

ModePool size
static (default)The Max slots you set
tunedThe value last applied from auto-tune; capacity_tuned_at records when
discoveredFollows the backend's ready replicas; see Pool sizes

static and tuned both use max_in_flight, so between them the mode is a record for you and the audit log. You can switch back to static without losing the value.

Management API

# Run a probe (changes nothing)
curl -X POST "http://localhost:9180/api/v1/models/$MODEL_ID/autotune" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"workload": "chat", "latency_headroom": 4.0, "replicas": 2}'

# Apply a recommendation
curl -X POST "http://localhost:9180/api/v1/models/$MODEL_ID/autotune/apply" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"max_in_flight": 32}'

The probe answers with recommended_max_in_flight, knee_reason, baseline_p99_ms, latency_ceiling_ms, recommended_throughput_rps and a steps array. Applying sets max_in_flight, switches the mode to tuned, stamps capacity_tuned_at and updates every gateway replica. Probes and applies are recorded in the audit log. See Management API.

Safety limits
LimitValue
Wall clock60 seconds for all steps together
Total requests20,000
Concurrency512
latency_headroomClamped to 1.5–20; default 4.0
Model typesChat and embeddings