参数寻优第一步——输入显卡型号、模型、量化方案、输入/输出长度、镜像、SLA,输出一批标准化的 SGLang 启动参数候选(spec.json),供 K8s 执行器批量实测。不含执行、不含剪枝、不含报告。当用户提到「生成启动参数」「参数寻优」「扫参数」「给我一批配置去跑」「sglang-param-search」时使用。
Resources
4Install
npx skillscat add wuhangxian/sglang-param-search Install via the SkillsCat registry.
This skill generates standardized SGLang startup parameter candidates in a spec.json format based on GPU models, model types, quantization schemes, sequence lengths, and SLA requirements. It solves the complexity of manual configuration by translating hardware and workload constraints into actionable parameter sets for downstream K8s executors to perform batch testing and optimization.
SGLang 启动参数候选生成
这个 skill 干什么、不干什么
你给这些事实 本 skill 下游(不在本 skill 范围)
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 显卡型号/显存 │ │ │ │ K8s 执行器 │
│ 卡数 / 模型 │───────▶│ 生成候选树 │───────▶│ 起服务/压测 │
│ 输入/输出长度 │ │ spec.json │ │ 剪枝/重试 │
│ SLA │ │ │ │ 入库/出报告 │
└──────────────┘ └──────────────┘ └──────────────┘干:把「机型 × 模型 × 输入输出长度 × SLA」翻译成一批可直接执行的启动命令,附带每个
参数轴的语义元信息(单调方向、互斥关系、失败模式),让执行器有依据自己做决策。
不干:起服务、压测、剪枝、入库、出报告。这些是下游的事。
怎么保证输出稳定
AI 每次回答可能不同,所以规则不放在模型里,放在文件里:
job.yaml (你的事实) ┐
├─→ gen_spec.py (纯函数,零 AI) ─→ spec.json + fingerprint
references/rules/*_rules ┘references/rules/是知识库,按「谁维护、多久变一次」拆成四份:gpu_rules(卡的内在
属性)、image_rules(绑 sglang 版本的兼容性)、model_rules(模型架构/权重)、tuning_rules(团队调优经验)。gen_spec 启动时合并这四份。每条规则带source:official(官方文档/源码)、source(读 sglang gate 条件)、measured(实测,标注硬件)、judgment(人的判断,最该被质疑)。想知道某条规则为什么存在,看它的why字段。gen_spec.py是纯函数:同样输入 → 字节级相同输出,带fingerprint可校验。- AI 的角色只剩「帮你填 job.yaml 里的事实」(读 config.json、跑 nvidia-smi)。
- 改规则:改对应的
*_rules.yaml并升那份的version,别让 AI 临时决定。四份的版本号
都记进 spec.json 的rules_versions。
用法
第 0 步(AI 必做):把用户的自然语言落成 job.yaml。
用户通常只说一句话,如「pro5000 上的 qwen3.6-35b,输入 64k 输出 1k,P99 TTFT 20s / TPOT 30ms」。
你的第一个动作是把它写成下面这个文件(写到工作目录,不要写进 references/):
# job.yaml
gpu: pro5000 # 显卡型号(字符串)
vram_gb: 72 # 单卡显存 GB —— 必问用户
cards: 8 # 打算用几张卡 —— 必问用户
model: qwen3.6-35b # 模型
input_len: 65536 # 输入长度 token —— 你要测的负载(64k = 65536)
output_len: 1024 # 输出长度 token
image: lmsysorg/sglang:v0.5.10 # 镜像(tag 带版本号)—— 用来核对 attention 后端表是否过期
quant: {format: fp8, granularity: per-tensor, method: dynamic} # 量化方案 —— 必问用户
sla: {max_ttft_ms: 20000, max_tpot_ms: 30, percentile: 99}必填九项,缺了必须问用户,绝不能替用户猜:
gpu/model/input_len/output_len/image/quant/sla—— 用户的选择。vram_gb(单卡显存)和cards(卡数)—— 每台机器都不同,必须问清楚,不能用型号
预设值代替。 同一型号有 48G/72G 不同版本、同机可插 4/8 张,写死必坑人。工具最终在
K8s 上跑、拿不到登录权限,所以这两个数只能由用户提供(问运维 / 看机器规格)。
规则:
- 缺任一必填项就问用户,不要自己编。 尤其
sla、vram_gb、cards、input_len/output_len。 - ★ 量化必问(拿到模型的第一件事):先问「按官方原始权重跑,还是某量化版?」;量化版
再追问 格式(fp8/nvfp4/int4)× 粒度(per-tensor/per-channel/block)× 方式
(static/dynamic)。这三者决定权重大小(→TP)且是硬兼容门槛 —— 同格式不同粒度在某
版本+某算力上可能就跑不了,所以必须问清、不能替用户猜。追问后仍说「随便」→ 按官方最
原始权重(不量化, bf16)跑,写quant: 随便。check_facts会拿量化去quantization_support
核该版本+该卡认不认这个组合;没记录就报缺口,让你读该镜像版本 tag 的quantization/源码核实后补进image_rules.yaml。 sm_major(算力版本)不用问用户:gpu_catalog按型号兜底推导(用户多半不知道
RTX PRO 是 SM120)。仅当check_facts报「型号不在表里」时,才让用户给sm_major
或compute_cap。image要带版本号的 tag(如lmsysorg/sglang:v0.5.10,别用latest)。attention
后端表是照某个 sglang 版本读源码抄的,check_facts会拿镜像版本跟它比:对得上直接跑;
对不上会报「表基于旧版本,需重新核对」。这时你(AI)的活是像查新显卡那样,去查该版本
的_get_default_attn_backendgate 条件 + 搜相关 issue,把变化写进attention_backends、
升attention_backends_validated_against和version,再重跑。用户不用手动比版本。
生成 spec.json 前必须先把镜像确认清楚 —— 只有latest/私有 tag 又不标魔改,check_facts会报硬缺口挡住生成。- 魔改镜像:用户明说是「魔改/私有/打过 patch」的镜像时,版本核对没意义 —— 在 job.yaml
标image_modified: true。这时不查版本,gen_spec直接把该 SM 的 attention 后端全集
铺进候选(含 triton 兜底),起不来的交给执行器实测筛(归bad_args作废)。你不用去猜它改了什么。 - 可选覆盖项(
tp_sizes、precision、search_kv_cache_dtype、context_length等)
见references/example-job.yaml,用户明确要求时才加,AI 不主动塞 —— 那是替用户做
搜索策略决策,违背「AI 只填事实」。不提就走tuning_rules.yaml的默认。
然后依次跑三条命令:
# 1. 查事实齐不齐 —— 缺什么会告诉你去哪查、写到规则库哪里
python3 scripts/check_facts.py job.yaml
# 2. 生成(事实齐全时纯脚本,零 AI)
python3 scripts/gen_spec.py --config job.yaml -o spec.json
# 3. 渲染 K8s YAML
python3 scripts/render_k8s.py spec.json --all -o yamls --namespace <ns> --image <镜像>若第 1 步报「缺事实」,按它给的来源去查证、补进对应的 references/rules/*_rules.yaml 并升那份的 version,再重跑第 1 步
(见下节「AI 在什么时候介入」)。
AI 在什么时候介入
只在规则库缺事实时。 check_facts.py 会明确报缺口 + 权威来源 + 写入位置:
❌ 缺 1 项事实,需先查证补进规则库:
[1] 显卡 'mi300x' 的算力版本 sm_major
为什么要: gpu_catalog 里没有这个型号,又没在 job.yaml 显式给 ——
sm_major 决定 attention 裁剪,填错整批候选起不来
去哪查: nvidia-smi --query-gpu=compute_cap --format=csv 取整数部分 /
https://developer.nvidia.com/cuda-gpus
写到哪: job.yaml → sm_major:(或在 rules/gpu_rules.yaml → gpu_catalog 加型号映射)
模板: sm_major: 10 # SM120→12 / Hopper→9 / SM100→10 / Ada→8(注:vram_gb/cards 不进 catalog —— 它们每台机器不同,由 job.yaml 提供;
catalog 只登记「型号 → 算力」这种不随机器变的属性。)
AI 按各 *_rules.yaml 的 fact_sources 去查证(官网 / nvidia-smi / config.json / sglang 源码),
补进对应那份并升它的 version。之后同一张卡再不需要 AI —— 直接跑脚本。规则库越用越厚,
AI 参与越来越少。
从输入推导出什么
以 pro5000 72G×8 + qwen3.6-35b + 64k/1k + P99(20s/30ms) 为例,全部自动:
sm_major=12 ← gpu_catalog.pro5000(仅算力,按型号推)
vram=72GB, cards=8 ← job.yaml(每台机器不同,必填)
model_path=Qwen/Qwen3.6-35B-A3B-FP8,
arch=moe_hybrid_gdn, hybrid_mamba=True ← model_catalog.qwen3.6-35b
quant=fp8/per-tensor/dynamic, precision=fp8 ← job.yaml(必问用户,核 quantization_support)
input/output=65536/1024 ← job.yaml(你要测的负载)
extra_flags.reasoning-parser=qwen3 ← model_defaults(cookbook 原文)
排除 TP1: 输入 65536 > 32768,实测长输入下 TP1 吞吐完全平坦
显存核算: TP1 权重35.0+KV125.8=160.8✗ | TP2 =80.4✗ | TP4 =40.2✓ | TP8 =20.1✓
可行 TP [4,8] → 取最大 2 档
⚠️ 72GB 卡无 NVLink,TP 通信走 PCIe —— 候选保留,实测判断
mamba ratio r*≈0.31 ← compute-mamba-ratio 公式
attention 轴 3 档(SM120 可用集) ← attention_backends.12换卡换模型会自动适配:H200 的 attention 轴变 [fa3, flashinfer];
4090(24GB)算出只有 TP8 可行;B200(183GB)连 TP1 都装得下。
怎么保证跨 session 输出一致
job.yaml (你的事实) ┐
├─→ gen_spec.py (纯函数,零AI) ─→ spec.json + fingerprint
references/rules/*_rules ┘references/rules/的四份*_rules.yaml是知识库(gpu / image / model / tuning,
gen_spec 启动时合并)。每条带source:official(官方文档/源码)、source(读 sglang
gate 条件)、measured(实测,标注硬件)、judgment(人的判断,最该被质疑)。想知道
某条规则为什么存在,看它的why字段。gen_spec.py是纯函数:同样输入 → 字节级相同输出,带fingerprint可校验。- 缺必填字段直接报错,不让 AI 静默瞎猜。
- 改规则:改对应的
*_rules.yaml并升那份的version。四份版本号(rules_versions)
和 fingerprint 都记进 spec.json。
spec.json 的结构
{
"fingerprint": "9336ea1c...", // 复现校验
"rules_version": 2,
"job": {...}, // 原样回显输入
"axes": { // 参数轴语义 → 执行器剪枝的依据
"mem-fraction-static": {
"values": [0.80, 0.84, 0.88, 0.92],
"monotonic": "higher_uses_more_gpu_memory",
"dominance": "higher_is_preferred_if_stable",
"failure_mode": "oom_at_startup 或 oom_at_peak_activation(后者更常见)"
}, ...
},
"pinned_flags": [...], // 固定不搜的,带证据
"hard_constraint_skipped": [...], // 被硬约束排除的组合 + 原因
"candidates": [
{"id": "c001",
"coord": {"mem-fraction-static": 0.8, "attention": "flashinfer", ...},
"params": {...}, // 结构化,执行器可直接比较
"memory_pressure": 0.222, // 0-1,供排序参考
"cmd": "python3 -m sglang.launch_server ..."}
],
"executor_contract": {...} // 执行器每个候选必须回报什么
}coord + axes.monotonic 是给执行器剪枝用的:比如 c341 的 mem=0.88 跑通了,
执行器可以找出所有 coord 里 mem 更低、其他轴相同的候选,按 dominance 判定被支配后跳过。
剪枝策略由执行器定,本 skill 不写死。
执行器必须回报的(否则数据不可信)
executor_contract 里列了完整清单,三个最容易漏的:
- 压测必须用
--backend sglang(走/generate) —— thinking 类模型走/v1/chat/completions时delta.content可能为空,按 content 统计会把 decode
吞吐算成 0。 - 区分「启动失败」和「压测崩溃」 —— 峰值激活 OOM 在启动时看不出来,只在压测时暴露。
失败原因要分类(oom/bad_args/cuda_error/infra),因为 OOM 恰好告诉执行器
显存边界在哪。 avg_output_tokens是否接近output_len—— 高并发下网关超时或并发限制会导致提前
终止,截断的档位数据必须作废,否则吞吐虚高。
另外要回报启动日志三个数(available_gpu_mem / max_total_num_tokens / max_num_reqs),
它们决定后续候选的取值上限。
目标函数(建议下游这样定)
goodput = max_C total_token_throughput(cfg, C)
s.t. Pxx_TTFT ≤ sla.max_ttft_ms
AND Pxx_TPOT ≤ sla.max_tpot_ms
AND avg_output_tokens ≈ output_len不能用裸吞吐排序 —— 峰值吞吐那一档几乎必然违反 SLA,拿它当最优上线就翻车。
⚠️ 前人对 percentile 无共识:vLLM auto_tune 用 P99、Vidur 用 P90 TTFT + P99 TBT、
SCOOT 用均值、BBuf skill 用 P50 且明确从 P99 迁移过来的(result-schema.md 原话:
"Older cookbook configs used stricter p99 targets and have been migrated to the p50 names")。
所以照抄 BBuf 的 schema 会静默放宽你的 SLA。 本 skill 从 job.yaml 读,不写死。
参考资料的可用与不可用
| 来源 | 能拿什么 | 别拿什么 |
|---|---|---|
SGLang 官方 hyperparameter_tuning.mdx(83 行) |
判据数字:available_gpu_mem 5-8GB、token usage > 0.9、#queue-req 100-2000、conservativeness 0.3/1.3 |
它是纯人工方法论,无工具、无调优顺序;不含 attention-backend / page-size / kv-cache-dtype / mamba 任何 flag |
官方 cookbook (docs/src/snippets/) |
模型专属参数(parser、投机解码参数值) | 硬件目录只有 B200/B300/H200/H100/MI300 系,无 RTX PRO;是 React 组件,程序读不了 |
BBuf llm-serving-auto-benchmark |
yaml schema、pin/search 分层思路、序列长度门禁 | P50 gate、具体数值(它 dataset 最长才 8k)、混合架构零覆盖 |
compute-mamba-ratio skill(sglang 主干自带) |
mamba ratio 计算公式(BBuf 完全没有这块) | — |
空白点:单框架深度寻优(BBuf 刻意不做,它要跨框架公平对比)、P99 gate、混合架构双池、
长上下文场景、执行链与入库报告。这些是本工具的立足点。