DeepSeek-V4-Pro on GB200
Overviewโ
This guide deploys DeepSeek-V4-Pro on NVIDIA
GB200 NVL72 with vLLM prefill/decode disaggregation (NIXL KV transfer) in a wide
expert-parallel pattern, managed as a single DisaggregatedSet (a pair of LeaderWorkerSets).
Wide-EP spans multiple nodes over GB200's cross-node NVLink (MNNVL) fabric, provisioned through
an NVIDIA DRA ComputeDomain.
It composes the wide expert parallelism and P/D disaggregation foundations with P/D-aware, prefix-cache-aware routing, and ships a range of prefill : decode operating points, from a 16-GPU low-latency layout up to a 56-GPU high-throughput layout.
These manifests were tested on Oracle Cloud Infrastructure (OCI, BM.GPU.GB200.4 nodes). Storage
and DRA may need to be adapted to your environment.
Default Configurationโ
| Parameter | Value |
|---|---|
| Model | deepseek-ai/DeepSeek-V4-Pro |
| Accelerator | NVIDIA GB200 NVL72 (4 GPUs per node), cross-node NVLink via ComputeDomain |
| Serving topology | P/D disaggregated DisaggregatedSet; prefill DEP8, decode TP=8, DEP8 or DEP16 (see Deployments) |
| DP model | Hybrid load balancing (--data-parallel-hybrid-lb), expert parallelism enabled |
| MoE backend | deep_gemm_mega_moe |
| KV transfer | NixlConnector |
| KV cache | FP8, block size 256 |
| Max model length | 9280 tokens |
| Model storage | Node-local NVMe (hostPath /mnt/numa0/hf-cache, ~850 GB model) |
Supported Accelerators and Model Serversโ
This guide includes configurations for the following accelerator and model server combinations:
| Accelerator | ACCELERATOR_TYPE | Served model | vLLM | Notes |
|---|---|---|---|---|
| NVIDIA GB200 NVL72 | gpu | deepseek-ai/DeepSeek-V4-Pro | ๐ก community | OCI BM.GPU.GB200.4 (4 GPUs per node) ยท 4 to 14 nodes (16 to 56 GPUs) by DEPLOYMENT ยท P/D disaggregated wide-EP; needs the NVIDIA DRA driver (ComputeDomain) |
โ validated: covered by a nightly E2E workflow ยท ๐ก community: maintained by the hardware vendor or community, not covered by nightly E2E ยท โ not supported: tracked in the linked issue ยท โ no configuration.
Prerequisitesโ
-
Have the proper client tools installed on your local system to use this guide.
-
Deploy the LeaderWorkerSet controller
v0.11.1or newer. When installing with Helm, pass--set enableDisaggregatedSet=trueto enable theDisaggregatedSetvalidating webhook and RBAC used by the model server. -
Install the NVIDIA DRA driver for GPUs. The cross-node NVLink fabric is provisioned through a
ComputeDomainresource. The guide ships its ownComputeDomainCR (providers/oci/compute-domain.yaml); applying a deployment creates it and the workers claim a channel from it, so no manual fabric setup is needed. -
Create a HuggingFace token and export it as
HF_TOKENin your shell. -
(Optional) Install the monitoring stack if you plan to enable Prometheus monitoring.
Get the guideโ
Every command below runs from a local clone of the llm-d repository: the manifests, Helm values, and Kustomize overlays it applies live next to this guide. Set the branch and clone the repo (if you already have a checkout, skip this and run the remaining commands from inside it):
export BRANCH=main
git clone https://github.com/llm-d/llm-d.git && cd llm-d && git checkout ${BRANCH}
Configure the environmentโ
Set the guide-specific environment variables (DEPLOYMENT picks one of the deployments):
export REPO_ROOT=$(realpath $(git rev-parse --show-toplevel))
export GUIDE_NAME=deepseek-v4
export NAMESPACE=llm-d-deepseek-v4
export MONITORING=false # options: false, true
export MONITORING_VALUES=
export ACCELERATOR_TYPE=gpu # options: gpu
export MODEL_SERVER=vllm # options: vllm
export DEPLOYMENT=oci-low-latency # options: oci-low-latency, oci-low-latency-scaled, oci-mid-curve, oci-balanced, oci-high-tpt, oci-high-tpt-dep16, oci-max-tpt, oci-ultra-tpt, oci-3p2d-dep8-dep16-flashinfer
export MODEL=deepseek-ai/DeepSeek-V4-Pro # the model every deployment serves
source ${REPO_ROOT}/guides/env.sh # defines GAIE_VERSION, ROUTER_CHART_VERSION, router chart URLs, and CURL_TEST_IMAGE
Install the Gateway API Inference Extension CRDs:
# GAIE_URL is automatically calculated from GAIE_VERSION at ${REPO_ROOT}/guides/env.sh
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api-inference-extension/${GAIE_URL}/v1-manifests.yaml
Check that the ComputeDomain CRD is present (if this returns NotFound, install the NVIDIA DRA driver before continuing):
# The NVIDIA DRA driver must be installed: the deployments claim a ComputeDomain
kubectl get crd computedomains.resource.nvidia.com
Create a target namespace for the installation:
kubectl create namespace ${NAMESPACE} --dry-run=client -o yaml | kubectl apply -f -
Create the llm-d-hf-token secret in your target namespace with the key HF_TOKEN matching a valid HuggingFace token to pull models:
kubectl create secret generic llm-d-hf-token \
--from-literal="HF_TOKEN=${HF_TOKEN}" \
--namespace "${NAMESPACE}" \
--dry-run=client -o yaml | kubectl apply -f -
Installation Instructionsโ
1. Deploy the llm-d Routerโ
Prepare the paths to the helm values files for the llm-d router. The router values
(deepseek-v4.values.yaml) run separate prefill and
decode scheduling profiles (prefix-cache affinity filtering and token-load scoring for
prefill; active-request scoring for decode) and pin each request to one
DisaggregatedSet revision during rollouts:
peakPrefillThroughput is an estimate for DeepSeek-V4-Pro on GB200, not a measurement.
The prefix-cache-affinity-filter ships with 20000 tokens/s per prefill pod. Each pod is one
router endpoint fronting 4 DP ranks, and the value is ~5000 tokens/s per rank x 4, estimated
by scaling measured MoE prefill rates to this model (plausible range 12000 to 25200). Measure
your own value with the router calibration tool
using CHUNK_SIZE=8192, because a request must fit --max-model-len 9280. A single
calibration request runs on one rank, so multiply the result by 4 before setting it in
router/deepseek-v4.values.yaml.
# Paths to values files
export ROUTER_BASE_VALUES="${REPO_ROOT}/guides/recipes/router/base.values.yaml"
export ROUTER_VALUES="${REPO_ROOT}/guides/models/${GUIDE_NAME}/router/${GUIDE_NAME}.values.yaml"
(Optional) Enable Prometheus monitoring on the llm-d router by defining the helm values file (requires installing the monitoring stack mentioned in Prerequisites):
# only when MONITORING=true:
export MONITORING_VALUES="-f ${REPO_ROOT}/guides/recipes/router/features/monitoring.values.yaml"
Deploy the router in Standalone Mode, with an Envoy sidecar in front of the router. Keep the release name ${GUIDE_NAME}: the verification steps look up the ${GUIDE_NAME}-epp Service by that name. To front the router with a Kubernetes Gateway instead, see Gateway Mode in the Optimized Baseline.
helm install ${GUIDE_NAME} \
${ROUTER_STANDALONE_CHART} \
-f ${ROUTER_BASE_VALUES} \
${MONITORING_VALUES} \
-f ${ROUTER_VALUES} \
-n ${NAMESPACE} --version ${ROUTER_CHART_VERSION}
2. Deploy the Model Serverโ
Each deployment is a different prefill : decode operating point. Set DEPLOYMENT to one of them
(default oci-low-latency, the smallest):
| Deployment | Layout | Nodes / GPUs |
|---|---|---|
oci-low-latency | 1 prefill (DEP8) : 1 decode (TP=8) | 4 / 16 |
oci-low-latency-scaled | 1 prefill (DEP8) : 4 decode (TP=8) | 10 / 40 |
oci-mid-curve | 1 prefill : 1 decode (DEP8 each) | 4 / 16 |
oci-balanced | 2 prefill (DEP8) : 1 decode (DEP16) | 8 / 32 |
oci-high-tpt | 2 prefill : 1 decode (DEP8 each) | 6 / 24 |
oci-high-tpt-dep16 | 3 prefill (DEP8) : 1 decode (DEP16) | 10 / 40 |
oci-max-tpt | 3 prefill : 1 decode (DEP8 each) | 8 / 32 |
oci-ultra-tpt | 4 prefill (DEP8) : 1 decode (DEP16) | 12 / 48 |
oci-3p2d-dep8-dep16-flashinfer | 3 prefill (DEP8) : 2 decode (DEP16), flashinfer | 14 / 56 |
Apply the Kustomize overlay for your deployment. The deployments compose the providers/oci
overlay (node-local NVMe model cache and the ComputeDomain claim), or base-low-latency with the
same OCI settings inlined for the two low-latency variants, with a topology component from
modelserver/gpu/vllm/components/:
kubectl apply -n ${NAMESPACE} \
-k ${REPO_ROOT}/guides/models/${GUIDE_NAME}/modelserver/${ACCELERATOR_TYPE}/${MODEL_SERVER}/deployments/${DEPLOYMENT}
Wait for the pods to become ready (the ~850 GB model takes a while to download and load):
kubectl get pods -n ${NAMESPACE} -l llm-d.ai/model=DeepSeek-V4-Pro -w
(Optional) Deploy the monitoring resources for model servers (requires installing the monitoring stack mentioned in Prerequisites):
# only when MONITORING=true:
kubectl apply -n ${NAMESPACE} -k ${REPO_ROOT}/guides/models/${GUIDE_NAME}/monitoring
Verificationโ
1. Get the IP of the Proxyโ
export IP=$(kubectl get service ${GUIDE_NAME}-epp -n ${NAMESPACE} -o jsonpath='{.spec.clusterIP}')
2. Send Test Requestsโ
Send a completion request from a temporary pod inside the cluster:
kubectl run curl-test --rm -i --restart=Never \
--image=${CURL_TEST_IMAGE} \
--namespace="${NAMESPACE}" \
--env="IP=${IP}" \
--env="MODEL=${MODEL}" \
-- /bin/sh -c 'curl -sS -X POST "http://${IP}/v1/completions" -H "Content-Type: application/json" -d "{\"model\": \"${MODEL}\", \"prompt\": \"How are you today?\"}"'
Check that the router reaches a model server that serves MODEL: the response must name the model and carry generated tokens:
# The router must reach a model server that serves MODEL and returns tokens
kubectl run serve-check --rm -i --restart=Never \
--image=${CURL_TEST_IMAGE} \
--namespace="${NAMESPACE}" \
--env="IP=${IP}" \
--env="MODEL=${MODEL}" \
-- /bin/sh -c 'R=$(curl -sS -X POST "http://${IP}/v1/completions" -H "Content-Type: application/json" -d "{\"model\": \"${MODEL}\", \"prompt\": \"Say hello.\", \"max_tokens\": 16}")
echo "${R}" | grep -q "\"model\":\"${MODEL}\"" && echo "${R}" | grep -q "\"choices\"" \
&& echo "OK: ${MODEL} served through the router" \
|| { echo "FAIL: ${R}"; exit 1; }'
Benchmarkingโ
TODO: benchmark profiles and results for this guide are not yet published. The first
published results should be measured with the current router config (prefix-cache affinity
filter + token-load scorer on prefill, active-request scorer on decode), after
peakPrefillThroughput has been measured for DeepSeek-V4-Pro on GB200 (see the
warning in Deploy the llm-d Router).
Cleanupโ
To remove the deployed components:
kubectl delete -n ${NAMESPACE} -k ${REPO_ROOT}/guides/models/${GUIDE_NAME}/modelserver/${ACCELERATOR_TYPE}/${MODEL_SERVER}/deployments/${DEPLOYMENT}
helm uninstall ${GUIDE_NAME} -n ${NAMESPACE}
kubectl delete -n ${NAMESPACE} -k ${REPO_ROOT}/guides/models/${GUIDE_NAME}/monitoring --ignore-not-found=true
kubectl delete namespace ${NAMESPACE}