
从年初到现在我几乎每个月都会被问到同一个问题推理框架怎么适配 Hybrid Model。问的人里有刚接触大模型推理的算法工程师也有部署运维的老手。他们手里的模型五花八门但核心词几乎都是 MoE混合专家、混合注意力结构这类“不是标准 Transformer 全家桶”的模型。很多人拿到一个 MoE 模型第一反应就是直接丢进 vLLM 里跑结果发现显存占用、吞吐表现和预期差得远甚至不如自己用 transformers 写个脚本来得顺。这篇文章不聊论文复现也不做框架源码逐行解析就从一个部署者的角度讲讲 Hybrid Model 到底在推理框架眼里特殊在哪、框架为了适配它改了什么以及我们在实际环境下怎么调参、怎么排坑。适合同样在跟 MoE、Mamba、混合注意力模型死磕的工程同学参考。1. 先搞清楚 Hybrid Model 到底指什么1.1 推理实践中最常见的几种 Hybrid Model 形态“Hybrid Model”在学术语境里含义很宽泛注意力机制混合、词嵌入混合、损失函数混合都算。但放到推理框架适配这个场景下真正让框架底层逻辑大改的只有两类第一类是MoEMixture of Experts混合专家模型比如 Mixtral 8x7B、DeepSeek-V3 这种。它的特点是把 FFN前馈网络层扩展成多个并行的专家子网络每个 token 只经过少数几个专家。模型总参数量看着吓人但每次前向计算只激活一小部分权重。第二类是混合注意力模型比如 Jamba、Zamba 这类把 Transformer 注意力层和 Mamba线性注意力层在模型结构上交替堆叠的模型。这种 Hybrid 的核心是一部分层使用传统的 KVCache 注意力机制另一部分层使用固定大小的状态变量来压缩历史信息完全没有 KVCache。这两类模型有一个共同点它们都不是“一层套一层”的标准结构而是带分支、带路由、带不同状态管理的复杂结构。这给推理框架带来的麻烦是本质性的不是多加点显存就能解决。1.2 为什么传统推理框架面对 MoE 会水土不服先说一个很多人忽略的事实HuggingFace transformers 是可以跑 MoE 模型的而且代码写起来很简单。但如果你真的在生产环境这么干吞吐会惨到没法看。原因很直接transformers 的推理是逐层 Python 调度每个 token 都要动态决定去哪几个专家然后循环加载专家权重。当模型里有几十上百个专家时这种 Python 层的调度开销会被放大到完全不可接受。推理框架要解决的核心问题就是把这个“动态、带分支”的计算图尽量变成高效、可复用的图结构并在 GPU 显存和通信层面做针对性优化。比如vLLM、SGLang、TensorRT-LLM这些框架对 MoE 的适配主要做了三件事把专家权重按特定方式切分和排布、把 token 到专家的调度做成连续且内存友好的操作、把不同的请求在专家维度上做合并计算。这背后还有一个所有做推理的人都会关心的点MoE 模型虽然总参数大但单个 token 的计算量并不大。这意味着MoE 推理往往是显存瓶颈和调度瓶颈而不是纯算力瓶颈。传统框架的优化思路集中在算力利用率上面对 MoE 时代需要转换重心。这是理解下文所有技术方案的出发点。提示如果你拿到一个 MoE 模型第一反应是“它参数多所以算力要求高”那后面大概率会走弯路。MoE 的真正矛盾在于“显存放不下全部专家”和“喂不饱 GPU 算力”同时存在。2. 框架适配 MoE 的核心技术路径2.1 Expert Parallel把专家真正放平而不是复制到每张卡推理框架适配 MoE 最关键的一项技术改造是引入Expert ParallelEP专家并行。传统的数据并行Data Parallel很简单每张 GPU 上都放一份完整模型各自服务不同的请求批次。但对 MoE 模型来说这个方案极其浪费。以 Mixtral 8x7B 为例总参数约 47B如果以 BF16 精度存储权重大约 94GB。你用 4 张 80GB 的卡做数据并行每张卡都要完整放下这 94GB显存利用率低得离谱。EP 的思路完全不同既然每个 token 只经过 2 个专家Top-2 路由那我为什么非要在每张卡上保留全部 8 个专家把专家们拆开分布到不同卡上每张卡只负责一部分专家路由时把 token 发给对应专家所在的卡。这样 8 张卡跑 8 个专家的模型每张卡只需要放 94/8 ≈ 12GB 的专家权重真正做到了“按需存储”。EP 的实现难点在于通信模式的改变。专家分布在不同的 GPU 上token 在层与层之间就要跨卡传输。框架需要把注意力层和 MoE 层之间的数据流转从“本地张量计算”改成“远程张量收发”这个过程在工程上叫All-to-All 通信。2.2 Token Routing 与 All-to-All 通信从数据流角度重新设计执行图现在聊一下 Token 是怎么在 MoE 层流动的这直接决定了框架执行图长什么样。一个 token 在注意力层计算完后进入 MoE 层的第一步是过Gate门控网络。Gate 会为每个 token 计算一个“该去哪几个专家”的分数然后选出 Top-k 个专家。第二步是根据路由结果把这一批请求中的所有 token 重新分组要发往同一个专家的 token 打包在一起这个动作就是Dispatch。第三步各个专家在自己的卡上处理完这批 token 后结果需要送回原来的位置供下一层注意力计算使用这个动作叫Combine。从框架角度看Dispatch 和 Combine 的本质是按 token 对数据进行重排同时必然伴随跨卡数据传输。以 vLLM 为例它在 DeepSeek 系列模型上已经开始支持 EP 模式核心执行图里就内置了这种 token 分组和跨卡收发逻辑。SGLang 对 MoE 的支持同理并且为了压低 Dispatch 延迟做了很多内核级优化。这里面有一个简单但很关键的数学关系需要讲清楚。假设一批请求里有 N 个 token模型有 E 个专家每个 token 激活 Top-k 个专家。那么这批 token 在 MoE 层的计算关系总量是 N × k和 E 无关。换句话说MoE 的计算量主要由激活专家数决定而不是总专家数。这也意味着在 EP 场景下真正的性能调节杆是 k 值、batch 大小、通信带宽三者的配合。2.3 显存究竟省在哪又多出哪些开销很多人有一个误区认为 EP 一定比 DP 快。实际上 EP 主要省的是显存算力本身并不会因为 EP 变高反而可能因为通信开销变慢。合理的框架适配要做的是让 EP 的显存收益最大化同时让通信开销可控。具体拆开看省下来的显存专家权重无需全量复制到每张卡上省下来的显存可以用来增大 KV Cache 存储区、增加并发请求数、容纳更长的上下文。在长文本场景下这收益非常明显。多出来的开销每层 MoE 都要做一次 All-to-All跨卡传输 token 的中间激活值。通信量和 batch size 成正比和序列长度也有关系。卡间通信走 NVLink 时延迟较低跨节点走 RDMA 网络时开销显著上升。所以框架适配 EP 时通常会让用户配置TPTensor Parallel和 EP 的组合比例。比如 8 卡环境你可以设 TP4、EP2也可以 TP1、EP8。前者通信局部性更好但每张卡显存压力更大后者显存最省但通信压力最大没有绝对正确只有适合场景的方案。这部分我会在第三节展开讲实际配置。3. 推理框架适配 Hybrid Model 的实操与部署参数3.1 一个具体案例8 卡环境部署 671B 级 MoE 模型的参数估算下面我用一个具体例子带你走一遍部署时的参数推理过程这里以 DeepSeek-V3 这类结构的模型为例说明计算方法不说具体品牌也能直接套用。DeepSeek-V3 总参数约 671B但激活参数只有约 37B。它用了 MLAMulti-head Latent Attention来压缩 KV Cache同时用共享专家 256 个路由专家的结构。如果以 BF16 精度部署671B × 2 字节 ≈ 1.34TB 权重。8 张 H800 80GB 显卡的总显存是 640GB显然放不下。如果做 FP8 量化权重降到约 671GB8 卡总量还是略吃紧而且显存完全没有余量给 KV Cache 和激活值。所以实际部署必然要拆到更多卡或者用 DeepSeek 官方给出的优化方案——把 MLA 和 MoE 层做特殊排布再配合更激进的量化。这个案例说明一个道理适配 MoE 模型显存规划是第一优先级。你拿到一个模型先别急着想吞吐先算清楚“权重占多少、激活占多少、KV Cache 要留多少、通信要占多少带宽”再决定 EP 和 TP 怎么切。我建议所有做推理的人养成一个习惯部署前先把显存规划写成一页纸。权重占用模型总参数 × 每参数字节数、KV Cache 预估与 batch size、序列长度、层数、注意力头维度相关、激活值余量一般预留 20%–30%、通信缓冲区All-to-All 需要额外 buffer这四项加起来必须明显小于单卡显存否则后面跑起来必然 OOM。3.2 三个必须理解的配置项top-k、专家容量、负载均衡 lossMoE 模型部署时有参数虽然名字看起来和推理框架没关系但实际效果影响极大。第一个是 top-k 路由数量。这个值在模型训练时就已经定了推理时一般不能改因为改了会破坏训练时的路由分布。但你要理解它的意义k 越大每个 token 激活的专家越多算力消耗越大显存周转越紧张。k2 是主流选择少数模型用 k3 甚至动态 k。第二个是专家容量expert capacity。这是推理框架调度中的一个核心概念每个专家在处理一个 batch 时能容纳的最大 token 数。因为 token 路由是动态的热门专家可能被分到远多于平均值的 token。如果框架严格按照“每个专家处理相同数量的 token”来预分配缓冲区那必然有一部分 token 会被丢到 overflow溢出通道而溢出通道通常走残差直连等价于这些 token 没经过专家计算模型质量会受影响。实际配置时框架一般允许设置 capacity factor比如 1.0、1.2。我建议在线服务场景设为 1.1 左右既不大幅浪费显存也不会频繁触发 overflow。如果是离线打分、质量要求高的场景可以设 1.5 甚至更高让每个专家有充足余量。这里没有标准答案只有“调试出来的答案”。第三个是负载均衡 loss很多同学会误以为这是训练时才用的东西。其实推理框架做 EP 显存排布时会参考训练时的路由统计。如果一批 token 在 Gate 上严重偏向少数热门专家EP 方案就会闲置大量“冷门专家”所在的显存和计算资源。你可以通过框架的 profiling 工具观察路由分布如果发现明显不均衡先检查是不是输入数据分布太窄再考虑是否需要动态路由策略。3.3 量化与 KV Cache 的适配策略MoE 模型的量化比 Dense 模型更讲究原因在于专家权重有很强的“独立性”。你量化一个专家时的精度损失只影响走这个专家的那部分 token而不是整个模型均匀退化。这既是坏事也是好事。实操中我建议对 MoE 模型采用分专家量化的策略热门专家用高精度比如 FP8冷门专家可以适当降低精度。框架层面vLLM 和 TensorRT-LLM 都支持 per-tensor 或 per-group 的权重量化但当你切换到 EP 模式后量化格式和通信格式必须对齐。比如你用了 INT8 权重但 All-to-All 传输的是 BF16 激活值那么通信时还得做一次反量化或者提前转换这里有额外开销要计入总时延。KV Cache 方面MoE 模型因为注意力参数占比相对小KV Cache 压力通常小于同规模 Dense 模型。如果你部署的 MoE 还用了 MLA/GQA 这类压缩 KV Cache 的结构那显存大头会集中在专家权重上KV Cache 反而不是瓶颈。不过有个反直觉的点KV Cache 变小后模型的吞吐上限更多由 batch size 和专家通信带宽决定而不是显存。换句话说你留出一大块 KV Cache 显存实际根本用不完还不如减少并发把单请求延迟拉低。4. 混合线性注意力模型的适配新问题4.1 为什么混合注意力模型也属于 Hybrid Model 的适配范畴第二类 Hybrid Model 是 Mamba 结构纯线性注意力与 Transformer 注意力结构混合的模型。这类模型在推理框架里遇到的适配问题和 MoE 完全不同它挑战的是“两种形态的内存管理”。Transformer 层的注意力需要显式保存 KVCache并且 KVCache 的大小随序列长度增长。Mamba 层则完全不同它维护一个固定大小的状态变量比如 16 × 64 的矩阵每读一个 token 就更新一次状态不产生随序列增长的缓存。因此一个 Jamba 这样的模型推理过程中同时存在“随序列增长的 KVCache”和“固定不变的状态变量”两种内存结构。推理框架适配这类模型时不能只按处理 Transformer 的结构来设计 buffer 管理。Mamba 的状态变量需要常驻显存、逐 token 更新而且状态更新的依赖关系是串行的——当前 token 的状态依赖于前一个 token 的计算结果这导致线性注意力部分天然难以做并行加速框架需要额外设计卷积核和分段扫描chunked scan策略来弥补。4.2 框架具体需要为线性注意力层做哪些事这里以 Mamba2 为例展开细节不堆代码但原理值得说透。Mamba 层的计算有两大块离散卷积 分段递归。离散卷积本质上是局部窗口操作可以很好地并行化分段递归才是真正的难点。分段递归的思路是把很长的序列切成若干 chunk在每个 chunk 内部先并行推进部分步骤再把 chunk 之间的状态依赖关系串行整合。推理框架为此需要实现一个专门的融合内核把“状态更新 权重矩阵乘法 非线性激活”合并到同一个 kernel 里否则每步都启动多个 kernel延迟根本压不下去。另一个让框架头疼的是Mamba 的状态更新在 decode 阶段必须强制串行这会导致显存利用率降低。框架层面对此的适配方案是更大胆的请求合并batching把多个请求的状态更新矩阵拼在一起做批量更新尽量把串行 GPU kernel 的启动开销摊薄到更多请求上。4.3 生产框架对混合注意力模型的支持现状坦白说截止到目前开源主流框架对这类模型的支持水平还远不如 MoE 成熟。vLLM 的 Mamba 支持处于实验性阶段SGLang 对基于 Mamba 的模型支持也相对有限TensorRT-LLM 的 Mamba 支持度高一些但仍集中在固定长度和特定配置下比较稳。所以我给这类 Hybrid 模型的适配建议是先想清楚你是追求多高吞吐还是只要跑通就行。如果只是验证模型效果直接用 transformers 原生推理能接受慢一点如果真要部署优先选有 Mamba 内核支持的框架并且做足 benchmark不要假设它和 Transformer 的部署一样“开箱即用”。注意混合注意力模型目前最大的坑不在显存容量而在框架对不同状态结构的兼容度。动手前先去框架官方文档看它支持哪些模型架构版本能省掉大量排错时间。5. 常见问题与排查技巧实录5.1 为什么我的 MoE 推理速度还不如同参数量的 Dense 模型这个问题的答案基本只有三个一是 token 路由不均导致专家空闲二是专家权重反复在显存和计算单元间搬运三是通信开销没有摊薄。逐个排查方法如下路由不均开启框架的 profiling打印每个专家的实际 token 分布。如果热门专家和冷门专家的负载比超过 3:1说明路由本身就偏优先考虑是不是 prompt 分布太单一。不要急着换框架先把输入数据分布捋一捋。权重搬运严重MoE 层如果没能把一批 token 的专家调用合并成大的 GEMM 运算而是每个 token 逐个调专家GPU 的算力利用率会掉到个位数。检查框架日志里的吞吐数据若 decoder 阶段吞吐远低于预期多半是 batch 太小导致专家合并度不够。通信瓶颈EP 模式下跨卡通信量太大。如果部署环境跨节点优先把通信密集的层尽量放在节点内部。5.2 专家负载不均衡的实际处理我跑 Mixtral 8x7B 时遇到过 Gate 输出几乎完全偏向两个专家的情况。一开始以为是模型问题后来定位到是测试集太窄——大量相似结构的 prompt 导致路由坍缩。处理办法有两个方向如果输入数据可控制做 prompt 多样性增强如果数据固定不可改就在调度侧引入专家负载感知的排队策略把不同路由倾向的请求混合进同一个 batch。这比调模型权重更实际。框架层面SGLang 在 batch 构造时考虑路由分布的整合策略效果比纯随机拼 batch 好不少。5.3 显存充足时如何进一步压榨吞吐显存如果充足最直接的收益来自增大 batch 和启用持久化 batchcontinuous batching。MoE 模型有个好处由于专家是分布的大 batch 能把每个专家要处理的 token 数堆起来专家计算块的矩阵规模变大GPU 利用率显著提升。我实测过一个 8 卡环境下的大 MoE 模型batch 从 64 提到 256吞吐提升远超线性就是因为专家 GEMM 的规模效应。另外可以尝试调高 decode 阶段的预填充prefill合并策略让首 token 延迟和吞吐得到更好的平衡。框架一般有相关开关但注意不同框架对 prefill 和 decode 合并的调度策略不同换框架时不能沿用同一套参数。5.4 不同推理框架如何选择这是一个永远有人问的话题我不好说“框架 A 一定比框架 B 好”只能说按模型类型和场景来筛。模型类型vLLMSGLangTensorRT-LLM说明稠密 Transformer稳定稳定高性能随便选MoE较小规模支持完善支持完善支持较好选熟悉度高的即可MoE超大规模大规模部署案例多路由优化积极企业级优化强建议先做小规模验证Mamba/混合注意力实验性支持有限支持定向支持较好提前确认模型版本选型建议是主流的 MoE 模型优先考虑 vLLM 或 SGLang社区案例多、坑容易搜到企业环境或有特定加速芯片时再看 TensorRT-LLM 这类闭源优化引擎。如果模型规模大到单机装不下多机通信方案比框架选型更关键优先把组网方案敲定再谈框架。5.5 部署过程中遇到过的两个诡异问题最后分享两个我印象深刻的排错实录都是从百度和各路社区里查不到、只能靠看源码定位的。第一个问题是MoE 模型在 FP8 量化后batch 大时偶发 NaN。排查了整整两天最后定位是某几个专家的权重分布范围比其他专家大量化到 FP8 时极值被截断导致特定 token 的计算结果溢出。解决方式是改为按专家分组做动态缩放而不是全模型统一缩放。第二个问题是EP 模式下跨节点通信频繁超时。表面看是网络配置问题实际原因是指定 EP 时没有关闭框架的隐性权重处理功能导致某些层仍在做非必要的 All-Gather。把相关开关手动关闭后通信量下降接近一半。这两个案例说明一个事实框架适配 MoE 不是“填几行 yaml 就能跑”的事你得理解框架在 EP、路由、调度三个层面分别做了什么以及这些行为在你具体的模型和数据上会带来什么后果。我个人这几年的经验是做 Hybrid Model 推理第一步永远是算显存账第二步是跑 profiling 看路由和通信第三步才是调参数。把这三步走稳无论模型是 MoE、Mamba 混合还是日后出现的新结构你都能快速找到一个“不优雅但能上线”的适配方案比照抄任何一份官方模板都管用。