<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>AI 基建 on 搬砖程序员带你飞</title>
        <link>https://lpflpf.cn/tags/ai-%E5%9F%BA%E5%BB%BA/</link>
        <description>Recent content in AI 基建 on 搬砖程序员带你飞</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-CN</language>
        <managingEditor>lipengfei634626165@163.com (lpflpf)</managingEditor>
        <webMaster>lipengfei634626165@163.com (lpflpf)</webMaster>
        <lastBuildDate>Thu, 22 Oct 2026 07:30:00 +0800</lastBuildDate><atom:link href="https://lpflpf.cn/tags/ai-%E5%9F%BA%E5%BB%BA/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>temperature=0 也复现不了的 bug：DeepInfer 把「确定性」拆成三层，多数人只开了第一层</title>
            <link>https://lpflpf.cn/posts/deepinfer-determinism-2026-10-22/</link>
            <pubDate>Thu, 22 Oct 2026 07:30:00 +0800</pubDate><author>lipengfei634626165@163.com (lpflpf)</author>
            <guid>https://lpflpf.cn/posts/deepinfer-determinism-2026-10-22/</guid>
            <description>&lt;img src=&#34;https://cdn.lpflpf.cn/covers/deepinfer-determinism-2026-10-22-v1-plain.png&#34; alt=&#34;Featured image of post temperature=0 也复现不了的 bug：DeepInfer 把「确定性」拆成三层，多数人只开了第一层&#34; /&gt;&lt;p&gt;评测集上个月 62.3，这个月 61.8，代码没改，模型没换。你把那条掉分的 case 捞出来，用同样的 prompt 在本地跑五遍，五遍五个结果。&lt;/p&gt;&#xA;&lt;p&gt;多数人的处理方式是加个 &lt;code&gt;temperature=0&lt;/code&gt;，或者干脆认了：&amp;ldquo;大模型本来就有随机性。&amp;ldquo;然后重试取多数、放弃分数的可比性、线上 badcase 复现不了就搁着。&lt;/p&gt;&#xA;&lt;p&gt;DeepSeek 上周把内部推理栈 DeepInfer 开源了。仓库七天涨了 17757 star，但 HN 上 881 条评论大半在争&amp;quot;推理到底赚不赚钱&amp;rdquo;。夹在中间真正值钱的东西只有一句 README 注释：把 &lt;code&gt;DEEPINFER_BATCH_INVARIANT=1&lt;/code&gt;、&lt;code&gt;DEEPINFER_ENABLE_MTP_VARLEN=0&lt;/code&gt; 和固定的 &lt;code&gt;seq_seed&lt;/code&gt; 三项同时满足，才能拿到逐 token 可复现（并且注明 NVIDIA only）。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;因为&amp;quot;确定性&amp;quot;从来不是一个开关，是三层互不包含的性质。&lt;/strong&gt; 这篇文章把它拆开，给你一张能对着自己启动脚本查的表。&lt;/p&gt;&#xA;&lt;p&gt;先划清边界：这套栈门槛很高——SM100 或 Ascend 950、GCC≥13、Python 3.12、CUDA 13 或 CANN 9.2、源码编译没有 pip 包，只支持一个默认 checkpoint。&lt;strong&gt;绝大多数人的机器跑不了，也别为这个迁移框架。&lt;/strong&gt; 但&amp;quot;确定性分几层&amp;quot;这件事，跟你用什么框架无关。&lt;/p&gt;&#xA;&lt;h2 id=&#34;temperature0-只关掉了采样噪声没关掉算术&#34;&gt;&lt;code&gt;temperature=0&lt;/code&gt; 只关掉了采样噪声，没关掉算术&#xA;&lt;/h2&gt;&lt;p&gt;大部分人脑子里的随机性来源只有一个：采样。温度不为零，每次都从分布里抽签，所以结果不同。温度归零，永远取 argmax，于是&amp;quot;确定&amp;quot;了。&lt;/p&gt;&#xA;&lt;p&gt;这个理解只覆盖了第一层。&lt;/p&gt;&#xA;&lt;p&gt;实际上一路走到 token id 出来，至少经过三个会引入不确定性的地方：&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;采样层&lt;/strong&gt;。从 logits 里挑哪个 token。这里的随机性来自随机数生成器的状态。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;前向层的浮点归约&lt;/strong&gt;。GPU 算矩阵乘、算 attention，是把很多数加起来。加法在浮点里不满足结合律，那么一批数据切成几块、哪一块先累加，末几位就不一样。末几位一旦不同，两个非常接近的候选 token 的排序可能翻转——于是 argmax 给出不同的 id。&lt;strong&gt;这就是为什么 temperature=0 不等于可复现&lt;/strong&gt;：你关掉的是抽签，没关掉算术。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;硬件与并行度层&lt;/strong&gt;。换卡、换驱动、换 CUDA 版本、换张量并行度，数值全部重新洗一遍。&lt;/p&gt;&#xA;&lt;p&gt;三层互不包含。第二层对了第一层不对，结果照样飘；第一层第二层都对了，换台机器还有可能漂。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;确定性推理的三层：采样层由 seq_seed 决定；前向层由归约顺序决定，DeepInfer 提供 batch-invariant 开关但仅限 NVIDIA；硬件与并行度层没有框架级开关，只能自建数值基线&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;321px&#34; data-flex-grow=&#34;133&#34; height=&#34;896&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://cdn.lpflpf.cn/images/posts/deepinfer-determinism-layers-2026-10-22.png&#34; srcset=&#34;https://lpflpf.cn/deepinfer-determinism-layers-2026-10-22_11260957667949195285_hu_dc20e2beade77ae5.png 800w, https://cdn.lpflpf.cn/images/posts/deepinfer-determinism-layers-2026-10-22.png 1200w&#34; width=&#34;1200&#34;&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;图注：每一层的不确定性由不同东西决定，所以开关也必须分开验收。依据 DeepInfer README 与源码整理。&lt;/p&gt;&#xA;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;把确定性当成&amp;quot;这一项解决了没有&amp;rdquo;，你永远查不到是哪儿漏的；把它当成三层，你才知道该在哪一层下断言。&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;采样能被钉死因为每个-token-只用自己那把钥匙&#34;&gt;采样能被钉死，因为每个 token 只用自己那把钥匙&#xA;&lt;/h2&gt;&lt;p&gt;DeepInfer 的采样实现里有一句 docstring，写得非常坦白：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Deterministic in (seq_seeds, sample_positions, is_nextn_predict):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;independent of batch size and row order&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;可复现的输入是三个：seed、位置、是否在投机解码的草稿阶段。输出跟 batch 大小、行顺序无关。&lt;/p&gt;&#xA;&lt;p&gt;为什么它天生跟 batch 无关？因为实现里每个 token 行开一个独立的 CTA，各自初始化自己的随机数流：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;T&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rng_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;seed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;seq&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;seq&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sample_positions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;row&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sample_case&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;随机数种子不是&amp;quot;一批里第几个&amp;quot;，而是&amp;quot;第几个位置&amp;quot;。第 7 个 token 的钥匙，不管这批是 1 条还是 8 条，永远是同一把。&lt;code&gt;N_CHUNKS = ceildiv(vocab_size, BD)&lt;/code&gt; 这个切分参数只跟词表大小有关（vocab ≥ 8192 时走 threads=256、bd=2048），&lt;strong&gt;跟 batch 无关&lt;/strong&gt;。所以这里不存在&amp;quot;整行跨 CTA 归约&amp;quot;的操作，也就没有归约顺序可变这回事。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;is_nextn_predict&lt;/code&gt; 那一位要单独换条流，是为了避免投机解码的草稿 token 跟正式 token 在同一个位置上拿到同一把钥匙——不然草稿和验证会用同一组随机数。&lt;/p&gt;&#xA;&lt;p&gt;这一层为什么容易做对？因为它&lt;strong&gt;没有跨行归约&lt;/strong&gt;，天然批不变。而前向层不是。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;反过来说：这一层如果没配好，你连第一层都不算开了。&lt;/strong&gt; &lt;code&gt;sampling_params.py&lt;/code&gt; 里 seed 的处理是这样的：&lt;code&gt;seed=None&lt;/code&gt; 时用 &lt;code&gt;random.getrandbits(64)&lt;/code&gt; 现生成一个。&lt;strong&gt;你不传 seed，它不会报错，也不会警告，就是每请求随机一次。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;要钉死前向就得钉死归约顺序这就是-nvidia-only-的来由&#34;&gt;要钉死前向，就得钉死归约顺序——这就是 NVIDIA only 的来由&#xA;&lt;/h2&gt;&lt;p&gt;前向层的不确定性，来源是把归约切成几块。split-k 这类 kernel 会按当前 batch 的形状决定切分方式：同样一个矩阵乘，batch 里塞 1 行和塞 8 行，可能选到不同数量的 split，累加顺序跟着变，浮点末几位跟着变。&lt;/p&gt;&#xA;&lt;p&gt;要让结果跟 batch 组成无关，只有一个办法：把切分方式固定死，不管这一批多大多小都用同一套归约树——也就是 batch-invariant。这样做等于放弃掉一部分动态调优的空间，有些形状会更慢。&lt;/p&gt;&#xA;&lt;p&gt;README 明确标注 batch-invariant 只在 NVIDIA 上提供。&lt;strong&gt;Ascend 侧能跑这套栈，但这个性质没有承诺。&lt;/strong&gt; HN 上有条评论问 Ascend 950 的采购价，没人回答——成本数据目前是空白。&lt;/p&gt;&#xA;&lt;p&gt;NVIDIA 也有个例外：官方 Q&amp;amp;A 文档自己承认 decoder 侧的 SWA replay 用的是 &lt;strong&gt;approximate&lt;/strong&gt; SWA KV cache，只重算最后 128 个 token（精确重建要 2560 token × 20 层）。这是近似值，跟 batch 无关——意味着&lt;strong&gt;即使你把两个开关都开了，换机器、换上下文长度的边界，分数仍可能动&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;顺带说一个容易被忽略的读法：这套栈开源了三块关键组件没给——KV cache 系统、E/P/D 分离、DP 负载均衡，官方原话是这三块&amp;quot;tightly coupled to our internal infrastructure&amp;quot;。&lt;strong&gt;所以它是能跑通的推理引擎，不是能直接替掉你线上 vLLM 的完整服务。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;官方把数值变了做成了要走流程的变更而它的示例脚本还没走这条路&#34;&gt;官方把「数值变了」做成了要走流程的变更，而它的示例脚本还没走这条路&#xA;&lt;/h2&gt;&lt;p&gt;这套栈里我最认同一件事，是它怎么对待&amp;quot;数值变了&amp;quot;。&lt;/p&gt;&#xA;&lt;p&gt;仓库里有一份 PPL 基线文件，注释写着逐样本精确比较（compared exactly sample by sample）。要改基线不能手改 JSON，得跑 &lt;code&gt;refresh_offline_decode_ppl.py&lt;/code&gt; 重新生成；那个脚本的 &lt;code&gt;--output&lt;/code&gt; 参数只支持单节点，多节点会直接报错让你走默认路径。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;翻译成团队语言就是：数值变化是要签字的。&lt;/strong&gt; 你在用自己的推理栈，也可以抄这个制度——把&amp;quot;某次升级后评测分数变了 0.5 分&amp;quot;从&amp;quot;大概是随机波动&amp;quot;变成&amp;quot;谁的 PR 动了它，给个理由&amp;quot;。&lt;/p&gt;&#xA;&lt;p&gt;但有意思的地方在下一层。&lt;/p&gt;&#xA;&lt;p&gt;README 给的确定性条件是三项同时成立：&lt;code&gt;BATCH_INVARIANT=1&lt;/code&gt;、&lt;code&gt;MTP_VARLEN=0&lt;/code&gt;、固定 &lt;code&gt;seq_seed&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;我去翻了它的示例脚本：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;offline_inference.py&lt;/code&gt; 里确实设了 &lt;code&gt;BATCH_INVARIANT&lt;/code&gt;，但写法是 &lt;code&gt;setdefault&lt;/code&gt;，而且加了 &lt;code&gt;if accelerator_kind() == &amp;quot;nvidia&amp;quot;&lt;/code&gt; 的判断——非 NVIDIA 静默跳过，不报错。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;_prompts.py&lt;/code&gt; 里确实给了 &lt;code&gt;seq_seed=i&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;但整个 examples 目录 grep 不到 &lt;code&gt;MTP_VARLEN&lt;/code&gt;&lt;/strong&gt;。&lt;code&gt;_config.py&lt;/code&gt; 里只 setdefault 了 &lt;code&gt;USE_NEXTN_DECODE=5&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;按 README 的字面条件，这条示例路径只满足了&amp;quot;两条半&amp;quot;。这不构成框架的 bug——示例脚本不是评测脚本，严格度本来就不一样。但足够说明一件事：&lt;strong&gt;&amp;ldquo;仓库提供了这个能力&amp;quot;和&amp;quot;你的运行路径享受到了这个能力&amp;quot;之间，隔着一段没人替你填的距离。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;顺带提一句它的测试：&lt;code&gt;tests/models/test_sampler.py&lt;/code&gt; 是验采样分布正确性的，它自己也设置 &lt;code&gt;BATCH_INVARIANT=1&lt;/code&gt;，但它验的是&amp;quot;从分布里抽出来的东西分布对不对&amp;rdquo;，不是&amp;quot;两次运行逐 token 一样&amp;quot;。&lt;strong&gt;别把测试通过当成确定性成立&lt;/strong&gt;——这两件事在同一份代码里，但不是同一件事。&lt;/p&gt;&#xA;&lt;h2 id=&#34;你能抄走的不是那两行变量&#34;&gt;你能抄走的不是那两行变量&#xA;&lt;/h2&gt;&lt;p&gt;先给那张表。四类不确定性，逐个说清谁管、怎么验：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;采样噪声&lt;/strong&gt;：由随机数流决定。验法：固定 &lt;code&gt;seq_seed&lt;/code&gt; 跑两遍，比 &lt;code&gt;token_id&lt;/code&gt;。拿不到固定 seed 的 API，这一层就无解——很多托管服务根本不让你传 seed。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;前向浮点&lt;/strong&gt;：由 kernel 归约顺序决定。验法：固定 seed 和 prompt token ids，跑两遍不同 &lt;code&gt;max_num_seqs&lt;/code&gt;（1 和 8），比 &lt;code&gt;token_logprobs&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;并行度变化&lt;/strong&gt;：由张量并行/数据并行配置决定。验法：改一次并行度，跟基线比 logprob。这一层没有框架级开关，只能靠自建基线。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;硬件驱动变化&lt;/strong&gt;：换卡、升 CUDA、升驱动。验法同上。这一层连 batch-invariant 都保不了。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这张表最有用的一条，是那个&lt;strong&gt;二分法&lt;/strong&gt;：&lt;/p&gt;&#xA;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;两次运行序列不一致 → 采样层出了问题。序列一致但 logprob 不一致 → 前向层在漂，采样层是干净的。&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;p&gt;这比&amp;quot;跑一遍看着差不多&amp;quot;有用得多，因为它直接告诉你去翻哪个开关。前者查 seed 有没有传、MTP_VARLEN 有没有关；后者查 batch 是否变了形状、并行度有没有动。&lt;/p&gt;&#xA;&lt;p&gt;第二个能带走的是启动脚本体检。四条 grep 就够：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;BATCH_INVARIANT&lt;/code&gt;——有没有设？设了是不是 &lt;code&gt;setdefault&lt;/code&gt;，被别处覆盖了？&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;MTP_VARLEN&lt;/code&gt; 和 &lt;code&gt;USE_NEXTN_DECODE&lt;/code&gt;——投机解码是开着还是关了？&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;seq_seed&lt;/code&gt;——是每请求固定传的，还是落到默认路径随机生成？&lt;/li&gt;&#xA;&lt;li&gt;seed 从哪来——如果代码里有 &lt;code&gt;seed=None&lt;/code&gt;，它实际是 &lt;code&gt;getrandbits(64)&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;最后这条最阴。&lt;strong&gt;它不报错，不警告，跑了也不异常，只是你所有关于可复现的假设都失效了。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;至于性能代价，诚实讲：&lt;code&gt;MTP_VARLEN=0&lt;/code&gt; 等于放弃变长验证的收益，官方 benchmark 表里 conc=16 时是 −1.5%、conc=60 时 +5.4%、conc=96 时 +11.0%（EP64/DP64 配置）。&lt;strong&gt;低并发几乎不亏，高并发才疼&lt;/strong&gt;——所以小集群做评测和回归时开着确定性，生产高并发关掉，是完全说得通的用法，不必一刀切。&lt;/p&gt;&#xA;&lt;p&gt;那谁该认真对待这件事？&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;8 卡自建的团队&lt;/strong&gt;：你现在拿不到 batch-invariant（那要 SM100，且这套栈门槛不止于此），但你今天就能做的是两件便宜事——写一个&amp;quot;同 prompt 跑两遍比 token id&amp;quot;的脚本进 CI，把数值变化当变更管理。这两件不需要换框架。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;几十卡以上的推理平台&lt;/strong&gt;：batch-invariant 才有讨论价值，因为你们的 batch 形状在动态变化，split-k 切分跟着变是真实存在的分数漂移源。但也别急着迁——它只支持一个模型，缺 KV cache 与 PD 分离、缺 DP 负载均衡，这三块恰恰是生产里最难自己补的。&lt;/p&gt;&#xA;&lt;p&gt;对绝大多数人，正确的动作是&lt;strong&gt;去 grep 自己现在的启动脚本&lt;/strong&gt;。你可能发现你以为开着的确定性，压根没开；也可能发现你从来没传过 seed，一直在拿随机的钥匙，跟&amp;quot;模型本来就有随机性&amp;quot;这个说法和平共处了半年。&lt;/p&gt;&#xA;</description>
        </item></channel>
</rss>
