<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>6. 结构化生成与 API on Machine Learning 学习笔记</title><link>https://kingye.me/study-ml/docs/book/sglang/structured-generation-and-api/</link><description>Recent content in 6. 结构化生成与 API on Machine Learning 学习笔记</description><generator>Hugo</generator><language>en</language><atom:link href="https://kingye.me/study-ml/docs/book/sglang/structured-generation-and-api/index.xml" rel="self" type="application/rss+xml"/><item><title>6.1 结构化生成与约束解码</title><link>https://kingye.me/study-ml/docs/book/sglang/structured-generation-and-api/structured-generation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kingye.me/study-ml/docs/book/sglang/structured-generation-and-api/structured-generation/</guid><description>&lt;h1 id="结构化生成与约束解码"&gt;结构化生成与约束解码&lt;a class="anchor" href="#%e7%bb%93%e6%9e%84%e5%8c%96%e7%94%9f%e6%88%90%e4%b8%8e%e7%ba%a6%e6%9d%9f%e8%a7%a3%e7%a0%81"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="这章解决什么问题"&gt;这章解决什么问题&lt;a class="anchor" href="#%e8%bf%99%e7%ab%a0%e8%a7%a3%e5%86%b3%e4%bb%80%e4%b9%88%e9%97%ae%e9%a2%98"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;这一章解决的是“模型输出怎样被约束成目标格式”。如果不单独讲这一层，读者很容易把结构化生成误读成“API 层的附加能力”，而忽略它其实直接插在 generation path 里，和 sampling、logits 选择、tool parser 一起工作。&lt;/p&gt;
&lt;p&gt;从官方文档看，SGLang 把 structured outputs 定义得很直接：你可以为请求指定 &lt;code&gt;json_schema&lt;/code&gt;、&lt;code&gt;regex&lt;/code&gt; 或 &lt;code&gt;ebnf&lt;/code&gt;，并且这三种约束参数是互斥的，只能选一种。这不是外围包装，而是 generation 过程本身的一部分。&lt;/p&gt;
&lt;h2 id="为什么它属于执行链而不是纯-api-功能"&gt;为什么它属于执行链，而不是纯 API 功能&lt;a class="anchor" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e5%ae%83%e5%b1%9e%e4%ba%8e%e6%89%a7%e8%a1%8c%e9%93%be%e8%80%8c%e4%b8%8d%e6%98%af%e7%ba%af-api-%e5%8a%9f%e8%83%bd"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;python/sglang/srt/sampling/sampling_params.py&lt;/code&gt; 里，&lt;code&gt;SamplingParams&lt;/code&gt; 直接包含 &lt;code&gt;json_schema&lt;/code&gt;、&lt;code&gt;regex&lt;/code&gt;、&lt;code&gt;ebnf&lt;/code&gt; 和 &lt;code&gt;structural_tag&lt;/code&gt; 字段，并在 &lt;code&gt;verify(...)&lt;/code&gt; 里明确检查 “Only one of regex, json_schema, or ebnf can be set.”。这说明约束解码不是协议层的装饰，而是采样参数对象的一部分。&lt;/p&gt;
&lt;p&gt;这也是本章和上一章衔接的原因。执行模型章节已经解释了 sampling 参数怎样参与 token 选择；这里进一步说明，当这些参数变成 grammar constraint 时，输出就不再只是“按概率采样”，而是“在满足约束的前提下继续生成”。从系统设计上看，这比单纯在最终文本上做后处理要更稳，因为约束是在生成过程中被满足，而不是生成后再去修正。&lt;/p&gt;
&lt;p&gt;这里最适合补图，因为“约束到底插在哪里”很难靠一两段话稳稳说清。下面这张图回答的是：Frontend / HTTP 两侧传入的 &lt;code&gt;json_schema&lt;/code&gt;、&lt;code&gt;regex&lt;/code&gt;、tool parser 配置，最终怎样汇入 sampling / generation path。&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TB
 A[&amp;#34;Frontend gen(...)\nregex / json_schema&amp;#34;] --&amp;gt; C[&amp;#34;SamplingParams&amp;#34;]
 B[&amp;#34;HTTP / OpenAI-compatible request\nresponse_format / extra body&amp;#34;] --&amp;gt; C
 C --&amp;gt; D[&amp;#34;Grammar backend\nXGrammar / Outlines / llguidance&amp;#34;]
 C --&amp;gt; E[&amp;#34;tool parser / function calling parser&amp;#34;]
 D --&amp;gt; F[&amp;#34;generation path\nconstrained token selection&amp;#34;]
 E --&amp;gt; F
 F --&amp;gt; G[&amp;#34;structured output / tool call payload&amp;#34;]&lt;/pre&gt;&lt;p&gt;相对于纯文字，这张图多解释了“参数对象是汇合点”这一层。调用方可能从不同表面进入系统，但只要最后落到 &lt;code&gt;SamplingParams&lt;/code&gt; 和对应 parser / grammar backend，结构化生成就不是外围技巧，而是 runtime 能力。&lt;/p&gt;</description></item><item><title>6.2 API 表面与协议集成</title><link>https://kingye.me/study-ml/docs/book/sglang/structured-generation-and-api/api-and-protocol-integration/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kingye.me/study-ml/docs/book/sglang/structured-generation-and-api/api-and-protocol-integration/</guid><description>&lt;h1 id="api-表面与协议集成"&gt;API 表面与协议集成&lt;a class="anchor" href="#api-%e8%a1%a8%e9%9d%a2%e4%b8%8e%e5%8d%8f%e8%ae%ae%e9%9b%86%e6%88%90"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="这章解决什么问题"&gt;这章解决什么问题&lt;a class="anchor" href="#%e8%bf%99%e7%ab%a0%e8%a7%a3%e5%86%b3%e4%bb%80%e4%b9%88%e9%97%ae%e9%a2%98"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;这一章解决的是“调用方到底通过哪些表面进入 SGLang，以及这些表面怎样回到同一条 runtime path”。如果不单独讲这一层，容易把 &lt;code&gt;OpenAI-compatible API&lt;/code&gt;、native APIs、offline engine 和 frontend language 当成互相独立的产品，而不是同一套系统暴露出的不同入口。&lt;/p&gt;
&lt;p&gt;对工程读者来说，这个问题很实际。因为你在排查行为差异、设计接口迁移方案，或者把某条业务流从 OpenAI 托管迁到自托管时，真正关心的不是“这个接口像不像”，而是“它最后落到同一套 runtime 了吗”。&lt;/p&gt;
&lt;h2 id="为什么要把协议表面单独拎出来"&gt;为什么要把协议表面单独拎出来&lt;a class="anchor" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e8%a6%81%e6%8a%8a%e5%8d%8f%e8%ae%ae%e8%a1%a8%e9%9d%a2%e5%8d%95%e7%8b%ac%e6%8b%8e%e5%87%ba%e6%9d%a5"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;从官方 docs 可以看到，SGLang 明确把 OpenAI-compatible APIs、native APIs 和 offline engine 分开写。&lt;code&gt;docs/basic_usage/openai_api.rst&lt;/code&gt; 聚合的是 OpenAI-compatible usage；&lt;code&gt;docs/basic_usage/native_api.ipynb&lt;/code&gt; 则罗列 &lt;code&gt;/generate&lt;/code&gt;、&lt;code&gt;/server_info&lt;/code&gt;、&lt;code&gt;/flush_cache&lt;/code&gt;、&lt;code&gt;/tokenize&lt;/code&gt;、&lt;code&gt;/detokenize&lt;/code&gt; 等 native endpoints；&lt;code&gt;docs/basic_usage/offline_engine_api.ipynb&lt;/code&gt; 则直接讨论不经过 HTTP server 的 inference engine。&lt;/p&gt;
&lt;p&gt;这说明协议表面本身就是系统的一层设计，而不是文档编排巧合。SGLang 一方面希望让调用方能平滑迁移到 OpenAI-compatible 表面，另一方面又保留自己的 native surface 和 offline engine path，让内部能力不被单一协议形状限制住。&lt;/p&gt;
&lt;h2 id="openai-compatible-api-在这套系统里的位置"&gt;OpenAI-compatible API 在这套系统里的位置&lt;a class="anchor" href="#openai-compatible-api-%e5%9c%a8%e8%bf%99%e5%a5%97%e7%b3%bb%e7%bb%9f%e9%87%8c%e7%9a%84%e4%bd%8d%e7%bd%ae"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OpenAI-compatible API 的价值在于降低迁移成本。官方 &lt;code&gt;openai_api_completions.ipynb&lt;/code&gt; 和相关 basic usage 文档都在强调这一点：你可以用接近 OpenAI 的请求格式对接本地模型服务。对于多数应用接入者来说，这是最容易上手的一层。&lt;/p&gt;
&lt;p&gt;但从运行时角度看，重要的不是“长得像 OpenAI”，而是它最终怎样落进 &lt;code&gt;http_server.py&lt;/code&gt; 和 &lt;code&gt;TokenizerManager.generate_request(...)&lt;/code&gt; 这条路径。也正因为如此，OpenAI-compatible 层更适合作为“协议适配面”来理解，而不是当作独立 runtime。&lt;/p&gt;</description></item></channel></rss>