Modelplane Modelplane docs

Moonshot AI/Kimi K3.1 Pro

A 2.8T hybrid-attention MoE served by SGLang on one 8x B300 node.

View on Hugging Face
This document is for an unreleased version of Modelplane.

This document applies to the Modelplane main branch and not to the latest release v0.7.

Moonshot AI’s Kimi K3.1 Pro (2.8 trillion parameters, 104 billion active) served by SGLang as one Standalone engine on one 8x B300 node on EKS. The weights (~1.42 TiB, MXFP4 routed experts and BF16 elsewhere) fit the node’s 8 × 288 GB with room for a large KV cache, so the engine is tensor-parallel across the 8 GPUs and doesn’t need a gang or prefill/decode disaggregation. Decode context parallelism shards the KV cache across the ranks, which gives a pool of about 8.6M tokens.

The model mixes linear attention with sparse attention layers, which changes how prefix caching behaves. SGLang reuses a cached prefix only up to the last linear-attention state it kept. The deployment keeps several states per prefix path. The comments in model-deployment.yaml explain the flags beyond SGLang’s basics.

This recipe ran on one p6-b300.48xlarge on EKS behind an InferenceGateway, serving recorded coding-agent traffic. That run read the weights from a copy staged on the node’s local NVMe; this recipe reads them from the shared ModelCache. moonshotai/Kimi-K3.1-Pro is a public repository under Moonshot AI’s own license, so no Hugging Face token or Secret is needed. Apply the platform side first, then the ML side.

Validated deployments

MoE 2.8T A104B 524,288 ctx SGLang
Cloud
Google Cloud Azure Nebius Vultr Civo B Bring your own
Accelerator
A16 16G L4 24G A100 40/80G H100 80G H200 141G B300 288G MI325X 256G CPU 8× per node
Serving mode
Standalone LeaderWorker PrefillDecode
Precision
Engine
vLLM SGLang llama.cpp
Image
lmsysorg/sglang:dev-kimi-k31-pro

Platform

inference-class.yaml
# InferenceClass for one EKS p6-b300.48xlarge: 8x NVIDIA B300 288GB over NVLink.
# The GPUs are DRA devices; the Kimi K3.1 Pro ModelDeployment's nodeSelector
# matches eight Blackwell GPUs with at least the 250Gi each this class
# advertises, so it can't land on an 8x B200 node, where the weights don't fit.
apiVersion: modelplane.ai/v1alpha1
kind: InferenceClass
metadata:
  name: eks-b300-8x-p6
spec:
  description: "EKS p6-b300.48xlarge, 8x NVIDIA B300 288GB"
  provisioning:
    provider: EKS
    eks:
      instanceType: p6-b300.48xlarge
      diskSizeGb: 200
      accelerator:
        type: nvidia-b300
        count: 8
  devices:
  - name: gpu
    claim: DRA
    driver: gpu.nvidia.com
    deviceClassName: gpu.nvidia.com
    count: 8
    attributes:
      architecture: { string: Blackwell }
      cudaComputeCapability: { version: "10.3.0" }
    capacity:
      memory: { value: "250Gi" }
inference-cluster.yaml
# EKS InferenceCluster with one 8x B300 node. p6-b300.48xlarge capacity is
# scarce on demand. To use an EC2 Capacity Block, register it as a
# CapacityReservation and set the pool's reservationRef, as
# qwen3-coder/inference-cluster.yaml does.
apiVersion: modelplane.ai/v1alpha1
kind: InferenceCluster
metadata:
  name: eks-b300
  labels:
    modelplane.ai/cloud: eks
    modelplane.ai/region: us-west
spec:
  cluster:
    source: EKS
    eks:
      region: us-west-2
  nodePools:
  - name: gpu-b300-8x
    className: eks-b300-8x-p6
    nodeCount: 1
    minNodeCount: 1
    maxNodeCount: 1

Deployment

model-cache.yaml
# The weights, staged once per cluster on shared storage (RWX) and mounted at
# /mnt/models in the serving pod. moonshotai/Kimi-K3.1-Pro is ~1.42 TiB
# (1,454 GiB: MXFP4 routed experts, BF16 elsewhere), so staging and every
# engine start that reads it take a while. Pin the revision the deployment
# serves.
apiVersion: modelplane.ai/v1alpha1
kind: ModelCache
metadata:
  name: kimi-k3-1-pro
  namespace: ml-team
spec:
  source: HuggingFace
  huggingFace:
    repo: moonshotai/Kimi-K3.1-Pro
    revision: d9e99b0792a5e93b78ea9bea62a68167e36ddd9e
    sizeGiB: 1600
model-deployment.yaml
# Kimi K3.1 Pro served by SGLang on one 8x B300 node: one Standalone engine,
# tensor-parallel across the 8 GPUs with decode context parallelism (DCP) over
# all 8, so each rank holds an eighth of the KV cache instead of a full copy.
# At --mem-fraction-static=0.88 that gives a KV pool of ~8.6M tokens.
#
# The image is SGLang's Kimi K3.1 day-0 build, pinned by digest (the tag
# dev-kimi-k31-pro moves). The model forces its own KV dtype (fp8_e4m3), page
# size (64) and attention backend, so none are set here.
#
# Flags beyond the basics:
#   --dcp-size=8, --dcp-comm-backend=fi_a2a: decode context parallelism over
#     the 8 ranks, from the SGLang cookbook's B300 DCP8 cell; it shards the KV
#     cache instead of copying it to every rank.
#   --ep-size=2: the same cell's expert-parallel size, kept as the cookbook
#     sets it; not tuned here.
#   --context-length=524288: half the model's native 1,048,576, so more
#     sessions share the KV pool. Raise it for single long-context requests.
#   --max-running-requests=48: the linear-attention (KDA) state pool scales
#     with slots; 48 leaves room for cached prefix states.
#   --mamba-max-states-per-path=4: how many linear-attention states the radix
#     cache keeps along one prefix path. A hybrid model reuses a cached prefix
#     only up to the deepest kept state, so 1 (the cookbook's value) misses most
#     reuse when a client edits its history between turns, as coding agents do;
#     4 reused noticeably more of that traffic's prefixes. SGLang's default, -1,
#     keeps every state; each kept state takes a
#     slot from the same pool as running requests, and only 4 has been measured
#     here, so the recipe keeps that bound.
#   --weight-loader-prefetch-checkpoints: prefetches the weight files, which
#     SGLang recommends for network storage such as the ModelCache's.
# No HiCache: a hybrid linear-attention model's prefix restored from host
# memory answers wrongly (sgl-project/sglang#39830). No speculative decoding:
# the model has no MTP layer.
apiVersion: modelplane.ai/v1alpha1
kind: ModelDeployment
metadata:
  name: kimi-k3-1-pro
  namespace: ml-team
spec:
  replicas: 1
  template:
    spec:
      modelCacheRef:
        name: kimi-k3-1-pro
      engines:
      - name: kimi
        members:
        - role: Standalone
          nodeSelector:
            devices:
            - name: gpu
              count: 8
              selectors:
              - cel: |
                  device.driver == "gpu.nvidia.com" && device.attributes["gpu.nvidia.com"].architecture == "Blackwell" && device.capacity["gpu.nvidia.com"].memory.compareTo(quantity("250Gi")) >= 0
          template:
            metadata:
              labels:
                llm-d.ai/engine-type: sglang   # the picker reads SGLang's metric names
            spec:
              containers:
              - name: engine
                image: lmsysorg/sglang:dev-kimi-k31-pro@sha256:67fc77d1cbe67de27ca54d874c82757a4844743fea899ea7d0df547e30c2c391
                command: ["python3", "-m", "sglang.launch_server"]
                args:
                - --model-path=moonshotai/Kimi-K3.1-Pro
                - --revision=d9e99b0792a5e93b78ea9bea62a68167e36ddd9e
                - --served-model-name=$(MODELPLANE_SERVED_MODEL_NAME)
                - --trust-remote-code
                - --tp-size=8
                - --dcp-size=8
                - --dcp-comm-backend=fi_a2a
                - --ep-size=2
                - --context-length=524288
                - --mem-fraction-static=0.88
                - --max-running-requests=48
                - --mamba-max-states-per-path=4
                - --weight-loader-prefetch-checkpoints
                - --reasoning-parser=kimi_k3
                - --tool-call-parser=kimi_k3
                # SGLang serves no /metrics without it, and Modelplane's
                # collector reads the engine's metrics from there.
                - --enable-metrics
                - --host=0.0.0.0
                - --port=8000
model-service.yaml
# Name the model, ml-team/kimi-k3-1-pro, in an OpenAI or Anthropic request to
# an InferenceGateway that serves it, e.g.:
#   ADDR=$(kubectl get ig public -o jsonpath='{.status.endpoints.openAI}')
#   curl "$ADDR/chat/completions" -H 'Content-Type: application/json' \
#     -d '{"model":"ml-team/kimi-k3-1-pro","messages":[{"role":"user","content":"hello"}]}'
apiVersion: modelplane.ai/v1alpha1
kind: ModelService
metadata:
  name: kimi-k3-1-pro
  namespace: ml-team
spec:
  endpoints:
  - name: kimi-k3-1-pro
    selector:
      matchLabels:
        modelplane.ai/deployment: kimi-k3-1-pro