moonshotai/Kimi-K3.1-Pro
2.8T-parameter native multimodal MoE with Kimi Delta Attention, sparse MLA, and a 1M-token context window
TP8 on two GB300 trays or one B300 node, or one MI355X node, for the MXFP4 checkpoint; TP32 on a 4-host TPU slice
export GLOO_SOCKET_IFNAME=$IFACE_NAME export NCCL_SOCKET_IFNAME=$IFACE_NAME export VLLM_ENGINE_READY_TIMEOUT_S=3600 vllm serve moonshotai/Kimi-K3.1-Pro \ --trust-remote-code \ --tensor-parallel-size 8 \ --nnodes 2 \ --node-rank 0 \ --master-addr $HEAD_IP \ --load-format fastsafetensors \ --enable-auto-tool-choice \ --tool-call-parser kimi_k3 \ --reasoning-parser kimi_k3
The interactive builder loads with JavaScript. Append .md to this page's URL, query string included, for any configuration's command as Markdown — e.g. /moonshotai/Kimi-K3.1-Pro.md.
Overview
Kimi-K3.1 keeps the Kimi-K3 layout (Kimi Delta Attention, 896 routed experts with 16 active per token, a latent MoE projection and a vision encoder) and adds sparse attention (DSA, top-2048 indexer) to 24 of its MLA layers. The checkpoint ships MXFP4 routed-expert weights; everything else is BF16.
The baseline is the simplest working setup on NVIDIA: one tensor-parallel group of 8 GPUs, either two GB300 trays or one B300 node. Throughput was not tuned.
VR200 (preview) takes the same TP8 layout on two trays, in the vllm/vllm-openai:kimi-k31-cu134
image (CUDA 13.4). It uses the Blackwell flags and hasn't been tuned or verified on Rubin.
On MI355X, one node takes the same TP8 layout with the AMD profile's AITER environment, in the
day-0 vllm/vllm-openai-rocm:kimi-k31 image. So far only the
AgentX TP8 configuration has run on MI355X: the tuned single-node AgentX
configuration for concurrency 48, with DCP8, the K3.1 DSpark draft and host KV offload.
On Zhenwu PPUs, the default MXFP4 checkpoint runs without speculative decoding on
two 16-PPU 810E nodes with TP32 / EP32, or four 8-PPU M890 nodes with TP8 / DP4 / EP32.
On 810E, ppu_deep_gemm_w4a16 loads the checkpoint with a W4A16 compute path.
Use the PPU image specified for each hardware configuration.
On TPU, the model is served by vLLM torch-TPU, text-only: the vision tower is not loaded. The validated layout is TP32 with expert parallelism on a 2x2x4 TPU v7x slice (16 chips, 32 devices, on 4 hosts). See TPU serving.
Tensor + expert parallelism
On one B300 node, the Tensor + Expert Parallel strategy keeps attention at TP8 and runs the routed experts with expert parallelism on the MegaMoE kernel. It has the lowest long-prompt time to first token of the single-node layouts: a single 340K-token prompt prefills in about 10 s, against about 15 s at plain TP8 (8x B300, one request at a time, pre-release checkpoint).
Long context: decode context parallelism
The Decode Context Parallelism row shards the MLA latent and indexer-key caches across the 8 GPUs of the TP group instead of replicating them, so DCP8 holds about 7x the KV cache tokens of TP8 (about 18.5M vs 2.6M tokens with FP8 KV on 8x B300). Prefill is as fast as at TP8. Decode steps are 7–25% slower than TP8 at the same batch, so use DCP when KV capacity is the limit: very long contexts or many long-lived agentic sessions.
Low-latency decode
The Low-latency decode feature switches decode steps to a fused CuTe DSL path tuned for small batches; prefill and mixed steps still run the default path. On 8x B300 at TP8 it cuts the decode step by 1.6–1.7x at batch 1 and 1.2–1.3x at batch 32–64. Under DCP8 it brings decode to within 6% of TP8. It requires the V2 model runner and FULL decode CUDA graphs (the defaults), TP8 or TP8 + DCP8, and no expert parallelism in this recipe.
NVFP4 KV cache
The NVFP4 KV cache feature stores the MLA latent in NVFP4 (352 bytes per token per layer instead of 576) and holds about 1.5x the KV cache tokens of FP8. The indexer keys stay FP8, so the top-2048 token selection is unchanged. GSM8K matched FP8 on 8x GB300 (96.1% vs 96.2%); long-context accuracy has not been measured yet.
TPU serving
TPU serving runs through vLLM torch-TPU and
is text-only: the vision tower is not loaded. K3.1 support is under review as
vllm-torchtpu#2775; until it merges,
the Install tab on TPU builds from the kimi-k31pro staging branch (Python 3.12, uv). No
published image or wheel carries it yet.
The generated command uses vllm-torchtpu's default multiprocessing multi-host backend: run the
head command on the slice's first host and the worker commands on the remaining hosts (the
builder renders both). The Multi-Node TEP strategy at 4 nodes matches the validated flags of
vllm-torchtpu#2775 with two
differences: #2775 ran one driver over a Ray cluster (TPU_MULTIHOST_BACKEND=ray), and its
GSM8K validation used the completions API, so the default-on chat and tool-call parsers were not
exercised on TPU. Validated on a 2x2x4 TPU v7x slice with an FP8 latent KV cache, the unified
block pool and prefix caching: the complete GSM8K split scored 97.50% (TP32) and 97.42%
(TP32 + DCP8), prefix-cache hits returned identical tokens and logprobs, and the BEAM-1M
long-context benchmark matched the GPU reference. The run-specific sizing of that validation
(10K context, 16 sequences, compile sizes) is not the TPU default — it lives in the two
Validated presets: TEP32 and
TEP32 + DCP8 for KV-capacity-bound workloads.
Spec decoding is gated off on TPU for now: DSpark with --async-scheduling (always on in
this configuration) needs vllm-torchtpu#2770,
still open. #2775 validated DSpark with 7 draft tokens once that fix is in.
Prefill/decode disaggregation
The Prefill/Decode Disaggregation strategy runs one TP8 prefill pool (with expert
parallelism) and one DEP16 decode pool (TP1 x DP16 with expert parallelism), and decode
pulls each request's KV from prefill over NIXL. Every PD worker sets
VLLM_SSM_CONV_STATE_LAYOUT=DS: NIXL transfers the Kimi Delta Attention conv state in three
reads, which needs that layout, and the NIXL connector refuses to start without it.
KV cache offloading
The Simple option on the KV Offload row adds SimpleCPUOffloadConnector, a host-DRAM
prefix tier for each GPU. Under Prefill/Decode Disaggregation it is added to the prefill pool
only, next to NIXL in a MultiConnector; decode keeps plain NIXL. The tier pins
cpu_bytes_to_use_per_rank of host memory for every GPU, so size it from the host DRAM that
is free after the engines are up. The tested GB300 prefill workers used 128 GiB per GPU
(512 GiB per tray).
Client usage
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "moonshotai/Kimi-K3.1-Pro",
"messages": [{"role": "user", "content": "Explain sparse attention in two sentences."}],
"temperature": 0.7,
"top_p": 0.95
}'
References
Configurations qualified on specific hardware, layered on the baseline command. Unless marked Opt-in, a preset applies automatically on its hardware and strategy; pick Baseline in the builder to drop it.
Concurrency 48 on one MI355X node: TP8 with DCP8, the K3.1 DSpark draft, host KV offload and the reduced-precision knobs of the best-performance band.
RunbookThroughput measurement only (synthetic acceptance)
The single-node MI355X TP8 AgentX configuration at concurrency 48, from the K3.1 best-performance band. It is a BF16 serving config plus three reduced-precision knobs. It serves text with tool-call and reasoning parsers, using DCP8/A2A.
Serving config.
--max-num-seqs 48and capture sizes 6 to 10240. At concurrency 48, decode batches are at most 48 requests × 6 rows (1 + 5 draft tokens), so the sizes 6 to 288 in steps of 6 cover every decode step exactly. The list then continues from 320 up to 10240, the value of--max-num-batched-tokens, to cover the prefill steps.VLLM_USE_BREAKABLE_CUDAGRAPH=1. K3.1 has notorch.compilesubmodule, so vLLM resolvesFULL_AND_PIECEWISEtoFULL_DECODE_ONLYand captures decode only. Breakable graphs are what let it capture the prefill sizes above 288 as well, so the AMD profile turns them on. They cost graph memory, which comes out of the KV cache: with the old 2-to-576 list (--max-num-seqs 96) they took 63.1 GiB and the server did not start. Keep the capture list to the sizes the workload really uses.--max-num-batched-tokens 10240. With prefix caching, the hybrid KV manager ends every non-final prefill chunk on a block boundary. In this preset (with the dense MLA DSpark draft sharing the block row) K3.1's packed DSA block is 1152 tokens, so after the decode rows a chunk floors to 9216 tokens (6912 at 8192).--gpu-memory-utilization 0.92gives more KV. Keep at least about 6 GiB free per GPU.- The indexer key cache is MXFP4 (
indexer_kv_dtype). AITER needs padded FP4 indexer pages for it. Stock AITER asserts on the page stride at startup. ROCM_AITER_FAis named as the MLA prefill backend, which ROCm already picks first.VLLM_ROCM_DCP_AITER_ALLGATHER=1, the FlyDSL sparse-MLA kernels and the DSA DCP prefill paths are on.kda_prefill_backend: fusedprefills the KDA layers with the fused gfx950 kernel.- Spec decoding (the Spec decoding feature, on in this preset) uses the K3.1 DSpark draft (5 layers, not the K3 draft) with 5 tokens,
ROCM_AITER_MLAattention, FP8 KV, probabilistic drafting and vLLM's default (standard) rejection sampler. The draft isInferact/Kimi-K3.1-Pro-DSpark-preview. - The Simple KV-offload option gets 224,875,000,000 bytes of host DRAM per rank. Size
cpu_bytes_to_use_per_rankto your host.
Reduced precision (best-performance band). The serving config keeps linear layers, MoE combine and all-reduce in BF16. This preset adds:
--quantization-config '{"targets":{"*in_proj_qkvgfab":"fp8_per_channel"}}': only the KDA input projections are quantized online to FP8 per channel.AITER_FLYDSL_STAGE2_FP8=1: the FlyDSL MoE down projection writes its per-route outputs as MXFP8 before they are summed.VLLM_ROCM_QUICK_REDUCE_QUANTIZATION=INT4withVLLM_ROCM_QUICK_REDUCE_MIN_SIZE_BYTES_MB=16: all-reduces of 16 MiB and more use the lossy INT4 codec. To serve with BF16 all-reduce, unset both.
Drop all three for BF16 precision.
Environment outside the builder. The lane also sets AITER_BF16_FP8_MOE_BOUND=0 (the SiTUv2 path does not read it), VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS=1200 for long agentic prefills, PYTHONNOUSERSITE=1, HSA_NO_SCRATCH_RECLAIM=0, and HSA_SCRATCH_SINGLE_LIMIT_ASYNC=25769803776 (24 GiB), which caps a single asynchronous scratch allocation.
Throughput measurement only (synthetic acceptance)
The AgentX runs replace real verification with synthetic acceptance at the golden acceptance length for 5 draft tokens, 3.62. Only --speculative-config changes:
--speculative-config '{"model":"Inferact/Kimi-K3.1-Pro-DSpark-preview","num_speculative_tokens":5,"method":"dspark","attention_backend":"ROCM_AITER_MLA","kv_cache_dtype":"fp8","draft_sample_method":"probabilistic","rejection_sample_method":"synthetic","synthetic_acceptance_length":3.62}'
Synthetic acceptance skips real verification. Never use it to serve users or to evaluate accuracy.
The #2775 validation config on a 2x2x4 v7x slice: complete GSM8K at 97.50%, prefix-cache hits returning identical tokens and logprobs, BEAM-1M matching the GPU reference.
Runbook
The configuration vllm-torchtpu#2775 validated on the real checkpoint on a 2x2x4 TPU v7x slice: complete GSM8K at 97.50% (1,286/1,319), prefix-cache probes returning identical tokens and logprobs, and BEAM-1M long context matching the GPU reference.
#2775 ran one vllm serve driver over a Ray cluster (TPU_MULTIHOST_BACKEND=ray); the builder renders torchtpu's default multiprocessing backend (per-host --nnodes / --node-rank / --headless). The flags match; the multi-host transport differs. GSM8K ran through the completions API, so the default-on chat and tool-call parsers were not exercised on TPU.
GSM8K capped outputs at 1,024 tokens with 8 concurrent requests; --max-model-len 10240 and --max-num-seqs 16 come from that run, not from a serving-quality target.
TEP32 + DCP8 on the same 2x2x4 v7x slice: complete GSM8K at 97.42%. Pick it when KV capacity, not decode speed, is the limit. DSpark does not support DCP on TPU, so this preset keeps Spec decoding off.
Runbook
The TP32 + DCP8 arm of the vllm-torchtpu#2775 validation on the same slice: complete GSM8K at 97.42% (1,285/1,319), with prefix-cache and long-context checks matching the TP32 arm. Compile sizes drop the 1-batch capture (DCP decode batches start at 8).