docs/cookbook/autoregressive/Moonshotai/Kimi-K3.mdx
For all methods and hardware platforms, see the official SGLang installation guide. The two paths below match the Python / Docker toggle in the command panel.
<Tabs> <Tab title="Python (pip / uv)">pip install --upgrade pip
pip install uv
uv pip install sglang
Then run the Python output of the command panel below in that environment.
</Tab> <Tab title="Docker">docker pull lmsysorg/sglang:latest # NVIDIA (CUDA)
docker pull lmsysorg/sglang-rocm:v0.5.17-rocm720-mi35x-20260817 # AMD MI350X / MI355X (ROCm)
For how to launch the image, see Install → Method 3: Using Docker. Substitute the inner sglang serve ... with what the command generator below produces.
Pick your hardware, then the deployment shape and operating point. Node count follows the hardware recipe (B200 2×8, GB200 4×4, H100 4×8, B300 1×8, H200 2×8 — 4×8 on Unified High-Throughput, GB300 2×4, MI350X/MI355X 1×8), so it is not a separate choice. If you serve the NVFP4 checkpoint (nvidia/Kimi-K3-NVFP4, the Quantization row in the panel below), use the lmsysorg/sglang:dev-dev-kimi-k3-nvfp4 image.
PD Mode — Unified serves prefill and decode together. Prefill / Decode split them into dedicated pools (see PD disaggregation); Prefill ships two strategies, both chunked at 16k. On the 8-GPU platforms (B300 1×8, GB300 2×4), Default is TP8 and Long-Context is --pp-size 8 --tp-size 1. On the 16-GPU platforms (B200 2×8, GB200 4×4), both are --pp-size 16 --tp-size 1 and differ only in --mem-fraction-static (0.85 vs 0.90) — deep PP is the throughput shape there, not just the long-context one (see Deep PP).
Strategy — the operating point within that shape:
extra_buffer_lazy) and H200 (widens to 4×8 TP32/EP32 at --mem-fraction-static 0.90).Long-Context appears only under the Prefill PD mode; for long-context unified serving on B200, start from High-Throughput and raise --context-length.
Spec Decode — layers onto the strategy without changing it, on every platform except B200. DSPARK proposes 7 draft tokens per step (tune in the Playground) and requires pp_size == 1, so on B200 it also drops the pipeline and re-lays the same 16 GPUs flat: PP2 × TP8 → TP16, PP2 × DCPEP8 → DCPEP16. DFLASH has no published draft checkpoint. The win is largest on short interactive traffic and fades as the prompt grows.
import { Deployment } from "/src/snippets/_deployment.jsx"; import { config } from "/src/snippets/configs/moonshotai/kimi-k3.jsx"; import { benchmarks } from "/src/snippets/configs/moonshotai/kimi-k3-benchmarks.jsx"; import { KimiK3MambaRatioCalculator } from "/src/snippets/_kimi_k3_mamba_ratio_calculator.jsx";
<Deployment config={config} benchmarks={benchmarks} />--mamba-full-memory-ratio is the ratio between the KDA state pool and the MLA KV pool. Every parameter below except L is read live from the Deploy panel and Playground selection; the balanced value is the per-request cost ratio:
ratio = (S + D) x state_bytes / (L x (mla_kv_bytes / DCP + draft_kv_bytes))
S — KDA state slots per request: extra_buffer=5, extra_buffer_lazy=4, no_buffer=3, disabled radix cache =1. SGLANG_OPT_MAMBA_SKIP_DECODE_LOCK frees one slot on the extra-buffer strategies; with the overlap scheduler off (or pp > 1, which disables it) the track buffer costs one slot instead of two.D — verify intermediate states under speculative decoding: 0 when disabled, otherwise DSPARK block size + 1 (8 at the default 7). ReplaySSM (--enable-linear-replayssm-spec) folds them into a per-slot ring, returning D to 0.state_bytes — one state slot's bytes, from K3's fixed geometry, the attention-TP width, and the SSM dtype.mla_kv_bytes — one token's MLA latent KV bytes (KV-dtype dependent); DCP shards it across its ranks. The DSPARK draft model's KV (~1.4 KB per token) is replicated on every rank, so it enters flat — negligible without DCP, the same order as the sharded MLA share under DCP8.L — average total request length in tokens: input + output.<a id="playground" style={{ scrollMarginTop: "96px" }} />
The Playground is where you experiment with SGLang features beyond the deployment matrix. The Deploy panel above emits the recipes the SGLang team is converging on; the Playground lets you turn on additional knobs on top of whichever cell the Deploy panel is currently showing.
import { Playground } from "/src/snippets/_playground.jsx";
<Playground config={config} />Kimi-K3 is Moonshot AI's flagship hybrid MoE vision-language model: 2.8 trillion parameters, 16 of 896 experts active per token, roughly 2.5× the scaling efficiency of Kimi-K2. The backbone interleaves Kimi Delta Attention (KDA) with MLA across 93 layers (plus Attention Residuals and Stable LatentMoE); serving supports image input and a 1M-token window with prefix caching. Weights ship in MXFP4: the FlashInfer MXFP4 (trtllm-gen SiTU) runner serves them on Blackwell, Marlin (W4A16) elsewhere, MegaMoE for short-context batch throughput.
K3 always runs with thinking enabled, with reasoning depth controlled by reasoning_effort (low / high / max; default max).
Every cell in the Deploy panel above is currently marked Final Verification In Progress: the recipe runs, but its serving round on the final weights and current code is still open. Re-measure throughput and accuracy before you rely on any of them. </Note>
Recommended generation: temperature=1.0, top_p=0.95, presence_penalty=0, frequency_penalty=0 (fixed by the model; informational — do not hardcode in sample code).
Resources: HuggingFace · Kimi-K3 Quickstart.
Memory: two pools, one flag. K3 splits static memory into a worst-case-reserved KDA state pool (it sets the concurrency ceiling) and a paged MLA KV pool, divided by --mamba-full-memory-ratio. The command panel pins that flag to the calculator's output — set your average request length there; every other calculator input follows the panels. After boot, read back max_total_num_tokens (the KV side) and the admitted-request cap (the state side).
Capacity levers, all in the Playground. Each trades precision or cache behavior for capacity — re-verify accuracy on your workload:
| Lever | Effect |
|---|---|
--mamba-radix-cache-strategy extra_buffer_lazy | 4 state slots per request instead of 5 |
--mamba-ssm-dtype bfloat16 | ~halves state bytes; with spec on, KDA verification falls back from the fused kernel to Triton |
--kv-cache-dtype fp8_e4m3 | halves KV bytes per token; under PD both roles must match at connect |
--mem-fraction-static 0.90–0.92 | cheapest first win when the boot log shows a large idle avail mem |
SGLANG_OPT_MAMBA_SKIP_DECODE_LOCK=1 | frees one more slot per request (experimental, under validation) |
Speculation: DSPARK holds block size + 1 (= 8) intermediate states per request — the calculator folds this in — and an unset --max-running-requests resets to 48 under spec (the command panel reminds you; set it explicitly to raise).
MoE runner. Leave --moe-runner-backend unset on Blackwell: FlashInfer MXFP4 (W4A8, official trtllm-gen SiTU kernels) is selected with the pinned FlashInfer 0.6.17 dependency; H100/H200 pin Marlin. The B200 Balanced and High-Throughput cells pin flashinfer_mxfp4 explicitly because that is the shape they were brought up on. The published Docker images install the matching official flashinfer-python, flashinfer-cubin, and flashinfer-jit-cache packages.
Attention backend. Leave all three attention knobs unset on Blackwell: K3 resolves prefill, decode, and — under DSPARK — verification as a set (trtllm_mla across the board; cutedsl_mla takes decode and verification under DCP). On the non-DCP recipes, setting any one of the three cancels the auto-resolution for the others. The B200 Balanced and High-Throughput cells pin --decode-attention-backend cutedsl_mla, which is what auto-resolution picks for those DCP recipes anyway — it is written out because it is the shape they were brought up on, not because it changes the resolution. H100/H200 pin flashmla for decode.
Context length. --context-length bounds the longest accepted request plus some context-scaled buffers; it does not size the KV pool. For long context the lever that adds capacity is fp8_e4m3 KV.
DSPARK. Adds --speculative-algorithm DSPARK plus the draft checkpoint on top of the showing strategy. Leave --speculative-draft-attention-backend unset. No serving round on the final draft checkpoint has landed — measure against the same recipe running NOSPEC before adopting.
Per-platform notes:
| Platform | Topology | Notes |
|---|---|---|
| B300 1×8 | TP8 (+DCP8) | accuracy-first defaults on Low-Latency and Balanced |
| GB300 2×4 | TP8/DCP8 | MNNVL transport and cuMem auto-detected |
| B200 2×8 | PP2 × TP8 on Low-Latency, PP2 × DCPEP8 on Balanced and High-Throughput. DSPARK re-lays the same 16 GPUs as TP16 / TP16+DCP16+EP16. PD prefill is TP1 × PP16 | Unified serves all three operating points; Long-Context is a Prefill-only strategy |
| GB200 4×4 | TP16/DCP16 | MNNVL auto-detected |
| H200 2×8 (4×8 on Unified High-Throughput) | TP16/EP16 + symm-mem, Marlin + FlashMLA; High-Throughput widens to TP32/EP32 over 4 nodes at mem-frac 0.90 with extra_buffer_lazy | same block on every node; export the cross-node NIC (GLOO_SOCKET_IFNAME / NCCL_SOCKET_IFNAME, SGLANG_HOST_IP); keep NCCL_MNNVL_ENABLE=1 NCCL_CUMEM_ENABLE=1 |
| H100 4×8 | TP32/EP32, Marlin + FlashMLA | SM90a build of the K3 image; pin NCCL/Gloo to the same NIC on all nodes; least post-weight headroom (80 GB) |
| MI350X/MI355X 1×8 | TP8 ROCm/AITER | AITER A8W4 FlyDSL MoE, Triton attention (SGLANG_MLA_DECODE_TUNE=1 for gfx950 MLA decode geometry), graph bs up to 256, fp8 kvcache; DSPARK supported |
DCP notes — the DCP cells are Balanced and High-Throughput on every Blackwell platform, in both the Unified and Decode roles:
--dcp-comm-backend unset (fabric-resolved: fi_a2a on GB200/GB300, a2a on B200/B300).--enable-symm-mem under DCP (force-disabled for decode-graph correctness).tokenspeed_mla force-rewrites --kv-cache-dtype to fp8; the default cutedsl_mla serves either dtype.r > 1 is legal): bfloat16 state buys admission, fp8 KV buys context.--moe-a2a-backend is set.No cell has a serving round in this exact shape — treat them as starting points to verify.
K3 always thinks; the kimi_k3 reasoning parser (toggle Reasoning Parser in the Parsers card of the Playground above) separates that thinking from the final answer — thinking lands in message.reasoning_content, the answer in message.content. Control the reasoning depth with reasoning_effort (low / high / max; default max).
from openai import OpenAI
client = OpenAI(base_url="http://localhost:30000/v1", api_key="EMPTY")
resp = client.chat.completions.create(
model="moonshotai/Kimi-K3",
messages=[{"role": "user", "content": "What is 15% of 240?"}],
reasoning_effort="high", # "low" | "high" | "max" (default max)
)
msg = resp.choices[0].message
print("Reasoning:", getattr(msg, "reasoning_content", None))
print("Answer:", msg.content)
Pending update...
Enable the kimi_k3 tool-call parser (toggle Tool Call Parser in the Parsers card of the Playground above) to surface structured tool calls via message.tool_calls. Because K3 is a thinking model, the follow-up turn may put text in reasoning_content as well as content — print both.
from openai import OpenAI
client = OpenAI(base_url="http://localhost:30000/v1", api_key="EMPTY")
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}]
resp = client.chat.completions.create(
model="moonshotai/Kimi-K3",
messages=[{"role": "user", "content": "What's the weather in Beijing?"}],
tools=tools,
)
msg = resp.choices[0].message
print("Reasoning:", getattr(msg, "reasoning_content", None))
print("Tool calls:", msg.tool_calls)
Pending update...
K3's hybrid HiCache tiers the paged MLA KV and the KDA/mamba state across L1 (GPU) / L2 (host) / L3 (Mooncake) — enable it from the HiCache card in the Playground above for long multi-turn workloads.
Unified and Decode roles), the host tiers are not fully DCP-aware yet: L3 always, and L1+L2 with Spec Decode on, drop the DCP flags (the command hints call it out — per-request KV capacity shrinks accordingly). L1+L2 with Spec Decode off keeps DCP. Only DCP goes: the MLA KV reverts to TP-replicated, but the cell's other parallelism stays, so B300/GB300/GB200 land on plain TP while B200 Unified keeps its --pp-size 2 / --ep-size.PD splits prefill and decode into separate server groups; because K3 is hybrid, the transfer moves both the paged MLA KV and the KDA recurrent state.
30000, decode 30100 (derived ZMQ/dist ranges must not collide on a shared host). The positional 8998 after --prefill must match --disaggregation-bootstrap-port, or only the decode worker registers.--mamba-radix-cache-strategy is inert. Keep --disaggregation-decode-extra-slots pinned: unpinned it defaults to twice the batch below 32 requests and zero above.Deep PP is --tp-size 1 with one pipeline stage per GPU — --pp-size 8 on B300/GB300, --pp-size 16 on B200/GB200. Pipeline P2P overlaps the next microbatch's compute, unlike TP/EP collectives, and each stage owns whole layers (a clean slice of KV and state). --tp-size 1 is also what buys context: above TP1 the MLA KV is replicated across the TP ranks, so TP2 × PP8 holds roughly half the tokens of TP1 × PP16 for the same memory.
Default stays TP8; on the 16-GPU platforms deep PP wins at the Default operating point too, so both strategies use it — measured on GB200 at ISL 8192 / concurrency 32, PP16 × TP1 reached 4550 prefill tok/s/GPU vs 3596 (PP8 × TP2), 2407 (TEP16), and 1652 (TP16). Below concurrency ~8 the pipeline cannot fill and TEP16 leads instead (1947 vs 1227) — use --tp-size 16 --ep-size 16 there.pp_size == 1 required) — on B200/GB200 that applies to Default as well.python3 -m sglang_router.launch_router \
--pd-disaggregation \
--prefill http://<prefill-host>:30000 8998 \
--decode http://<decode-host>:30100 \
--host 0.0.0.0 --port 8000 \
--disable-circuit-breaker \
--health-check-interval-secs 999999
Clients then send requests to the router (:8000) instead of an individual role server.
The open-source K3 serving contract currently supports image input only — its processor rejects video and audio input.
Use VLM Transport in the command picker. Auto is a topology-aware starting
point, not a claim that one configuration is fastest for every workload.
| Picker selection | Processor-to-scheduler feature path |
|---|---|
| Auto · single-node Unified CUDA | CUDA IPC |
| Auto · Unified GB200/GB300 | CUDA VMM when IMEX is available; CPU otherwise |
| Auto · PD or other topologies | CPU |
| CPU | CPU, with no GPU feature pool |
CUDA IPC and CUDA VMM reserve up to SGLANG_MM_FEATURE_CACHE_MB (1 GiB by
default) on the base GPU and fall back to CPU per tensor when full. This setting
does not control EPD encoder output or PD KV/KDA transfer. K3 already defaults to
2 processor workers and 16 I/O workers; leave those flags unset unless tuning.
| Feature | K3 behavior |
|---|---|
| PD | Supported. Image processing and ViT run on prefill; the PD transfer then moves both paged MLA KV and KDA recurrent state as described in PD disaggregation. |
| EPD | Supported on the public kimi-k3 branch. Use an --encoder-only vision role and a --language-only prefill role; add the normal decode role for full EPD. See the EPD guide. |
| MM encoder DP | Built in. K3 shards complete images across TP ranks, so leave --mm-enable-dp-encoder unset in unified, PD-prefill, and encoder-only roles. |
| MM feature transport | Processor-to-scheduler features only. EPD encoder output and PD KV/KDA transfer use their own backends. |
| ViT BCG | Compatible with unified and encoder-only roles, but recommended only for repeated encoder shapes after measuring the HBM trade-off below. |
Keep ViT BCG off for general serving; enable SGLANG_VIT_ENABLE_CUDA_GRAPH=1 only for ViT-only / EPD encoder workloads with recurring image shapes and spare HBM.
Use this profile when keeping HBM headroom matters more than peak concurrency. It removes the GPU feature pool, keeps ViT BCG disabled, halves the context window, caps concurrency, and lowers the static-memory target:
sglang serve \
--trust-remote-code \
--model-path moonshotai/Kimi-K3 \
--tp-size 8 \
--context-length 65536 \
--enable-symm-mem \
--mem-fraction-static 0.82 \
--mm-feature-transport cpu \
--reasoning-parser kimi_k3 \
--tool-call-parser kimi_k3 \
--host 0.0.0.0 \
--port 30000
--mem-fraction-static 0.82 is a conservative B300 starting point, not a portable minimum: raise it toward 0.85 if startup reports insufficient memory; if HBM must go back to other workloads, reduce context/concurrency first. The precision levers (fp8_e4m3 KV, bfloat16 SSM state) save far more but stay accuracy-gated.
The KDA state pool is the concurrency ceiling — DP, EP, and DCP do not shard it; only attention-TP width, SSM dtype, and cache strategy change the per-GPU bill. The MLA KV is cheap to shrink (fp8) or deduplicate (DCP).
Two presets come out of this, at N = 8k GPUs:
| Preset | What it trades | Pick it for |
|---|---|---|
Peak Throughput — dp = k, attention-TP 8 | State shards 8-way. The per-step KDA all-reduce stays within one 8-GPU B200/B300 node, or spans two 4-GPU GB200/GB300 nodes over MNNVL. --kv-cache-dtype fp8_e4m3 is load-bearing — bf16 KV does not fit 128 requests per replica. | Maximum sustained TPS — the default large-scale shape. |
Peak Capacity (+DCP8) — dp = k + --dcp-size 8 | Deduplicates the attention-TP group's MLA KV: concurrency ceiling +72% at the same engine throughput, ~1.8× ITL. | Context ≥ ~16K, or per-replica concurrency past 128. |
--dp-size = GPU count, attention-TP 1) — the shape behind the 64-GPU sweep's ~3K tok/s per GPU — is not a preset: 288 GB GPUs only, radix forced off, no head-to-head against the preset shape.The Peak Throughput preset at 32 GPUs on B200/B300 (4 nodes × 8; every node runs the same command with its own --node-rank). On GB200/GB300 the same 32-GPU shape uses 8 nodes × 4, and the Playground emits --nnodes 8:
SGLANG_OPT_DEEPGEMM_MEGA_MOE_NUM_MAX_TOKENS_PER_RANK=20480 \
sglang serve \
--trust-remote-code \
--model-path moonshotai/Kimi-K3 \
--tp-size 32 --ep-size 32 \
--enable-dp-attention --dp-size 4 --enable-dp-lm-head \
--nnodes 4 --node-rank <rank> --dist-init-addr <node0-ip>:20000 \
--moe-a2a-backend megamoe --moe-runner-backend deep_gemm \
--kv-cache-dtype fp8_e4m3 \
--mamba-ssm-dtype bfloat16 \
--mamba-radix-cache-strategy extra_buffer_lazy \
--mem-fraction-static 0.92 \
--reasoning-parser kimi_k3 --tool-call-parser kimi_k3 \
--host 0.0.0.0 --port 30000
Scale by holding the per-replica shape fixed and moving only the replica count; pool sizing rides the calculator-driven --mamba-full-memory-ratio, which folds in DP, DCP, precision, and speculation:
| GPUs | B200/B300 nodes | GB200/GB300 nodes | --tp-size / --ep-size | --dp-size |
|---|---|---|---|---|
| 16 | 2×8 | 4×4 | 16 | 2 |
| 32 | 4×8 | 8×4 | 32 | 4 |
| 64 | 8×8 | 16×4 | 64 | 8 |
For Peak Capacity, add --dcp-size 8 and re-derive the pool split with the Mamba ratio calculator.
Both presets are one click away in the Playground above: pick a Cluster Size and a Large-Scale Preset and the full command composes onto whichever cell is showing.
Decisions the preset already makes:
deep_gemm — the fused DeepGEMM all-to-all/MoE path used by these large-scale DP/EP throughput presets, with K3's SiTU activation.