|
Download docs/serving-contract.md from staccs/ds4-winhip: direct link, hf CLI and curl.
- Browser
- Download file 11.8 kB
-
https://huggingface.co/staccs/ds4-winhip/resolve/main/docs/serving-contract.md
- Command line
-
hf download hf://staccs/ds4-winhip/docs/serving-contract.md
-
curl -L -o serving-contract.md https://huggingface.co/staccs/ds4-winhip/resolve/main/docs/serving-contract.md
11.8 kB
| # Serving contract | |
| Use one set of options across families. Implementation, memory and verified | |
| limits remain specific to the [artifact](ds4-dfm-model-families.md). | |
| See the [v0.1.3 ledger](releases/v0.1.3.md) for recorded gates. | |
| [Flags](#flags) · [Inspect](#inspect) · [Request trace](#request-trace) · | |
| [Owner/worker](#weight-owner-and-worker) · [Model replacement](#replacing-a-model) | |
| The host resolves one [`ServingRequest`](../crates/ds4-core/src/serving.rs) | |
| into a [`ResolvedPlan`](../crates/ds4-core/src/serving.rs): requested, | |
| effective, and qualified. `--print-plan` prints it. `--check-config` | |
| exits 2 if any requested feature is unsupported. `GET /v1/stats` includes | |
| the same object plus `last_request`. | |
| ## Flags | |
| | Flag | Meaning | Aliases | | |
| |---|---|---| | |
| | `--ctx` / `-c` | Per-sequence context limit, capped per family | | | |
| | `--max-seqs N\|auto` | Concurrent banks/sequences | `--cont-width`, `DS4_SERVER_COALESCE_MAX` | | |
| | `--prefix-reuse off\|exact\|partial\|auto` | Conversation reuse policy | `DS4_SERVER_FORK`, `DS4_SERVER_FORK_PARTIAL` | | |
| | `--mtp-mode off\|auto\|on` | Speculation policy | `DS4_MTP_SPEC_DISABLE` for off-with-weights | | |
| | `--mtp PATH`, `--mtp-draft N` | Sidecar and draft length | | | |
| | `--ignore-eos-in-reasoning` | Suppress EOS/EOT while the reasoning block is open | | | |
| | `--ignore-eos` | Suppress EOS/EOT for the whole generation | | | |
| | `--kv-disk-dir`, `--kv-disk-space-mb` | Persistent checkpoint store | `--kv-disk-space 32G` | | |
| | `--prefill-chunk`, `--prefill-chunk-live` | Scheduler yield sizes, capped at 8,192 | `DS4_CONT_PREFILL_CHUNK`, `DS4_CONT_PREFILL_CHUNK_LIVE`, `DS4_CONT_PREFILL_NOFENCE=1` lifts the cap | | |
| | `--mem-floor-gb` | Single host floor | `DS4_MEM_FLOOR_GB` (published for native) | | |
| | `--print-plan` | Print resolved JSON and continue | | | |
| | `--check-config` | Print resolved JSON and exit | | | |
| ### Prefix reuse | |
| `auto` reuse is the best *qualified* path. Forced `partial` on a family | |
| that only has exact-frontier reuse is an error, and so is forcing it when | |
| this process cannot run it: checkpoint replay lives in the bank driver and | |
| needs the opened runtime's checkpoint store, so serial-only serving or a | |
| runtime without that store rejects `partial` and downgrades `auto` to | |
| `exact` with a warning rather than reporting reuse it will not perform. | |
| ### Stop policy | |
| EOS follows the model by default. These server-wide flags are explicit | |
| workarounds for models that emit a terminator too early. Both mask the | |
| model's EOS and any EOT registered as a generation stop before sampling; | |
| other generation stops, request stop strings, and output/context limits | |
| still apply. The reasoning flag stops masking | |
| after `</think>`; `--ignore-eos` takes precedence if both are set. Global | |
| suppression can make generation run until another stop or a length limit. | |
| The policy is enforced in serial and continuous decoding, including MTP | |
| target sampling. `--check-config` validates that an opted-in model has EOS. | |
| ### Context and concurrency | |
| `--max-seqs` is not context length. Keeping N banks is not the same as | |
| batching N requests in one kernel. Step banks each own KV and prefill | |
| scratch; more banks are not a linear tok/s gain. `auto` may fit fewer | |
| banks than it asked for; an explicit `--max-seqs N` the native fit | |
| cannot honour is an error, not a narrower start. | |
| ### Memory fit | |
| The quote's `floor` includes native fit headroom where required: normally | |
| the host floor plus a 2 GiB burst reserve. `DS4_BATCH_FIT_HEADROOM_MB` | |
| overrides that reserve; `DS4_BATCH_FIT_HEADROOM_DERIVED=0` selects 6 GiB, | |
| otherwise `DS4_BATCH_FIT_BURST_MB` changes the burst. The quote always | |
| preserves at least `--mem-floor-gb`. | |
| CUDA serial graph fitting also reserves 1 GiB by default, configurable | |
| with `DS4_SESSION_GRAPH_HEADROOM_MB` (disabled by `DS4_SESSION_GRAPH_FIT=0`). | |
| The quote keeps the larger of the applicable serial and batch reserves. | |
| DeepSeek shared graph costs include its initial caches and native workspace; | |
| packed cache mirrors are conservatively included even when native VMM | |
| support may disable them. The same native chunk sizes serial and batch graphs. | |
| DeepSeek bank costs use full-depth compressed-cache capacity plus raw rings | |
| and rollback states. Loaded DSpark runtime costs count even with `DS4_CONT_DSPARK=0`. | |
| A manifest with drafter ranges defers the pre-open quote: import can soft-fail. | |
| After open, a successful import excludes shared drafter weights; fallback | |
| retains the local weight cost. Runtime allocations remain charged in both cases. | |
| ### Serving lanes | |
| `--cont-width 0` and `DS4_SERVER_COALESCE_MAX=0` keep the legacy serial | |
| meaning: no bank lane. `DS4_SERVER_CONTINUOUS=0` is narrower — it forces | |
| the static/serial route, so the banks stay for the static lane to coalesce | |
| over while no request enters the bank driver. Qwen and DeepSeek speculate only inside that | |
| lane, so the combination rejects `--mtp-mode on` instead of reporting | |
| MTP enabled. Inkling and Step also speculate on the serial engine and | |
| are unaffected. | |
| ### Disk checkpoints | |
| Disk KV is not active-bank offload. Resident bank state, partial | |
| checkpoint memory, and disk budget are separate. A directory does not | |
| persist conversations below the bank persist threshold (default 8,192 | |
| tokens on the continuous lane, `DS4_SERVER_PERSIST_MIN_TOKENS`). That is a | |
| different number from the disk store's record minimum | |
| (`--kv-cache-min-tokens`, default 512); the plan reports both. | |
| MiMo's [256K mixed gate](mimo2-serving-2026-09-25.md) uses disk KV for text | |
| bank continuation; media runs on the serial lane. | |
| Resident-bank protection and SSD checkpoint eligibility are independent: | |
| `DS4_SERVER_PIN_MIN_TOKENS` defaults to 65,536, while | |
| `DS4_SERVER_PERSIST_MIN_TOKENS` defaults to 8,192. Lowering the persistence | |
| threshold does not pin shallow sessions in memory. | |
| HTTP disk records require a matching `local-file-stat-v1` identity: all | |
| GGUF/sidecar file metadata, template contents, runtime files and effective | |
| inference settings. This is local file identity, not full weight-content | |
| attestation. Inputs must remain unchanged during model open. Legacy records | |
| without this identity miss safely; all identities share the directory budget. | |
| Native restore holds the validated file open through the payload read. | |
| ### Draft execution | |
| MTP weights loaded is not "this request speculated". Sampled Step | |
| requests keep predictor state and use ordinary decode. | |
| ## Inspect | |
| ```sh | |
| ./ds4-server --check-config --cuda -m "$MODEL" \ | |
| --prefix-reuse auto --max-seqs 2 --mem-floor-gb 12 \ | |
| --kv-disk-dir /tmp/ds4-kv --kv-disk-space 32G --mtp-mode auto | |
| ``` | |
| The JSON has `requested`, `effective`, `qualified`, `issues`, and when | |
| the host supplied a memory ceiling, `quote`. `effective.native_chunk` is | |
| the allocated workspace/graph max, not the scheduler yield. | |
| `qualified.prompt` is the verified request length when it is smaller | |
| than configured `--ctx`. A family's session cap is separate from its | |
| qualified context: GLM sessions refuse anything above 2,048, so the | |
| shared default is an error there, not a warning. `--native-chunk` sets | |
| the allocated native capacity so `--check-config` can refuse a yield | |
| the process cannot run. | |
| ## Request trace | |
| `GET /v1/stats` field `last_request`: | |
| | Field | Meaning | | |
| |---|---| | |
| | `effective_lane` | `serial`, `continuous`, or `static` | | |
| | `reuse_kind` | `cold`, `exact`, `partial`, or `fork` | | |
| | `speculation_active` | This request used speculative decode | | |
| | `reuse_miss` | Why a candidate was refused, when one was | | |
| | `fallback_reason` | Why a requested path was not used | | |
| The same fields may appear next to HTTP `timings`. | |
| Each field is recorded where the decision is made, not inferred from | |
| counters. `exact` reuses a state that ends at this prompt's common | |
| prefix and prefills only the appended turn, so cached and computed | |
| tokens are both positive; `partial` restores a checkpoint below that | |
| prefix and replays the gap, including a partial copy into another bank; | |
| `fork` copies a complete retained frontier into another bank and preserves | |
| the source. `speculation_active` follows the executed path: the serial | |
| engine's speculative eval, or a native sequence that ran draft rows. | |
| ## Miss reasons | |
| Restore miss is not "disk broken". `reuse_miss` carries the reason from the | |
| decision that produced it, and is absent when nothing was refused: | |
| - `rendered prefix changed` (template dropped an empty thinking block). | |
| Step and Motif official follow-up renders omit a generation-only empty | |
| `<think>` pair. Their history checkpoints capture matching native KV, | |
| tokens and logits before that suffix; the completed bank retains its | |
| original token sequence. A Motif append can therefore require `partial` | |
| rollback even when the visible messages only grow. Without a compatible | |
| checkpoint, the request stays cold: shortening a text key cannot change KV. | |
| - `below minimum token threshold` | |
| - `payload family/layout mismatch`. Also the answer when the chosen | |
| payload cannot be read back — a truncated or corrupt record is refused | |
| by its payload, whatever wrote it. | |
| - `no checkpoint at or below LCP` | |
| - `session state requires prefix replay`. Cached tokens count only the | |
| prefix preserved by the native sync plan. Dots3 MTP replays an unaligned | |
| append from zero (`cold`); plain Dots3 replays its final partial chunk | |
| (`partial`). An identical prompt or aligned append retains its full hit. | |
| ## Capability table | |
| The [generated capability table](serving-capabilities.md) reads | |
| `ds4_core::serving_caps` and the same resolved controls consumed by | |
| `ds4-perf serving-controls`. Its model-free check runs with the core tests; | |
| the page includes the regeneration command. Dated reports stay historical. | |
| ## Weight owner and worker | |
| On a 128 GB unified-memory machine, keep one weight owner alive and restart | |
| only inference workers while developing or profiling. The owner maps split | |
| GGUFs as one logical model, uploads VMM ranges, builds byte-neutral aligned | |
| IQ2/Q2K expert artifacts, and brokers POSIX file descriptors to workers. | |
| Keep the manifest path short: its Unix socket is `<manifest>.sock`. | |
| Start with a dry run: | |
| ```sh | |
| MODEL=/path/to/model.gguf | |
| RUN=/path/to/run-directory | |
| ./ds4_weight_server \ | |
| --base "$MODEL" \ | |
| --manifest "$RUN/weights.manifest" \ | |
| --backend vmm \ | |
| --scope base \ | |
| --reserve-gb 24 \ | |
| --no-repack-q8-aligned \ | |
| --dry-run | |
| ``` | |
| If the memory preflight passes, run the same command without `--dry-run` in a | |
| durable tmux session. Do not start a worker until the owner reports both | |
| `broker listening` and `ready manifest=...`. | |
| A VMM-backed worker uses this launch shape. Select its context, memory reserve, | |
| repack policy and sidecars from the [family recipe](ds4-dfm-model-families.md). | |
| ```sh | |
| DS4_CUDA_WEIGHT_IPC_MANIFEST="$RUN/weights.manifest" \ | |
| DS4_CUDA_WEIGHT_IPC_SCOPE=base \ | |
| ./ds4-server -m "$MODEL" --cuda -c 2048 \ | |
| --host 127.0.0.1 --port 8001 --no-update-check | |
| ``` | |
| For a split GGUF, `MODEL` is its first shard. Keep the owner resident across | |
| worker restarts; enable drafting only through the artifact's explicit contract. | |
| Use the [memory guard](host-memory-guard.md) for large-model validation. | |
| ## Replacing a model | |
| Before replacing your large model on DGX Spark: | |
| 1. Inspect compute processes in `nvtop` and process memory in `btop` or `htop`. | |
| 2. Stop your inference worker; verify its PID and listening port are gone. | |
| 3. Stop its weight owner; verify that owner's PID and GPU allocations are gone. | |
| 4. Run `/usr/local/bin/clear_cache` after those processes have exited. | |
| 5. Recheck process memory, `free -h` and swap before starting the next owner. | |
| Preserve unrelated servers and resident owners. Cache reclamation cannot free | |
| allocations held by a live CUDA process. Do not load independent huge model | |
| copies concurrently on the reference machine. | |