快速上手:5 分钟跑通第一个请求
谁该读这一篇? 装好了 GPU 环境,想立刻让 SGLang 跑起来、发一个请求看到 token 流出来的工程师。 前置阅读:
02-architecture.md看个鸟瞰图就行。 耗时: 25 分钟(含下载小模型时间) 学完能: 1. 装好 SGLang 并用最小命令起 server; 2. 用 curl 和 openai SDK 发一个请求看到流式输出; 3. 看懂启动日志里"我开了什么"(attention backend、CUDA Graph、kv pool 等); 4. 切换到前端 DSL 模式,写出第一个三行 DSL 程序; 5. 知道每一步出问题该去哪儿排查。
1. 环境要求(cheatsheet)
| 项 | 要求 |
|---|---|
| OS | Linux(Ubuntu 22.04 / 24.04 验证最稳) |
| GPU | NVIDIA Compute Capability ≥ 8.0(A100 / H100 / H200 / L4 / L40 / RTX 4090 / RTX 5090 等) |
| CUDA | 12.4 / 12.6 / 12.8(看官方 release notes 的精确支持矩阵) |
| Python | 3.10 / 3.11 / 3.12 |
| 显存 | 跑 Qwen2.5-7B fp16 至少 24 GB;fp8 至少 12 GB |
| 网络 | 第一次需要从 HuggingFace 下模型,~15 GB 起 |
⚠️ macOS / AMD GPU 当前都是实验级支持,不建议第一次上手就走这条路。
2. 装 SGLang(uv 推荐)
# 1) 装 uv(如果还没有)
curl -LsSf https://astral.sh/uv/install.sh | sh
# 2) 建一个干净 venv
mkdir sglang-play && cd sglang-play
uv venv --python 3.11
source .venv/bin/activate
# 3) 装 sglang(含 srt 后端)
uv pip install "sglang[all]" --upgrade
想从源码装(开发用):
git clone https://github.com/sgl-project/sglang && cd sglang/python && uv pip install -e .[all]。
验证装好了
python -m sglang.check_env
会输出 CUDA / driver / FlashInfer / Triton 等的版本和 OK/FAIL。 如果某项 FAIL,先 fix 它再继续——后面出问题大概率就是这里没过。
3. 起 server(最小命令)
第一次先用最小的开源模型 + 小显存设置,确保链路通:
python -m sglang.launch_server \
--model-path Qwen/Qwen2.5-0.5B-Instruct \
--host 0.0.0.0 \
--port 30000 \
--mem-fraction-static 0.5
--mem-fraction-static 0.5 表示只用 50% GPU 显存给 KV cache + 模型,第一次玩留余量。
启动日志关键行(教你看日志)
INFO ... server_args=ServerArgs(...) ← 全部启动参数
INFO ... Attention backend not specified. ← 自动选了 attention 后端
Use ... backend by default.
INFO ... Init torch distributed begin. ← 单卡也会建 process group
INFO ... Memory pool end. avail mem=XX.X GB ← KV pool 留多少显存
INFO ... Use cuda graph for decoding mode. ← CUDA Graph 开启了
INFO ... Capture cuda graph begin. ... ← 在录 CUDA Graph
INFO ... Capture cuda graph end. ... ← 录完,启动完成
INFO ... Application startup complete.
INFO ... The server is fired up and ready to roll!
看到 "ready to roll" 就稳了。
4. 用 curl 发第一个请求
curl http://localhost:30000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen2.5-0.5B-Instruct",
"messages": [{"role": "user", "content": "1+1 等于几?"}],
"max_tokens": 32
}'
正常返回:
{
"id": "...",
"model": "Qwen/Qwen2.5-0.5B-Instruct",
"choices": [{
"index": 0,
"message": {"role": "assistant", "content": "1+1=2。"},
"finish_reason": "stop"
}],
"usage": {"prompt_tokens": ..., "completion_tokens": ...}
}
5. 流式输出(SSE)
curl -N http://localhost:30000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen2.5-0.5B-Instruct",
"messages": [{"role": "user", "content": "讲一个短笑话"}],
"stream": true
}'
会看到一行行 data: {"choices":[{"delta":{"content":"..."}}]} 实时打印,最后是 data: [DONE]。
这就是 02-architecture.md §4 时序图最后那段。
6. 用 openai SDK 接
from openai import OpenAI
client = OpenAI(base_url="http://localhost:30000/v1", api_key="EMPTY")
# 非流式
resp = client.chat.completions.create(
model="Qwen/Qwen2.5-0.5B-Instruct",
messages=[{"role": "user", "content": "1+1?"}],
max_tokens=32,
)
print(resp.choices[0].message.content)
# 流式
stream = client.chat.completions.create(
model="Qwen/Qwen2.5-0.5B-Instruct",
messages=[{"role": "user", "content": "说三个颜色"}],
stream=True,
max_tokens=64,
)
for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True)
print()
如果你的客户端已经接的是 OpenAI / Anthropic / Together 等,改 base_url 就能直接转过来。
7. 第一个 SGLang DSL 程序
import sglang as sgl
sgl.set_default_backend(sgl.RuntimeEndpoint("http://localhost:30000"))
@sgl.function
def hello(s, name):
s += "User: 你好,我叫 " + name + ",请用一句话欢迎我。\nAssistant: "
s += sgl.gen("reply", max_tokens=64, stop="\n")
state = hello.run(name="Zoe")
print(state["reply"])
跑一次。然后试这个:
@sgl.function
def multi_choice(s, q):
s += f"问题:{q}\n答案是:"
s += sgl.select("ans", choices=["A", "B", "C", "D"])
print(multi_choice.run(q="天空是什么颜色?A.红 B.蓝 C.绿 D.黄")["ans"])
sgl.select 让 LLM 在 4 个选项里挑一个——这是 vLLM API 做不到的,因为它需要前端跟运行时商量"我只想要这 4 个 token 序列里命中最长的"。
8. 看看刚才发生了什么(Metrics)
curl http://localhost:30000/metrics | head -50
会看到 Prometheus 格式的指标:
sglang:num_requests_total{...} 5
sglang:num_input_tokens_total{...} 42
sglang:num_output_tokens_total{...} 137
sglang:e2e_request_latency_seconds_bucket{le="0.05",...} 2
sglang:e2e_request_latency_seconds_bucket{le="0.1",...} 5
sglang:gen_throughput{...} 23.4
sglang:cache_hit_rate{...} 0.62 ← 重要:前缀命中率
...
cache_hit_rate 是 SGLang 最该盯的指标。后续 08-production-deployment/03-monitoring.md 会展开。
9. 当事情不对劲(排查 cheatsheet)
| 现象 | 第一步排查 |
|---|---|
pip install 拉不下 sglang |
换源 --index-url https://pypi.tuna.tsinghua.edu.cn/simple |
python -m sglang.check_env 报 CUDA 错 |
看 nvidia-smi 驱动版本;CUDA toolkit 是否在 PATH |
| 起 server 卡在 "Init torch distributed" | 检查 NCCL 端口是否被占;unset NCCL_* 试试 |
| 起 server 报 CUDA OOM | 降 --mem-fraction-static 或 --max-running-requests,或换更小模型 |
| 起 server 后 curl timeout | 检查 --host 0.0.0.0 是否设置;防火墙 |
| 起 server 巨慢(> 5 分钟) | 第一次拉模型;之后会缓存在 ~/.cache/huggingface |
| 输出乱码 | tokenizer 不对;确认 --model-path 是个 Instruct 模型;检查 tokenizer 文件完整 |
| 输出截断 | max_tokens 太小、或停止符匹配错 |
| TTFT 很慢 | cache_hit_rate 低;CUDA Graph 没开;试 --enable-cuda-graph |
| TPOT 很慢 | 检查 batch 大小、attention backend、量化是否开 |
详细排障手册见 08-production-deployment/05-incident-playbook.md。
10. 常用启动参数(速查)
python -m sglang.launch_server --help | head -50 # 完整列表
最常用的 10 个:
| 参数 | 含义 |
|---|---|
--model-path |
HF repo id 或本地路径 |
--port |
HTTP 端口(默认 30000) |
--host |
监听 host(默认 127.0.0.1,远程访问要改 0.0.0.0) |
--tp |
tensor parallel size |
--dp |
data parallel size(多副本同进程组) |
--mem-fraction-static |
静态显存占比上限 |
--max-running-requests |
同时 in-flight 请求数 |
--max-total-tokens |
KV pool 总 token 上限 |
--attention-backend |
flashinfer / triton / torch |
--quantization |
fp8 / awq / gptq / marlin / ... |
--log-level |
debug / info / warning |
--enable-metrics |
暴露 Prometheus /metrics |
参数完整定义看 server_args.py。
11. 关掉 server
# Ctrl-C 优雅退出(会等当前请求结束)
# 或者
pkill -f sglang.launch_server
⚠️ 如果用了 --tp > 1,要确认所有 scheduler 子进程都退了,否则下次启动会端口/显存冲突。
08-production-deployment/05-incident-playbook.md 里专门有"残留进程清理"小节。
12. 下一步该读哪章
跟着你的目的走:
| 你接下来想 | 去 |
|---|---|
| 系统学完整本书 | 02-core-concepts/01-radix-attention.md 开始 |
| 立刻写一个生产服务 | 08-production-deployment/01-docker.md |
| 跑 benchmark 出真实数字 | 07-hands-on/02-benchmark-throughput.md |
| 调试一个慢请求 | 07-hands-on/03-debug-scheduler.md |
| 写复杂 agent 程序 | 06-frontend-language/01-dsl-walkthrough.md |
| 接受面试官拷问 | 02-core-concepts/ 全部 |
13. 自检
python -m sglang.check_env报错 FlashInfer 没装,你怎么办?
答案
按 PyTorch + CUDA 版本装匹配版的 FlashInfer: ```bash pip install flashinfer-python -i https://flashinfer.ai/whl/cu124/torch2.5/ # 例 ``` 关键:FlashInfer 的 wheel 严格绑定 (torch_major, torch_minor, cu_major, cu_minor)。版本不匹配装上也会运行时报 symbol 找不到。 FlashInfer 缺失会 fallback 到 Triton backend(性能差 10-30%),不是致命,但生产不推荐。- 我起了 server,curl 能通,但 openai SDK 报 401,可能是什么?
答案
SGLang 默认不校验 API key,但 openai SDK 要求 client 传一个非空 `api_key`。 解决:`OpenAI(base_url="http://localhost:30000/v1", api_key="EMPTY")`(任意非空字符串即可)。 如果启动了 `--api-key`,则要传匹配的 key。生产部署常用 nginx / envoy 在外层做 key 校验,SGLang 本身不做。cache_hit_rate只有 0.05 是为什么?怎么提高?
答案
原因可能:(a) 请求间几乎没有共享 prefix(独立单轮场景,正常);(b) prompt 末尾带了 timestamp/user_id 这类每次变化的字段,让"看似相同"的请求 cache miss;(c) KV pool 太小,evict 太快;(d) 业务才上线,cache 还没沉淀。 提高方法:去掉 prompt 中的可变字段;把高频 system prompt 在启动时 warmup 一次;增 `--mem-fraction-static` 让 cache 容量大;确认没用 `--disable-radix-cache`。- 我用
--mem-fraction-static 0.9起 7B 模型反而更慢,可能原因?
答案
7B 模型只占 14 GB,0.9 把剩下都给 KV pool。问题: (a) **FlashInfer workspace** 不够(每个 wrapper 要几百 MB 到几 GB),运行时 `plan` 失败 fallback 到非优化路径。 (b) **CUDA Graph** 捕获时给多 batch size 各录一份 graph 也要显存;workspace + graph 加起来溢出,graph 失败回 eager。 (c) **OOM 边缘**触发 PyTorch 频繁同步 + 碎片整理。 一般 0.8-0.85 就够,不必拉到 0.9。sgl.select(choices=["A","B","C","D"])在底层走了什么路径?为什么纯 OpenAI API 实现不了同等性能?
答案
路径:(1) 把 4 个 choice 各自 tokenize;(2) 一次 prefill 拿到 prompt 末尾的 hidden state + logits;(3) 对每个 choice 算 `∑ log P(token_i | prompt + token_14. 必备 bookmark
server_args.py— 启动参数完整定义environ.py— 环境变量定义examples/— 直接抄的示例bench_serving.py— 跑 benchmark