生产 9:版本管理(SGLang / 模型 / API)
谁该读这一篇? 平台运维 / 上线负责人 —— 处理"换 SGLang 版本怎么平滑"、"模型怎么灰度切换"等问题。 前置阅读:
07-router.md、05-incident-playbook.md。 耗时: 25 分钟 学完能: 1. 区分 SGLang 版本、模型版本、API 版本; 2. 用 router + 双副本灰度切版本; 3. 处理 OpenAI API 兼容协议的版本差异; 4. 写一份发布检查表; 5. 知道权重热更新的几种路径(用于 RL / online learning)。
1. 三个独立的版本维度
| 维度 | 频率 | 影响 |
|---|---|---|
| SGLang 版本 | 月度 release | 性能 / 修 bug / 偶尔 breaking |
| 模型版本 | 不定(业务驱动) | 输出质量 / 兼容性 |
| API 版本 | 季度 / 半年 | 客户端代码兼容 |
三者独立但要协调。
2. SGLang 版本升级
升级前检查
- Read release notes(breaking changes / 新特性 / 废弃)。
- 跑 benchmark 对比新版 vs 旧版。
- 跑业务 eval 验证模型行为不变。
- 准备回滚预案。
灰度发布
# 用 router 权重灰度
spec:
args:
- --worker-urls
- http://sglang-v0_5:30001
- http://sglang-v0_6_canary:30001
- --worker-weights
- "0.95,0.05" # 5% canary
观察 canary 的 SLO 指标 24 小时,没问题再 10% → 50% → 100%。
配置变化
新版常加新参数。配置管理(Helm values / kustomize)要同步更新。
3. 模型版本切换
场景
- 新训练 checkpoint 发布。
- 切量化版本(BF16 → FP8)。
- 换基础模型(Llama-3.1 → Llama-3.3)。
切换方法
方案 A:滚动重启
简单粗暴。逐 Pod 改 --model-path,等加载完再起下一个。
代价:滚动期间容量减半,需 N+1 副本。
方案 B:影子副本
新模型起独立副本组,router 权重灰度切。 代价:双倍 GPU。 优势:随时回滚。
方案 C:热权重更新
模型架构不变(fine-tune),只换权重:
# SGLang Engine API(不重启)
curl -X POST localhost:30000/update_weights_from_disk \
-d '{"model_path": "/models/qwen-7b-v2"}'
model_runner.py:update_weights_from_disk 实现。
4. RL / Online Learning 场景的权重同步
训练侧每 N step 给推理侧一份新权重:
# 训练侧
import torch.distributed as dist
dist.send(weights, dst=inference_rank)
# 推理侧
curl -X POST localhost:30000/update_weights_from_distributed \
-d '{"name": "lm_head.weight", "dtype": "float16", "shape": [...]}'
或者用 CUDA IPC(最快):
# 训练侧把 tensor 注册为 IPC handle
handle = tensor.share_memory_().get_handle()
# 推理侧通过 IPC handle 直接读
curl -X POST localhost:30000/update_weights_from_ipc -d '{"handle": "..."}'
model_runner.py:update_weights_from_ipc。
详见 srt/weight_sync/。
5. API 版本兼容
SGLang 对外有几套 API:
| API | 路径 | 用途 |
|---|---|---|
| OpenAI 兼容 v1 | /v1/chat/completions |
主流 |
| 原生 | /generate |
DSL / 内部 |
| Embedding | /v1/embeddings |
embedding |
| Anthropic 兼容 | /v1/messages |
Anthropic SDK |
| 控制 | /update_weights* /abort /flush_cache |
运维 |
字段兼容
OpenAI 协议偶尔加字段(如 response_format、reasoning_effort)。
SGLang 跟进相对快,但有时滞后。
客户端用最新 SDK 时记得验证 SGLang 版本是否支持。
弃用字段
不推荐:直接删字段。 推荐:保留字段 + 加 deprecation warning(log + metric)。
6. 灰度发布检查表
Pre-flight:
[ ] Release notes 已读 + 内部 review
[ ] 新版本镜像 build + push 完成
[ ] 业务 eval 通过
[ ] Benchmark 没退化
[ ] 回滚预案准备好
[ ] 监控面板 ready
Phase 1: 5% canary (24 hr)
[ ] Router weight 5%
[ ] 监控 canary 副本: TTFT / TPOT / cache hit / abort
[ ] 业务方观察输出质量
[ ] Postmortem 候选: 任何异常都记
Phase 2: 50% (24 hr)
[ ] Router weight 50%
[ ] 监控总体 SLO 不退化
Phase 3: 100%
[ ] Router weight 100%
[ ] 旧版本副本下线
[ ] 镜像 retention 至少 30 天
Post-release:
[ ] 写 release report
[ ] Update internal docs
7. 回滚
任何阶段发现 SLO 退化:
- 立刻 router weight 切回旧版本。
- 通知 oncall 监控。
- 不立刻删 canary —— 留着诊断。
- 写 incident report。
回滚时间目标:< 5 分钟。
8. 配置版本化
把所有部署相关配置存 git:
ops/
├── helm/
│ ├── values-prod.yaml
│ └── values-staging.yaml
├── kubectl/
│ └── deployments/
└── scripts/
├── upgrade.sh
└── rollback.sh
每次变更 git tag,与镜像 tag 一一对应:
git tag deploy-2026-05-29-sglang-0.6
docker push mycompany/sglang:0.6-2026-05-29
9. 模型权重版本管理
模型 checkpoint 也要版本化:
s3://models/qwen-7b/v1.0/ # 初版
s3://models/qwen-7b/v1.1/ # fine-tune 增量
s3://models/qwen-7b/v1.2/ # bug fix
每个版本:
- 元信息(训练数据、checkpoint hash、训练 loss)。
- Eval 结果(GSM8K / MMLU / 业务 eval)。
- 切换记录(哪天切到这版,切回哪版)。
10. 兼容性矩阵
维护一张表:
| SGLang 版本 | 兼容 model | 兼容 client SDK | 兼容 router |
|---|---|---|---|
| 0.4.x | Qwen2.5 / Llama-3.1 | openai>=1.30 | sgl-router>=0.2 |
| 0.5.x | + DeepSeek-V3 / Qwen3 | openai>=1.45 | sgl-router>=0.3 |
| 0.6.x | + GPT-OSS | openai>=1.50 | sgl-router>=0.3 |
每次升级前看这张表。
11. 小结
- 三个独立版本维度:SGLang / 模型 / API。
- 升级走灰度 + canary,5% → 50% → 100%。
- 模型可以热权重更新(disk / distributed / tensor / IPC)。
- 配置 git 化,与镜像 tag 一一对应。
- 维护兼容性矩阵防交叉冲突。
12. 自检
- SGLang 版本升级前必做的 3 件事?
答案
(1) **Read release notes**:看 breaking changes(参数改名 / 删字段 / 行为变化)、新特性、性能 regression(有时新版个别场景慢)。 (2) **Benchmark 对比**:同硬件 / 同模型 / 同 dataset 跑 `bench_serving.py`,至少 TTFT / TPOT / Throughput 三个指标不退化。 (3) **业务 eval**:用业务私有 eval set 跑两版本,输出质量 / 业务指标不退化(特别是受约束输出、tool calling 行为)。 还有第 4 件强烈推荐:(4) **回滚预案准备**:旧版本镜像保留、Helm values 备份、Router weight 切换脚本就绪。出问题时 5 分钟内能回滚。 不做的话:上线发现 regression 时手忙脚乱、决策迟缓、用户感知差。- 热权重更新有 4 种路径,哪个最快?
答案
(1) `update_weights_from_disk`:磁盘读 safetensors → 反序列化 → CPU → GPU。慢(10s-几分钟,看模型大小)。 (2) `update_weights_from_distributed`:训练侧通过 NCCL broadcast 给推理侧。中速(GPU 间 IB / NVLink,几秒)。 (3) `update_weights_from_tensor`:直接传 torch.Tensor 对象(同进程)。快(仅 device-device copy)。 (4) `update_weights_from_ipc`:CUDA IPC handle 共享同 GPU 内存。**最快**(零拷贝,毫秒级,因为不真复制,是引用)。 排序:IPC > tensor > distributed > disk。 RL online learning 场景一般用 IPC(训练 worker 和推理 worker 同节点);多机训练时用 distributed;冷启动 / 模型切换用 disk。- 模型切换为什么推荐影子副本而非滚动重启?
答案
滚动重启:逐 Pod 改 `--model-path` 重启 → 滚动期间容量减半(已下线的 Pod + 新 Pod 还在 capture cuda graph)→ 需要 N+1 副本扛压力。 影子副本:新模型起独立副本组(双倍资源),router 灰度切流量 → 老副本一直能用,验证完一键切换。 影子的优势: (a) **零容量损失**:滚动期间无能力下降。 (b) **随时回滚**:流量切回老副本秒级生效。 (c) **AB test**:可以对比两版本的业务指标。 (d) **金丝雀**:1% → 50% → 100% 渐进切。 代价:双倍 GPU 几小时 - 几天(视验证周期)。对核心业务这个成本完全可接受。 滚动重启只用于:(a) 资源极紧无法双倍;(b) 测试 / 内部环境。- 客户端 SDK 比 SGLang 新可能出现什么问题?
答案
openai SDK 跟随 OpenAI API 协议演进,会先于 SGLang 加入新字段: (1) **新字段被忽略**:客户端发 `response_format: {type: "json_schema"}`,老 SGLang 不识别,按 free-form gen 处理;输出可能不符合 schema。 (2) **行为差异**:新 SDK 默认开 `stream_options.include_usage`,老 server 不返回 usage 字段,客户端报错。 (3) **404 端点**:客户端调 `/v1/responses`(新 API),server 没注册路由,404。 (4) **类型不匹配**:新 SDK 用 typed dataclass 接收响应,server 返回字段缺失导致 pydantic 校验失败。 解决: - 客户端钉住兼容版本(`openai==1.45.x` 与 SGLang 0.5.x 配套)。 - 维护兼容性矩阵([§10](#10-兼容性矩阵))。 - 升 SGLang 前先在 staging 用最新客户端跑完整 API 测试。- 回滚时为什么不立刻删 canary?
答案
保留用于诊断: (1) **现场保留**:canary 的容器、日志、metric、core dump 都还在;删了就丢了;重现这种 regression 可能要花几天。 (2) **附加测试**:在 canary 上跑特定输入复现问题,不影响生产。 (3) **变量隔离**:canary 是出问题的版本,停接流量但保留,避免"问题不见了"误判已修复。 (4) **postmortem 证据**:写报告时引用 canary 当时的状态。 做法:rollback 时把 router weight 切回 stable,但 canary Pod 不删;postmortem 完成、根因明确后再删(通常 1-7 天)。 K8s 配 PDB 防止 canary 被自动清理;标 `app.kubernetes.io/role: canary-retained` 让运维知道。13. 下一步
05-incident-playbook.md— 出问题时的 runbook。09-advanced-features/— 高级功能进阶。- 源码:
srt/model_executor/model_runner.py的update_weights_*方法、srt/weight_sync/。
上游源码:
sglang/python/sglang/srt/model_executor/model_runner.py:1598+。