SGLang 架构学习指南
你好!👋 我是你的 SGLang 学习教练。这份指南将带你从零开始,深入理解 SGLang 这个超级强大的 LLM 推理引擎。别担心,我会像朋友聊天一样,一步步带你走进这个每天处理数万亿 tokens 的生产级系统。准备好了吗?让我们开始这段激动人心的学习之旅!🚀
第一部分:项目架构深度解析(像架构师一样俯瞰全景)🔍
本部分目标: 让你理解 SGLang 为什么这样设计,而不仅仅是它是什么样的。我会从宏观视角带你理解整个系统的"为什么",然后逐步深入到"怎么做"的细节。
1. 项目架构概览
1.1 用一个生动的类比理解 SGLang ✨
想象一下,SGLang 就像一家超高效的AI餐厅🍽️:
• 前台服务员(TokenizerManager):接待客人(接收请求),把菜单翻译成厨房能懂的语言(分词)
• 调度经理(Scheduler):智能安排哪个厨师做哪道菜,确保厨房效率最高(批次调度)
• 后厨团队(TPWorker + GPU):真正做菜的地方(模型推理)
• 记忆宫殿(RadixCache):记住常点的菜品配方,下次直接复用(前缀缓存)
• 外卖路由(Router):当有多家分店时,智能分配订单到最合适的店(负载均衡)
这个类比的精妙之处在于:传统的推理引擎就像普通餐厅,每次都从头开始做菜;而 SGLang 通过 RadixAttention 这个"记忆宫殿",能记住之前做过的菜(prompt 前缀),下次遇到相似订单直接复用,速度快了 5 倍!
1.2 核心设计特征:三位一体的高性能架构
SGLang 采用了一种独特的三层架构设计,每一层都专注于自己最擅长的事情:
第一层:Python 主框架(python/sglang) 🐍
• 职责:业务逻辑、请求处理、调度管理
• 优势:灵活易扩展,快速迭代
• 核心模块:
•
srt/
(SGLang Runtime):整个推理引擎的核心•
lang/
:前端编程语言接口•
managers/
:调度器、分词管理器等核心管理组件
第二层:CUDA 内核库(sgl-kernel) ⚡
• 职责:高性能计算内核
• 优势:极致的计算性能
• 核心技术:
• FlashAttention 3 集成
• CUTLASS MoE 内核
• DeepGEMM 优化
• 各种量化内核(FP8/FP4/INT4)
第三层:Rust 路由器(sgl-router) 🦀
• 职责:数据并行、负载均衡
• 优势:高并发、低延迟
• 核心特性:
• Cache-aware 负载均衡
• Prefill-Decode 分离路由
• Kubernetes 服务发现
这种设计的智慧在于:让合适的语言做合适的事。Python 负责灵活的业务逻辑,CUDA 负责极致的计算性能,Rust 负责高并发的网络路由。这就是所谓的"用对工具,事半功倍"。
1.3 与同类项目的对比:SGLang 的独特优势 🏆
在 LLM 推理引擎这个赛道上,SGLang 并不孤单。让我给你介绍一下它与其他明星项目的对比:
vs. vLLM:
• 共同点:都使用 PagedAttention、Continuous Batching
• SGLang 的优势:
• ✅ RadixAttention:更智能的前缀缓存,vLLM 的 Prefix Caching 只能精确匹配,SGLang 能做树状匹配
• ✅ Zero-overhead 调度器:CPU 调度开销几乎为零
• ✅ 前端语言:SGLang 提供了强大的编程接口,vLLM 只有 API
• ⚡ 性能数据:Llama-3-8B 推理,SGLang 比 vLLM 快约 1.5-2x(v0.4 blog)
vs. TensorRT-LLM:
• 共同点:都追求极致性能
• SGLang 的优势:
• ✅ 易用性:Python 原生,无需 C++ 编译
• ✅ 灵活性:支持动态 batch、动态 shape
• ✅ 生态:与 Hugging Face 生态无缝集成
- • TensorRT-LLM 的优势:
- • ✅ 在特定硬件(如 H100)上的极限性能
SGLang 的杀手锏特性:
-
- Prefill-Decode Disaggregation:将 prefill 和 decode 分离到不同 GPU 上,资源利用率提升 2.7x(DeepSeek on GB200)
-
- Large-scale Expert Parallelism:支持 96+ GPU 的 MoE 模型并行(DeepSeek-V3)
-
- 结构化输出:原生支持 JSON Schema、正则表达式约束,性能远超竞品
1.4 技术栈分析:生产级系统的底层依赖
让我带你看看 SGLang 依赖的核心技术组件(基于 python/pyproject.toml
):
核心深度学习框架:
torch = "2.8.0" # PyTorch 最新版
transformers = "4.57.0" # Hugging Face 模型库
高性能注意力内核:
flashinfer_python = "0.4.0rc3" # FlashInfer 注意力库(默认)
💡 小贴士:FlashInfer 是 SGLang 的秘密武器之一,它比 PyTorch 原生注意力快 3-10 倍!
结构化输出引擎:
xgrammar = "0.1.24" # 高性能语法约束
llguidance = ">=0.7.11" # 结构化生成引导
outlines = "0.1.11" # 结构化输出库
量化与优化:
torchao = "0.9.0" # PyTorch 量化加速
compressed-tensors = "*" # 压缩张量支持
Web 服务:
fastapi = "*" # 高性能 Web 框架
uvicorn = "*" # ASGI 服务器
uvloop = "*" # 事件循环加速
分布式通信:
pyzmq = ">=25.1.2" # ZeroMQ 进程间通信
grpcio = "1.75.1" # gRPC 通信(P-D disaggregation)
观测与监控:
prometheus-client = ">=0.20.0" # Prometheus 指标
opentelemetry-* # 分布式追踪(可选)
设计考量解析:
-
- 为什么选择 ZMQ 而不是普通队列?
• ZMQ 提供了进程间的高性能、低延迟通信
• 支持多种通信模式(PUB-SUB、REQ-REP)
• TokenizerManager 和 Scheduler 跨进程通信必须高效
-
- 为什么需要这么多结构化输出库?
•
xgrammar
:最新、最快的语法约束引擎•
llguidance
:支持更复杂的生成引导•
outlines
:兼容性考虑,历史遗留• 策略:根据任务复杂度自动选择最合适的引擎
-
- 为什么使用 FastAPI 而不是 Flask?
• FastAPI 是异步框架,与
asyncio
完美配合• 自动生成 OpenAPI 文档
• 类型检查和数据验证
• 性能是 Flask 的 3-5 倍
1.5 外部系统集成
SGLang 是一个**"好相处"的系统**,它与各种外部服务都能很好地集成:
模型存储:
• Hugging Face Hub:默认的模型下载来源
export HF_TOKEN=your_token
• ModelScope:国内用户的友好选择
• 本地文件系统:直接指定本地路径
缓存后端(HiCache - 分层缓存):
• Redis:适合共享缓存场景
• S3:适合大规模、持久化缓存
• 本地 SSD:性能最佳
分布式 KV Cache 传输:
• Mooncake:华为的高性能传输后端
• NIXL:NVIDIA 的 RDMA 传输
• ASCEND:华为昇腾 NPU 专用
监控与追踪:
• Prometheus:指标收集
• OpenTelemetry:分布式追踪
• Grafana:可视化(需自行配置)
1.6 架构流程描述:一个请求的完整旅程 🛤️
让我们跟随一个具体的请求,看看它在 SGLang 内部是如何被处理的:
场景:用户发送一个聊天请求
curl -X POST http://localhost:30000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "meta-llama/Llama-3.1-8B-Instruct",
"messages": [{"role": "user", "content": "什么是机器学习?"}]
}'
请求流经的八大步骤:
RadixCache(内存)TPWorker(GPU进程)Scheduler(Python进程)TokenizerManager(Python进程)HTTP Server(FastAPI)客户端RadixCache(内存)TPWorker(GPU进程)Scheduler(Python进程)TokenizerManager(Python进程)HTTP Server(FastAPI)客户端1. 应用聊天模板2. 分词3. 检查长度4. 在 RadixCache 中查找前缀5. 批次调度6. 分配 KV Cache7. GPU 模型推理(prefill + decode)8. 解码并流式返回POST /v1/chat/completionsGenerateReqInputTokenizedGenerateReqInput (ZMQ)命中部分前缀ForwardBatch输出 tokenBatchStrOutput (ZMQ)流式响应Server-Sent Events
详细步骤解析:
步骤 1-3:TokenizerManager 的预处理
• 位置:
python/sglang/srt/managers/tokenizer_manager.py
• 核心操作:```
1. 应用聊天模板(将多轮对话转成单个 prompt)
prompt = template_manager.apply_chat_template(messages)
结果:"<|begin_of_text|><|start_header_id|>user<|end_header_id|>什么是机器学习?<|eot_id|>..."
2. 分词
input_ids = tokenizer.encode(prompt)
3. 验证长度
if len(input_ids) > context_len - reserve_output_len:
raise ValueError("输入过长")
```
步骤 4:RadixCache 前缀匹配
• 位置:
python/sglang/srt/mem_cache/radix_cache.py
• 核心逻辑:```
RadixCache 是一个 Trie 树结构
假设之前有请求:"<|begin_of_text|><|start_header_id|>user<|end_header_id|>..."
这次请求的前面部分可以复用!
prefix_len = radix_cache.match_prefix(input_ids)
结果:前 15 个 token 命中缓存,可以跳过 prefill!
```💡 这就是 SGLang 速度快的秘密:聊天场景中,system prompt 和格式 token 每次都一样,RadixCache 让它们只需要计算一次!
步骤 5-6:Scheduler 的批次调度
• 位置:
python/sglang/srt/managers/scheduler.py
• 核心操作:```
将新请求加入调度队列
req = Req(input_ids, prefix_len=15, ...)
尝试将多个请求组成一个 batch
batch = ScheduleBatch()
batch.add_req(req) # 可能还会加入其他请求分配 KV Cache(使用 Paged Attention)
req.allocate_kv_cache(need_len=len(input_ids) - prefix_len + output_len)
```
步骤 7:TPWorker 的模型推理
• 位置:
python/sglang/srt/managers/tp_worker.py
• 核心操作:```
Prefill:处理输入序列
hidden_states = model.forward(
input_ids=batch.input_ids[prefix_len:], # 只处理未缓存的部分! positions=batch.positions, kv_cache=batch.kv_ptrs,
)
logits = model.lm_head(hidden_states)
next_token = sample(logits, temperature=0.7)Decode:自回归生成
while not finished:
next_token = model.forward_decode(...)
```
步骤 8:TokenizerManager 的流式返回
- • 核心操作:```
async def stream_output():
```while not req.finished: await asyncio.sleep(0.001) # 等待新 token if req.output_ids: delta_text = tokenizer.decode(req.output_ids[last_pos:]) yield {"choices": [{"delta": {"content": delta_text}}]} last_pos = len(req.output_ids)
关键时间节点:
• TTFT(Time To First Token):通常 < 50ms(如果命中 RadixCache)
• 解码速度:取决于模型大小和 GPU(Llama-3-8B 在 A100 上约 100 tokens/s)
2. 目录结构与核心流程
理解了宏观架构后,让我们深入代码层面,看看项目的"筋骨"是如何搭建的。这部分内容可能会有点技术化,但别担心,我会像导游一样带你逐个"景点"参观。😊
2.1 目录组织逻辑:按功能模块清晰划分
SGLang 的目录组织非常直观,遵循了**"关注点分离"**的原则。让我画个地图给你:
sglang/
├── python/sglang/ # 主框架(你会花 90% 的时间在这里)
│ ├── lang/ # 🎨 前端编程语言(写 LLM 应用的 DSL)
│ ├── srt/ # ⚙️ 后端运行时(推理引擎核心)
│ │ ├── managers/ # 👔 管理层(调度器、分词器等)
│ │ ├── models/ # 🤖 模型实现(115+ 模型支持)
│ │ ├── layers/ # 🧱 神经网络层(attention、MoE 等)
│ │ ├── mem_cache/ # 💾 内存缓存(RadixCache 核心)
│ │ ├── entrypoints/ # 🚪 服务入口(HTTP/gRPC server)
│ │ ├── distributed/ # 🌐 分布式并行
│ │ ├── disaggregation/ # 🔀 Prefill-Decode 分离
│ │ └── ...
│ ├── test/ # 🧪 测试代码
│ └── ...
├── sgl-kernel/ # ⚡ CUDA 内核库
│ ├── csrc/ # C++/CUDA 源码
│ ├── python/ # Python 绑定
│ └── tests/ # 内核测试
├── sgl-router/ # 🦀 Rust 路由器
│ ├── src/ # Rust 源码
│ └── py_src/ # Python 接口
├── benchmark/ # 📊 各种 benchmark 脚本
├── examples/ # 💡 示例代码
├── docs/ # 📚 文档
└── docker/ # 🐳 Docker 配置
设计意图解析:
-
- 为什么
lang/
和srt/
分离?
- 为什么
•
lang/
:前端语言,可以独立使用(连接 OpenAI API 也行)•
srt/
:后端运行时,专注于本地推理• 好处:前端开发者不需要 GPU,后端优化不影响 API
-
- 为什么单独有一个
sgl-kernel/
仓库?
- 为什么单独有一个
• CUDA 代码编译慢,单独管理可以预编译 wheel
• 版本独立发布(
sgl-kernel
可以单独升级)• 降低主仓库的复杂度
-
- 为什么
sgl-router/
用 Rust 而不是 Python?
- 为什么
• 路由器需要处理高并发、低延迟
• Rust 的内存安全保证 + 零成本抽象
• 编译后的二进制性能接近 C++
2.2 关键文件定位:你的学习起点
这里我为你标注了"第一个应阅读"的关键文件,按照学习顺序排列:
🌟 Level 1:理解项目入口(1-2小时)
-
README.md
(项目根目录)
• 为什么读:了解项目定位、核心特性、快速开始
• 重点看:Features、Benchmark、Getting Started
-
python/sglang/launch_server.py
(约30行)
• 为什么读:这是启动服务器的入口,逻辑很简单
• 核心代码:```
本质上就是:解析参数 -> 启动 HTTP 服务器
server_args = prepare_server_args(sys.argv[1:])
launch_server(server_args)
```
-
python/sglang/srt/server_args.py
(约800行)
• 为什么读:所有命令行参数的定义都在这里
• 学习目标:理解有哪些配置选项(模型路径、并行策略、缓存设置等)
• 💡 小技巧:不需要全部记住,知道有这个文件,需要时来查就行
🔥 Level 2:理解核心业务流程(3-5天)
-
python/sglang/srt/entrypoints/http_server.py
(约1500行)
• 为什么读:这是 HTTP API 的实现,看懂它就理解了请求是如何被处理的
• 关键函数:
•
generate_request()
:处理生成请求•
v1_chat_completions()
:OpenAI 兼容的聊天 API
- • 学习策略:先看主流程,跳过错误处理和边界情况
-
python/sglang/srt/managers/tokenizer_manager.py
(约1900行)
• 为什么读:理解请求的预处理和后处理
• 核心类:
TokenizerManager
• 关键方法:
•
generate_request()
:主入口•
handle_generate_request()
:分词和验证•
handle_batch_result()
:处理解码结果
-
python/sglang/srt/managers/scheduler.py
(约2900行)
• 为什么读:这是整个系统的"大脑",调度逻辑都在这里
• 核心类:
Scheduler
• 关键方法:
•
event_loop_normal()
:主事件循环•
process_input_requests()
:处理新请求•
get_next_batch_to_run()
:批次调度
- • ⚠️ 警告:这是最复杂的文件之一,建议先看 Level 1-2 的其他文件
⚙️ Level 3:深入核心模块(1-2周)
-
python/sglang/srt/mem_cache/radix_cache.py
(约600行)
• 为什么读:RadixAttention 的核心实现
• 核心类:
RadixCache
• 学习目标:理解前缀缓存的 Trie 树结构
-
python/sglang/srt/managers/schedule_batch.py
(约1200行)
• 为什么读:理解
ScheduleBatch
和Req
的数据结构• 这是调度器操作的核心数据结构
-
python/sglang/srt/models/*.py
(115+ 文件)
• 为什么读:如果你想添加新模型支持,必须理解现有模型的实现
• 推荐从简单的模型开始:
llama.py
、qwen2.py
-
python/sglang/srt/layers/attention/*.py
(69 文件)
• 为什么读:理解不同的 attention 实现(FlashInfer、Triton、PyTorch)
• 核心文件:
flashinfer_backend.py
🔬 Level 4:高级特性(根据兴趣选择)
-
- Prefill-Decode 分离:
python/sglang/srt/disaggregation/
- Prefill-Decode 分离:
-
- LoRA 支持:
python/sglang/srt/lora/
- LoRA 支持:
-
- 结构化输出:
python/sglang/srt/constrained/
- 结构化输出:
-
- Expert Parallelism:
python/sglang/srt/eplb/
- Expert Parallelism:
2.3 模块依赖关系分析
让我画出核心模块之间的依赖关系,这样你就能理解"谁依赖谁":
创建ZMQ 通信管理使用使用加载使用HTTP Serverentrypoints/http_server.pyTokenizerManagermanagers/tokenizer_manager.pySchedulermanagers/scheduler.pyTPWorkermanagers/tp_worker.pyScheduleBatchmanagers/schedule_batch.pyRadixCachemem_cache/radix_cache.pyModelsmodels/*.pyLayerslayers/*.py
依赖层级解析:
L1 - 入口层(最上层):
•
http_server.py
:依赖 FastAPI,独立性最强• 设计原则:这一层可以被替换(比如换成 gRPC 入口)
L2 - 管理层:
•
TokenizerManager
:依赖transformers
库和http_server
• 单向依赖:TokenizerManager -> Scheduler(通过 ZMQ),无反向依赖
• 好处:两者可以在不同进程甚至不同机器上运行
L3 - 调度层:
•
Scheduler
:系统最复杂的模块,依赖TPWorker
、ScheduleBatch
、RadixCache
• 关键设计:Scheduler 不直接依赖 HTTP 层,保持了调度逻辑的纯粹性
L4 - 执行层:
•
TPWorker
:依赖models/
和layers/
• 并行策略:一个 Scheduler 可以管理多个 TPWorker(Tensor Parallelism)
L5 - 基础层:
•
models/
和layers/
:依赖 PyTorch 和sgl-kernel
• 最底层:基本不依赖上层模块,可复用性最高
循环依赖检查: ✅ 无循环依赖
• 所有依赖都是单向的、自顶向下的
• 这是一个健康的依赖结构
2.4 典型业务流程:Chat Completion 详解
现在让我们选取最常用的场景——Chat Completion,详细分析其数据流和控制流。
场景:用户发送一个多轮对话请求
# 客户端代码
import openai
client = openai.Client(base_url="http://localhost:30000/v1")
response = client.chat.completions.create(
model="meta-llama/Llama-3.1-8B-Instruct",
messages=[
{"role": "system", "content": "你是一个helpful assistant"},
{"role": "user", "content": "什么是机器学习?"}
],
temperature=0.7,
max_tokens=512,
stream=True
)
for chunk in response:
print(chunk.choices[0].delta.content, end='')
数据流图(Data Flow):
HTTP POSTChatCompletionRequestGenerateReqInputApply Templatesystem + user promptTokenizeinput_idsTokenizedGenerateReqInputvia ZMQCheck CachePrefix MatchForwardInferenceLogitsSamplingnext_token_idResultBatchStrOutputvia ZMQDecodetextStreamSSEOpenAI ClientFastAPI EndpointOpenAIServingChatTokenizerManagerTemplateManagerHF TokenizerSchedulerRadixCacheTPWorkerGPU ModelSampler
详细步骤拆解(带代码定位):
Step 1:HTTP 请求解析
• 文件:
python/sglang/srt/entrypoints/openai/serving_chat.py
• 函数:
create_chat_completion()
• 操作:```
验证请求格式
assert request.model == server_args.served_model_name
转换为内部请求格式
generate_req = GenerateReqInput(
text=None, # 聊天请求暂时不设置 text messages=request.messages, sampling_params=SamplingParams( temperature=request.temperature, max_new_tokens=request.max_tokens, ), stream=request.stream,
)
```
Step 2:应用聊天模板
• 文件:
python/sglang/srt/managers/template_manager.py
• 函数:
apply_chat_template()
• 操作:```
Llama-3.1 的聊天模板示例
prompt = (
"<|begin_of_text|>" "<|start_header_id|>system<|end_header_id|>\n\n" "你是一个helpful assistant<|eot_id|>" "<|start_header_id|>user<|end_header_id|>\n\n" "什么是机器学习?<|eot_id|>" "<|start_header_id|>assistant<|end_header_id|>\n\n"
)
```💡 注意:不同模型的模板不同!这也是为什么 SGLang 支持 115+ 模型还能保持高性能——模板管理做得好。
Step 3:分词(Tokenization)
• 文件:
python/sglang/srt/managers/tokenizer_manager.py
• 函数:
handle_generate_request()
• 操作:```
input_ids = tokenizer.encode(prompt, add_special_tokens=False # 模板中已经包含了特殊 token
)
结果:[128000, 128006, 9125, 128007, ...] # 数字是 token IDs
```
Step 4:验证输入长度
• 文件:
python/sglang/srt/managers/utils.py
• 函数:
validate_input_length()
• 操作:```
if len(input_ids) + max_new_tokens > context_len:raise ValueError( f"Input too long: {len(input_ids)} + {max_new_tokens} > {context_len}" )
```
Step 5:通过 ZMQ 发送到 Scheduler
• 文件:
python/sglang/srt/managers/tokenizer_manager.py
• 通信方式:
out_pyobj = self.send_to_scheduler.send_pyobj(req)
• 数据格式:```
TokenizedGenerateReqInput(rid="req_abc123", input_ids=[128000, 128006, ...], sampling_params=SamplingParams(...), return_logprob=False, ...
)
```
Step 6:Scheduler 接收并调度
• 文件:
python/sglang/srt/managers/scheduler.py
• 函数:
event_loop_normal()
->process_input_requests()
• 核心逻辑:```
1. 从 ZMQ 接收请求
recv_reqs = recv_from_tokenizer.recv_pyobj()
2. 创建 Req 对象
req = Req(
rid=recv_req.rid, input_ids=recv_req.input_ids, sampling_params=recv_req.sampling_params,
)
3. RadixCache 前缀匹配
prefix_len = radix_cache.match_prefix(req.input_ids)
req.prefix_indices = radix_cache.get_indices(prefix_len)4. 加入等待队列
waiting_queue.append(req)
```
Step 7:批次调度
• 文件:
python/sglang/srt/managers/scheduler.py
• 函数:
get_next_batch_to_run()
• 核心逻辑:```
从等待队列中取出请求,组成 batch
batch = ScheduleBatch()
while waiting_queue and batch.can_add_more():
req = waiting_queue.popleft() # 尝试分配 KV Cache if not req.allocate_kv_cache(): break # 内存不足,等下一轮 batch.add_req(req)
return batch
```💡 Continuous Batching:这里不是等一个固定大小的 batch,而是"能加多少加多少",充分利用 GPU。
Step 8:GPU 模型推理
• 文件:
python/sglang/srt/managers/tp_worker.py
+python/sglang/srt/models/llama.py
• 函数:
forward_batch_generation()
• Prefill 阶段:```
只处理未缓存的部分
actual_input_ids = batch.input_ids[:, prefix_len:]
模型前向传播
hidden_states = model.forward(
input_ids=actual_input_ids, positions=batch.positions, kv_cache=batch.kv_ptrs,
)
logits = model.lm_head(hidden_states)
```• Decode 阶段(循环):```
while not all_finished:# 只处理 batch 中最后一个 token hidden_states = model.forward( input_ids=batch.last_token_ids, positions=batch.current_positions, kv_cache=batch.kv_ptrs, ) logits = model.lm_head(hidden_states) next_tokens = sample(logits, temperature=0.7) # 更新 batch batch.append_new_tokens(next_tokens) batch.check_finished() # 检查是否有请求完成
```
Step 9:采样(Sampling)
• 文件:
python/sglang/srt/sampling/penaltylib.py
• 操作:```
1. 应用 temperature
logits = logits / temperature
2. 应用 top-p / top-k
if top_p < 1.0:
logits = apply_top_p_filter(logits, top_p)
3. 采样
probs = torch.softmax(logits, dim=-1)
next_token = torch.multinomial(probs, num_samples=1)
```
Step 10:返回结果给 TokenizerManager
• 通信方式:
send_to_tokenizer.send_pyobj(output)
• 数据格式:```
BatchStrOutput(rids=["req_abc123"], output_ids=[[128000, ..., 12345]], # 新生成的 token IDs finished_reasons=[None], # None 表示未完成 ...
)
```
Step 11:TokenizerManager 解码
• 文件:
python/sglang/srt/managers/tokenizer_manager.py
• 操作:```
解码新生成的 token
new_text = tokenizer.decode(
req_state.output_ids[last_pos:], skip_special_tokens=True
)
req_state.text += new_text
```
Step 12:流式返回给客户端
• 文件:
python/sglang/srt/entrypoints/openai/serving_chat.py
• SSE 格式:```
async def generate_stream():while not req_state.finished: await req_state.event.wait() # 构造 SSE 响应 chunk = ChatCompletionStreamResponse( choices=[{ "delta": {"content": new_text}, "finish_reason": None }] ) yield f"data: {chunk.model_dump_json()}\n\n"
```
时间节点统计(Llama-3-8B on A100):
• Step 1-6(预处理):约 5-10ms
• Step 7(RadixCache 匹配):约 0.1-1ms(如果命中,节省大量时间!)
• Step 8 Prefill:约 10-50ms(取决于输入长度)
• Step 8 Decode(每个 token):约 10ms(100 tokens/s)
• Step 9-12(后处理):约 1-2ms per token
总 TTFT:约 15-60ms(如果 RadixCache 命中良好,可降至 15ms)
2.5 流程图绘制:可视化系统交互
让我用 Mermaid 绘制一个完整的序列图,展示所有组件的交互:
GPU ModelTPWorkerRadixCacheSchedulerHF TokenizerTemplateManagerTokenizerManagerOpenAIServingChatHTTP Server(FastAPI)ClientGPU ModelTPWorkerRadixCacheSchedulerHF TokenizerTemplateManagerTokenizerManagerOpenAIServingChatHTTP Server(FastAPI)Clientalt[Still Generating]loop[Prefill + Decode]POST /v1/chat/completions1ChatCompletionRequest2generate_request()3apply_chat_template(messages)4formatted_prompt5encode(prompt)6input_ids7validate_input_length()8TokenizedGenerateReqInput (ZMQ)9match_prefix(input_ids)10prefix_indices, prefix_len11allocate_kv_cache()12build_schedule_batch()13ForwardBatch14forward()15logits16sampling()17next_tokens18BatchStrOutput (partial, ZMQ)19decode(output_ids)20text21yield chunk22SSE chunk23data: {...}24BatchStrOutput (finished, ZMQ)25final result26SSE [DONE]27data: [DONE]28
关键观察:
-
- 异步并行:TokenizerManager 和 Scheduler 在不同进程,互不阻塞
-
- 流式响应:每生成一个 token 就返回,用户体验好
-
- RadixCache 提前介入:在调度阶段就完成前缀匹配
2.6 实现文件索引:快速定位关键代码
为了方便你后续学习,我整理了一个"代码地图",按功能模块列出核心文件:
📁 HTTP 服务层:
• 主入口:
python/sglang/srt/entrypoints/http_server.py
• OpenAI API:
• Chat:
python/sglang/srt/entrypoints/openai/serving_chat.py
• Completion:
python/sglang/srt/entrypoints/openai/serving_completions.py
• Embedding:
python/sglang/srt/entrypoints/openai/serving_embedding.py
- • 协议定义:
python/sglang/srt/entrypoints/openai/protocol.py
📁 管理层:
• TokenizerManager:
python/sglang/srt/managers/tokenizer_manager.py
• Scheduler:
python/sglang/srt/managers/scheduler.py
• TPWorker:
python/sglang/srt/managers/tp_worker.py
• ScheduleBatch:
python/sglang/srt/managers/schedule_batch.py
• 调度策略:
python/sglang/srt/managers/schedule_policy.py
📁 内存缓存:
• RadixCache:
python/sglang/srt/mem_cache/radix_cache.py
• ChunkCache:
python/sglang/srt/mem_cache/chunk_cache.py
• HiRadixCache(分层缓存):
python/sglang/srt/mem_cache/hiradix_cache.py
📁 模型层:
- • 模型实现:
python/sglang/srt/models/
(115+ 文件,按模型名称命名)
• Llama:
llama.py
• Qwen:
qwen2.py
、qwen2_vl.py
• DeepSeek:
deepseek.py
、deepseek_v3.py
- • 模型加载:
python/sglang/srt/model_loader/loader.py
📁 神经网络层:
- • Attention:
python/sglang/srt/layers/attention/
• FlashInfer:
flashinfer_backend.py
• Triton:
triton_backend.py
• MoE:
python/sglang/srt/layers/moe/
• 量化:
python/sglang/srt/layers/quantization/
📁 分布式:
• 并行状态:
python/sglang/srt/distributed/parallel_state.py
• 通信操作:
python/sglang/srt/distributed/communication_op.py
📁 Prefill-Decode 分离:
• Prefill:
python/sglang/srt/disaggregation/prefill.py
• Decode:
python/sglang/srt/disaggregation/decode.py
📁 结构化输出:
• XGrammar:
python/sglang/srt/constrained/xgrammar_backend.py
• LLGuidance:
python/sglang/srt/constrained/llguidance_backend.py
📁 CUDA 内核:
• Flash Attention:
sgl-kernel/csrc/flashinfer/
• MoE 内核:
sgl-kernel/csrc/moe/
• 量化内核:
sgl-kernel/csrc/quantization/
3. 代码结构观察
了解了"在哪里"之后,让我们看看代码"长什么样"——这部分会帮你理解 SGLang 的编码风格和设计模式。
3.1 代码组织模式
SGLang 的代码遵循了一些清晰的组织原则,让我带你观察:
模式 1:Mixin 模式(混入模式)
Scheduler 是项目中最复杂的类,如果把所有逻辑写在一个类里会有几千行。SGLang 使用 Mixin 模式将不同功能分离:
# python/sglang/srt/managers/scheduler.py
class Scheduler(
SchedulerOutputProcessorMixin, # 处理输出
SchedulerMetricsMixin, # 收集指标
SchedulerProfilerMixin, # 性能分析
SchedulerUpdateWeightsMixin, # 权重更新
SchedulerDisaggregationPrefillMixin, # P-D 分离(Prefill)
SchedulerDisaggregationDecodeMixin, # P-D 分离(Decode)
):
def __init__(self, ...):
# 主要的初始化逻辑
...
def event_loop_normal(self):
# 主事件循环
while True:
self.process_input_requests() # 处理新请求
batch = self.get_next_batch() # 获取下一批
self.run_batch(batch) # 执行批次
self.process_batch_result() # 处理结果(来自 Mixin)
好处:
• 每个 Mixin 负责一个独立的功能模块
• 代码易于维护和测试
• 可以选择性地启用功能(比如不需要 profiler 时可以不混入)
模式 2:数据类(Dataclass)+ 类型提示
SGLang 大量使用 Python 3.10+ 的 @dataclass
和类型提示:
# python/sglang/srt/managers/io_struct.py
@dataclasses.dataclass
class GenerateReqInput:
"""用户的生成请求输入"""
text: Optional[str] = None
messages: Optional[List[Dict]] = None
sampling_params: SamplingParams = None
rid: Optional[str] = None
return_logprob: bool = False
stream: bool = False
# 多模态相关
image_data: Optional[List[str]] = None
modalities: Optional[List[str]] = None
好处:
• 自动生成
__init__
、__repr__
等方法• 类型提示帮助 IDE 提供更好的代码补全
• 运行时可以进行类型检查(使用
pydantic
或typeguard
)
模式 3:工厂模式(Factory Pattern)
在需要根据配置创建不同实现时,SGLang 使用工厂函数:
# python/sglang/srt/layers/attention/__init__.py
def get_attention_backend(backend_name: str):
"""根据配置返回不同的 attention 实现"""
if backend_name == "flashinfer":
from sglang.srt.layers.attention.flashinfer_backend import FlashInferBackend
return FlashInferBackend
elif backend_name == "triton":
from sglang.srt.layers.attention.triton_backend import TritonBackend
return TritonBackend
elif backend_name == "torch":
from sglang.srt.layers.attention.torch_backend import TorchBackend
return TorchBackend
else:
raise ValueError(f"Unknown backend: {backend_name}")
模式 4:领域模型分离
核心的业务对象(如 Req
、ScheduleBatch
)与具体实现解耦:
# python/sglang/srt/managers/schedule_batch.py
class Req:
"""表示一个请求的领域模型"""
def __init__(self, rid, input_ids, sampling_params):
self.rid = rid
self.input_ids = input_ids
self.sampling_params = sampling_params
# 状态相关
self.output_ids = []
self.finished = False
# 缓存相关
self.prefix_indices = None
self.kv_pages = []
def allocate_kv_cache(self) -> bool:
"""分配 KV Cache,返回是否成功"""
# 具体实现
...
好处:
•
Req
对象不关心底层的 KV Cache 实现细节• 可以轻松替换 KV Cache 的实现(RadixCache、ChunkCache 等)
3.2 设计模式识别
让我指出 SGLang 中使用的几个经典设计模式:
1. 策略模式(Strategy Pattern)
不同的调度策略(FCFS、优先级队列等)使用策略模式:
# python/sglang/srt/managers/schedule_policy.py
class SchedulePolicy(ABC):
@abstractmethod
def get_priority(self, req: Req) -> float:
"""计算请求的优先级"""
pass
class FCFSPolicy(SchedulePolicy):
"""先来先服务"""
def get_priority(self, req: Req) -> float:
return req.arrival_time # 越早到达优先级越高
class PriorityPolicy(SchedulePolicy):
"""基于用户指定的优先级"""
def get_priority(self, req: Req) -> float:
return req.priority
2. 观察者模式(Observer Pattern)
请求的状态变化通过 asyncio.Event
通知等待的协程:
# python/sglang/srt/managers/tokenizer_manager.py
class ReqState:
def __init__(self):
self.event = asyncio.Event() # 观察者等待的事件
self.finished = False
self.output_ids = []
async def generate_stream(req_state: ReqState):
"""流式生成(观察者)"""
while not req_state.finished:
await req_state.event.wait() # 等待通知
req_state.event.clear()
# 处理新数据
yield process_output(req_state.output_ids)
# Scheduler 通知观察者
def notify_output_ready(req_state: ReqState):
req_state.event.set() # 唤醒所有等待的观察者
3. 单例模式(Singleton Pattern)
全局的配置对象使用单例模式:
# python/sglang/global_config.py
class GlobalConfig:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
self.verbosity = 2
self.enable_metrics = False
# ... 其他全局配置
global_config = GlobalConfig() # 全局单例
4. 适配器模式(Adapter Pattern)
不同的 attention 后端通过适配器模式提供统一接口:
# python/sglang/srt/layers/attention/flashinfer_backend.py
class FlashInferBackend:
def forward(self, q, k, v, ...):
# 调用 FlashInfer 的实现
return flashinfer.single_prefill_with_kv_cache(...)
# python/sglang/srt/layers/attention/triton_backend.py
class TritonBackend:
def forward(self, q, k, v, ...):
# 调用 Triton 内核
return triton_attention_kernel(...)
两者都实现了相同的 forward
接口,上层代码不需要关心具体使用的是哪个后端。
3.3 代码质量观察
让我客观地描述一下 SGLang 代码的特点:
✅ 优点:
-
- 清晰的模块划分
• 每个模块职责明确
• 依赖关系简单、无循环依赖
-
- 丰富的类型提示
• 大部分函数都有类型注解
• 使用
Optional[]
、List[]
等泛型类型• 帮助 IDE 和类型检查工具
-
- 完善的文档字符串
• 核心类和函数都有 docstring
• 关键算法有注释说明
-
- 模块化的测试
•
test/
目录下有丰富的单元测试•
benchmark/
目录下有性能测试
⚠️ 可以改进的地方(学习机会):
-
- 部分函数过长```
python/sglang/srt/managers/scheduler.py
def event_loop_normal(self):这个函数约 200+ 行,包含了主事件循环的所有逻辑
可以考虑进一步拆分成更小的函数
...
```💡 学习机会:你可以尝试重构这个函数,拆分成更小的、单一职责的方法。
- 部分函数过长```
-
- 一些类的职责过多
•
Scheduler
类即使用了 Mixin,仍然承担了太多职责• 💡 思考题:如果你来设计,会如何进一步拆分
Scheduler
?
-
- 部分代码存在TODO注释```
搜索 TODO 注释
$ grep -r "TODO" python/sglang/srt/ | wc -l结果:约 50+ 处
```💡 贡献机会:这些 TODO 是很好的贡献入口!
- 部分代码存在TODO注释```
3.4 改进方向提示
基于代码观察,我为不同阶段的学习者提供一些改进方向:
📚 初学者(学习重点):
• 理解为什么使用
asyncio
而不是多线程• 理解 ZMQ 的通信模式(REQ-REP、PUSH-PULL)
• 理解为什么需要 Continuous Batching
💻 有经验者(可探索的重构机会):
• 将
Scheduler.event_loop_normal()
拆分成更小的方法• 为关键路径添加性能 profiling
• 改进错误处理和日志(目前部分地方用的
print
而不是logger
)
🚀 进阶者(值得探索的优化方向):
• 实现更智能的调度策略(如基于历史统计的优先级)
• 优化 RadixCache 的内存管理(当前可能存在内存碎片)
• 支持更细粒度的 KV Cache 共享(跨 request 共享)
3.5 潜在改进点(学习机会)
通过搜索代码中的特定标记,我找到了一些值得探索的学习机会:
🔍 TODO 标记(改进任务):
# 示例 TODO 标记
python/sglang/srt/managers/schedule_batch.py:129
# TODO: support input pruning for sparse attention
python/sglang/srt/mem_cache/radix_cache.py:234
# TODO: implement better eviction policy
python/sglang/srt/layers/attention/triton_backend.py:87
# TODO: optimize for long context (>32k tokens)
💡 这些 TODO 是绝佳的贡献机会! 你可以从简单的 TODO 入手,逐步深入。
🐛 FIXME 标记(已知问题):
# 示例 FIXME 标记
python/sglang/srt/managers/tokenizer_manager.py:456
# FIXME: this may cause race condition in multi-tokenizer mode
🔍 代码坏味道(Potential Code Smells):
-
- 重复代码```
多个地方都有类似的验证逻辑
if len(input_ids) > context_len:
raise ValueError("Input too long")``💡 **改进建议**:提取为工具函数
validate_input_length()`
- 重复代码```
-
- 魔法数字```
python/sglang/srt/managers/scheduler.py
if len(batch) > 256: # 256 是什么意思?
...``💡 **改进建议**:定义为常量
MAX_BATCH_SIZE = 256`
- 魔法数字```
-
- 过长的参数列表```
def init(self, model_path, tokenizer_path, tensor_parallel_size,
...pipeline_parallel_size, max_total_tokens, context_len, trust_remote_code, ...): # 超过 10 个参数
``💡 **改进建议**:使用配置对象(已经在做了,如
ServerArgs`)
- 过长的参数列表```
学习建议:
• 不要把这些"坏味道"看成批评,而是看成学习和贡献的机会
• 尝试改进一个小的坏味道,提交 PR,这是参与开源最好的方式!
第二部分:技能需求清单(你的学习弹药库)📚
本部分目标: 明确告诉你需要掌握哪些技能,以及掌握到什么程度。我会分成基础技能、进阶技能,并针对不同水平的学习者给出具体建议。
1. 基础技能要求
这部分技能是"必须掌握"的,没有这些基础,后面的学习会很吃力。但别担心,我会告诉你需要掌握到什么程度。
1.1 编程语言和框架
Python 3.10+ 🐍
• 必需程度:⭐⭐⭐⭐⭐(必须)
• 需要掌握的特性:```
1. 类型提示(Type Hints)
from typing import Optional, List, Dict
def process_request(text: str, max_tokens: Optional[int] = None) -> List[str]:...
2. 数据类(Dataclass)
from dataclasses import dataclass, field
@dataclass
class Request:text: str tokens: List[int] = field(default_factory=list)
3. 异步编程(Asyncio)
async def handle_request(req: Request):
await asyncio.sleep(0.1) return result
4. 上下文管理器(Context Manager)
with open("file.txt") as f:
content = f.read()
5. 生成器(Generator)和异步生成器
async def stream_results():
for item in data: yield item
```
• 学习资源:
• 官方文档:Python 3.10 新特性[1]
• 推荐书籍:《Fluent Python》第 2 版(中文版:《流畅的 Python》)
PyTorch 2.8 🔥
• 必需程度:⭐⭐⭐⭐⭐(必须)
• 需要掌握的内容:```
1. 基本的张量操作
import torch
x = torch.randn(2, 3, 4)
y = x.view(2, -1) # reshape
z = torch.matmul(x, y.T)2. 自动求导(虽然推理不需要,但理解原理很重要)
x.requires_grad = True
loss = (x ** 2).sum()
loss.backward()3. CUDA 操作
device = torch.device("cuda:0")
x = x.to(device)4. torch.nn 模块(理解 Linear、LayerNorm、Embedding 等)
linear = torch.nn.Linear(768, 3072)
output = linear(x)
```• 不需要:深入的训练技巧、复杂的优化器
• 学习资源:
• 官方教程:PyTorch Tutorials[2]
• 推荐课程:Stanford CS224N、CS231N
CUDA 编程基础 ⚡
• 必需程度:⭐⭐⭐☆☆(了解即可,除非你要开发内核)
• 需要了解的概念:
• GPU 线程模型(grid、block、thread)
• 内存层次(global memory、shared memory、register)
• 同步机制(
__syncthreads()
)• 为什么 CUDA 比 CPU 快(并行计算)
• 示例(不需要会写,但要能看懂):```
global void vector_add(float a, float b, float* c, int n) {int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < n) { c[idx] = a[idx] + b[idx]; }
}
```• 学习资源:
• NVIDIA 官方:CUDA C Programming Guide[3]
• 推荐课程:UIUC CS483(GPU Programming)
FastAPI + Uvicorn 🌐
• 必需程度:⭐⭐⭐⭐☆(重要)
• 需要掌握的内容:```
from fastapi import FastAPI, HTTPException
from pydantic import BaseModelapp = FastAPI()
class Request(BaseModel):
text: str max_tokens: int = 100
@app.post("/generate")
async def generate(req: Request):result = await process(req.text) return {"output": result}
流式响应
from fastapi.responses import StreamingResponse
@app.post("/stream")
async def stream_generate(req: Request):async def generate(): async for chunk in process_stream(req.text): yield f"data: {chunk}\n\n" return StreamingResponse(generate(), media_type="text/event-stream")
```
• 学习资源:
• 官方文档:FastAPI Documentation[4]
• 推荐教程:FastAPI 官方教程(非常详细!)
Asyncio(异步 I/O) ⏱️
• 必需程度:⭐⭐⭐⭐⭐(必须)
• 核心概念:
• Event Loop(事件循环)
• Coroutine(协程):
async def
• Task(任务):
asyncio.create_task()
• Future(未来对象)
•
await
的含义:暂停当前协程,让其他协程运行
• 示例:```
import asyncioasync def task1():
print("Task 1 start") await asyncio.sleep(1) print("Task 1 done")
async def task2():
print("Task 2 start") await asyncio.sleep(0.5) print("Task 2 done")
async def main():
await asyncio.gather(task1(), task2()) # 并发执行
asyncio.run(main())
输出:
Task 1 start
Task 2 start
Task 2 done # 0.5秒后
Task 1 done # 1秒后
```
• 为什么 SGLang 需要 asyncio?
• TokenizerManager 需要同时处理多个请求
• 等待 Scheduler 返回结果时不能阻塞其他请求
- • 学习资源:
• 官方文档:asyncio — Asynchronous I/O[5]
• 推荐文章:Real Python 的 asyncio 系列教程
1.2 具体版本要求和兼容性
从 pyproject.toml
可以看到 SGLang 对依赖版本有明确要求,这不是随便定的——每个版本都有其原因:
核心依赖及其版本:
# 深度学习框架
torch = "2.8.0" # 最新版本,支持 CUDA 12.8、torch.compile 优化
transformers = "4.57.0" # 支持最新模型(Llama-3, Qwen-3, DeepSeek-V3)
torchvision = "*" # 多模态模型需要
torchaudio = "2.8.0" # 语音模态
# 高性能注意力
flashinfer_python = "0.4.0rc3" # ⚠️ 版本精确,不同版本 API 不兼容
# 结构化输出
xgrammar = "0.1.24" # ⚠️ 版本精确,内部 API 变化频繁
llguidance = ">=0.7.11,<0.8.0" # 允许小版本更新
# 量化
torchao = "0.9.0" # 量化和优化工具
# Web 服务
fastapi = "*" # 允许任意版本(API 稳定)
uvicorn = "*"
uvloop = "*" # 加速 asyncio
# 通信
pyzmq = ">=25.1.2" # ZeroMQ Python 绑定
grpcio = "1.75.1" # ⚠️ gRPC 版本需与 grpcio-tools 一致
grpcio-tools = "1.75.1"
# 监控
prometheus-client = ">=0.20.0" # Prometheus 指标导出
# 其他
sgl-kernel = "0.3.14.post1" # ⚠️ 必须与 sglang 版本匹配
版本兼容性重要提示:
-
- CUDA 版本
• 推荐:CUDA 12.8(对应 torch 2.8.0)
• 最低要求:CUDA 11.8
• 为什么:FlashInfer 和 sgl-kernel 依赖特定 CUDA 版本
• 检查命令:
nvcc --version # 查看 CUDA 版本 python -c "import torch; print(torch.version.cuda)" # 查看 PyTorch 的 CUDA 版本
-
- GPU 架构要求
• FlashInfer 要求:sm_75+(即 Turing 架构及以上)
• 支持的 GPU:T4、A10、A100、L4、L40S、H100、H200、B100、B200
• 不支持:P100、V100(可以使用
--attention-backend triton
替代)
-
- Python 版本
• 要求:Python >= 3.10
• 推荐:Python 3.11(性能更好)
• 不支持:Python 3.9 及以下(因为使用了 3.10+ 的类型提示语法)
-
- 操作系统
• 推荐:Ubuntu 22.04 LTS
• 支持:任何支持 CUDA 的 Linux 发行版
• 部分支持:Windows(WSL2)、macOS(CPU only)
1.3 基础工具和概念
Git 版本控制 📦
• 必需程度:⭐⭐⭐⭐☆(重要)
• 需要掌握的命令:```
克隆项目
git clone https://github.com/sgl-project/sglang.git
切换分支
git checkout -b feature/my-feature
查看修改
git diff
git status提交
git add .
git commit -m "Fix: xxx"同步上游
git fetch upstream
git rebase upstream/main
```
Docker 容器 🐳
• 必需程度:⭐⭐⭐☆☆(建议掌握)
• 核心概念:镜像、容器、卷挂载
• 常用命令:```
拉取镜像
docker pull lmsysorg/sglang:latest
运行容器
docker run --gpus all -p 30000:30000 lmsysorg/sglang:latest
进入容器
docker exec -it bash
```
Shell 脚本 💻
• 必需程度:⭐⭐⭐☆☆(建议掌握)
• 需要了解:环境变量、管道、重定向```
设置环境变量
export CUDA_VISIBLE_DEVICES=0,1
管道
ps aux | grep python
后台运行
nohup python server.py > log.txt 2>&1 &
```
2. 进阶技能要求
如果你想深入理解 SGLang 的设计,或者贡献高质量的代码,这些进阶技能非常重要。
2.1 架构模式和设计原则
Transformer 架构深度理解 🤖
• 必需程度:⭐⭐⭐⭐⭐(核心)
• 需要理解的内容:
-
- Self-Attention 机制```
Q、K、V 的含义
Q = input @ W_q # Query: "我在找什么"
K = input @ W_k # Key: "我是什么"
V = input @ W_v # Value: "我的内容是什么"
注意力计算
scores = Q @ K.T / sqrt(d_k) # 计算相似度
attn = softmax(scores) # 归一化
output = attn @ V # 加权求和
``` - Self-Attention 机制```
-
- KV Cache 机制
• 为什么需要:自回归生成时,之前的 token 的 K、V 不会变化,可以缓存避免重复计算
• 内存占用:对于 Llama-3-8B,单个 token 的 KV Cache 约 0.5MB
• 计算节省:有 KV Cache 时,decode 阶段复杂度从 O(n²) 降到 O(n)
-
- Multi-Head Attention
• 为什么要多头:不同的头可以关注不同的信息
• Grouped-Query Attention (GQA):K、V 的头数少于 Q
• Multi-Query Attention (MQA):所有 Q 共享同一组 K、V
-
- 位置编码
• RoPE(Rotary Position Embedding):Llama 使用的位置编码
• ALiBi:另一种位置编码方案
- • 学习资源:
• 论文:Attention Is All You Need[6]
• 推荐博客:Jay Alammar 的 The Illustrated Transformer[7]
• 推荐视频:李沐的论文精读系列
LLM 推理优化技术 ⚡
• 必需程度:⭐⭐⭐⭐⭐(核心)
• 关键技术:
-
- Paged Attention(vLLM 提出)
• 核心思想:像操作系统的虚拟内存一样管理 KV Cache
• 好处:减少内存碎片,提高内存利用率
• 实现:KV Cache 分成固定大小的 block,按需分配
-
- RadixAttention(SGLang 的创新)
• 核心思想:用 Trie 树结构存储 KV Cache,实现前缀共享
• 好处:相同前缀只需要计算一次
• 性能提升:聊天场景下 5x 加速
-
- Continuous Batching
• 传统 Batching:等所有请求都完成才开始下一批
• Continuous Batching:请求完成后立即加入新请求,GPU 利用率更高
-
- Prefill-Decode Disaggregation
• 核心思想:将 prefill(处理输入)和 decode(生成输出)分离到不同 GPU
• 为什么:prefill 是计算密集型,decode 是内存密集型,分离后各取所长
• 性能提升:DeepSeek-V3 在 GB200 上 2.7x 加速
-
- Speculative Decoding(推测解码)
• 核心思想:用小模型快速生成多个 token,大模型一次性验证
• 好处:减少大模型的调用次数
• 适用场景:对延迟敏感的场景
- • 学习资源:
• 论文:Efficient Memory Management for Large Language Model Serving with PagedAttention[8](vLLM)
• 博客:SGLang v0.2 Blog[9]
分布式系统基础 🌐
• 必需程度:⭐⭐⭐⭐☆(重要)
• 需要理解的内容:
-
- 数据并行(Data Parallelism, DP)
• 核心思想:每个 GPU 有完整模型,处理不同的 batch
• 适用场景:SGLang Router 实现的就是 DP
-
- 张量并行(Tensor Parallelism, TP)
• 核心思想:将模型的某一层(如 Linear)的权重切分到多个 GPU
• 通信量:每层都需要 All-Reduce,通信开销大
• 适用场景:单个 GPU 放不下模型时
-
- 流水线并行(Pipeline Parallelism, PP)
• 核心思想:将模型的不同层放到不同 GPU(如前 16 层在 GPU0,后 16 层在 GPU1)
• 挑战:气泡(bubble)问题——GPU 可能空闲等待
-
- 专家并行(Expert Parallelism, EP)
• 核心思想:MoE 模型中,不同的 expert 放到不同 GPU
• SGLang 的创新:Large-scale EP,支持 96+ GPU(DeepSeek-V3)
-
- 通信原语
• All-Reduce:所有进程的数据求和并广播
• All-Gather:收集所有进程的数据
• Reduce-Scatter:求和后切分到各进程
- • 学习资源:
• 论文:Megatron-LM: Training Multi-Billion Parameter Language Models[10]
• 博客:HuggingFace 的 Parallelism Guide[11]
2.2 领域特定知识
LLM 推理服务架构 🏗️
- • 核心组件:
-
- 前端:接收用户请求、流式返回
-
- 调度器:批次调度、资源管理
-
- 执行器:模型推理、采样
-
- 缓存:KV Cache 管理
- • 性能指标:
• Throughput(吞吐量):每秒处理多少个 token
• Latency(延迟):单个请求的响应时间
• TTFT(Time To First Token):第一个 token 的延迟
• TBT(Time Between Tokens):token 之间的时间间隔
量化技术 🔢
- • 类型:
• INT8:8位整数量化
• FP8:8位浮点量化(H100+ 硬件支持)
• INT4:4位整数量化(GPTQ、AWQ)
• FP4:4位浮点量化(仅 B100/B200 支持)
- • 权衡:精度 vs. 速度 vs. 显存
结构化输出(Constrained Decoding) 📋
• 应用场景:强制模型输出符合 JSON Schema、正则表达式等格式
• 技术:
• XGrammar:编译期优化的语法约束
• LLGuidance:运行时的生成引导
- • 性能:SGLang 的结构化输出比其他框架快 3-10x
2.3 技能掌握程度建议
我为不同水平的学习者制定了技能树:
🌱 初学者(目标:能跑起来、能修简单 bug)
必须掌握:
• ✅ Python 基础(类、函数、模块)
• ✅ PyTorch 基础(tensor 操作、模型加载)
• ✅ 基本的 Linux 命令
• ✅ Git 基本操作(clone、commit、push)
需要了解:
• 🔍 Transformer 架构(概念层面,不需要能手写)
• 🔍 Asyncio 基础(知道什么是协程即可)
• 🔍 Docker 基本使用
学习路径:
1. 先把项目跑起来(用 Docker 最简单)
2. 修改一些配置参数,观察效果
3. 阅读
launch_server.py
和http_server.py
4. 尝试修复一个简单的 bug 或添加日志
🌿 有经验的开发者(目标:能理解核心流程、能优化性能)
必须掌握:
• ✅ Asyncio 深入理解(event loop、task、future)
• ✅ PyTorch 进阶(自定义 op、CUDA 集成)
• ✅ Transformer 架构深入理解(能手写 attention)
• ✅ 性能分析工具(
py-spy
、nsys
、torch.profiler
)
需要了解:
• 🔍 CUDA 编程基础(能看懂内核代码)
• 🔍 分布式系统基础(TP、PP、DP)
• 🔍 RadixAttention 原理
学习路径:
1. 理解完整的请求处理流程(从 HTTP 到 GPU)
2. 使用 profiler 分析性能瓶颈
3. 阅读 Scheduler 和 RadixCache 的实现
4. 尝试优化一个性能热点或实现一个新功能
🌳 进阶者(目标:能贡献核心代码、能设计新特性)
必须掌握:
• ✅ CUDA 编程(能手写高性能 kernel)
• ✅ 分布式系统深入理解(通信原语、容错)
• ✅ LLM 推理优化技术全栈(Paged Attention、Continuous Batching 等)
• ✅ 系统设计能力(能权衡不同方案)
需要了解:
• 🔍 最新的学术论文(FlashAttention、Speculative Decoding 等)
• 🔍 硬件特性(GPU 架构、内存带宽、计算吞吐)
• 🔍 编译器优化(Triton、Torch.compile)
学习路径:
1. 阅读相关论文,理解前沿技术
2. 实现一个新的调度策略或优化算法
3. 贡献高性能 CUDA kernel
4. 参与架构设计讨论
第三部分:学习路径规划(你的专属教练计划)🎯
本部分目标: 为你提供一个清晰、可执行的学习计划,从环境搭建到架构理解,每一步都有具体的操作指南和检查点。
了解了需要什么技能后,让我们进入最实用的部分——如何一步步学习 SGLang。我会像健身教练制定训练计划一样,为你设计一个循序渐进的学习路径。💪
1. 项目运行入口定位(快速上手)
1.1 一键启动指南(15-30分钟完成)
方法一:使用 Docker(最简单,强烈推荐) 🐳
# Step 1: 确保你有 GPU 和 Docker
# 检查 GPU
nvidia-smi
# 检查 Docker 和 NVIDIA Container Toolkit
docker run --rm --gpus all nvidia/cuda:12.8.0-base-ubuntu22.04 nvidia-smi
# Step 2: 设置 Hugging Face token(用于下载模型)
export HF_TOKEN=your_huggingface_token # 在 https://huggingface.co/settings/tokens 获取
# Step 3: 运行 SGLang 服务器(以 Llama-3.1-8B 为例)
docker run --gpus all \
--shm-size 32g \
-p 30000:30000 \
-v ~/.cache/huggingface:/root/.cache/huggingface \
--env "HF_TOKEN=$HF_TOKEN" \
--ipc=host \
lmsysorg/sglang:latest \
python3 -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-8B-Instruct \
--host 0.0.0.0 \
--port 30000
# 💡 参数解释:
# --gpus all:使用所有 GPU
# --shm-size 32g:设置共享内存大小(重要!太小会导致错误)
# -p 30000:30000:端口映射
# -v ~/.cache/huggingface:挂载模型缓存目录(避免重复下载)
# --ipc=host:使用主机的 IPC 命名空间(多进程通信需要)
方法二:使用 pip 安装(适合开发) 📦
# Step 1: 安装 Python 3.10+ 和 CUDA 12.8
# 检查版本
python --version # 应该 >= 3.10
nvcc --version # 应该是 CUDA 12.8
# Step 2: 安装 UV(加速 pip)
pip install --upgrade pip
pip install uv
# Step 3: 安装 SGLang
uv pip install "sglang[all]>=0.5.3rc2"
# 如果遇到 "CUDA_HOME environment variable is not set" 错误:
export CUDA_HOME=/usr/local/cuda-12.8 # 设置 CUDA 路径
# Step 4: 启动服务器
python -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-8B-Instruct \
--host 0.0.0.0 \
--port 30000
# 💡 第一次运行会下载模型(约 16GB),需要等待几分钟
方法三:从源码安装(适合贡献代码) 🔧
# Step 1: 克隆项目
git clone https://github.com/sgl-project/sglang.git
cd sglang
# Step 2: 安装依赖
pip install --upgrade pip
pip install -e "python[all]"
# Step 3: 启动服务器
python -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-8B-Instruct \
--port 30000
1.2 环境配置清单和常见陷阱
✅ 环境配置清单:
# 1. 硬件要求
# - GPU: 至少 16GB 显存(Llama-3-8B 需要约 16GB)
# - RAM: 至少 32GB
# - 存储: 至少 50GB 空闲空间(用于模型和缓存)
# 2. 软件要求
# - Ubuntu 22.04 LTS(推荐)
# - Python 3.10 或 3.11
# - CUDA 12.8
# - Docker 24.0+ 和 NVIDIA Container Toolkit(如果使用 Docker)
# 3. 检查命令
nvidia-smi # 检查 GPU
nvcc --version # 检查 CUDA
python --version # 检查 Python
docker --version # 检查 Docker
⚠️ 最常见的 5 个陷阱及解决方案:
陷阱 1:CUDA 版本不匹配
# 症状:
# RuntimeError: CUDA error: no kernel image is available for execution on the device
# 原因:PyTorch 的 CUDA 版本与系统 CUDA 版本不匹配
# 解决方案:
python -c "import torch; print(torch.version.cuda)" # 查看 PyTorch 的 CUDA 版本
nvcc --version # 查看系统 CUDA 版本
# 如果不匹配,重新安装 PyTorch:
pip install torch==2.8.0 --index-url https://download.pytorch.org/whl/cu128
陷阱 2:共享内存不足
# 症状:
# RuntimeError: DataLoader worker (pid XXXXX) is killed by signal: Bus error
# 原因:Docker 默认的共享内存只有 64MB,太小了
# 解决方案:
# 在 docker run 时添加 --shm-size 32g
docker run --shm-size 32g ...
陷阱 3:FlashInfer 不支持你的 GPU
# 症状:
# RuntimeError: FlashInfer only supports sm_75 and above
# 原因:你的 GPU 架构太老(如 V100)
# 解决方案:切换到 Triton 后端
python -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-8B-Instruct \
--attention-backend triton \
--sampling-backend pytorch \
--port 30000
陷阱 4:显存不足(OOM)
# 症状:
# torch.cuda.OutOfMemoryError: CUDA out of memory
# 原因:模型太大或 batch size 太大
# 解决方案 1:使用量化模型
python -m sglang.launch_server \
--model-path neuralmagic/Meta-Llama-3.1-8B-Instruct-FP8 \
--port 30000
# 解决方案 2:减少 max_total_tokens
python -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-8B-Instruct \
--max-total-tokens 8192 \ # 默认是 32768
--port 30000
# 解决方案 3:使用张量并行(需要多个 GPU)
python -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-70B-Instruct \
--tp-size 2 \ # 使用 2 个 GPU
--port 30000
陷阱 5:端口被占用
# 症状:
# OSError: [Errno 48] Address already in use
# 解决方案:
# 查找占用端口的进程
lsof -i :30000
# 或者
netstat -tunlp | grep 30000
# 杀死进程
kill -9 <PID>
# 或者换个端口
python -m sglang.launch_server --port 30001 ...
1.3 验证成功标志
启动服务器后,你应该看到类似的输出:
INFO: Uvicorn running on http://0.0.0.0:30000 (Press CTRL+C to quit)
INFO: Model meta-llama/Llama-3.1-8B-Instruct loaded successfully
INFO: Memory usage: 15.2 GB / 24.0 GB
INFO: Max batch size: 256
INFO: Ready to serve requests
测试 API 是否正常:
# 测试 1:健康检查
curl http://localhost:30000/health
# 期望输出:
# {"status":"OK","model":"meta-llama/Llama-3.1-8B-Instruct","version":"0.5.3rc2"}
# 测试 2:生成请求
curl http://localhost:30000/v1/completions \
-H "Content-Type: application/json" \
-d '{
"model": "meta-llama/Llama-3.1-8B-Instruct",
"prompt": "Hello, my name is",
"max_tokens": 50,
"temperature": 0.7
}'
# 期望输出(大致):
# {
# "choices": [{
# "text": " John Smith and I am a software engineer...",
# "finish_reason": "length"
# }],
# "usage": {"prompt_tokens": 6, "completion_tokens": 50}
# }
# 测试 3:聊天 API
curl http://localhost:30000/v1/chat/completions \
-H "Content-Type: "application/json" \
-d '{
"model": "meta-llama/Llama-3.1-8B-Instruct",
"messages": [
{"role": "user", "content": "什么是机器学习?"}
],
"max_tokens": 100
}'
使用 Python 客户端测试:
# test_sglang.py
import openai
client = openai.Client(
base_url="http://localhost:30000/v1",
api_key="EMPTY" # SGLang 默认不需要 API key
)
# 测试聊天
response = client.chat.completions.create(
model="meta-llama/Llama-3.1-8B-Instruct",
messages=[
{"role": "user", "content": "用一句话解释什么是 Transformer"}
],
max_tokens=100
)
print(response.choices[0].message.content)
# 测试流式输出
print("\n流式输出:")
for chunk in client.chat.completions.create(
model="meta-llama/Llama-3.1-8B-Instruct",
messages=[{"role": "user", "content": "数到10"}],
stream=True
):
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end='', flush=True)
运行测试:
python test_sglang.py
如果一切正常,恭喜你!🎉 你已经成功运行起 SGLang 了!
2. 循序渐进学习计划(四阶段法)
现在进入系统学习阶段。我设计了四个阶段,每个阶段都有明确的目标和可验证的成果。
阶段一:环境搭建和项目启动(1-2天)
目标: 成功运行项目,能发送请求并获得响应,理解基本的配置参数。
Day 1上午:环境搭建(2-3小时)
# 任务 1:安装 SGLang
# 选择方法一(Docker)或方法二(pip),完成安装
# 任务 2:下载一个小模型测试
python -m sglang.launch_server \
--model-path Qwen/Qwen2.5-0.5B-Instruct \ # 只有 1GB
--port 30000
# 任务 3:测试 API
curl http://localhost:30000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen2.5-0.5B-Instruct",
"messages": [{"role": "user", "content": "Hello"}]
}'
Day 1下午:理解配置参数(2-3小时)
# 任务 4:查看所有参数
python -m sglang.launch_server --help | less
# 任务 5:尝试修改参数,观察效果
# 实验 1:修改 max_total_tokens(影响能缓存多少 KV Cache)
python -m sglang.launch_server \
--model-path Qwen/Qwen2.5-0.5B-Instruct \
--max-total-tokens 4096 \ # 默认是 32768
--port 30000
# 观察:启动日志中的 "Memory usage" 会减少
# 实验 2:修改 context_len(影响最大输入长度)
python -m sglang.launch_server \
--model-path Qwen/Qwen2.5-0.5B-Instruct \
--context-len 4096 \ # 默认是模型支持的最大值
--port 30000
# 实验 3:启用日志记录
python -m sglang.launch_server \
--model-path Qwen/Qwen2.5-0.5B-Instruct \
--log-requests \ # 记录所有请求
--log-requests-level text \ # 记录请求的文本内容
--port 30000
# 发送请求后,查看日志输出
Day 2:打断点、阅读代码(3-4小时)
# 任务 6:在代码中添加断点,观察请求处理流程
# 安装 ipdb(调试工具)
pip install ipdb
# 修改 python/sglang/srt/managers/tokenizer_manager.py
# 在 handle_generate_request 方法中添加断点:
def handle_generate_request(self, obj: GenerateReqInput):
import ipdb; ipdb.set_trace() # 在这里暂停
# 原有代码...
prompt = self.template_manager.apply_chat_template(obj.messages)
input_ids = self.tokenizer.encode(prompt)
...
# 重启服务器并发送请求,程序会在断点处暂停
# 你可以检查变量的值:
# >>> obj
# >>> prompt
# >>> input_ids
# ipdb 常用命令:
# n:下一行
# c:继续执行
# p 变量名:打印变量
# q:退出
阶段一检查点: ✅
• 能成功启动服务器
• 能发送请求并获得正确响应
• 理解至少 5 个配置参数的作用
• 能在代码中添加断点并查看变量
阶段二:核心流程理解(3-5天)
目标: 能够追踪一个完整的请求流程,理解从 HTTP 请求到 GPU 推理再到返回结果的全过程。
Day 3-4:追踪请求流程(每天 3-4小时)
# 任务 1:绘制请求流程图
# 创建一个文件 request_flow.md,记录你追踪到的流程:
## 请求流程(我的理解)
1. **HTTP 入口**(`http_server.py:v1_chat_completions`)
- 接收 ChatCompletionRequest
- 验证请求格式
- 调用 OpenAIServingChat.create_chat_completion()
2. **聊天服务**(`serving_chat.py:create_chat_completion`)
- 转换为 GenerateReqInput
- 调用 tokenizer_manager.generate_request()
3. **分词管理器**(`tokenizer_manager.py:generate_request`)
- 应用聊天模板
- 分词(encode)
- 通过 ZMQ 发送到 Scheduler
... (继续记录)
# 💡 学习技巧:
# - 不要一次读完所有代码,先抓主线
# - 用注释标记你看不懂的地方,后面再研究
# - 画图!画图!画图!(图比文字更容易理解)
实践任务:添加自定义日志
# 任务 2:在关键路径添加日志,观察请求流动
# 修改 python/sglang/srt/managers/tokenizer_manager.py
import logging
logger = logging.getLogger(__name__)
def handle_generate_request(self, obj: GenerateReqInput):
logger.info(f"🔵 [TokenizerManager] Received request: {obj.rid}")
prompt = self.template_manager.apply_chat_template(obj.messages)
logger.info(f"🔵 [TokenizerManager] Prompt: {prompt[:100]}...") # 只打印前100字符
input_ids = self.tokenizer.encode(prompt)
logger.info(f"🔵 [TokenizerManager] Input IDs length: {len(input_ids)}")
# ... 原有代码
# 修改 python/sglang/srt/managers/scheduler.py
def process_input_requests(self, recv_reqs):
for req in recv_reqs:
logger.info(f"🟢 [Scheduler] Processing request: {req.rid}")
logger.info(f"🟢 [Scheduler] Input length: {len(req.input_ids)}")
# RadixCache 查找
prefix_len = self.radix_cache.match_prefix(req.input_ids)
logger.info(f"🟢 [Scheduler] RadixCache hit: {prefix_len}/{len(req.input_ids)} tokens")
# ... 原有代码
# 修改 python/sglang/srt/managers/tp_worker.py
def forward_batch_generation(self, batch):
logger.info(f"🟡 [TPWorker] Forward batch size: {len(batch.reqs)}")
logger.info(f"🟡 [TPWorker] Total tokens: {batch.input_ids.shape}")
# ... 原有代码
# 重启服务器,发送请求,观察日志:
# 你应该看到类似的输出:
# 🔵 [TokenizerManager] Received request: req_abc123
# 🔵 [TokenizerManager] Prompt: <|begin_of_text|><|start_header_id|>...
# 🔵 [TokenizerManager] Input IDs length: 42
# 🟢 [Scheduler] Processing request: req_abc123
# 🟢 [Scheduler] Input length: 42
# 🟢 [Scheduler] RadixCache hit: 15/42 tokens
# 🟡 [TPWorker] Forward batch size: 1
# 🟡 [TPWorker] Total tokens: torch.Size([1, 27])
Day 5:深入 RadixCache(3-4小时)
# 任务 3:理解 RadixCache 的 Trie 树结构
# 阅读 python/sglang/srt/mem_cache/radix_cache.py
# 关键类:
# - TreeNode:Trie 树的节点
# - RadixCache:管理 Trie 树
# 核心方法:
# - match_prefix():查找前缀匹配
# - insert():插入新的 token 序列
# - evict():驱逐 LRU 节点
# 实验:观察 RadixCache 的命中率
# 修改 python/sglang/srt/managers/scheduler.py
def process_input_requests(self, recv_reqs):
for req in recv_reqs:
prefix_len = self.radix_cache.match_prefix(req.input_ids)
hit_rate = prefix_len / len(req.input_ids) if len(req.input_ids) > 0 else 0
logger.info(f"RadixCache hit rate: {hit_rate:.2%}")
# 发送多个相似的请求,观察 hit rate 的变化:
# 请求 1:"什么是机器学习?" -> hit rate: 0%(第一次)
# 请求 2:"什么是深度学习?" -> hit rate: 80%(前缀"什么是"相同)
# 请求 3:"什么是强化学习?" -> hit rate: 80%
阶段二检查点: ✅
• 能画出完整的请求流程图(从 HTTP 到 GPU)
• 理解 TokenizerManager、Scheduler、TPWorker 的职责
• 理解 RadixCache 的工作原理
• 能添加自定义日志并观察请求流动
阶段三:模块深入和定制开发(1-2周)
目标: 能修改或扩展一个现有功能,如添加新的采样参数、优化调度策略等。
Week 1:深入核心模块
Day 6-7:调度策略(Scheduler)
# 任务 1:理解调度策略
# 阅读 python/sglang/srt/managers/schedule_policy.py
# 当前策略:FCFS(First Come First Serve)
# 实践:实现一个简单的优先级调度策略
# 创建新文件 python/sglang/srt/managers/priority_schedule_policy.py
from sglang.srt.managers.schedule_policy import SchedulePolicy
from sglang.srt.managers.schedule_batch import Req
class PrioritySchedulePolicy(SchedulePolicy):
"""基于请求长度的优先级调度:短请求优先"""
def get_priority(self, req: Req) -> float:
# 返回优先级分数(越小优先级越高)
# 短请求优先,可以减少其他请求的等待时间
return len(req.input_ids)
def select_next_batch(self, waiting_queue, current_batch_size):
# 对等待队列按优先级排序
sorted_queue = sorted(waiting_queue, key=self.get_priority)
# 选择优先级最高的请求
batch = []
for req in sorted_queue:
if len(batch) >= current_batch_size:
break
batch.append(req)
return batch
# 修改 scheduler.py 使用新策略
# (这里只是示例,实际集成需要更多代码)
Day 8-9:采样策略(Sampling)
# 任务 2:添加新的采样参数
# 阅读 python/sglang/srt/sampling/sampling_params.py
# 实践:添加 "min_p" 采样参数(只保留概率 >= min_p * max_prob 的 token)
# 修改 python/sglang/srt/sampling/sampling_params.py
@dataclasses.dataclass
class SamplingParams:
# ... 现有参数
# 添加新参数
min_p: Optional[float] = None # 新增:Min-P 采样
# 修改 python/sglang/srt/sampling/penaltylib.py
def apply_min_p_filter(logits, min_p):
"""应用 Min-P 过滤"""
if min_p is None or min_p <= 0:
return logits
probs = torch.softmax(logits, dim=-1)
max_prob = probs.max(dim=-1, keepdim=True).values
threshold = min_p * max_prob
# 将低于阈值的 token 概率设为 -inf
logits = torch.where(probs >= threshold, logits, float('-inf'))
return logits
# 在采样流程中调用
# 修改 python/sglang/srt/layers/sampler.py
class Sampler:
def forward(self, logits, sampling_params):
# ... 现有逻辑
# 应用 min_p
if sampling_params.min_p is not None:
logits = apply_min_p_filter(logits, sampling_params.min_p)
# ... 采样
# 测试新参数
curl http://localhost:30000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "meta-llama/Llama-3.1-8B-Instruct",
"messages": [{"role": "user", "content": "Hello"}],
"min_p": 0.1
}'
Day 10-12:性能优化实践
# 任务 3:使用 profiler 分析性能瓶颈
# 安装 profiler
pip install py-spy
# 在服务器运行时进行采样
py-spy top --pid <scheduler_pid>
# 或者生成火焰图
py-spy record -o profile.svg --pid <scheduler_pid> --duration 60
# 查看火焰图,找出最耗时的函数
# 常见优化方向:
# 1. 减少 Python 函数调用开销(用 @njit 编译)
# 2. 优化数据结构(用 numpy 代替 list)
# 3. 批处理小操作(减少 GPU kernel launch 次数)
# 实践:优化 token 解码
# 当前实现(每个 token 单独解码):
for token_id in output_ids:
text += tokenizer.decode([token_id])
# 优化后(批量解码):
text = tokenizer.decode(output_ids)
# 测试性能提升
Week 2:扩展功能
Day 13-14:添加新模型支持
# 任务 4:为 SGLang 添加一个新模型的支持
# 示例:添加 Mistral 模型(如果还未支持)
# Step 1:创建模型文件
# 复制一个相似的模型作为模板
cp python/sglang/srt/models/llama.py python/sglang/srt/models/mistral.py
# Step 2:修改模型定义
# python/sglang/srt/models/mistral.py
class MistralForCausalLM(nn.Module):
def __init__(self, config: MistralConfig):
super().__init__()
self.config = config
self.model = MistralModel(config)
self.lm_head = ParallelLM Head(config)
def forward(
self,
input_ids: torch.Tensor,
positions: torch.Tensor,
kv_cache: Any,
...
):
hidden_states = self.model(input_ids, positions, kv_cache, ...)
logits = self.lm_head(hidden_states)
return logits
# Step 3:注册模型
# 修改 python/sglang/srt/models/__init__.py
from sglang.srt.models.mistral import MistralForCausalLM
MODELS = {
"llama": LlamaForCausalLM,
"qwen": Qwen2ForCausalLM,
"mistral": MistralForCausalLM, # 新增
# ...
}
# Step 4:测试
python -m sglang.launch_server \
--model-path mistralai/Mistral-7B-Instruct-v0.3 \
--port 30000
阶段三检查点: ✅
• 理解调度策略的实现
• 能添加新的采样参数
• 能使用 profiler 分析性能
• (可选)能为 SGLang 添加新模型支持
阶段四:架构理解和贡献指南(2周+)
目标: 理解技术选型的原因,能参与架构讨论,能修复复杂 bug 或实现新特性。
Week 3:深入理解设计决策
问题驱动学习法:
## 为什么这样设计?(Why Questions)
### Q1: 为什么使用 ZMQ 而不是 Python 队列?
- **答案**:TokenizerManager 和 Scheduler 在不同进程
- **深入**:进程间通信的选择(共享内存 vs 消息队列 vs RPC)
- **权衡**:ZMQ 提供了灵活的通信模式(REQ-REP、PUSH-PULL),且性能高
### Q2: 为什么需要 RadixCache?Paged Attention 不够吗?
- **答案**:Paged Attention 解决内存碎片,RadixCache 解决重复计算
- **场景**:聊天应用中,system prompt 和格式 token 每次都一样
- **效果**:结合两者,既减少内存占用又减少计算量
### Q3: 为什么要做 Prefill-Decode 分离?
- **答案**:prefill 和 decode 的资源需求不同
- **细节**:
- Prefill:计算密集,需要高算力(FLOPS)
- Decode:内存密集,需要高带宽(Bandwidth)
- **好处**:分离后可以针对性优化,提高整体吞吐量
### Q4: 为什么 Scheduler 这么复杂?能简化吗?
- **答案**:需要处理的情况很多
- **挑战**:
- Continuous Batching:动态加入/移除请求
- RadixCache:前缀匹配和缓存管理
- 多种并行策略:TP、PP、EP、DP
- Prefill-Decode 分离:跨 GPU 通信
- LoRA:动态加载/卸载适配器
- **简化**:可以,但会牺牲功能或性能
### Q5: 为什么需要三个子项目(sglang、sgl-kernel、sgl-router)?
- **答案**:关注点分离、独立发布
- **好处**:
- sgl-kernel:CUDA 代码编译慢,单独管理可以预编译 wheel
- sgl-router:Rust 编译后是二进制,可以独立部署
- sglang:Python 代码变更频繁,不影响内核和路由器
...(继续提问并回答)
Week 4:贡献代码
任务:修复一个真实的 Issue
# Step 1:找一个适合新手的 Issue
# 访问 https://github.com/sgl-project/sglang/issues
# 筛选标签:good first issue
# Step 2:Fork 项目
# 在 GitHub 上点击 Fork 按钮
# Step 3:克隆你的 Fork
git clone https://github.com/YOUR_USERNAME/sglang.git
cd sglang
# Step 4:添加上游仓库
git remote add upstream https://github.com/sgl-project/sglang.git
# Step 5:创建新分支
git checkout -b fix/issue-1234
# Step 6:修改代码、添加测试
# ... 编码 ...
# Step 7:运行测试
cd test
pytest srt/test_*.py # 运行相关测试
# Step 8:提交代码
git add .
git commit -m "Fix #1234: description of the fix"
# Step 9:推送到你的 Fork
git push origin fix/issue-1234
# Step 10:创建 Pull Request
# 在 GitHub 上点击 "Create Pull Request"
# Step 11:等待 Review
# 根据 reviewer 的反馈修改代码
代码贡献指南:
-
- 代码风格```
遵循 PEP 8
使用 black 格式化
pip install black
black python/sglang/
使用 isort 排序 import
pip install isort
isort python/sglang/
``` - 代码风格```
-
- 测试要求
• 所有新功能必须有测试
• Bug 修复需要有回归测试
• 测试应该快速、独立、可重复
-
- 文档要求
• 新功能需要更新文档
• API 变更需要更新示例
-
- Commit 规范```
类型: 简短描述 (#Issue编号)
详细描述(可选)
类型可以是:
- feat: 新功能
- fix: Bug 修复
- docs: 文档修改
- refactor: 代码重构
- test: 测试相关
- chore: 其他修改
```
- Commit 规范```
阶段四检查点: ✅
• 理解至少 5 个关键设计决策的原因
• 能回答"为什么不用 XX 方案"的问题
• 提交了至少 1 个 PR(即使没被合并也算)
• 参与了社区讨论(GitHub Issue、Slack 等)
3. 学习路径流程图
让我用 Mermaid 画一个完整的学习路径流程图:
否是否是否是性能优化功能开发架构研究否是是否开始学习 SGLang是否具备基础技能?学习 Python/PyTorch 基础预计 2-4 周阶段一:环境搭建1-2 天能否成功启动服务器?查看常见陷阱章节排查问题阶段二:核心流程理解3-5 天绘制请求流程图添加自定义日志理解 RadixCache能否画出完整流程图?重新阅读代码寻求帮助选择深入方向性能优化路径功能开发路径架构研究路径使用 Profiler 分析优化热点代码阶段四:贡献代码2 周+实现新功能如新采样参数编写测试阅读相关论文编写设计文档找 good first issue提交 Pull RequestPR 被接受?根据反馈改进🎉 恭喜成为贡献者!继续深入?高级主题- CUDA 内核开发- 分布式优化- 新架构设计持续关注项目参与社区成为核心贡献者结束/持续学习
第四部分:实践建议和进阶指导(从会用到精通)💡
本部分目标: 提供实用的调试技巧、常见问题解决方案、扩展练习建议,以及参与社区贡献的具体途径。
恭喜你走到这一步!现在你已经掌握了 SGLang 的核心知识。这一部分我会分享一些实战经验和进阶技巧,帮助你从"会用"到"精通"。
1. 调试技巧和常见陷阱
1.1 推荐的调试方法
方法一:日志大法(最简单最有效) 📝
# 在关键位置添加详细日志
import logging
logger = logging.getLogger(__name__)
# 不同级别的日志
logger.debug(f"详细的调试信息:{variable_state}")
logger.info(f"关键流程节点:Request {rid} reached stage X")
logger.warning(f"潜在问题:Cache hit rate low: {hit_rate:.2%}")
logger.error(f"错误发生:{error_message}", exc_info=True)
# 💡 技巧:使用结构化日志
logger.info("request_processed", extra={
"rid": req.rid,
"input_len": len(req.input_ids),
"output_len": len(req.output_ids),
"duration_ms": duration * 1000,
})
方法二:断点调试(深入分析) 🔍
# 使用 ipdb(交互式调试器)
import ipdb; ipdb.set_trace()
# 或者使用 VSCode 的图形化调试器
# 在 .vscode/launch.json 中配置:
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: SGLang Server",
"type": "python",
"request": "launch",
"module": "sglang.launch_server",
"args": [
"--model-path", "Qwen/Qwen2.5-0.5B-Instruct",
"--port", "30000"
],
"console": "integratedTerminal"
}
]
}
方法三:性能分析(找瓶颈) ⚡
# 1. 使用 py-spy(Python 程序的采样profiler)
pip install py-spy
# 实时查看最耗时的函数
sudo py-spy top --pid <scheduler_pid>
# 生成火焰图
sudo py-spy record -o flamegraph.svg --pid <scheduler_pid> --duration 60
# 2. 使用 PyTorch Profiler(GPU 性能分析)
# 修改代码添加 profiler
import torch
with torch.profiler.profile(
activities=[
torch.profiler.ProfilerActivity.CPU,
torch.profiler.ProfilerActivity.CUDA,
],
with_stack=True,
) as prof:
# 运行一些推理
output = model.forward(...)
prof.export_chrome_trace("trace.json")
# 然后在 Chrome 浏览器中打开 chrome://tracing 加载 trace.json
# 3. 使用 NVIDIA Nsight Systems(系统级性能分析)
nsys profile -o profile python -m sglang.launch_server ...
# 然后用 Nsight Systems GUI 查看 profile.qdrep
方法四:单元测试(验证逻辑) 🧪
# 为核心逻辑编写单元测试
import pytest
from sglang.srt.mem_cache.radix_cache import RadixCache
def test_radix_cache_prefix_match():
cache = RadixCache(max_size=1000)
# 插入一个序列
seq1 = [1, 2, 3, 4, 5]
cache.insert(seq1)
# 测试完全匹配
assert cache.match_prefix([1, 2, 3, 4, 5]) == 5
# 测试部分匹配
assert cache.match_prefix([1, 2, 3, 6, 7]) == 3
# 测试无匹配
assert cache.match_prefix([9, 8, 7]) == 0
# 运行测试
pytest test_radix_cache.py -v
1.2 新人常见的 5 个陷阱
陷阱 1:忘记同步更新多个进程 ⚠️
# 问题:修改了 tokenizer_manager.py,但没有重启 scheduler
# 结果:看不到效果,还以为代码有问题
# 解决方案:
# SGLang 使用多进程架构,修改代码后需要完全重启服务器
pkill -9 -f sglang.launch_server # 杀死所有相关进程
python -m sglang.launch_server ... # 重新启动
陷阱 2:KV Cache 管理不当导致 OOM 💾
# 问题:长时间运行后突然 OOM
# 原因:RadixCache 缓存了太多无用的前缀
# 解决方案 1:设置合理的 max_total_tokens
python -m sglang.launch_server \
--max-total-tokens 16384 \ # 根据显存大小调整
--port 30000
# 解决方案 2:定期清理缓存
curl -X POST http://localhost:30000/flush_cache
# 解决方案 3:监控内存使用
curl http://localhost:30000/get_load
# 输出:{"gpu_memory_used": 15.2, "gpu_memory_total": 24.0}
陷阱 3:批处理大小设置不合理 📊
# 问题:吞吐量低于预期
# 原因:batch size 太小,GPU 利用率不足
# 检查当前 batch size
# 在 scheduler.py 中添加日志:
logger.info(f"Current batch size: {len(batch.reqs)}")
# 优化策略:
# 1. 增加 max_running_requests
python -m sglang.launch_server \
--max-running-requests 512 \ # 默认是 256
--port 30000
# 2. 调整 schedule_policy
# (高级用户可以自定义调度策略)
陷阱 4:Tensor 并行配置错误 🔀
# 问题:使用 TP 后性能反而下降
# 原因:通信开销大于计算收益
# 经验法则:
# - 单个 GPU 能放下模型:不要用 TP
# - 模型需要 2-4 个 GPU:TP=2 或 4
# - 模型需要 8+ 个 GPU:考虑 TP+PP 组合
# 错误配置:
python -m sglang.launch_server \
--model-path Qwen/Qwen2.5-7B \
--tp-size 4 \ # 浪费!7B 模型用不了 4 个 GPU
--port 30000
# 正确配置:
python -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-70B-Instruct \
--tp-size 4 \ # 合理!70B 模型需要多个 GPU
--port 30000
陷阱 5:忽略错误日志 📋
# 问题:遇到错误只看最后一行,找不到根因
# 解决方案:
# 1. 查看完整的堆栈跟踪
# 2. 搜索第一个 ERROR 或 WARNING
# 3. 检查 scheduler.log 和 tokenizer.log
# 启用详细日志:
python -m sglang.launch_server \
--model-path ... \
--log-level debug \ # 打印所有日志
--log-requests \ # 记录所有请求
--port 30000
# 分析日志的技巧:
grep -i "error" logs/scheduler.log # 查找错误
grep -i "warning" logs/scheduler.log # 查找警告
grep "OOM" logs/scheduler.log # 查找内存不足
2. 扩展练习建议
我为不同水平的学习者设计了一系列练习题,从易到难,帮助你巩固知识。
Level 1:初级练习(1-2 天完成)
练习 1:修改默认参数
# 目标:修改 temperature 的默认值为 0.8
# 文件:python/sglang/srt/sampling/sampling_params.py
@dataclasses.dataclass
class SamplingParams:
temperature: float = 0.8 # 修改这里,原本是 1.0
# ...
# 测试:重启服务器,不指定 temperature,观察输出是否更确定性
练习 2:添加自定义指标
# 目标:添加一个指标,统计平均 KV Cache 命中率
# 文件:python/sglang/srt/managers/scheduler.py
from prometheus_client import Histogram
cache_hit_rate = Histogram(
'cache_hit_rate',
'RadixCache hit rate distribution',
buckets=[0, 0.2, 0.4, 0.6, 0.8, 1.0]
)
def process_input_requests(self, recv_reqs):
for req in recv_reqs:
prefix_len = self.radix_cache.match_prefix(req.input_ids)
hit_rate = prefix_len / len(req.input_ids) if len(req.input_ids) > 0 else 0
cache_hit_rate.observe(hit_rate) # 记录到 Prometheus
# 测试:访问 http://localhost:30000/metrics 查看指标
练习 3:实现简单的请求过滤
# 目标:拒绝长度超过 1000 token 的请求
# 文件:python/sglang/srt/managers/tokenizer_manager.py
def handle_generate_request(self, obj: GenerateReqInput):
# ... 现有代码
if len(input_ids) > 1000:
raise ValueError(f"Input too long: {len(input_ids)} tokens (max 1000)")
# ... 原有代码
# 测试:发送一个超长请求,应该返回错误
Level 2:中级练习(3-5 天完成)
练习 4:实现请求优先级
# 目标:允许用户指定请求优先级,高优先级请求优先处理
# Step 1:修改请求定义
# 文件:python/sglang/srt/managers/io_struct.py
@dataclasses.dataclass
class GenerateReqInput:
# ... 现有字段
priority: int = 0 # 新增:优先级(数字越大优先级越高)
# Step 2:修改调度逻辑
# 文件:python/sglang/srt/managers/scheduler.py
def get_next_batch_to_run(self):
# 按优先级排序等待队列
self.waiting_queue = sorted(
self.waiting_queue,
key=lambda req: -req.priority # 优先级高的在前
)
# ... 原有调度逻辑
# Step 3:修改 API
# 文件:python/sglang/srt/entrypoints/openai/protocol.py
class ChatCompletionRequest(BaseModel):
# ... 现有字段
priority: Optional[int] = 0 # 新增
# 测试:
curl http://localhost:30000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"messages": [{"role": "user", "content": "Urgent task"}],
"priority": 10
}'
练习 5:实现动态 batch size 调整
# 目标:根据 GPU 负载动态调整 max batch size
# 文件:python/sglang/srt/managers/scheduler.py
class Scheduler:
def adjust_batch_size(self):
gpu_util = torch.cuda.utilization() # 获取 GPU 利用率
if gpu_util < 50:
# GPU 空闲,增加 batch size
self.max_batch_size = min(self.max_batch_size + 8, 512)
elif gpu_util > 90:
# GPU 过载,减少 batch size
self.max_batch_size = max(self.max_batch_size - 8, 64)
logger.info(f"Adjusted batch size to {self.max_batch_size} (GPU util: {gpu_util}%)")
def event_loop_normal(self):
while True:
# ... 原有代码
# 每 100 次迭代调整一次
if self.iteration_count % 100 == 0:
self.adjust_batch_size()
# 测试:发送大量请求,观察 batch size 的变化
练习 6:添加请求超时机制
# 目标:如果请求在队列中等待超过 30 秒,自动取消
# 文件:python/sglang/srt/managers/schedule_batch.py
@dataclasses.dataclass
class Req:
# ... 现有字段
enqueue_time: float = field(default_factory=time.time) # 加入队列的时间
# 文件:python/sglang/srt/managers/scheduler.py
def process_input_requests(self, recv_reqs):
# 检查超时请求
current_time = time.time()
timeout_reqs = []
for req in self.waiting_queue:
if current_time - req.enqueue_time > 30: # 30秒超时
timeout_reqs.append(req)
logger.warning(f"Request {req.rid} timed out")
# 移除超时请求
for req in timeout_reqs:
self.waiting_queue.remove(req)
req.finished_reason = FINISH_TIMEOUT
# 通知 tokenizer_manager
# 测试:在高负载下发送请求,观察是否有超时
Level 3:高级练习(1-2 周完成)
练习 7:实现智能批次调度
# 目标:实现一个智能调度算法,平衡延迟和吞吐量
# 核心思想:
# - 短请求(预估输出 < 100 tokens)优先处理
# - 长请求批量处理以提高吞吐量
# - 使用历史数据预测输出长度
# 提示:
# 1. 收集历史数据(输入长度 vs 输出长度)
# 2. 训练一个简单的线性回归模型
# 3. 在调度时预测输出长度,分配到不同队列
# 4. 短队列用小 batch、高频调度;长队列用大 batch、低频调度
# 评估指标:
# - P50/P90/P99 latency
# - Throughput (tokens/s)
# - GPU utilization
练习 8:支持部分结果缓存
# 目标:缓存中间结果,支持"继续生成"功能
# 应用场景:
# 用户先生成 100 tokens,觉得不够,继续生成 100 tokens
# 第二次生成可以直接从第 100 个 token 继续,无需重新计算前 100 个
# 实现要点:
# 1. 在 Req 中添加 session_id 字段
# 2. 在 RadixCache 中保存 session 的中间状态
# 3. 继续生成时,从中间状态恢复
# 挑战:
# - 如何处理 session 过期
# - 如何在多用户间公平分配缓存空间
3. 参与贡献的途径
3.1 找到合适的 Issue
Step 1:浏览 Issue 列表
访问:https://github.com/sgl-project/sglang/issues
筛选条件:
• 标签
good first issue
:适合新手• 标签
help wanted
:需要社区帮助• 标签
documentation
:文档相关(相对简单)• 标签
bug
:修复 bug(有挑战性但很有成就感)
示例 Issue:
• "Add support for Model X":添加新模型支持
• "Improve error message for OOM":优化错误提示
• "Fix typo in documentation":修复文档错误(最简单)
• "Optimize RadixCache eviction policy":优化算法(较难)
Step 2:评估难度
看 Issue 的描述和讨论,判断:
• 有没有清晰的复现步骤?
• 有没有人提供了解决思路?
• 是否涉及核心模块(核心模块较难)?
• 预计需要修改多少行代码?
Step 3:表达意向
在 Issue 下评论:
Hi! I'm interested in working on this issue.
Could you provide more context about [specific question]?
I'm planning to [your approach]. Does this sound reasonable?
💡 小贴士:先评论表达意向,避免和他人重复工作。
3.2 提交高质量的 PR
Pull Request 清单:
✅ 代码质量
• 代码遵循 PEP 8 规范(使用 black 格式化)
• 有清晰的变量命名和注释
• 无明显的代码坏味道
✅ 测试覆盖
• 添加了单元测试
• 测试覆盖了主要分支和边界情况
• 所有测试通过:
pytest test/srt/test_xxx.py
✅ 文档更新
• 更新了相关文档(如果有 API 变更)
• 更新了示例代码(如果需要)
• 在 PR 描述中说明了改动
✅ Commit 规范
# 好的 commit message:
feat: add min_p sampling parameter (#1234)
- Add min_p field to SamplingParams
- Implement apply_min_p_filter in penaltylib
- Add unit tests for min_p sampling
- Update API documentation
Fixes #1234
# 不好的 commit message:
update code
fix bug
✅ PR 描述模板
## 描述 (Description)
简要描述这个 PR 做了什么改动。
## 动机和背景 (Motivation and Context)
为什么需要这个改动?解决了什么问题?
Fixes #1234 <!-- 关联 Issue -->
## 改动类型 (Type of Change)
- [ ] Bug 修复
- [ ] 新功能
- [ ] 性能优化
- [ ] 文档更新
- [ ] 代码重构
## 测试 (Testing)
描述你如何测试这个改动。
```bash
# 测试命令
python -m sglang.launch_server --model-path ... --port 30000
curl http://localhost:30000/v1/chat/completions -d '...'
检查清单 (Checklist)
• 代码遵循 PEP 8
• 添加了单元测试
• 所有测试通过
• 更新了文档
• Commit message 遵循规范
#### 3.3 参与社区讨论
**官方渠道:**
1. **GitHub Discussions**
- 网址:https://github.com/sgl-project/sglang/discussions
- 用途:技术讨论、问题求助、分享经验
2. **Slack**
- 加入:https://slack.sglang.ai/
- 频道:
- `#general`:一般讨论
- `#help`:问题求助
- `#dev`:开发者讨论
- `#benchmark`:性能相关
3. **Bi-Weekly Meeting**
- 加入:https://meeting.sglang.ai/
- 频率:每两周一次
- 内容:Roadmap 讨论、新特性介绍、社区问答
**参与建议:**
- 💬 多提问,不要害怕问"愚蠢"的问题
- 📖 回答别人的问题,巩固自己的理解
- 📊 分享你的 benchmark 结果
- 💡 提出改进建议,参与讨论
---
## 第五部分:技术栈学习指引(你的知识地图)🌐
> **本部分目标:** 为你识别出的关键技能提供精准、高质量的学习路径指引,构建完整的学习支持体系。
这一部分我会为你提供一个完整的学习资源地图,包括官方文档、推荐书籍、教程、论文等。所有资源都经过筛选,确保高质量和权威性。
### 1. 官方文档定位(学习的基石)
#### 1.1 SGLang 项目文档
**必读文档:**
- **官方文档**:https://docs.sglang.ai/
- [安装指南](https://docs.sglang.ai/get_started/install.html)
- [快速开始](https://docs.sglang.ai/basic_usage/send_request.html)
- [Server Arguments](https://docs.sglang.ai/references/sampling_params.html)
- [贡献指南](https://docs.sglang.ai/developer_guide/contribution_guide.html)
**进阶主题:**
- [RadixAttention](https://docs.sglang.ai/advanced_features/radix_attention.html)
- [Prefill-Decode Disaggregation](https://docs.sglang.ai/advanced_features/disaggregation.html)
- [LoRA 支持](https://docs.sglang.ai/advanced_features/lora.html)
- [结构化输出](https://docs.sglang.ai/advanced_features/structured_output.html)
**技术博客(深度解析):**
- [v0.2 Release: Llama3 Performance](https://lmsys.org/blog/2024-07-25-sglang-llama3/)
- [v0.3 Release: DeepSeek MLA](https://lmsys.org/blog/2024-09-04-sglang-v0-3/)
- [v0.4 Release: Zero-Overhead Scheduler](https://lmsys.org/blog/2024-12-04-sglang-v0-4/)
- [Large-scale Expert Parallelism](https://lmsys.org/blog/2025-05-05-large-scale-ep/)
#### 1.2 核心技术栈文档
**PyTorch 2.8**
- 官方教程:https://pytorch.org/tutorials/
- 重点章节:
- [Introduction to PyTorch](https://pytorch.org/tutorials/beginner/basics/intro.html)
- [Autograd Mechanics](https://pytorch.org/docs/stable/notes/autograd.html)
- [CUDA Semantics](https://pytorch.org/docs/stable/notes/cuda.html)
- **推荐学习路径**:
1. 基础:Tensor 操作、自动求导
2. 进阶:自定义算子、CUDA 集成
3. 高级:torch.compile、分布式训练
**Transformers (Hugging Face)**
- 官方文档:https://huggingface.co/docs/transformers/
- 重点章节:
- [Model Architecture](https://huggingface.co/docs/transformers/model_doc/llama)
- [Generation Strategies](https://huggingface.co/docs/transformers/generation_strategies)
- [Model Parallelism](https://huggingface.co/docs/transformers/parallelism)
**FastAPI**
- 官方文档:https://fastapi.tiangolo.com/
- 重点章节:
- [First Steps](https://fastapi.tiangolo.com/tutorial/first-steps/)
- [Path Parameters](https://fastapi.tiangolo.com/tutorial/path-params/)
- [Request Body](https://fastapi.tiangelo.com/tutorial/body/)
- [Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/)
**FlashInfer**
- 官方文档:https://docs.flashinfer.ai/
- 重点:Single Prefill、Paged Attention API
- GitHub:https://github.com/flashinfer-ai/flashinfer
#### 1.3 相关论文(深入原理)
**必读论文:**
1. **Attention is All You Need** (Transformer)
- 链接:https://arxiv.org/abs/1706.03762
- 为什么读:理解 Transformer 架构的基础
2. **FlashAttention: Fast and Memory-Efficient Exact Attention**
- 链接:https://arxiv.org/abs/2205.14135
- 为什么读:理解高效 attention 的实现原理
3. **Efficient Memory Management for Large Language Model Serving** (vLLM)
- 链接:https://arxiv.org/abs/2309.06180
- 为什么读:理解 Paged Attention 和 Continuous Batching
4. **Efficiently Programming Large Language Models using SGLang** (SGLang)
- 链接:https://arxiv.org/abs/2312.07104
- 为什么读:理解 SGLang 的设计理念和 RadixAttention
**扩展阅读:**
5. **Speculative Decoding**: https://arxiv.org/abs/2211.17192
6. **Mixture-of-Experts**: https://arxiv.org/abs/1701.06538
7. **LoRA**: https://arxiv.org/abs/2106.09685
---
### 2. 学习路径建议(社区智慧)
#### 2.1 Python 异步编程
**学习路径:**
1. **基础**:理解协程、事件循环的概念
- 教程:Real Python 的 [Async IO in Python](https://realpython.com/async-io-python/)
- 视频:[David Beazley - Topics of Interest (Python Asyncio)](https://www.youtube.com/watch?v=ZzfHjytDceU)
2. **进阶**:理解 asyncio 的内部机制
- 文章:[How Asyncio Works](https://tenthousandmeters.com/blog/python-behind-the-scenes-12-how-asyncio-works/)
- 源码:阅读 `asyncio` 库的源码(从 Event Loop 开始)
3. **实践**:编写异步 Web 服务
- 项目:用 FastAPI 实现一个简单的异步 API
- 练习:实现并发请求、超时控制、错误处理
#### 2.2 GPU 编程和 CUDA
**学习路径:**
1. **基础**:理解 GPU 架构和 CUDA 编程模型
- 课程:NVIDIA 的 [CUDA Programming](https://developer.nvidia.com/cuda-education)
- 书籍:《Programming Massively Parallel Processors》
2. **进阶**:优化 CUDA kernel
- 文章:[CUDA Pro Tips](https://developer.nvidia.com/blog/cuda-pro-tip-optimizing-memory-access-patterns/)
- 工具:使用 Nsight Compute 进行性能分析
3. **实践**:实现高性能算子
- 项目:实现一个 matrix multiplication kernel
- 优化目标:达到理论带宽的 80%
#### 2.3 Transformer 和 LLM
**学习路径:**
1. **基础**:理解 Attention 机制
- 博客:[The Illustrated Transformer](https://jalammar.github.io/illustrated-transformer/)
- 视频:李沐的 [Transformer 论文逐段精读](https://www.bilibili.com/video/BV1pu411o7BE/)
2. **进阶**:理解 LLM 推理优化
- 论文:FlashAttention、Paged Attention
- 博客:[LLM Inference Optimization](https://lilianweng.github.io/posts/2023-01-10-inference-optimization/)
3. **实践**:手写 Transformer
- 项目:从零实现一个 mini-GPT
- 参考:[minGPT](https://github.com/karpathy/minGPT)
#### 2.4 分布式系统
**学习路径:**
1. **基础**:理解分布式系统的基本概念
- 课程:MIT 6.824 Distributed Systems
- 书籍:《Designing Data-Intensive Applications》
2. **进阶**:理解 LLM 的分布式并行
- 论文:Megatron-LM、GPipe、PipeDream
- 文档:HuggingFace 的 [Model Parallelism](https://huggingface.co/docs/transformers/parallelism)
3. **实践**:实现简单的数据并行
- 项目:用 PyTorch DDP 训练一个模型
- 进阶:实现 Tensor Parallelism
---
### 3. 工具与环境配置指南
#### 3.1 开发环境搭建
**推荐 IDE:VSCode**
配置文件 `.vscode/settings.json`:
```json
{
"python.linting.enabled": true,
"python.linting.pylintEnabled": false,
"python.linting.flake8Enabled": true,
"python.formatting.provider": "black",
"editor.formatOnSave": true,
"[python]": {
"editor.rulers": [88]
}
}
推荐扩展:
• Python
• Pylance
• Jupyter
• GitLens
• Remote - SSH(远程开发)
3.2 常用工具使用
Git 高效工作流:
# 配置 Git
git config --global user.name "Your Name"
git config --global user.email "your@email.com"
# 设置默认编辑器
git config --global core.editor "vim"
# 配置别名(提高效率)
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.last 'log -1 HEAD'
# 常用工作流
git fetch upstream
git rebase upstream/main
git push origin feature-branch --force-with-lease
Docker 最佳实践:
# 构建镜像时使用缓存
docker build -t sglang:dev --cache-from lmsysorg/sglang:latest .
# 清理无用镜像和容器
docker system prune -a
# 查看容器日志
docker logs -f <container_id>
# 进入运行中的容器
docker exec -it <container_id> bash
4. 进阶拓展方向
4.1 技术博客与专家观点
推荐博客:
- • Lil'Log (Lilian Weng): https://lilianweng.github.io/
- • 主题:LLM、Prompt Engineering、RLHF
- • Jay Alammar: https://jalammar.github.io/
- • 主题:Transformer 可视化讲解
- • Sebastian Raschka: https://sebastianraschka.com/blog/
- • 主题:深度学习、PyTorch
SGLang 团队成员:
• Lianmin Zheng: https://lmzheng.net/
• Ying Sheng: https://sites.google.com/view/yingsheng
• (关注他们的 Twitter/X 账号获取最新动态)
4.2 相关技术大会
推荐会议(视频回放):
• NeurIPS:Machine Learning 顶会
• ICML:International Conference on Machine Learning
• MLSys:Machine Learning Systems
• PyTorch Conference:PyTorch 官方会议
SGLang 相关的演讲:
• NeurIPS 2024: SGLang Poster Session
• PyTorch Conference 2024: Efficient LLM Serving
4.3 社区与论坛
官方社区:
- • GitHub Discussions: https://github.com/sgl-project/sglang/discussions
- • 适合:技术讨论、功能请求
- • Slack: https://slack.sglang.ai/
- • 适合:实时沟通、快速问答
- • Discord (社区维护): 搜索"SGLang Community"
- • 适合:非正式交流
相关社区:
- • Hugging Face Forums: https://discuss.huggingface.co/
- • 主题:Transformers、模型部署
- • PyTorch Forums: https://discuss.pytorch.org/
- • 主题:PyTorch 使用、深度学习
- • Reddit r/MachineLearning: https://www.reddit.com/r/MachineLearning/
- • 主题:ML 新闻、论文讨论
结语:你的 SGLang 学习之旅 🎓
恭喜你读到这里!🎉 如果你认真跟随这份指南学习,相信你已经:
✅ 理解了 SGLang 的架构设计
• 知道为什么这样设计,而不仅仅是它是什么样的
• 能够评估不同技术方案的权衡
✅ 掌握了核心技能
• Python 异步编程、PyTorch、CUDA 基础
• Transformer 架构、LLM 推理优化
✅ 获得了实践经验
• 能够运行和调试 SGLang
• 能够修改代码、添加功能
• 能够分析性能瓶颈
✅ 融入了社区
• 知道如何寻求帮助
• 知道如何贡献代码
• 知道如何持续学习
下一步建议 🚀
根据你的兴趣和职业规划,你可以选择不同的深入方向:
🔬 如果你对研究感兴趣:
• 阅读最新的 LLM 推理优化论文
• 尝试实现论文中的算法
• 参加学术会议,与研究者交流
💻 如果你对工程感兴趣:
• 深入学习 CUDA 编程,优化内核性能
• 学习分布式系统,优化通信效率
• 参与 SGLang 的核心功能开发
🏢 如果你对应用感兴趣:
• 学习如何在生产环境部署 SGLang
• 优化资源使用,降低成本
• 开发基于 SGLang 的应用
🌍 如果你对开源社区感兴趣:
• 持续贡献代码和文档
• 帮助新人解答问题
• 组织线下 Meetup
最后的话 💬
学习一个复杂的系统从来都不是一蹴而就的。就像我在开头说的,我是你的学习教练,这份指南是我为你精心设计的训练计划。但真正的成长,来自于你一行行代码的实践,一次次调试的尝试,一个个问题的解决。
记住:
• 不要害怕犯错:每个 bug 都是学习的机会
• 不要害怕提问:社区很友好,大家都是从新手过来的
• 不要害怕尝试:最好的学习方式就是动手实践
希望这份指南对你有所帮助!如果你有任何问题或建议,欢迎在 GitHub Discussions 或 Slack 上与我交流。
祝你学习愉快,成为 SGLang 社区的一员! 🌟
引用链接
[1]
Python 3.10 新特性:https://docs.python.org/3/whatsnew/3.10.html[2]
PyTorch Tutorials:https://pytorch.org/tutorials/[3]
CUDA C Programming Guide:https://docs.nvidia.com/cuda/cuda-c-programming-guide/[4]
FastAPI Documentation:https://fastapi.tiangolo.com/[5]
asyncio — Asynchronous I/O:https://docs.python.org/3/library/asyncio.html[6]
Attention Is All You Need:https://arxiv.org/abs/1706.03762[7]
The Illustrated Transformer:https://jalammar.github.io/illustrated-transformer/[8]
Efficient Memory Management for Large Language Model Serving with PagedAttention:https://arxiv.org/abs/2309.06180[9]
SGLang v0.2 Blog:https://lmsys.org/blog/2024-07-25-sglang-llama3/[10]
Megatron-LM: Training Multi-Billion Parameter Language Models:https://arxiv.org/abs/1909.08053[11]
Parallelism Guide:https://huggingface.co/docs/transformers/parallelism