长上下文部署
本教程展示如何在 4×RTX 5090 上部署 DeepSeek V4 Flash,开出 1,048,576(1M)token 的上下文窗口。核心方案是 KTransformers 的 MXFP4 混合量化 + CPU/GPU 协同推理:10 个 routed experts 常驻 GPU,其余 routed experts 走 CPU。
- 前置条件
- 步骤 1:设置环境变量
- 步骤 2:启动 sglang server
- 步骤 3:等待 server READY 并验证
- 步骤 4:发起长上下文请求
- 关键参数解析(为何这么配)
- 调优:上下文长度 vs KV cache 容量
- 已知限制
前置条件
硬件
| 组件 | 推荐配置 |
|---|---|
| GPU | 4 × NVIDIA RTX 5090 32 GB (Blackwell, SM_120) |
| CPU | 双路 64 核(支持 AVX-512) |
| 内存 | 256 GB DDR5 |
| 存储 | NVMe SSD(用于权重加载) |
| 互联 | PCIe 5.0 |
软件
| 组件 | 版本 | 备注 |
|---|---|---|
| CUDA | 12.8 | RTX 5090 最低要求 |
| Python | 3.10 | |
| ktransformers | 0.6.2.post3+ | 含 MXFP4 量化 |
| sglang | kt-sglang 子模块 | 含 V4 Flash 适配 |
| transformers | 4.57.1 | 5.x 存在兼容问题 |
模型权重:DeepSeek V4 Flash(MXFP4 + FP8 混合格式),放在本地 NVMe 上的某个目录,例如 /path/to/DeepSeek-V4-Flash。
步骤 1:设置环境变量
export CUDA_VISIBLE_DEVICES=0,1,2,3
export FLASHINFER_CUDA_ARCH_LIST=12.0a
export TORCH_CUDA_ARCH_LIST="12.0+PTX"
export SGLANG_DSV4_MODE=2604
export SGLANG_DSV4_2604_SUBMODE=2604B
其中:
FLASHINFER_CUDA_ARCH_LIST=12.0a/TORCH_CUDA_ARCH_LIST="12.0+PTX":5090 (SM_120) 上 flashinfer JIT 必备,否则 fp4 kernel 误报 "sm75 or higher"。SGLANG_DSV4_MODE=2604+SGLANG_DSV4_2604_SUBMODE=2604B:DeepSeek V4 Flash 必传,缺失会在 mxfp4_deepseek.py 的 swiglu_limit 断言处崩溃。
步骤 2:启动 sglang server
numactl --interleave=all python -m sglang.launch_server \
--host 0.0.0.0 --port 40001 \
--model /path/to/DeepSeek-V4-Flash \
--kt-weight-path /path/to/DeepSeek-V4-Flash \
--kt-method MXFP4 \
--kt-num-gpu-experts 10 \
--kt-cpuinfer 60 \
--kt-threadpool-count 2 \
--kt-gpu-prefill-token-threshold 2048 \
--kt-enable-dynamic-expert-update \
--tensor-parallel-size 4 \
--context-length 1048576 \
--attention-backend flashinfer \
--mem-fraction-static 0.7 \
--chunked-prefill-size 4096 \
--max-prefill-tokens 4096 \
--max-running-requests 2 \
--watchdog-timeout 1200 \
--disable-shared-experts-fusion \
--trust-remote-code \
--cuda-graph-bs 1 \
--cuda-graph-max-bs 1 \
--disable-radix-cache \
--skip-server-warmup
每个参数为什么这样配,见下文 关键参数解析。
步骤 3:等待 server READY 并验证
启动后会先做权重加载 + MXFP4 swizzling + CUDA Graph 捕获,整体约 80 秒。看到下面这行即就绪:
The server is fired up and ready to roll!
启动日志里检查以下关键指标,确认资源分配符合预期:
max_total_num_tokens=964864 # KV cache 总容量(应 ≥ 上下文长度)
chunked_prefill_size=4096 # 分块 prefill 大小
available_gpu_mem=5.34 GB # CUDA Graph + KV pool 后剩余显存
Capture cuda graph end. Time elapsed: 5.45 s # CUDA Graph 捕获成功
健康检查:
curl -s http://localhost:40001/health
# HTTP 200 OK
步骤 4:发起长上下文请求
服务兼容 OpenAI Chat Completions API。
cURL 短请求:
curl http://localhost:40001/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "DeepSeek-V4-Flash",
"messages": [{"role": "user", "content": "你好,请介绍一下你自己"}],
"max_tokens": 256,
"temperature": 0.7
}'
Python 长文本请求:
from openai import OpenAI
client = OpenAI(base_url="http://localhost:40001/v1", api_key="none")
with open("very_long_document.txt") as f:
long_text = f.read() # 例如 60 万 token 长文
resp = client.chat.completions.create(
model="DeepSeek-V4-Flash",
messages=[{"role": "user", "content": long_text + "\n\n请总结上文。"}],
max_tokens=1024,
temperature=0.7,
timeout=3600, # ← 必须给够时间,见下
)
print(resp.choices[0].message.content)
长请求注意事项
prefill 速度随上下文长度线性下降。600K token 的请求 prefill 阶段约 20–25 分钟,因此:
- HTTP 客户端 timeout 必须 ≥ 1800 秒,推荐直接
timeout=3600。 - 如通过 SSH 远程调用,客户端脚本需要
setsid nohup后台化:SSH 一断 SIGHUP 会传给客户端进程;客户端被杀后 server 会检测到对端断连并 abort 这个请求。 - 客户端机器不能休眠/断网,否则同样会触发 abort。
关键参数解析(为何这么配)
上下文 / KV cache
| 参数 | 值 | 作用 |
|---|---|---|
--context-length | 1048576 | 1M token 上下文窗口(硬上限) |
--mem-fraction-static | 0.7 | 控制权重 + CUDA Graph + KV pool 占用显存的比例,0.7 留出 ~5 GB workspace |
--disable-radix-cache | - | 长上下文必须禁用,否则 prefix 缓存内存管理会异常崩溃 |
--chunked-prefill-size | 4096 | prefill 按 4096 token 分块,避免一次性占用过多 workspace |
--max-prefill-tokens | 4096 | 单次 forward 最多处理 4096 token,与 chunked 配合 |
MoE 路由(CPU/GPU 划分)
| 参数 | 值 | 作用 |
|---|---|---|
--kt-method | MXFP4 | routed experts 使用 MXFP4 量化(I8 + ue8m0) |
--kt-num-gpu-experts | 10 | 10 个常驻 GPU,其余走 CPU |
--kt-cpuinfer | 60 | CPU 推理线程数(×2 threadpool = 120 线程) |
--kt-gpu-prefill-token-threshold | 2048 | 单次 forward token 数超阈值时走 GPU MoE prefill |
--kt-enable-dynamic-expert-update | - | 根据访问统计动态调整 GPU 上的专家 |
--kt-gpu-prefill-token-threshold比对的是单次 forward 的 token 数(chunked 后),而不是 prompt 总长。所以这里设 2048 让每个 chunk 都能触发 GPU MoE 路径。
并行与并发
| 参数 | 值 | 作用 |
|---|---|---|
--tensor-parallel-size | 4 | 4 张 5090 张量并行 |
--max-running-requests | 2 | 最多 2 个请求并行执行,避免 KV 抢占 |
--cuda-graph-bs 1 | 1 | 仅捕获 batch=1 的 CUDA Graph |
--cuda-graph-max-bs 1 | 1 |
稳定性
| 参数 | 值 | 作用 |
|---|---|---|
--watchdog-timeout | 1200 | 长 prefill 防误杀,默认 watchdog 太短 |
--disable-shared-experts-fusion | - | V4 Flash 当前要求关闭该融合 |
--skip-server-warmup | - | 跳过 sglang 自带 warmup(V4 路径有兼容问题) |
numactl --interleave=all | - | 防止 CPU 推理线程跨 NUMA 抢 cache,否则 hybrid 性能骤降 |
调优:上下文长度 vs KV cache 容量
--mem-fraction-static 决定 KV pool 的大小(即能容纳多少 token)。下表基于 4×RTX 5090:
| 目标上下文场景 | mem-fraction-static | KV pool 容量 | 剩余 workspace | 建议 |
|---|---|---|---|---|
| ≤600K token | 0.6 | ~759k token | ~8.3 GB | profiling / 开发调试 |
| 600K – 900K | 0.7 | ~965k token | ~5.3 GB | 生产推荐 |
| 接近 1M | 0.75+ | ~1.1M token | <4 GB | 显存紧张,仅边界用例 |
调优经验:
- 单卡 / TP=1 时 mem-fraction-static 超过 0.7 即可能 OOM,因为 workspace 留得太少,2048 chunk prefill 时一个 512 MiB 的中间 buffer 就能撑爆显存。
- 不需要满血 1M 时先降 context-length 再降 mf,前者立刻省 KV,后者把省下的显存还给 workspace。
已知限制
- prefill 速度随上下文增长衰减:600K token 时从峰值 ~590 tok/s 降到 ~320 tok/s(约 47% 衰减),attention 机制的固有特性。
- 长请求客户端超时:600K prefill 约 23 分钟,HTTP timeout 必须 ≥1800 s。
- CUDA Graph 仅在 batch=1 生效:两个请求并行 decode 时退化到 eager,decode 吞吐会下降。
- 客户端断连即 abort:远端调用必须
setsid nohup,且客户端机器不能休眠。