<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>模型部署 | 林子杨的个人网站</title><link>https://ziyanglin.netlify.app/zh/tags/%E6%A8%A1%E5%9E%8B%E9%83%A8%E7%BD%B2/</link><atom:link href="https://ziyanglin.netlify.app/zh/tags/%E6%A8%A1%E5%9E%8B%E9%83%A8%E7%BD%B2/index.xml" rel="self" type="application/rss+xml"/><description>模型部署</description><generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>zh-Hans</language><lastBuildDate>Fri, 27 Jun 2025 03:00:00 +0000</lastBuildDate><image><url>https://ziyanglin.netlify.app/img/icon-192.png</url><title>模型部署</title><link>https://ziyanglin.netlify.app/zh/tags/%E6%A8%A1%E5%9E%8B%E9%83%A8%E7%BD%B2/</link></image><item><title>大型语言模型超参数调优指南：从生成到部署的全面解析</title><link>https://ziyanglin.netlify.app/zh/post/llm-hyperparameters-documentation/</link><pubDate>Fri, 27 Jun 2025 03:00:00 +0000</pubDate><guid>https://ziyanglin.netlify.app/zh/post/llm-hyperparameters-documentation/</guid><description>&lt;h2 id="heading">引言&lt;/h2>
&lt;h2 id="span-stylefontsize-09emllm-vllm--openai--apisampling--servingspan">&lt;span style="font-size: 0.9em;">大型语言模型（LLM）的强大能力背后，是一系列复杂的超参数在&amp;quot;默默奉献&amp;rdquo;。无论是在本地部署一个像 vLLM 一样的推理服务，还是调用 OpenAI 的 API，精确地调整这些参数对于获得理想的性能、成本和输出质量至关重要。这份文档将&amp;quot;掰开了，揉碎了&amp;quot;地深入解析两大类关键超参数：&lt;strong>生成（Sampling）超参数&lt;/strong> 和 &lt;strong>部署（Serving）超参数&lt;/strong>，帮助你完全掌握它们的作用、取值、影响以及在不同场景下的最佳实践。&lt;/span>&lt;/h2>
&lt;h3 id="sampling">第一部分：生成（Sampling）超参数——掌控模型的创造力与确定性&lt;/h3>
&lt;p>生成超参数直接控制模型在生成下一个 token 时的行为。它们主要围绕着一个核心问题：如何在模型给出的成千上万个可能的下一个词的概率分布中进行选择。&lt;/p>
&lt;h3 id="1-temperature-">1. &lt;code>temperature&lt;/code> (温度)&lt;/h3>
&lt;p>&lt;strong>一句话解释：&lt;/strong> 控制生成文本的随机性。&lt;code>temperature&lt;/code> 越高，随机性越强，回答越具创造性和多样性；&lt;code>temperature&lt;/code> 越低，随机性越弱，回答越趋于确定性和保守。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>底层原理：&lt;/strong>
在生成下一个 token 时，模型会为词汇表中的所有词计算一个 &lt;code>logits&lt;/code>（原始的、未归一化的预测分数）。通常，我们会使用 &lt;code>Softmax&lt;/code> 函数将这些 &lt;code>logits&lt;/code> 转换成一个概率分布。&lt;code>temperature&lt;/code> 参数在 &lt;code>Softmax&lt;/code> 计算之前被引入，它会&amp;quot;平滑&amp;quot;或&amp;quot;锐化&amp;quot;这个概率分布。&lt;/p>
&lt;p>标准的 Softmax 公式是： &lt;code>P(i) = exp(logit_i) / Σ_j(exp(logit_j))&lt;/code>&lt;/p>
&lt;p>引入 &lt;code>temperature&lt;/code> (T) 后的公式是：&lt;code>P(i) = exp(logit_i / T) / Σ_j(exp(logit_j / T))&lt;/code>&lt;/p>
&lt;ul>
&lt;li>当 &lt;code>T&lt;/code> -&amp;gt; 0 时，&lt;code>logit_i / T&lt;/code> 的差异会急剧拉大。拥有最高 logit 的那个 token 的概率会无限接近 1，而其他所有 token 的概率会无限接近 0。这使得模型几乎总是选择最有可能的那个词，表现得非常确定和&amp;quot;贪心&amp;rdquo;。&lt;/li>
&lt;li>当 &lt;code>T&lt;/code> = 1 时，公式回归标准 Softmax，模型的行为就是其&amp;quot;原始&amp;quot;状态。&lt;/li>
&lt;li>当 &lt;code>T&lt;/code> &amp;gt; 1 时，&lt;code>logit_i / T&lt;/code> 的差异会被缩小。原本概率较低的 token 的概率会被提升，整个概率分布变得更加&amp;quot;平坦&amp;rdquo;。这增加了模型选择到不那么常见的词的几率，从而引入了更多的随机性和创造性。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>取值范围与建议：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>范围:&lt;/strong> &lt;code>[0.0, 2.0]&lt;/code> (理论上可以更高, 但 OpenAI API 通常限制在 2.0)。&lt;/li>
&lt;li>&lt;strong>&lt;code>temperature&lt;/code> = 0.0:&lt;/strong> 适用于需要确定性、可复现和高准确度输出的场景。例如：代码生成、事实问答、文本分类、数据提取。每次输入相同，输出也几乎完全相同（除非模型本身有更新）。&lt;/li>
&lt;li>&lt;strong>低 &lt;code>temperature&lt;/code> (例如 &lt;code>0.1&lt;/code> - &lt;code>0.4&lt;/code>):&lt;/strong> 适用于需要严谨、忠于原文的半创作性任务。例如：文章摘要、翻译、客服机器人。输出会略有变化，但大体上忠实于核心内容。&lt;/li>
&lt;li>&lt;strong>中等 &lt;code>temperature&lt;/code> (例如 &lt;code>0.5&lt;/code> - &lt;code>0.8&lt;/code>):&lt;/strong> 创造性与一致性的良好平衡点，是大多数应用场景的默认和推荐值。例如：撰写邮件、市场文案、头脑风暴。&lt;/li>
&lt;li>&lt;strong>高 &lt;code>temperature&lt;/code> (例如 &lt;code>0.9&lt;/code> - &lt;code>1.5&lt;/code>):&lt;/strong> 适用于高度创造性的任务。例如：写诗、创作故事、生成对话脚本。输出会非常多样，甚至可能出人意料，但有时也可能产生无意义或不连贯的内容。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>注意事项:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;code>temperature&lt;/code> 和 &lt;code>top_p&lt;/code> 通常不建议同时修改，最好只调整其中一个。OpenAI 的文档也明确指出，通常建议只修改其中之一。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="2-topp-">2. &lt;code>top_p&lt;/code> (核心采样)&lt;/h3>
&lt;p>&lt;strong>一句话解释：&lt;/strong> 通过保留一个累积概率阈值（&lt;code>p&lt;/code>）内的最高概率词汇，来动态地决定采样池的大小，从而控制生成的多样性。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>底层原理：&lt;/strong>
&lt;code>top_p&lt;/code> 是一种比 &lt;code>temperature&lt;/code> 更智能的采样策略，也称为 &lt;strong>核心采样 (Nucleus Sampling)&lt;/strong>。它不是调整所有 token 的概率，而是直接划定一个&amp;quot;核心&amp;quot;候选集。&lt;/p>
&lt;p>具体步骤如下：&lt;/p>
&lt;ol>
&lt;li>模型计算出所有候选 token 的概率分布。&lt;/li>
&lt;li>将所有 token 按概率从高到低排序。&lt;/li>
&lt;li>从概率最高的 token 开始，依次累加它们的概率，直到这个累积概率总和超过设定的 &lt;code>top_p&lt;/code> 阈值。&lt;/li>
&lt;li>所有被累加过的这些 token 构成了采样的&amp;quot;核心集合&amp;rdquo;（nucleus）。&lt;/li>
&lt;li>模型将只从这个核心集合中进行采样（通常会重新归一化它们的概率），所有其他 token 将被忽略。&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>举个例子：&lt;/strong> 假设 &lt;code>top_p&lt;/code> = &lt;code>0.9&lt;/code>。&lt;/p>
&lt;ul>
&lt;li>如果概率最高的 token &amp;ldquo;the&amp;rdquo; 的概率是 &lt;code>0.95&lt;/code>，那么核心集合里就只有 &amp;ldquo;the&amp;rdquo; 这一个词，模型会 100% 选择它。&lt;/li>
&lt;li>如果 &amp;ldquo;the&amp;rdquo; 的概率是 &lt;code>0.5&lt;/code>，&amp;ldquo;a&amp;rdquo; 的概率是 &lt;code>0.3&lt;/code>，&amp;ldquo;an&amp;rdquo; 的概率是 &lt;code>0.1&lt;/code>，那么这三个词的累积概率是 &lt;code>0.9&lt;/code>。核心集合就包含 {&amp;ldquo;the&amp;rdquo;, &amp;ldquo;a&amp;rdquo;, &amp;ldquo;an&amp;rdquo;}。模型将从这三个词中按其（重新归一化的）概率进行采样。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>取值范围与建议：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>范围:&lt;/strong> &lt;code>(0.0, 1.0]&lt;/code>。&lt;/li>
&lt;li>&lt;strong>&lt;code>top_p&lt;/code> = 1.0:&lt;/strong> 意味着模型会考虑所有 token，不进行任何截断（等同于没有 &lt;code>top_p&lt;/code>）。&lt;/li>
&lt;li>&lt;strong>高 &lt;code>top_p&lt;/code> (例如 &lt;code>0.9&lt;/code> - &lt;code>1.0&lt;/code>):&lt;/strong> 允许更多样化的选择，适用于创造性任务，效果类似于较高的 &lt;code>temperature&lt;/code>。&lt;/li>
&lt;li>&lt;strong>低 &lt;code>top_p&lt;/code> (例如 &lt;code>0.1&lt;/code> - &lt;code>0.3&lt;/code>):&lt;/strong> 极大地限制了模型的选择范围，使其输出非常确定和保守，效果类似于极低的 &lt;code>temperature&lt;/code>。&lt;/li>
&lt;li>&lt;strong>通用建议值:&lt;/strong> &lt;code>0.9&lt;/code> 是一个非常常见的默认值，因为它在保持高质量的同时，也允许一定的多样性。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>&lt;code>top_p&lt;/code> vs &lt;code>temperature&lt;/code>:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;code>top_p&lt;/code> 更加动态和自适应。在模型对下一步非常确信时（概率分布很尖锐），&lt;code>top_p&lt;/code> 会自动缩小候选集，保证质量。在模型不那么确信时（概率分布很平坦），它会扩大候选集，增加多样性。&lt;/li>
&lt;li>&lt;code>temperature&lt;/code> 则是&amp;quot;一视同仁&amp;quot;地调整整个分布，不管分布本身是尖锐还是平坦。&lt;/li>
&lt;li>因此，&lt;code>top_p&lt;/code> 通常被认为是比 &lt;code>temperature&lt;/code> 更安全、更鲁棒的控制多样性的方法。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="3-topk">3. &lt;code>top_k&lt;/code>&lt;/h3>
&lt;p>&lt;strong>一句话解释：&lt;/strong> 简单粗暴地只从概率最高的 &lt;code>k&lt;/code> 个 token 中进行采样。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>底层原理：&lt;/strong> 这是最简单的截断采样方法。直接选择概率最高的 &lt;code>k&lt;/code> 个 token，组成候选集，然后从这 &lt;code>k&lt;/code> 个 token 中进行采样。所有其他 token 都被忽略。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>取值范围与建议：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>范围:&lt;/strong> 整数，例如 &lt;code>1&lt;/code>, &lt;code>10&lt;/code>, &lt;code>50&lt;/code>。&lt;/li>
&lt;li>&lt;strong>&lt;code>top_k&lt;/code> = 1:&lt;/strong> 等同于贪心搜索，总是选择最有可能的词。&lt;/li>
&lt;li>&lt;strong>建议:&lt;/strong> &lt;code>top_k&lt;/code> 通常不作为首选的采样策略，因为它太&amp;quot;死板&amp;rdquo;。在某些概率分布非常平坦的情况下，它可能会意外地排除掉很多合理的词；而在分布非常尖锐时，它又可能包含进很多概率极低的无用词。&lt;code>top_p&lt;/code> 通常是更好的选择。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="4-repetitionpenalty-">4. &lt;code>repetition_penalty&lt;/code> (重复惩罚)&lt;/h3>
&lt;p>&lt;strong>一句话解释：&lt;/strong> 对在上下文中已经出现过的 token 施加惩罚，以降低它们再次被选中的概率，从而减少重复内容。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>底层原理：&lt;/strong> 在计算 &lt;code>logits&lt;/code> 后，但在 &lt;code>Softmax&lt;/code> 之前，该参数会遍历所有候选 token。如果一个 token 已经在之前的上下文中出现过，它的 &lt;code>logit&lt;/code> 值就会被降低（通常是除以 &lt;code>repetition_penalty&lt;/code> 的值）。&lt;/p>
&lt;p>&lt;code>new_logit = logit / penalty&lt;/code> (如果 token 已出现)
&lt;code>new_logit = logit&lt;/code> (如果 token 未出现)&lt;/p>
&lt;p>这样，已经出现过的词的最终概率就会下降。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>取值范围与建议：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>范围:&lt;/strong> &lt;code>1.0&lt;/code> 到 &lt;code>2.0&lt;/code> 之间比较常见。&lt;/li>
&lt;li>&lt;strong>&lt;code>1.0&lt;/code>:&lt;/strong> 不施加任何惩罚 (默认值)。&lt;/li>
&lt;li>&lt;strong>&lt;code>1.1&lt;/code> - &lt;code>1.3&lt;/code>:&lt;/strong> 是一个比较安全的范围，可以有效减少不必要的重复，而不过度影响正常的语言表达（比如必要的冠词 &amp;ldquo;the&amp;rdquo;）。&lt;/li>
&lt;li>&lt;strong>过高的值:&lt;/strong> 可能会导致模型刻意回避常用词，产生不自然甚至奇怪的句子。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="5-frequencypenalty--presencepenalty-">5. &lt;code>frequency_penalty&lt;/code> &amp;amp; &lt;code>presence_penalty&lt;/code> (频率与存在感惩罚)&lt;/h3>
&lt;p>这两个参数是 &lt;code>repetition_penalty&lt;/code> 的更精细化版本。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>&lt;code>presence_penalty&lt;/code> (存在感惩罚):&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>作用:&lt;/strong> 对所有在上下文中 &lt;strong>至少出现过一次&lt;/strong> 的 token 施加一个固定的惩罚。它不关心这个 token 出现了多少次，只要出现过，就惩罚。&lt;/li>
&lt;li>&lt;strong>底层原理:&lt;/strong> &lt;code>new_logit = logit - presence_penalty&lt;/code> (如果 token 至少出现过一次)。&lt;/li>
&lt;li>&lt;strong>场景:&lt;/strong> 当你想鼓励模型引入全新的概念和词汇，而不是反复讨论已经提到过的话题时，这个参数很有用。&lt;/li>
&lt;li>&lt;strong>范围:&lt;/strong> &lt;code>0.0&lt;/code> 到 &lt;code>2.0&lt;/code>。正值会惩罚新 token，负值会鼓励。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>&lt;code>frequency_penalty&lt;/code> (频率惩罚):&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>作用:&lt;/strong> 惩罚的大小与 token 在上下文中出现的 &lt;strong>频率&lt;/strong> 成正比。一个词出现的次数越多，它受到的惩罚就越重。&lt;/li>
&lt;li>&lt;strong>底层原理:&lt;/strong> &lt;code>new_logit = logit - count(token) * frequency_penalty&lt;/code>。&lt;/li>
&lt;li>&lt;strong>场景:&lt;/strong> 当你发现模型倾向于反复使用某些特定的高频词（即使它们是必要的），导致语言单调时，这个参数可以有效降低这些词的概率。&lt;/li>
&lt;li>&lt;strong>范围:&lt;/strong> &lt;code>0.0&lt;/code> 到 &lt;code>2.0&lt;/code>。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>总结:&lt;/strong> &lt;code>presence_penalty&lt;/code> 解决&amp;quot;是否出现过&amp;quot;的问题，&lt;code>frequency_penalty&lt;/code> 解决&amp;quot;出现了多少次&amp;quot;的问题。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="6-seed-">6. &lt;code>seed&lt;/code> (随机种子)&lt;/h3>
&lt;p>&lt;strong>一句话解释：&lt;/strong> 通过提供一个固定的 &lt;code>seed&lt;/code>，可以使得在其他参数（如 &lt;code>temperature&lt;/code>）相同的情况下，模型的输出是可复现的。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>作用:&lt;/strong> 在机器学习中，很多操作看似随机，实则是&amp;quot;伪随机&amp;rdquo;，它们由一个初始的&amp;quot;种子&amp;quot;决定。设置相同的种子，就能得到相同的随机数序列。在 LLM 中，这意味着采样过程将是完全确定的。&lt;/li>
&lt;li>&lt;strong>场景:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>调试与测试:&lt;/strong> 当你需要验证某个改动是否影响了输出时，固定 &lt;code>seed&lt;/code> 可以排除随机性干扰。&lt;/li>
&lt;li>&lt;strong>可复现的研究:&lt;/strong> 在学术研究中，可复现性至关重要。&lt;/li>
&lt;li>&lt;strong>生成一致性内容:&lt;/strong> 当你需要模型对同一输入始终产生相同风格的输出时。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>注意:&lt;/strong> 要想完全复现，&lt;strong>所有&lt;/strong> 生成参数（&lt;code>prompt&lt;/code>, &lt;code>model&lt;/code>, &lt;code>temperature&lt;/code>, &lt;code>top_p&lt;/code> 等）都必须完全相同。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="serving">第二部分：部署（Serving）超参数——优化服务的性能与容量&lt;/h3>
&lt;p>部署超参数决定了 LLM 推理服务如何管理 GPU 资源、处理并发请求以及优化整体吞吐量和延迟。这些参数在 vLLM 这样的高性能推理引擎中尤为重要。&lt;/p>
&lt;h3 id="1-gpumemoryutilization">1. &lt;code>gpu_memory_utilization&lt;/code>&lt;/h3>
&lt;p>&lt;strong>一句话解释：&lt;/strong> 控制 vLLM 可以使用的 GPU 显存的比例，核心用途是为 &lt;strong>KV Cache&lt;/strong> 预留空间。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>底层原理 (PagedAttention):&lt;/strong>
vLLM 的核心是 PagedAttention 机制。传统的注意力机制会为每个请求预分配一个连续的、最大长度的显存空间来存储 Key-Value (KV) Cache。这导致了严重的内存浪费，因为大部分请求的长度都远小于最大长度。&lt;/p>
&lt;p>PagedAttention 将 KV Cache 像操作系统的虚拟内存一样进行管理：&lt;/p>
&lt;ol>
&lt;li>它将每个序列的 KV Cache 拆分成很多小的、固定大小的&amp;quot;块&amp;rdquo;（Block）。&lt;/li>
&lt;li>这些块可以非连续地存储在 GPU 显存中。&lt;/li>
&lt;li>一个中央的&amp;quot;块管理器&amp;rdquo;（Block Manager）负责分配和释放这些块。&lt;/li>
&lt;/ol>
&lt;p>&lt;code>gpu_memory_utilization&lt;/code> 正是告诉 vLLM：&amp;ldquo;你可以用掉总显存的这么多比例来自由管理（主要是存放模型权重和 KV Cache 的物理块）&amp;quot;。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>取值范围与影响：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>范围:&lt;/strong> &lt;code>(0.0, 1.0]&lt;/code>。&lt;/li>
&lt;li>&lt;strong>默认值:&lt;/strong> &lt;code>0.9&lt;/code> (即 90%)。&lt;/li>
&lt;li>&lt;strong>值越高 (例如 &lt;code>0.95&lt;/code>):&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>优点:&lt;/strong> vLLM 有更多的显存用于 KV Cache，可以支持更长的上下文、更大的批处理大小（batch size），从而提高吞吐量。&lt;/li>
&lt;li>&lt;strong>风险:&lt;/strong> 如果设置得太高，可能会没有足够的备用显存留给 CUDA 内核、驱动或其他系统进程，容易导致 &lt;strong>OOM (Out of Memory)&lt;/strong> 错误。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>值越低 (例如 &lt;code>0.8&lt;/code>):&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>优点:&lt;/strong> 更安全，不易 OOM，为系统和其他应用保留了更多显存。&lt;/li>
&lt;li>&lt;strong>缺点:&lt;/strong> KV Cache 的可用空间变小，可能导致 vLLM 无法处理高并发或长序列请求，性能下降。当 KV Cache 不足时，vLLM 会触发 &lt;strong>抢占 (Preemption)&lt;/strong>，将一些正在运行的序列换出，等待有足够空间后再换入，这会严重影响延迟。vLLM 的警告日志 &lt;code>&amp;quot;there is not enough KV cache space. This can affect the end-to-end performance.&amp;quot;&lt;/code> 就是在提醒你这一点。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>建议:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>从默认值 &lt;code>0.9&lt;/code> 开始。&lt;/li>
&lt;li>如果遇到 OOM，适当调低此值。&lt;/li>
&lt;li>如果遇到大量抢占警告，且确认没有其他进程占用大量显存，可以适当调高此值。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="2-maxnumseqs">2. &lt;code>max_num_seqs&lt;/code>&lt;/h3>
&lt;p>&lt;strong>一句话解释：&lt;/strong> 限制 vLLM 调度器在 &lt;strong>一个迭代（或一个批处理）中&lt;/strong> 可以处理的最大序列（请求）数量。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>底层原理:&lt;/strong>
vLLM 的调度器会在每个处理周期，从等待队列中选择一批请求来共同执行。这个参数直接限制了这个&amp;quot;批&amp;quot;的大小。它与 &lt;code>max_num_batched_tokens&lt;/code>（限制一个批次中所有序列的总 token 数）共同决定了批处理的规模。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>取值范围与影响:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>范围:&lt;/strong> 正整数，例如 &lt;code>16&lt;/code>, &lt;code>64&lt;/code>, &lt;code>256&lt;/code>。&lt;/li>
&lt;li>&lt;strong>值越高:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>优点:&lt;/strong> 允许更高的并发度，可能提高 GPU 的利用率和整体吞吐量。&lt;/li>
&lt;li>&lt;strong>缺点:&lt;/strong> 需要更多的中间内存（例如，存储 &lt;code>logits&lt;/code> 和采样状态），并可能增加单个批处理的延迟。如果设置得过高，即使 KV Cache 还有空间，也可能因为其他临时内存不足而 OOM。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>值越低:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>优点:&lt;/strong> 对内存更友好，单个批次延迟可能更低。&lt;/li>
&lt;li>&lt;strong>缺点:&lt;/strong> 限制了并发能力，可能导致 GPU 利用率不足，吞吐量下降。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>建议:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>这个值需要根据你的 GPU 显存大小、模型大小和预期的并发负载来调整。&lt;/li>
&lt;li>对于高并发场景，可以尝试逐步增加此值，并监控 GPU 利用率和内存使用情况。&lt;/li>
&lt;li>对于交互式、低延迟要求的场景，可以适当调低此值。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="3-maxmodellen">3. &lt;code>max_model_len&lt;/code>&lt;/h3>
&lt;p>&lt;strong>一句话解释：&lt;/strong> 设定模型能够处理的 &lt;strong>最大上下文长度&lt;/strong>（包括 prompt 和生成的 token）。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>底层原理:&lt;/strong>
这个参数直接决定了 vLLM 需要为 KV Cache 预留多大的逻辑空间。例如，如果 &lt;code>max_model_len&lt;/code> = &lt;code>4096&lt;/code>，vLLM 就必须确保其内存管理机制能够支持每个序列最多存储 &lt;code>4096&lt;/code> 个 token 的 KV 对。
这会影响 vLLM 启动时的内存规划，比如 Position Embedding 的大小。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>取值范围与影响:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>范围:&lt;/strong> 正整数，不能超过模型原始训练时的最大长度。&lt;/li>
&lt;li>&lt;strong>值越高:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>优点:&lt;/strong> 可以处理更长的文档、更复杂的上下文。&lt;/li>
&lt;li>&lt;strong>缺点:&lt;/strong> &lt;strong>显著增加&lt;/strong> 内存消耗。每个 token 都需要存储 KV Cache，长度翻倍，内存占用也大致翻倍。即使当前请求很短，vLLM 也需要为潜在的长请求做好准备，这会占用更多的 KV Cache 块。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>值越低:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>优点:&lt;/strong> &lt;strong>显著节省&lt;/strong> 显存。如果你知道你的应用场景永远不会超过 1024 个 token，那么将此值设为 1024 会比默认的 4096 或 8192 释放出大量的 KV Cache 空间，从而支持更高的并发。&lt;/li>
&lt;li>&lt;strong>缺点:&lt;/strong> 任何超过此长度的请求都会被拒绝或截断。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>建议:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>按需设置！&lt;/strong> 这是优化 vLLM 内存使用的最有效参数之一。根据你的实际应用场景，将此值设置为一个合理的、略带余量的最大值。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="4-tensorparallelsize---pipelineparallelsize-">4. &lt;code>tensor_parallel_size&lt;/code> (张量并行) &amp;amp; &lt;code>pipeline_parallel_size&lt;/code> (流水线并行)&lt;/h3>
&lt;p>这两个参数用于在多个 GPU 或多个节点上部署超大模型。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>&lt;code>tensor_parallel_size&lt;/code>:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>作用:&lt;/strong> 将模型的 &lt;strong>每一层&lt;/strong>（比如一个大的权重矩阵）都切分成 &lt;code>N&lt;/code> 份（&lt;code>N&lt;/code> = &lt;code>tensor_parallel_size&lt;/code>），分别放到 &lt;code>N&lt;/code> 个 GPU 上。在计算时，每个 GPU 只处理它自己那一部分的数据，然后通过高速互联（如 NVLink）交换必要的结果（All-Reduce 操作），最后合并得到完整输出。&lt;/li>
&lt;li>&lt;strong>场景:&lt;/strong> 当单个模型的体积超过单张 GPU 的显存时使用。例如，一个 70B 的模型无法放入一张 40GB 的 A100，但可以设置 &lt;code>tensor_parallel_size=2&lt;/code> 部署在两张 A100 上。&lt;/li>
&lt;li>&lt;strong>影响:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>优点:&lt;/strong> 实现了模型并行，解决了单卡存不下的问题。&lt;/li>
&lt;li>&lt;strong>缺点:&lt;/strong> 引入了大量的跨 GPU 通信开销，可能会影响延迟。需要 GPU 之间有高速互联。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>&lt;code>pipeline_parallel_size&lt;/code>:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>作用:&lt;/strong> 将模型的 &lt;strong>不同层&lt;/strong> 分配到不同的 GPU 或节点上。例如，将 1-10 层放在 GPU 1，11-20 层放在 GPU 2，以此类推。数据像流水线一样流过这些 GPU。&lt;/li>
&lt;li>&lt;strong>场景:&lt;/strong> 当模型非常非常大，需要跨多个节点（机器）部署时。&lt;/li>
&lt;li>&lt;strong>影响:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>优点:&lt;/strong> 可以将模型扩展到任意数量的 GPU/节点。&lt;/li>
&lt;li>&lt;strong>缺点:&lt;/strong> 会产生&amp;quot;流水线气泡&amp;rdquo;（pipeline bubble）的额外开销，即在流水线的开始和结束阶段，部分 GPU 会处于空闲等待状态，降低了利用率。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>组合使用:&lt;/strong>
vLLM 支持同时使用这两种并行策略，以在大型集群上高效部署巨型模型。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="heading1">总结与最佳实践&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th align="left">场景&lt;/th>
&lt;th align="left">&lt;code>temperature&lt;/code>&lt;/th>
&lt;th align="left">&lt;code>top_p&lt;/code>&lt;/th>
&lt;th align="left">&lt;code>repetition_penalty&lt;/code>&lt;/th>
&lt;th align="left">&lt;code>gpu_memory_utilization&lt;/code>&lt;/th>
&lt;th align="left">&lt;code>max_num_seqs&lt;/code>&lt;/th>
&lt;th align="left">&lt;code>max_model_len&lt;/code>&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td align="left">&lt;strong>代码生成/事实问答&lt;/strong>&lt;/td>
&lt;td align="left">&lt;code>0.0&lt;/code> - &lt;code>0.2&lt;/code>&lt;/td>
&lt;td align="left">(不建议修改)&lt;/td>
&lt;td align="left">&lt;code>1.0&lt;/code>&lt;/td>
&lt;td align="left">&lt;code>0.9&lt;/code> (默认)&lt;/td>
&lt;td align="left">根据并发调整&lt;/td>
&lt;td align="left">按需设置&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>文章摘要/翻译&lt;/strong>&lt;/td>
&lt;td align="left">&lt;code>0.2&lt;/code> - &lt;code>0.5&lt;/code>&lt;/td>
&lt;td align="left">(不建议修改)&lt;/td>
&lt;td align="left">&lt;code>1.1&lt;/code>&lt;/td>
&lt;td align="left">&lt;code>0.9&lt;/code>&lt;/td>
&lt;td align="left">根据并发调整&lt;/td>
&lt;td align="left">设为文档最大可能长度&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>通用聊天/文案写作&lt;/strong>&lt;/td>
&lt;td align="left">&lt;code>0.7&lt;/code> (默认)&lt;/td>
&lt;td align="left">&lt;code>0.9&lt;/code> (推荐)&lt;/td>
&lt;td align="left">&lt;code>1.1&lt;/code> - &lt;code>1.2&lt;/code>&lt;/td>
&lt;td align="left">&lt;code>0.9&lt;/code>&lt;/td>
&lt;td align="left">根据并发调整&lt;/td>
&lt;td align="left">按需设置，例如&lt;code>4096&lt;/code>|&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>创意写作/头脑风暴&lt;/strong>&lt;/td>
&lt;td align="left">&lt;code>0.8&lt;/code> - &lt;code>1.2&lt;/code>&lt;/td>
&lt;td align="left">&lt;code>0.95&lt;/code>&lt;/td>
&lt;td align="left">&lt;code>1.0&lt;/code>&lt;/td>
&lt;td align="left">&lt;code>0.9&lt;/code>&lt;/td>
&lt;td align="left">根据并发调整&lt;/td>
&lt;td align="left">按需设置&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>高并发吞吐量优化&lt;/strong>&lt;/td>
&lt;td align="left">(根据任务)&lt;/td>
&lt;td align="left">(根据任务)&lt;/td>
&lt;td align="left">(根据任务)&lt;/td>
&lt;td align="left">尝试 &lt;code>0.9&lt;/code> - &lt;code>0.95&lt;/code>&lt;/td>
&lt;td align="left">逐步调高&lt;/td>
&lt;td align="left">设为满足业务的&lt;strong>最小值&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>低延迟交互优化&lt;/strong>&lt;/td>
&lt;td align="left">(根据任务)&lt;/td>
&lt;td align="left">(根据任务)&lt;/td>
&lt;td align="left">(根据任务)&lt;/td>
&lt;td align="left">&lt;code>0.9&lt;/code> (默认)&lt;/td>
&lt;td align="left">设为较低值 (如&lt;code>16-64&lt;/code>)&lt;/td>
&lt;td align="left">按需设置&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>内存极度受限&lt;/strong>&lt;/td>
&lt;td align="left">(根据任务)&lt;/td>
&lt;td align="left">(根据任务)&lt;/td>
&lt;td align="left">(根据任务)&lt;/td>
&lt;td align="left">调低至 &lt;code>0.8&lt;/code>&lt;/td>
&lt;td align="left">设为较低值&lt;/td>
&lt;td align="left">设为满足业务的&lt;strong>最小值&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>最终建议：&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>&lt;strong>从生成参数开始调优：&lt;/strong> 首先通过调整 &lt;code>temperature&lt;/code> 或 &lt;code>top_p&lt;/code> 获得满意的输出质量。&lt;/li>
&lt;li>&lt;strong>按需设置部署参数：&lt;/strong> 在部署时，首先根据你的应用场景，将 &lt;code>max_model_len&lt;/code> 设置为一个合理的最小值。&lt;/li>
&lt;li>&lt;strong>监控并迭代：&lt;/strong> 使用默认的 &lt;code>gpu_memory_utilization=0.9&lt;/code> 和一个适中的 &lt;code>max_num_seqs&lt;/code> 开始。通过监控工具（如 &lt;code>nvidia-smi&lt;/code> 和 vLLM 的日志）观察显存使用率和抢占情况，然后逐步迭代调整这些值，以在你的特定硬件和负载下找到最佳的平衡点。&lt;/li>
&lt;/ol></description></item><item><title>vLLM技术详解：高性能LLM推理引擎</title><link>https://ziyanglin.netlify.app/zh/post/vllm-documentation/</link><pubDate>Thu, 26 Jun 2025 01:05:00 +0000</pubDate><guid>https://ziyanglin.netlify.app/zh/post/vllm-documentation/</guid><description>&lt;h2 id="1-vllm-">1. vLLM 简介&lt;/h2>
&lt;p>vLLM 是一个为大型语言模型（LLM）设计的开源推理和服务引擎，以其高吞吐量和内存效率而闻名。在 LLM 服务领域，vLLM 解决了一个核心痛点：传统推理系统在处理 Transformer 模型中注意力机制的键值缓存（KV Cache）时效率低下，导致大量内存被浪费，推理速度受限。&lt;/p>
&lt;p>LLM 推理过程中的内存瓶颈主要源于 KV Cache。这个缓存存储了序列中每个先前 token 的注意力键（Key）和值（Value），以加速后续 token 的生成。然而，KV Cache 的大小是动态变化的，且难以预测，这给内存管理带来了巨大挑战。传统系统（如 HuggingFace Transformers）通常会预先分配一块连续的大内存空间来存储 KV Cache，但这会导致严重的内存碎片化和浪费。&lt;/p>
&lt;p>vLLM 通过引入其核心创新 &lt;strong>PagedAttention&lt;/strong> 机制，从根本上解决了这个问题。&lt;/p>
&lt;h2 id="2-">2. 核心特性与优势&lt;/h2>
&lt;p>vLLM 之所以能在众多 LLM 推理框架中脱颖而出，得益于其以下几个关键特性：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>极高的吞吐量&lt;/strong>：通过 PagedAttention 和持续的批处理（Continuous Batching），vLLM 能够显著提升 GPU 的利用率，其吞吐量比 HuggingFace Transformers 高出数倍，也优于其他主流推理库。&lt;/li>
&lt;li>&lt;strong>高效的内存管理&lt;/strong>：PagedAttention 机制将 KV Cache 划分为非连续的内存块，极大地减少了内存的内部和外部碎片。根据官方数据，它可以节省高达 55% 的内存，这意味着您可以用相同的硬件加载更大的模型或服务更多的并发请求。&lt;/li>
&lt;li>&lt;strong>灵活的解码策略&lt;/strong>：vLLM 支持多种复杂的解码算法，包括并行采样（Parallel Sampling）、波束搜索（Beam Search）和 Top-K/Top-P 采样，可以满足不同应用场景的需求。&lt;/li>
&lt;li>&lt;strong>与 OpenAI API 兼容&lt;/strong>：vLLM 提供了一个与 OpenAI API 完全兼容的服务端点。这意味着您可以将 vLLM 无缝集成到现有的、基于 OpenAI API 构建的应用生态中，只需更改几个配置即可。&lt;/li>
&lt;li>&lt;strong>分布式推理&lt;/strong>：对于无法在单个 GPU 上容纳的超大模型，vLLM 支持张量并行（Tensor Parallelism），可以将模型的权重和计算负载分散到多个 GPU 上，实现高效的分布式推理。&lt;/li>
&lt;li>&lt;strong>流式输出与结构化输出&lt;/strong>：支持流式传输（Streaming）生成的 token，并能通过引导式生成（Guided Generation）产生符合特定格式（如 JSON Schema 或正则表达式）的结构化输出。&lt;/li>
&lt;/ul>
&lt;h2 id="3--pagedattention">3. 核心架构：深入 PagedAttention&lt;/h2>
&lt;p>PagedAttention 是 vLLM 的灵魂，其设计灵感来源于现代操作系统中用于管理虚拟内存的分页（Paging）技术。&lt;/p>
&lt;h3 id="31-">3.1 工作原理&lt;/h3>
&lt;p>在传统方法中，KV Cache 为每个序列存储在连续的内存空间中。这种方式看似简单，但由于不同序列长度差异巨大，会导致严重的内存碎片。&lt;/p>
&lt;p>PagedAttention 则将每个序列的 KV Cache 划分为固定大小的 &lt;strong>块（Blocks）&lt;/strong>。每个块可以存储固定数量 token 的键和值。在推理过程中，vLLM 的核心调度器会根据需要动态地为序列分配这些块。&lt;/p>
&lt;p>这种设计的优势在于：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>消除内部碎片&lt;/strong>：由于块的大小固定，一个序列的最后一个块可能会有少量空间未被使用，但这种浪费远小于为整个序列预留连续内存所造成的浪费。&lt;/li>
&lt;li>&lt;strong>灵活的内存分配&lt;/strong>：块存储在非连续的内存空间中，使得内存管理更加灵活，类似于操作系统管理物理内存页。&lt;/li>
&lt;li>&lt;strong>高效的内存共享&lt;/strong>：PagedAttention 使得在不同序列之间共享 KV Cache 变得异常简单和高效。例如，在并行采样或波束搜索中，多个候选序列都源自同一个提示（Prompt）。vLLM 可以让这些序列共享存储提示部分的 KV 块，只有在生成新 token 时才需要为每个序列分配新的、独立的块。这种&amp;quot;写时复制&amp;rdquo;（Copy-on-Write）的机制极大地降低了复杂解码算法的内存开销。&lt;/li>
&lt;/ol>
&lt;p>下面是一个 Mermaid 图，更直观地展示了 PagedAttention 的内存管理方式：&lt;/p>
&lt;pre>&lt;code class="language-mermaid">graph TD
subgraph Physical_Memory [KV Cache Physical Memory]
direction LR
B1(Block 1)
B2(Block 2)
B3(Block 3)
B4(Block 4)
B5(Block 5)
B6(Block 6)
B7(Block 7)
B8(Block 8)
end
subgraph Logical_View [Sequence Logical View]
direction TB
subgraph Seq1 [Sequence 1]
P1(Prompt) --&amp;gt; T1(Token 1)
end
subgraph Seq2 [Sequence 2]
P2(Prompt) --&amp;gt; T2(Token 1) --&amp;gt; T3(Token 2)
end
subgraph Seq3 [Parallel Sampling]
P3(Prompt) --&amp;gt; T4(Token 1a)
P3 --&amp;gt; T5(Token 1b)
end
end
subgraph Block_Table [Block Table]
direction TB
Map1[&amp;quot;Seq 1: [B1, B5]&amp;quot;]
Map2[&amp;quot;Seq 2: [B2, B6, B8]&amp;quot;]
Map3[&amp;quot;Seq 3a: [B3, B7]&amp;quot;]
Map4[&amp;quot;Seq 3b: [B3, B4]&amp;quot;]
end
Seq1 --&amp;gt; Map1
Seq2 --&amp;gt; Map2
Seq3 --&amp;gt; Map3
Seq3 --&amp;gt; Map4
Map1 --&amp;gt; B1
Map1 --&amp;gt; B5
Map2 --&amp;gt; B2
Map2 --&amp;gt; B6
Map2 --&amp;gt; B8
Map3 --&amp;gt; B3
Map3 --&amp;gt; B7
Map4 --&amp;gt; B3
Map4 --&amp;gt; B4
style B3 fill:#f9f,stroke:#333,stroke-width:2px
linkStyle 8 stroke-width:2px,stroke:green,fill:none;
linkStyle 11 stroke-width:2px,stroke:green,fill:none;
linkStyle 12 stroke-width:2px,stroke:green,fill:none;
&lt;/code>&lt;/pre>
&lt;p>&lt;em>上图说明：&lt;/em>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>KV Cache 物理内存&lt;/strong>：代表 GPU 上非连续的物理内存块。&lt;/li>
&lt;li>&lt;strong>序列逻辑视图&lt;/strong>：代表正在处理的多个请求（序列）。&lt;/li>
&lt;li>&lt;strong>块映射表&lt;/strong>：vLLM 的核心组件，将逻辑上的 token 位置映射到物理内存块。&lt;/li>
&lt;li>&lt;strong>内存共享&lt;/strong>：注意到&amp;quot;并行采样&amp;quot;中的两个分支（3a 和 3b）共享了同一个 Prompt 块（B3），这就是 PagedAttention 高效内存共享的体现。&lt;/li>
&lt;/ul>
&lt;h3 id="32--continuous-batching">3.2 持续批处理 (Continuous Batching)&lt;/h3>
&lt;p>基于 PagedAttention，vLLM 实现了一种更先进的批处理策略——持续批处理。传统的批处理（Static Batching）需要等待批次中所有序列都生成完毕后，才能开始处理下一个批次。而持续批处理则允许在批次中的某个序列完成生成后，立即将新的请求插入到批处理中，从而避免了 GPU 的空闲等待，进一步提升了吞吐量。&lt;/p>
&lt;p>下面通过 Mermaid 序列图对比两种批处理方式：&lt;/p>
&lt;pre>&lt;code class="language-mermaid">sequenceDiagram
participant C as Client
participant S as Server
participant G as GPU
note over C, G: --- Static Batching ---
C-&amp;gt;&amp;gt;S: Request [R1, R2, R3, R4]
S-&amp;gt;&amp;gt;G: Process Batch 1 [R1, R2, R3, R4]
note right of G: All requests process in parallel
G--&amp;gt;&amp;gt;S: Batch 1 Finished
note right of S: Wait for the entire batch to complete
S--&amp;gt;&amp;gt;C: Response [O1, O2, O3, O4]
C-&amp;gt;&amp;gt;S: Request [R5, R6]
S-&amp;gt;&amp;gt;G: Process Batch 2 [R5, R6]
note over C, G: --- Continuous Batching ---
C-&amp;gt;&amp;gt;S: Request [R1, R2, R3, R4]
S-&amp;gt;&amp;gt;G: Process [R1, R2, R3, R4]
G--&amp;gt;&amp;gt;S: R2 Finished
S--&amp;gt;&amp;gt;C: Response O2
C-&amp;gt;&amp;gt;S: New Request R5
S-&amp;gt;&amp;gt;G: Add R5 to queue (GPU is not idle)
note right of G: R1, R3, R4, R5 are now processing
G--&amp;gt;&amp;gt;S: R4 Finished
S--&amp;gt;&amp;gt;C: Response O4
&lt;/code>&lt;/pre>
&lt;h2 id="4-">4. 快速上手指南&lt;/h2>
&lt;p>下面，我们将通过几个简单的步骤来展示如何安装和使用 vLLM。&lt;/p>
&lt;h3 id="41-">4.1 安装&lt;/h3>
&lt;p>您可以使用 &lt;code>pip&lt;/code> 或 &lt;code>uv&lt;/code>（一个更快的包安装工具）来安装 vLLM。推荐使用 &lt;code>uv&lt;/code>，因为它可以自动检测您的 CUDA 版本并安装匹配的 PyTorch 后端。&lt;/p>
&lt;p>&lt;strong>使用 uv (推荐):&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-bash"># 创建并激活虚拟环境
uv venv
source .venv/bin/activate
# 安装 vLLM
uv pip install vllm --torch-backend=auto
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>使用 pip:&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-bash">pip install vllm
&lt;/code>&lt;/pre>
&lt;h3 id="42-">4.2 离线推理&lt;/h3>
&lt;p>使用 &lt;code>vllm.LLM&lt;/code> 类可以非常方便地进行离线推理。&lt;/p>
&lt;pre>&lt;code class="language-python">from vllm import LLM, SamplingParams
# 定义输入提示
prompts = [
&amp;quot;Hello, my name is&amp;quot;,
&amp;quot;The capital of France is&amp;quot;,
&amp;quot;The future of AI is&amp;quot;,
]
# 定义采样参数
sampling_params = SamplingParams(temperature=0.8, top_p=0.95)
# 初始化 LLM 引擎 (模型会自动从 Hugging Face 下载)
llm = LLM(model=&amp;quot;facebook/opt-125m&amp;quot;)
# 生成文本
outputs = llm.generate(prompts, sampling_params)
# 打印结果
for output in outputs:
prompt = output.prompt
generated_text = output.outputs[0].text
print(f&amp;quot;Prompt: {prompt!r}, Generated text: {generated_text!r}&amp;quot;)
&lt;/code>&lt;/pre>
&lt;h3 id="43--openai-">4.3 启动 OpenAI 兼容服务器&lt;/h3>
&lt;p>vLLM 最强大的功能之一是其内置的 API 服务器。只需一行命令，即可启动一个与 OpenAI API 兼容的服务。&lt;/p>
&lt;pre>&lt;code class="language-bash">vllm serve Qwen/Qwen2.5-1.5B-Instruct
&lt;/code>&lt;/pre>
&lt;p>默认情况下，服务器会在 &lt;code>http://localhost:8000&lt;/code> 上运行。&lt;/p>
&lt;h3 id="44-">4.4 与服务器交互&lt;/h3>
&lt;p>您可以使用 &lt;code>curl&lt;/code> 或 &lt;code>openai&lt;/code> Python 客户端与服务器进行交互。&lt;/p>
&lt;p>&lt;strong>使用 curl:&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-bash">curl http://localhost:8000/v1/completions \
-H &amp;quot;Content-Type: application/json&amp;quot; \
-d '{
&amp;quot;model&amp;quot;: &amp;quot;Qwen/Qwen2.5-1.5B-Instruct&amp;quot;,
&amp;quot;prompt&amp;quot;: &amp;quot;San Francisco is a&amp;quot;,
&amp;quot;max_tokens&amp;quot;: 7,
&amp;quot;temperature&amp;quot;: 0
}'
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>使用 OpenAI Python 客户端:&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-python">from openai import OpenAI
client = OpenAI(
base_url=&amp;quot;http://localhost:8000/v1&amp;quot;,
api_key=&amp;quot;not-used&amp;quot; # API 密钥不是必需的
)
completion = client.chat.completions.create(
model=&amp;quot;Qwen/Qwen2.5-1.5B-Instruct&amp;quot;,
messages=[
{&amp;quot;role&amp;quot;: &amp;quot;system&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;You are a helpful assistant.&amp;quot;},
{&amp;quot;role&amp;quot;: &amp;quot;user&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;Who won the world series in 2020?&amp;quot;}
]
)
print(completion.choices[0].message)
&lt;/code>&lt;/pre>
&lt;h2 id="5--serving">5. 模型服务 (Serving)&lt;/h2>
&lt;h3 id="51-">5.1 分布式服务&lt;/h3>
&lt;p>如果模型太大无法放入单个 GPU，您可以使用张量并行将其分布在多个 GPU 上。&lt;/p>
&lt;pre>&lt;code class="language-bash"># 在 4 个 GPU 上启动服务
vllm serve facebook/opt-13b --tensor-parallel-size 4
&lt;/code>&lt;/pre>
&lt;h3 id="52-docker-">5.2 Docker 部署&lt;/h3>
&lt;p>vLLM 提供了官方的 Docker 镜像，可以方便地进行容器化部署。&lt;/p>
&lt;pre>&lt;code class="language-bash">docker run --runtime nvidia --gpus all \
-v ~/.cache/huggingface:/root/.cache/huggingface \
--env &amp;quot;HUGGING_FACE_HUB_TOKEN=&amp;lt;your-hf-token&amp;gt;&amp;quot; \
-p 8000:8000 \
--ipc=host \
vllm/vllm-openai:latest \
--model mistralai/Mistral-7B-v0.1
&lt;/code>&lt;/pre>
&lt;h2 id="6-">6. 高级功能详解&lt;/h2>
&lt;h3 id="61--structured-outputs">6.1 结构化输出 (Structured Outputs)&lt;/h3>
&lt;p>vLLM 支持多种方式来约束模型的输出格式，这对于需要可靠、可解析输出的应用至关重要。&lt;/p>
&lt;p>&lt;strong>使用 Pydantic 模型生成 JSON:&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-python">from pydantic import BaseModel
from openai import OpenAI
client = OpenAI(base_url=&amp;quot;http://localhost:8000/v1&amp;quot;, api_key=&amp;quot;dummy&amp;quot;)
model = client.models.list().data[0].id
class People(BaseModel):
name: str
age: int
completion = client.chat.completions.create(
model=model,
messages=[
{&amp;quot;role&amp;quot;: &amp;quot;user&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;Generate a JSON with the name and age of one random person.&amp;quot;}
],
response_format={
&amp;quot;type&amp;quot;: &amp;quot;json_schema&amp;quot;,
&amp;quot;json_schema&amp;quot;: {
&amp;quot;name&amp;quot;: &amp;quot;people&amp;quot;,
&amp;quot;schema&amp;quot;: People.model_json_schema()
}
},
)
print(completion.choices[0].message.content)
&lt;/code>&lt;/pre>
&lt;h3 id="62-lora-">6.2 LoRA 支持&lt;/h3>
&lt;p>vLLM 可以在同一个基础模型上高效地服务多个 LoRA 适配器。这对于需要为不同客户或任务提供定制化模型的场景非常有用。&lt;/p>
&lt;p>&lt;strong>启动支持 LoRA 的服务器:&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-python">from vllm import LLM
llm = LLM(model=&amp;quot;meta-llama/Llama-2-7b-hf&amp;quot;, enable_lora=True)
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>在请求中指定 LoRA 适配器:&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-bash">curl http://localhost:8000/v1/completions \
-H &amp;quot;Content-Type: application/json&amp;quot; \
-d '{
&amp;quot;model&amp;quot;: &amp;quot;sql-lora&amp;quot;, # 指定 LoRA 模型的 ID
&amp;quot;prompt&amp;quot;: &amp;quot;San Francisco is a&amp;quot;,
&amp;quot;max_tokens&amp;quot;: 7
}'
&lt;/code>&lt;/pre>
&lt;h3 id="63--quantization">6.3 量化 (Quantization)&lt;/h3>
&lt;p>量化是一种通过降低模型权重的精度来减小模型大小和内存占用的技术。vLLM 支持多种量化方案，如 AWQ 和 FP8 KV 缓存。&lt;/p>
&lt;p>&lt;strong>启用 FP8 KV 缓存:&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-python">from vllm import LLM
llm = LLM(
model=&amp;quot;meta-llama/Llama-2-7b-chat-hf&amp;quot;,
kv_cache_dtype=&amp;quot;fp8&amp;quot;,
calculate_kv_scales=True # 动态计算量化尺度
)
&lt;/code>&lt;/pre>
&lt;h2 id="7-">7. 框架集成&lt;/h2>
&lt;p>vLLM 可以轻松地与 Langchain 和 LlamaIndex 等流行的 LLM 应用框架集成，用于构建复杂的系统，如检索增强生成（RAG）。通常，vLLM 会作为后端提供快速的 LLM 推理和嵌入生成服务。&lt;/p>
&lt;p>&lt;strong>安装相关依赖:&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-bash">pip install -U vllm langchain_openai langchain_community
&lt;/code>&lt;/pre>
&lt;p>之后，在 Langchain 中，您可以将 &lt;code>ChatOpenAI&lt;/code> 或 &lt;code>OpenAIEmbeddings&lt;/code> 的 &lt;code>base_url&lt;/code> 指向 vLLM 服务器的地址，即可完成集成。&lt;/p>
&lt;h2 id="8-">8. 总结&lt;/h2>
&lt;p>vLLM 通过其创新的 PagedAttention 架构，成功地解决了 LLM 推理中的内存管理和性能瓶颈，为开发者提供了一个极其高效、灵活且易于使用的推理服务引擎。无论是进行快速的离线实验，还是部署生产级的、高并发的 LLM 服务，vLLM 都展现出了卓越的性能和强大的功能。随着社区的不断发展，vLLM 正在成为 LLM 服务领域的标准工具之一。&lt;/p></description></item><item><title>LoRA 技术详解：深入浅出理解与实战</title><link>https://ziyanglin.netlify.app/zh/post/lora-documentation/</link><pubDate>Thu, 26 Jun 2025 00:00:00 +0000</pubDate><guid>https://ziyanglin.netlify.app/zh/post/lora-documentation/</guid><description>&lt;h2 id="1--lora">1. 引言：为什么需要 LoRA？&lt;/h2>
&lt;p>在大型语言模型（LLM）和生成式 AI 飞速发展的今天，我们见证了模型规模的爆炸式增长，从数亿到数万亿参数不等。这些庞大的模型在各种任务上都展现出了惊人的能力。然而，一个巨大的挑战随之而来：如何针对特定的下游任务对这些模型进行微调？&lt;/p>
&lt;p>传统的**全量微调（Full Fine-Tuning）**方法，即更新模型的所有参数，面临着严峻的问题：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>计算成本高昂&lt;/strong>：微调一个数十亿参数的模型需要巨大的计算资源和数百 GB 的显存，这对于大多数开发者和中小型企业来说是难以承受的。&lt;/li>
&lt;li>&lt;strong>存储成本巨大&lt;/strong>：每针对一个任务微调一次，就需要保存一份完整的模型副本，导致存储成本急剧上升。&lt;/li>
&lt;li>&lt;strong>部署困难&lt;/strong>：在生产环境中，为不同任务维护和切换多个庞大的模型副本是一场噩梦。&lt;/li>
&lt;/ul>
&lt;p>为了解决这些痛点，**参数高效微调（Parameter-Efficient Fine-Tuning, PEFT）**技术应运而生。其核心思想是在微调过程中冻结大部分预训练模型的参数，只调整一小部分（通常远小于总参数的 1%）新增的或特定的参数。&lt;/p>
&lt;p>在众多 PEFT 技术中，**LoRA（Low-Rank Adaptation of Large Language Models）**以其出色的效果、高效的性能和实现的简洁性脱颖而出，成为目前最主流、应用最广泛的方案之一。本篇文档将深入浅出地介绍 LoRA 的核心原理，并提供详细的实战指南。&lt;/p>
&lt;h2 id="2-lora-">2. 核心原理：LoRA 的魔法&lt;/h2>
&lt;p>LoRA 的核心假设是：&lt;strong>大型语言模型在适应新任务时，其权重的变化是低秩的（low-rank）&lt;/strong>。换句话说，尽管预训练模型的权重矩阵 &lt;code>W&lt;/code> 非常庞大（例如 &lt;code>d x d&lt;/code> 维），但在微调过程中，权重的改变量 &lt;code>ΔW&lt;/code> 具有一个很低的&amp;quot;内在秩&amp;rdquo;。&lt;/p>
&lt;p>基于这个假设，LoRA 不直接更新 &lt;code>W&lt;/code>，而是通过训练两个更小的、低秩的矩阵 &lt;code>B&lt;/code> 和 &lt;code>A&lt;/code> 来近似 &lt;code>ΔW&lt;/code>，即 &lt;code>ΔW ≈ BA&lt;/code>。&lt;/p>
&lt;ul>
&lt;li>&lt;code>W&lt;/code> 是预训练好的、被冻结的权重矩阵。&lt;/li>
&lt;li>&lt;code>A&lt;/code> 是一个 &lt;code>r x d&lt;/code> 维的矩阵，其中 &lt;code>r&lt;/code> 是一个远小于 &lt;code>d&lt;/code> 的秩（rank）。&lt;/li>
&lt;li>&lt;code>B&lt;/code> 是一个 &lt;code>d x r&lt;/code> 维的矩阵。&lt;/li>
&lt;/ul>
&lt;p>在微调过程中，只有矩阵 &lt;code>A&lt;/code> 和 &lt;code>B&lt;/code> 的参数是可训练的。前向传播的计算过程也相应地变为：&lt;/p>
&lt;p>&lt;code>h = Wx + BAx&lt;/code>&lt;/p>
&lt;p>下面是一个图示，更直观地展示了这个过程：&lt;/p>
&lt;pre>&lt;code class="language-mermaid">graph TD
A[输入 x] --&amp;gt; B(预训练权重 W);
A --&amp;gt; C(低秩矩阵 A);
C --&amp;gt; D(低秩矩阵 B);
B --&amp;gt; E[Wx];
D --&amp;gt; F[BAx];
E --&amp;gt; G((求和));
F --&amp;gt; G;
G --&amp;gt; H[最终输出 h];
style B fill:#eee,stroke:#333,stroke-width:2px,stroke-dasharray: 5, 5
style C fill:#9cf,stroke:#333,stroke-width:2px
style D fill:#9cf,stroke:#333,stroke-width:2px
&lt;/code>&lt;/pre>
&lt;p>其中 &lt;code>x&lt;/code> 是输入，&lt;code>h&lt;/code> 是输出。这种方式极大地减少了需要训练的参数数量。例如，如果 &lt;code>d = 4096&lt;/code>，&lt;code>r = 8&lt;/code>，那么原始矩阵 &lt;code>W&lt;/code> 有 &lt;code>4096 * 4096 ≈ 16.7M&lt;/code> 个参数，而 &lt;code>A&lt;/code> 和 &lt;code>B&lt;/code> 加起来只有 &lt;code>4096 * 8 + 8 * 4096 ≈ 65K&lt;/code> 个参数，参数量减少了约 256 倍！&lt;/p>
&lt;p>&lt;strong>关键参数 &lt;code>r&lt;/code>&lt;/strong>：秩 &lt;code>r&lt;/code> 是 LoRA 中最重要的超参数。它控制了低秩矩阵的大小，直接决定了新增参数的数量。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>较小的 &lt;code>r&lt;/code>&lt;/strong>：可训练参数少，训练速度快，显存占用低，但可能无法充分学习到任务的复杂特征。&lt;/li>
&lt;li>&lt;strong>较大的 &lt;code>r&lt;/code>&lt;/strong>：可训练参数多，模型拟合能力更强，但会增加计算成本和过拟合的风险。
在实践中，&lt;code>r&lt;/code> 通常被设置为 8, 16, 32 或 64，就能在性能和效率之间取得很好的平衡。&lt;/li>
&lt;/ul>
&lt;h2 id="3-lora-">3. LoRA 的显著优势&lt;/h2>
&lt;p>相比于全量微调，LoRA 展现出多方面的压倒性优势：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>极高的参数效率&lt;/strong>：如上所述，LoRA 只需训练极少量的参数。我们可以通过 &lt;code>print_trainable_parameters()&lt;/code> 函数直观地看到这一点，训练的参数占比通常低于 1%。&lt;/li>
&lt;li>&lt;strong>更快的训练速度&lt;/strong>：由于需要计算梯度和更新的参数数量大幅减少，训练时间也随之缩短，从而加速了迭代周期。&lt;/li>
&lt;li>&lt;strong>更低的硬件门槛&lt;/strong>：LoRA 显著减少了训练过程中的显存（VRAM）占用，使得在消费级 GPU（如 RTX 3090/4090）上微调拥有数百亿参数的大模型成为可能。&lt;/li>
&lt;li>&lt;strong>部署和管理的灵活性&lt;/strong>：这是 LoRA 最具吸引力的优点之一。预训练模型始终保持不变，可以被所有任务共享。对于每个下游任务，我们只需要保存一个轻量级（通常只有几 MB 到几十 MB）的 LoRA 适配器（即矩阵 A 和 B 的权重）。在部署时，可以根据需求动态加载对应的适配器，极大地简化了多任务场景下的模型管理和切换。&lt;/li>
&lt;/ol>
&lt;h2 id="4-lora-">4. 动手实践：LoRA 训练方法&lt;/h2>
&lt;p>下面，我们将通过一个完整的例子，展示如何使用 Hugging Face 生态中的 &lt;code>transformers&lt;/code>、&lt;code>peft&lt;/code> 和 &lt;code>trl&lt;/code> 库来对一个大模型进行 LoRA 微调。&lt;/p>
&lt;h3 id="-1-">步骤 1: 环境准备&lt;/h3>
&lt;p>首先，确保你已经安装了必要的 Python 库：&lt;/p>
&lt;pre>&lt;code class="language-bash">pip install transformers peft trl datasets torch
&lt;/code>&lt;/pre>
&lt;h3 id="-2-">步骤 2: 加载模型、分词器和数据集&lt;/h3>
&lt;p>我们选择一个预训练模型作为基础，并加载相应的分词器。同时，我们从 Hugging Face Hub 加载一个用于微调的数据集。&lt;/p>
&lt;pre>&lt;code class="language-python">from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments
from datasets import load_dataset
# 模型 ID，可以是任何支持的 Causal LM
model_id = &amp;quot;facebook/opt-350m&amp;quot;
# 加载预训练模型
model = AutoModelForCausalLM.from_pretrained(model_id)
# 加载分词器
tokenizer = AutoTokenizer.from_pretrained(model_id)
# 加载数据集（以英文名言数据集为例）
dataset = load_dataset(&amp;quot;Abirate/english_quotes&amp;quot;, split=&amp;quot;train&amp;quot;)
&lt;/code>&lt;/pre>
&lt;h3 id="-3--lora-loraconfig">步骤 3: 配置 LoRA (&lt;code>LoraConfig&lt;/code>)&lt;/h3>
&lt;p>这是 LoRA 微调的核心步骤。我们需要创建一个 &lt;code>LoraConfig&lt;/code> 对象，来定义 LoRA 适配器的行为。&lt;/p>
&lt;pre>&lt;code class="language-python">from peft import LoraConfig
lora_config = LoraConfig(
r=16, # 低秩矩阵的秩，推荐值为 8, 16, 32
lora_alpha=32, # 缩放因子，通常设置为 r 的两倍
target_modules=[&amp;quot;q_proj&amp;quot;, &amp;quot;v_proj&amp;quot;], # 指定要应用 LoRA 的模型层。对于 Transformer 模型，通常是 q_proj 和 v_proj
lora_dropout=0.05, # LoRA 层的 dropout 概率
bias=&amp;quot;none&amp;quot;, # 是否训练偏置项，&amp;quot;none&amp;quot; 表示不训练
task_type=&amp;quot;CAUSAL_LM&amp;quot; # 任务类型，这里是因果语言模型
)
&lt;/code>&lt;/pre>
&lt;ul>
&lt;li>&lt;code>target_modules&lt;/code>: 这个参数非常关键。它告诉 PEFT 库应该在模型的哪些模块（通常是 &lt;code>nn.Linear&lt;/code> 层）上应用 LoRA。对于大多数 Transformer 模型，将其应用于 Attention 机制中的查询（query）和值（value）投影层（即 &lt;code>q_proj&lt;/code> 和 &lt;code>v_proj&lt;/code>）是常见的做法。你可以通过打印 &lt;code>model&lt;/code> 对象来查看其所有模块的名称，以确定可以作为目标的选择。&lt;/li>
&lt;/ul>
&lt;h3 id="-4--lora--sfttrainer-">步骤 4: 应用 LoRA 并使用 &lt;code>SFTTrainer&lt;/code> 进行训练&lt;/h3>
&lt;p>&lt;code>trl&lt;/code> 库提供的 &lt;code>SFTTrainer&lt;/code> (Supervised Fine-tuning Trainer) 极大地简化了微调流程。它内置了对 &lt;code>peft&lt;/code> 的支持，我们只需将模型、分词器、数据集和 &lt;code>peft_config&lt;/code> 传递给它即可。&lt;/p>
&lt;pre>&lt;code class="language-python">from trl import SFTTrainer
# 定义训练参数
training_args = TrainingArguments(
output_dir=&amp;quot;./lora_finetuned_model&amp;quot;, # 模型输出目录
num_train_epochs=3, # 训练轮次
per_device_train_batch_size=4, # 每个设备的训练批量大小
logging_dir='./logs', # 日志目录
logging_steps=50, # 每隔多少步记录一次日志
learning_rate=2e-4, # 学习率
)
# 初始化 SFTTrainer
trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
args=training_args,
train_dataset=dataset,
peft_config=lora_config, # 传入 LoRA 配置
dataset_text_field=&amp;quot;quote&amp;quot;, # 数据集中包含文本的字段名
)
# 开始训练
trainer.train()
# 保存训练好的 LoRA 适配器
trainer.save_model()
&lt;/code>&lt;/pre>
&lt;p>训练完成后，&lt;code>output_dir&lt;/code> 目录下会生成一个 &lt;code>adapter_model.bin&lt;/code> 文件和 &lt;code>adapter_config.json&lt;/code> 文件，这就是我们训练得到的轻量级 LoRA 适配器。&lt;/p>
&lt;h3 id="-5--lora-">步骤 5: 使用训练好的 LoRA 适配器进行推理&lt;/h3>
&lt;p>在推理时，我们首先加载原始的预训练模型，然后加载训练好的 LoRA 适配器权重。&lt;/p>
&lt;pre>&lt;code class="language-python">from peft import PeftModel
# 加载原始的、未经微调的模型
base_model = AutoModelForCausalLM.from_pretrained(model_id)
# 加载 LoRA 适配器
model_with_lora = PeftModel.from_pretrained(base_model, &amp;quot;./lora_finetuned_model&amp;quot;)
# 现在 model_with_lora 就是一个融合了 LoRA 权重的、可以用于推理的模型
prompt = &amp;quot;The best way to predict the future is to&amp;quot;
inputs = tokenizer(prompt, return_tensors=&amp;quot;pt&amp;quot;)
# 生成文本
outputs = model_with_lora.generate(**inputs, max_new_tokens=20)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
&lt;/code>&lt;/pre>
&lt;h2 id="5-lora-">5. LoRA 模型部署：从静态到动态&lt;/h2>
&lt;p>训练完成后，如何高效地将 LoRA 模型投入生产环境是关键的下一步。LoRA 的部署策略主要分为两大类：&lt;strong>权重合并（静态部署）&lt;/strong> 和 &lt;strong>动态适配器加载（动态部署）&lt;/strong>。下面的流程图分别展示了这两种路径：&lt;/p>
&lt;p>&lt;strong>方案一：权重合并 (静态部署)&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-mermaid">graph TD
A[LoRA 训练完成] --&amp;gt; B[Base Model + LoRA Adapter];
B --&amp;gt; C[&amp;quot;调用 merge_and_unload()&amp;quot;];
C --&amp;gt; D[生成独立的全量模型];
D --&amp;gt; E[标准部署];
style D fill:#c9f,stroke:#333,stroke-width:2px
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>方案二：动态适配器加载 (动态部署)&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-mermaid">graph TD
A[LoRA 训练完成] --&amp;gt; B[vLLM / TGI 服务器];
B --&amp;gt; C[加载 Base Model];
C --&amp;gt; D[加载多个 LoRA Adapters];
D --&amp;gt; E[按需组合推理];
style E fill:#9cf,stroke:#333,stroke-width:2px
&lt;/code>&lt;/pre>
&lt;h3 id="-">方案一：权重合并与标准部署 (静态)&lt;/h3>
&lt;p>这是最简单直接的部署方式。其核心思想是将轻量级的 LoRA 适配器权重合并到原始的基础模型权重中，生成一个全新的、独立的全量模型。&lt;/p>
&lt;p>&lt;strong>操作方法&lt;/strong>:
使用 &lt;code>peft&lt;/code> 库的 &lt;code>merge_and_unload()&lt;/code> 方法可以轻松完成这个过程。&lt;/p>
&lt;pre>&lt;code class="language-python">from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
# 假设 model_id 和 lora_path 已定义
base_model = AutoModelForCausalLM.from_pretrained(model_id)
model_with_lora = PeftModel.from_pretrained(base_model, &amp;quot;./lora_finetuned_model&amp;quot;)
# 合并权重
merged_model = model_with_lora.merge_and_unload()
# 现在 merged_model 就是一个标准的 Transformers 模型
# 你可以像保存任何其他模型一样保存它
merged_model.save_pretrained(&amp;quot;./merged_lora_model&amp;quot;)
tokenizer.save_pretrained(&amp;quot;./merged_lora_model&amp;quot;)
&lt;/code>&lt;/pre>
&lt;p>之后，你可以像加载任何普通 Hugging Face 模型一样加载并使用这个 &lt;code>merged_lora_model&lt;/code>。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>优点&lt;/strong>:
&lt;ul>
&lt;li>&lt;strong>零推理延迟&lt;/strong>: 合并后，推理过程与标准模型完全相同，没有任何额外的计算开销。&lt;/li>
&lt;li>&lt;strong>部署简单&lt;/strong>: 无需任何额外的推理框架支持，可直接用于 &lt;code>transformers&lt;/code> 等标准库。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>缺点&lt;/strong>:
&lt;ul>
&lt;li>&lt;strong>失去灵活性&lt;/strong>: 每有一个 LoRA 适配器，就需要保存和加载一个完整的模型副本，违背了 LoRA 轻量化的初衷。&lt;/li>
&lt;li>&lt;strong>存储成本高&lt;/strong>: 如果有多个适配器，存储开销巨大。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="-vllm--">方案二：使用 vLLM 进行高性能动态部署 (推荐)&lt;/h3>
&lt;p>对于需要同时服务多个 LoRA 适配器的场景，&lt;strong>vLLM&lt;/strong> 是目前业界领先的高性能推理和服务引擎。它通过 &lt;strong>PagedAttention&lt;/strong> 等核心技术，实现了对多个 LoRA 适配器的高效管理和动态加载，能够在不显著牺牲性能的前提下，实现极高的吞吐量。&lt;/p>
&lt;p>&lt;strong>操作方法&lt;/strong>:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>安装 vLLM&lt;/strong>:&lt;/p>
&lt;pre>&lt;code class="language-bash">pip install vllm
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>启动 vLLM 服务器&lt;/strong>:
使用 &lt;code>vllm serve&lt;/code> 命令启动一个 OpenAI 兼容的 API 服务器。关键在于使用 &lt;code>--enable-lora&lt;/code> 开启 LoRA 支持，并可以通过 &lt;code>--lora-modules&lt;/code> 预加载适配器。&lt;/p>
&lt;pre>&lt;code class="language-bash"># lora_path 指向你训练好的适配器目录
vllm serve meta-llama/Llama-2-7b-hf \
--enable-lora \
--lora-modules my_sql_lora=/path/to/your/sql_lora_adapter
&lt;/code>&lt;/pre>
&lt;p>这里，我们将名为 &lt;code>my_sql_lora&lt;/code> 的适配器预加载了进来。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>发送推理请求&lt;/strong>:
你可以通过 &lt;code>curl&lt;/code> 或任何 HTTP 客户端向 vLLM 服务器发送请求。只需在请求体中指定 &lt;code>model&lt;/code> 为你加载的 LoRA 适配器名称即可。&lt;/p>
&lt;pre>&lt;code class="language-bash">curl http://localhost:8000/v1/completions \
-H &amp;quot;Content-Type: application/json&amp;quot; \
-d '{
&amp;quot;model&amp;quot;: &amp;quot;my_sql_lora&amp;quot;,
&amp;quot;prompt&amp;quot;: &amp;quot;Write a SQL query for all users.&amp;quot;,
&amp;quot;max_tokens&amp;quot;: 64
}'
&lt;/code>&lt;/pre>
&lt;p>vLLM 会自动将请求路由到对应的 LoRA 适配器进行推理。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>使用 Python 客户端&lt;/strong>:
vLLM 也提供了 Python API，可以在代码中直接调用。&lt;/p>
&lt;pre>&lt;code class="language-python">from vllm import LLM, SamplingParams
from vllm.lora.request import LoRARequest
# 初始化 LLM 引擎，并开启 LoRA 支持
llm = LLM(model=&amp;quot;meta-llama/Llama-2-7b-hf&amp;quot;, enable_lora=True)
sampling_params = SamplingParams(max_tokens=64)
# 在 generate 调用中，通过 lora_request 指定要使用的适配器
outputs = llm.generate(
&amp;quot;Write a SQL query for all users.&amp;quot;,
sampling_params,
lora_request=LoRARequest(&amp;quot;my_sql_lora&amp;quot;, 1, &amp;quot;/path/to/your/sql_lora_adapter&amp;quot;)
)
&lt;/code>&lt;/pre>
&lt;ul>
&lt;li>&lt;strong>优点&lt;/strong>:
&lt;ul>
&lt;li>&lt;strong>极高吞吐量&lt;/strong>: 专为大规模并发推理设计。&lt;/li>
&lt;li>&lt;strong>动态灵活&lt;/strong>: 可同时服务成百上千个 LoRA 适配器，按需加载，完美支持多租户场景。&lt;/li>
&lt;li>&lt;strong>显存高效&lt;/strong>: PagedAttention 机制有效管理显存，避免浪费。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>缺点&lt;/strong>:
&lt;ul>
&lt;li>&lt;strong>部署稍复杂&lt;/strong>: 需要额外学习和配置 vLLM 服务。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="--tgi">方案三：其他动态部署方案 (如 TGI)&lt;/h3>
&lt;p>Hugging Face 自家的 &lt;strong>Text Generation Inference (TGI)&lt;/strong> 是另一个强大的生产级推理服务器。与 vLLM 类似，TGI 也支持在启动时加载多个 LoRA 适配器，并根据传入的请求头动态应用。它与 Hugging Face 生态系统集成得最好，是 vLLM 的一个有力竞争者。&lt;/p>
&lt;h3 id="heading">部署方案对比总结&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th align="left">特性&lt;/th>
&lt;th align="left">权重合并 (静态)&lt;/th>
&lt;th align="left">vLLM (动态)&lt;/th>
&lt;th align="left">TGI (动态)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td align="left">&lt;strong>性能/吞吐量&lt;/strong>&lt;/td>
&lt;td align="left">最高（单请求延迟最低）&lt;/td>
&lt;td align="left">非常高&lt;/td>
&lt;td align="left">高&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>灵活性&lt;/strong>&lt;/td>
&lt;td align="left">低（无动态能力）&lt;/td>
&lt;td align="left">非常高&lt;/td>
&lt;td align="left">高&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>部署复杂度&lt;/strong>&lt;/td>
&lt;td align="left">低&lt;/td>
&lt;td align="left">中等&lt;/td>
&lt;td align="left">中等&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>显存占用&lt;/strong>&lt;/td>
&lt;td align="left">非常高（N个适配器N倍显存）&lt;/td>
&lt;td align="left">低（高效共享）&lt;/td>
&lt;td align="left">低（高效共享）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>适用场景&lt;/strong>&lt;/td>
&lt;td align="left">单一、固定的任务&lt;/td>
&lt;td align="left">多租户、高并发、多任务场景&lt;/td>
&lt;td align="left">Hugging Face 生态的生产部署&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="6-">6. 高级话题&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>多适配器管理&lt;/strong>：PEFT 支持在单个模型上动态添加、切换和禁用多个适配器，使用 &lt;code>model.add_adapter()&lt;/code> 和 &lt;code>model.set_adapter()&lt;/code> 等方法，这为构建灵活的多任务系统提供了极大的便利。&lt;/li>
&lt;/ul>
&lt;h2 id="7-">7. 总结&lt;/h2>
&lt;p>LoRA 作为一种革命性的参数高效微调技术，成功地解决了大模型时代微调成本高昂的难题。它通过巧妙的低秩分解思想，在保证微调效果的同时，极大地降低了对计算资源和存储的需求。结合 vLLM 等先进的推理引擎，LoRA 的部署和服务也变得前所未有的高效和灵活，正在推动大模型在更多特定场景下的落地和应用。&lt;/p></description></item></channel></rss>