<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>第八章 代码库导读 on Machine Learning 学习笔记</title><link>https://kingye.me/study-ml/docs/book/sglang-internals/part4-debugging-maintenance/codebase-walkthrough/</link><description>Recent content in 第八章 代码库导读 on Machine Learning 学习笔记</description><generator>Hugo</generator><language>en</language><atom:link href="https://kingye.me/study-ml/docs/book/sglang-internals/part4-debugging-maintenance/codebase-walkthrough/index.xml" rel="self" type="application/rss+xml"/><item><title>8.1 如何从入口开始读仓库</title><link>https://kingye.me/study-ml/docs/book/sglang-internals/part4-debugging-maintenance/codebase-walkthrough/how-to-start-reading-the-repo/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kingye.me/study-ml/docs/book/sglang-internals/part4-debugging-maintenance/codebase-walkthrough/how-to-start-reading-the-repo/</guid><description>&lt;h1 id="如何从入口开始读仓库"&gt;如何从入口开始读仓库&lt;a class="anchor" href="#%e5%a6%82%e4%bd%95%e4%bb%8e%e5%85%a5%e5%8f%a3%e5%bc%80%e5%a7%8b%e8%af%bb%e4%bb%93%e5%ba%93"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;这一节会把&amp;quot;第一次打开仓库应该先看哪里&amp;quot;这件事流程化，同时告诉你在每个文件里应该具体找什么。&lt;/p&gt;
&lt;h2 id="为什么仓库入口顺序很重要"&gt;为什么仓库入口顺序很重要&lt;a class="anchor" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e4%bb%93%e5%ba%93%e5%85%a5%e5%8f%a3%e9%a1%ba%e5%ba%8f%e5%be%88%e9%87%8d%e8%a6%81"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;如果你第一次进入 SGLang 仓库，最容易犯的错误是直接钻进 &lt;code&gt;python/sglang/srt&lt;/code&gt;。这样当然能看到大量核心实现，但你会很快失去&amp;quot;哪些入口是给用户的，哪些入口是给 runtime 的&amp;quot;这层方位感。&lt;/p&gt;
&lt;h2 id="第一站readmemd"&gt;第一站：&lt;code&gt;README.md&lt;/code&gt;&lt;a class="anchor" href="#%e7%ac%ac%e4%b8%80%e7%ab%99readmemd"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;看什么&lt;/strong&gt;：快速安装块（&lt;code&gt;pip install sglang&lt;/code&gt;）和两个最小示例——一个展示 language API，一个展示 OpenAI-compatible serving。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;你应该能答出来&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SGLang 的语言 API（&lt;code&gt;sgl.function&lt;/code&gt;、&lt;code&gt;sgl.gen()&lt;/code&gt;）和 serving API（&lt;code&gt;launch_server&lt;/code&gt; + HTTP 请求）是两条平行入口，还是一条路径的两种写法？（答案：平行，两条独立入口）&lt;/li&gt;
&lt;li&gt;一个最简服务是一个进程还是多个进程？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;读完 README，你对整个项目的外形应该有了基本感知。&lt;/p&gt;
&lt;h2 id="第二站pythonsglang__init__py"&gt;第二站：&lt;code&gt;python/sglang/__init__.py&lt;/code&gt;&lt;a class="anchor" href="#%e7%ac%ac%e4%ba%8c%e7%ab%99pythonsglang__init__py"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;命令&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 先看 __init__.py 暴露了什么&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat python/sglang/__init__.py | grep -v &lt;span style="color:#e6db74"&gt;&amp;#34;^#&amp;#34;&lt;/span&gt; | grep -v &lt;span style="color:#e6db74"&gt;&amp;#34;^&lt;/span&gt;$&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;看什么&lt;/strong&gt;：&lt;code&gt;__init__.py&lt;/code&gt; 里 &lt;code&gt;from ... import&lt;/code&gt; 的符号就是项目对外承诺的 public API。&lt;/p&gt;
&lt;p&gt;重点找这两类：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;语言层符号&lt;/strong&gt;：&lt;code&gt;function&lt;/code&gt;、&lt;code&gt;gen&lt;/code&gt;、&lt;code&gt;user&lt;/code&gt;、&lt;code&gt;assistant&lt;/code&gt;、&lt;code&gt;system&lt;/code&gt;、&lt;code&gt;image&lt;/code&gt; 等——这些是 language API 的构造块；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;runtime 层符号&lt;/strong&gt;：&lt;code&gt;Engine&lt;/code&gt;、&lt;code&gt;launch_server&lt;/code&gt;、&lt;code&gt;RuntimeEndpoint&lt;/code&gt; 等——这些是 serving API 的入口。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;看完之后你应该能画一条分界线：&lt;code&gt;lang/&lt;/code&gt; 下的是给 Python 程序调用的语言 API，&lt;code&gt;srt/&lt;/code&gt; 下的是 runtime 本体。&lt;/p&gt;</description></item><item><title>8.2 按问题定位源码</title><link>https://kingye.me/study-ml/docs/book/sglang-internals/part4-debugging-maintenance/codebase-walkthrough/how-to-locate-code-by-problem/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kingye.me/study-ml/docs/book/sglang-internals/part4-debugging-maintenance/codebase-walkthrough/how-to-locate-code-by-problem/</guid><description>&lt;h1 id="按问题定位源码"&gt;按问题定位源码&lt;a class="anchor" href="#%e6%8c%89%e9%97%ae%e9%a2%98%e5%ae%9a%e4%bd%8d%e6%ba%90%e7%a0%81"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;这一节从症状出发，告诉你如果问题发生在请求主线、batch 调度、cache 或输出侧，第一步该打开哪个文件、grep 什么符号。&lt;/p&gt;
&lt;h2 id="为什么按问题定位比按目录阅读更值钱"&gt;为什么&amp;quot;按问题定位&amp;quot;比&amp;quot;按目录阅读&amp;quot;更值钱&lt;a class="anchor" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e6%8c%89%e9%97%ae%e9%a2%98%e5%ae%9a%e4%bd%8d%e6%af%94%e6%8c%89%e7%9b%ae%e5%bd%95%e9%98%85%e8%af%bb%e6%9b%b4%e5%80%bc%e9%92%b1"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;知道仓库结构，和真正会用仓库排障，是两件不同的事。很多人在知道&amp;quot;目录有哪些&amp;quot;之后，面对真实问题时还是不知道第一步该打开哪个文件。&lt;/p&gt;
&lt;p&gt;这一节不再讲&amp;quot;目录长什么样&amp;quot;，而是讲&amp;quot;遇到具体症状，先从哪里下手&amp;quot;。&lt;/p&gt;
&lt;h2 id="症状-1请求进来了但没有响应"&gt;症状 1：请求进来了，但没有响应&lt;a class="anchor" href="#%e7%97%87%e7%8a%b6-1%e8%af%b7%e6%b1%82%e8%bf%9b%e6%9d%a5%e4%ba%86%e4%bd%86%e6%b2%a1%e6%9c%89%e5%93%8d%e5%ba%94"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;首先&lt;/strong&gt;确认请求有没有到达 TokenizerManager：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 在 server 日志里找 request id&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;grep &lt;span style="color:#e6db74"&gt;&amp;#34;rid=&amp;#34;&lt;/span&gt; server.log | tail -20
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 如果看不到 rid=xxx，说明请求没有通过 HTTP 层进入主链&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;如果没有 rid&lt;/strong&gt;，问题在 &lt;code&gt;entrypoints/&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 找 /v1/chat/completions 路由注册&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;grep -n &lt;span style="color:#e6db74"&gt;&amp;#34;chat/completions\|completions&amp;#34;&lt;/span&gt; python/sglang/srt/entrypoints/openai/serving_chat.py | head -10
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 找 /generate 路由&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;grep -n &lt;span style="color:#e6db74"&gt;&amp;#34;@router\|add_route\|route&amp;#34;&lt;/span&gt; python/sglang/srt/entrypoints/http_server.py | head -20&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;如果有 rid 但没有后续日志&lt;/strong&gt;，问题在 TokenizerManager 和 Scheduler 之间的 IPC：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 找 TokenizerManager 把请求发给 Scheduler 的位置&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;grep -n &lt;span style="color:#e6db74"&gt;&amp;#34;send_to_scheduler\|send.*generate&amp;#34;&lt;/span&gt; python/sglang/srt/managers/tokenizer_manager.py | head -20
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 找 Scheduler 接收请求的位置&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;grep -n &lt;span style="color:#e6db74"&gt;&amp;#34;recv_from_tokenizer\|handle_generate&amp;#34;&lt;/span&gt; python/sglang/srt/managers/scheduler.py | head -20&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="症状-2请求在-waiting-queue-里停太久"&gt;症状 2：请求在 waiting queue 里停太久&lt;a class="anchor" href="#%e7%97%87%e7%8a%b6-2%e8%af%b7%e6%b1%82%e5%9c%a8-waiting-queue-%e9%87%8c%e5%81%9c%e5%a4%aa%e4%b9%85"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;首先&lt;/strong&gt;通过 metrics 确认是哪种等待：&lt;/p&gt;</description></item><item><title>8.3 关键目录、关键对象与关键证据</title><link>https://kingye.me/study-ml/docs/book/sglang-internals/part4-debugging-maintenance/codebase-walkthrough/key-directories-objects-and-evidence/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kingye.me/study-ml/docs/book/sglang-internals/part4-debugging-maintenance/codebase-walkthrough/key-directories-objects-and-evidence/</guid><description>&lt;h1 id="关键目录关键对象与关键证据"&gt;关键目录、关键对象与关键证据&lt;a class="anchor" href="#%e5%85%b3%e9%94%ae%e7%9b%ae%e5%bd%95%e5%85%b3%e9%94%ae%e5%af%b9%e8%b1%a1%e4%b8%8e%e5%85%b3%e9%94%ae%e8%af%81%e6%8d%ae"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;这一节把全书反复出现的源码位置、关键对象和调试证据面压缩成一张实际可用的索引，方便在排障时快速回到正确入口。&lt;/p&gt;
&lt;h2 id="五类目录及其职责"&gt;五类目录及其职责&lt;a class="anchor" href="#%e4%ba%94%e7%b1%bb%e7%9b%ae%e5%bd%95%e5%8f%8a%e5%85%b6%e8%81%8c%e8%b4%a3"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;python/sglang/srt/
├── entrypoints/ # 门：HTTP 服务、OpenAI-compatible API、Engine 入口
│ ├── http_server.py 路由注册和请求分发
│ └── openai/
│ ├── protocol.py ChatCompletionRequest → SamplingParams 转换
│ ├── serving_chat.py /v1/chat/completions 处理
│ └── serving_completions.py /v1/completions 处理
│
├── managers/ # 编排：三管理器和进程边界
│ ├── tokenizer_manager.py API server 侧、状态持有、tokenize
│ ├── scheduler.py batch 组织、admission、KV 分配
│ └── detokenizer_manager.py token → text，流式回传
│
├── model_executor/ # 执行：forward pass 和模型
│ ├── model_runner.py 接收 ForwardBatch，执行前向，返回 logits
│ └── forward_batch_info.py ForwardBatch 定义（调度层→执行层的契约）
│
├── mem_cache/ # 缓存：KV 池和 RadixCache
│ ├── radix_cache.py 前缀复用的核心数据结构
│ ├── base_prefix_cache.py RadixCache 的接口定义
│ └── memory_pool.py ReqToTokenPool + TokenToKVPool 的物理分配
│
└── observability/ # 证据：metrics 上报和请求日志
 ├── prometheus_client.py Prometheus metrics 注册和上报
 └── request_logger.py 请求级别的时间戳和日志&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这五类目录对应的是整本书的五层架构：入口 → 编排 → 执行 → 缓存 → 证据。每当你不确定问题出在哪一层时，从这个结构出发能最快缩小范围。&lt;/p&gt;</description></item></channel></rss>