最近在帮一家制造企业做内部知识库问答平台的底层模型部署,整个项目从模型选型到上线用了三周左右。最后落地的方案是 Qwen3.5-Plus,核心推理模型用的是 Qwen3.5 LLM 系列里的 Qwen3.5-397B-A17B。这个案例比较有代表性:业务方要求数据绝对不能出内网,并发要求不低,运维团队又没有专职的大模型工程师。今天把整个过程拆开来讲,包括为什么选这个模型、显存怎么算、推理服务怎么调、有哪些坑必须避开。不管你是刚要评估私有化大模型,还是已经在部署途中,这份实操记录应该都能用上。
1. 部署需求与方案选型:为什么最终锁定 Qwen3.5-Plus
1.1 项目背景与核心诉求
先说背景。某制造企业要做企业知识库问答,产线技术文档、维修手册、质量报告散落在多个系统。业务侧想做一个统一入口,让一线工程师可以直接用自然语言问 SOP、查故障代码。数据安全要求很硬:所有语料只能在内网流转,不能碰外网 API。所以私有化部署是必选项,不是可选项。
业务侧还给了几个硬指标。高峰期大约同时 50 个人在用,回答要能引用来源,不能凭空编工艺参数。换句话说,模型的“知识容量”和“检索跟随能力”比单条回答的华丽程度更重要。团队评估下来,决定不再纠结更小的 7B/14B 模型,直接看能支撑生产级效果的 MoE 大模型。另外团队里只有两三个后端工程师,没有专职算法人员,所以方案必须足够成熟、可维护,不能搞成一次性实验。
1.2 模型选型对比:稠密模型、MoE 模型与 Qwen3.5-397B-A17B
选型时我们列过几个方向。7B/14B 稠密模型部署成本低,但在需要翻长文档、理解复杂故障树时,幻觉率偏高,经常找不到关键参数,一句话里出现多个错误数字,业务方很难接受。70B 级别稠密模型效果好一些,可每一个 token 的前向计算量都很大,在 50 并发下想扛住同样的吞吐,需要堆更多卡,成本并不便宜。
| 方案 | 部署成本 | 单Token推理成本 | 长文档能力 | 结论 |
|---|---|---|---|---|
| 7B/14B 稠密 | 低 | 低 | 弱,易丢细节 | 不适合生产问答 |
| 70B 稠密 | 高 | 高 | 中上 | 成本偏高 |
| Qwen3.5-397B-A17B | 中高 | 低(激活17B) | 强 | 本次选定 |
最后我们把重点放在 MoE 架构上。Qwen3.5-397B-A17B 总参数量是 397B,但每次推理只激活约 17B 参数。打个比方,它像一个大型专家团队,平时所有专家都在“备勤”,真正接到一个问题时只叫相关领域的几个人上场。这样既保留了接近大参数模型的知识容量,又把单 token 的推理成本压到了接近 17B 稠密模型的水平。
我们还比对了同系列里的一些稠密版本。在代码理解、多轮工具调用、长文档抽取这几个内部测试集上,Qwen3.5-397B-A17B 属于明显靠前的一档。企业场景里经常出现几百行日志、几十页技术规范的大上下文,小模型会“看了后面忘前面”,这个 MoE 模型在长文本上的表现能撑住我们的 RAG 方案。最终选它,不是因为它参数最大,而是在算力、效果、运维复杂度之间找到了平衡点。
1.3 私有化部署与 API 调用的成本账
为什么不上 API?最直接的原因是数据合规。客户内部的工艺参数和故障代码属于核心生产信息,明文发送到外部接口早就被安全团队否决了。从成本角度算,API 模式适合调用量起伏不大、对延迟不敏感的场景,而私有化部署是一次性算力投入加固定电费,请求量越大,边际成本越低。
我们当时做了一个简单估算。假设高峰期每月调用 500 万 token 左右,包括检索增强后的长输入和输出,走外部 API 的月度费用是数千元起步,再叠加网络延迟和数据出域风险,长期看并不便宜。私有化部署要买加速卡、准备机房、养运维,看起来门槛高,但模型能力、数据权和响应延迟都握在自己手里。对于要把大模型当核心生产力工具的企业,这笔账通常越算越划算。
2. 硬件规划与环境准备:把显存和算力算清楚再动手
2.1 从参数量到显存需求:一张表算明白
部署大模型的第一步不是拉镜像,而是算显存。Qwen3.5-397B-A17B 虽然激活参数只有 17B,但权重是 397B 的完整集合,GPU 显存必须装得下所有权重。这就是很多人忽略的“激活参数不等于总参数量”。
权重显存很好算。BF16 格式下每个参数占 2 字节,397B 参数大约是 794GB;如果转成 FP8,每个参数 1 字节,大约 397GB。而 KV Cache 是另一笔大开销,取决于层数、隐藏维度、batch 大小、上下文长度和缓存精度。一个常用的估算式是:2 × 层数 × 每层KV维度 × 并发序列数 × 上下文长度 × 每元素字节数,实际部署时可以用模型 config 里的参数代入。
| 配置 | 权重显存 | KV Cache预留 | 总显存需求 | 推荐卡数 |
|---|---|---|---|---|
| BF16权重 | ~794GB | ~160GB | ~954GB | 12-16卡 |
| FP8权重 | ~397GB | ~160GB | ~557GB | 8卡 |
| FP8+短上下文 | ~397GB | ~80GB | ~477GB | 8卡可用 |
以我们最后的生产配置为例,FP8 权重约 400GB,KV Cache 预留 160GB 左右,再加上临时激活值和框架缓冲,整份模型在 8 张 80GB 显存的加速卡上基本占满 640GB。如果坚持 BF16 权重,就需要双节点 16 卡。显存规划的核心结论是:能用 FP8 尽量用 FP8,把省下来的显存留给 Context,比盲目上 BF16 要实用得多。
2.2 算力集群规划与节点拓扑
确定了“FP8 + 8卡”的大方向后,选型时重点看三样东西:单卡显存容量、显存带宽、卡间互联。当时评估的市场主流 80GB 级加速卡都有不错的显存带宽,但真正影响 MoE 模型吞吐的往往是卡间通信。专家并行的 All-to-All 通信非常频繁,节点内部如果走普通 PCIe,多卡并行后通信会成为明显短板。
比较保守的方案是单机 8 卡,节点内使用厂商自带的高速互联,避免跨节点做张量并行。如果后续业务上下文长度继续涨,再考虑双节点 16 卡并配高速远程直接内存访问网络,但那是后话。我们最终部署在单机 8 卡上,主机配了 512GB 内存和 2 块 NVMe 固态盘。CPU 内存主要用来加载权重和做分片缓存,512GB 能给运行留足余量。
2.3 基础软件栈部署:容器、驱动与内核参数
环境部分不要做过多的手工编译,否则后期升级会很痛苦。操作系统用的标准 Linux 发行版,内核参数按 GPU 推理常见要求调整:共享内存调大、打开文件数调大、内存映射数量限制调高。这些不调好,模型一启动就可能莫名其妙报错。
驱动和运行时我们直接用容器方案解决。Docker 加 GPU 容器运行时后,宿主机只需要装好显卡驱动,CUDA 和加速库都锁在镜像里。镜像统一维护,团队可以用同一套镜像在测试环境、预发环境和生产环境之间流转,版本可控。容器启动时记得给足共享内存,PyTorch 的并行加载器非常依赖/dev/shm,实测给 1GB 经常不够,我们直接给到 32GB。
3. 模型获取、格式转换与推理框架选型
3.1 原始权重下载与完整性校验
模型权重的体积不小,FP8 版本也有接近 400GB,下载环节很容易在最后发现文件损坏。我们内部定了一个土规矩:先把所有权重的 SHA256 校验和拉下来,单个大文件下载完立刻校验,不合格就重下,绝不让坏文件进入后续流程。仓库里的模型通常按分片存放,单个分片从几 GB 到几十 GB 都有,如果下载工具支持并发分片,速度能快不少。
实操上我最常用“先验证再并行”的流程:先单独下载一个中等大小的分片,跑通加载流程,确认路径、权限、校验都正常,再启动并发下载。不要一上来就开几十个线程全量拉,免得中途报错找不到是哪一步出了问题。下载完成后,把权重目录固定在一个纯路径下,尽量不要用中文目录或带空格的路径,很多推理框架对这类路径处理得很脆弱,踩过一次坑就不想再踩第二次。
3.2 格式转换:Safetensors、FP8 与低比特量化怎么选
从开源社区拿到的原始权重一般是 BF16 的 Safetensors 分片,这种格式加载快、安全性好,直接作为标准分发格式没有问题。可进入生产后,通常需要把权重切成更省显存的版本。FP8 权重只有 BF16 的一半,在当前主流加速卡上又有硬件级支持,精度损失很小,是企业部署的第一选择。
如果显存资源更紧张,还可以做 4bit AWQ 之类的低比特量化。但量化是有代价的。我们内部用一千条业务问答做过 AB 测试,FP8 对比 BF16 在答案正确率上几乎没有差异,而 4bit 量化在需要精确引用长文数字的场景下,错误率明显上升了几个百分点。所以建议把低比特量化当成显存不够时的兜底方案,而不是默认选项。量化校准集也要尽量贴近业务数据,别用通用的新闻语料去校准一个制造知识库模型,效果会偏。
3.3 推理框架选型:vLLM 与 SGLang 的取舍
现在企业部署基本不会直接用原生加载权重的方式跑推理,那样并发一高吞吐就崩。主流的两个开源推理框架是 vLLM 和 SGLang。vLLM 的 PagedAttention 解决了 KV Cache 碎片问题,continuous batching 可以让多个请求交错生成,尾延迟控制得不错,生态也成熟。SGLang 的 RadixAttention 则在长上下文和复杂多轮对话的缓存复用上有优势,当一个请求前缀被大量重复使用时效果特别明显。
我们这次选 vLLM,主要考虑生产生态。它和 Kubernetes、Prometheus 的集成资料多,问题好搜,社区迭代快。业务里大量请求会共用系统提示词和检索前缀,vLLM 的 prefix caching 也够用。如果是做复杂 Agent 工作流,频繁切换不同的 prompt 前缀,SGLang 的缓存策略会更舒服。框架没有绝对的好,匹配业务特征才重要。
4. 推理服务部署与性能调优实录
4.1 服务启动的核心参数与含义
部署时我们用一个 Docker 镜像跑服务,启动命令的核心参数大致长这样:
docker run --gpus all --shm-size=32g \ -v /data/qwen3.5:/models \ -p 8000:8000 \ vllm-prod:latest \ --model /models/Qwen3.5-397B-A17B \ --tensor-parallel-size 8 \ --max-model-len 32768 \ --gpu-memory-utilization 0.87 \ --max-num-seqs 32 \ --dtype auto \ --quantization fp8 \ --enable-prefix-caching \ --trust-remote-code这里每个参数都不是随便填的。--tensor-parallel-size 8表示把模型切到 8 张卡上并行,单卡显存放不下完整的 397B 权重,必须切。--max-model-len 32768直接决定了 KV Cache 的上限,开得越大显存占用越高,我们按业务请求长度的 P99 来设,不是越大越好。--gpu-memory-utilization 0.87是给框架分配显存的比例,一开始填 0.95 看着很爽,实际跑起来碎片一多就 OOM,降到 0.87 反而稳定。
--max-num-seqs 32是同时处理的序列数量。这个值调大能提高吞吐,但超过一定限度后,每个请求分到的 KV Cache 变少,反而会阻塞,所以最优值要靠压测找。--enable-prefix-caching会把相同前缀的 KV Cache 缓存下来,对 RAG 场景非常划算。如果加载的是原始 BF16 权重,把--quantization fp8去掉,--dtype改成bfloat16即可。
4.2 压测结果与调优记录
服务起来以后,我们先用一个内部脚本模拟真实问答请求,并发从 10 慢慢加到 100,记录三个核心指标:首 token 延迟、单 token 生成时间、整体吞吐。初始配置跑出来的数据很有参考价值。并发 10 时首 token 延迟约 0.37 秒,整体吞吐约 800 tokens/s;并发 50 时首 token 延迟约 1.25 秒,吞吐约 1400 tokens/s;并发 100 时首 token 延迟已经涨到 3.8 秒,吞吐只比 50 并发时高一点,说明瓶颈出现了。
顺着瓶颈做了两处调整。第一,把--gpu-memory-utilization从 0.95 降到 0.87,避免系统在 KV Cache 接近上限时频繁抖动。第二,把--max-num-seqs从 64 降到 32,表面上看并发处理能力变低了,实际上一批请求不再互相争抢显存,每个请求的 TTFT 反而更稳定。这是压测最能带来价值的地方:不要只看单点最高吞吐,要看生产水位下的延迟方差。
4.3 生成质量与性能的平衡
性能调完不能忘了质量。同样的模型,解码参数不同,业务结果可能天差地别。企业内部知识库问答,不追求“文采”,追求“可核对”。温度设置得比较保守,top_p 也收窄,长回答限制在 512 token 以内,尽量让模型直接给出结论和引用来源,而不是展开长篇论述。
另外,量化版本需要在业务集上复测。我们留下了一套固定的评测集,每次调整量化方案或解码参数都会跑一遍。这也是为什么建议把模型版本和解码参数一起纳入版本管理,不然性能优化和效果优化会互相牵制,最后说不清是哪次改动导致回答变差。
5. 高可用与运维体系:企业级部署的另外一半
5.1 多副本、负载均衡与优雅启停
单节点推理服务再快,也不是高可用。我们的做法是同一套模型权重启动至少两个推理实例,前端用四层负载均衡做 TCP 转发,避免七层网关额外解析开销。负载均衡只按连接数分发,不感知请求内容,配置简单,也足够应付企业内网流量。
更关键的是滚动重启。大模型推理实例启动很慢,加载 400GB 权重需要好几分钟,直接 kill 会造成服务闪断。我们要先在负载均衡中摘掉实例的流量,等正在处理的请求跑完,再触发优雅退出。在容器平台里可以配置一段缓冲时间,保证新实例拉完权重、注册到负载均衡之后,旧实例才完全下线。
5.2 监控告警:GPU、显存与请求延迟
推理服务的监控和普通 Web 服务不一样。除了要看 GPU 利用率和显存使用率,更要看 KV Cache 的占用率、当前排队请求数、TTFT 和 TPOT。我们用的 vLLM 自带 Prometheus 指标,可以直接采集请求运行数和等待数、KV Cache 使用情况等数据,再配合硬件厂商的 exporter 拿到算力层指标。
告警规则我们设了三条,都比较保守。显存使用率超过 95% 持续 5 分钟要告警,因为随时可能 OOM;等待队列超过 20 个请求要告警,说明容量不足;TTFT 的 P95 超过 3 秒要告警,业务方对这个延迟非常敏感。日志统一打成 JSON,每条请求带上唯一 request_id,出问题可以直接把从负载均衡到推理框架再到最终响应的全链路日志串起来。
5.3 模型更新与灰度发布
大模型不是部署完就一劳永逸,权重升级、量化方案调整、解码参数变更都需要灰度。我们给模型目录带上了版本号,每次新版权重先放到灰度副本上,负载均衡只放 5% 流量进去。用固定评测集对比新旧版本的回答质量,跑半天没有明显劣化再逐步放量。
如果新版本表现不好,回滚也很直接:把负载均衡里新版本的权重调回 0,流量全部回到旧版本,不需要重新部署整套服务。这个流程看着简单,但很重要,因为大模型行为不可穷举测试,线上回滚能力就是最后的安全网。任何模型升级都别跳过灰度,哪怕只是改一个解码参数。
6. 常见问题与排查技巧实录
6.1 显存不足和启动崩溃
企业部署最常见的报错是 OOM。症状很简单,服务起来没多久就退出,日志里出现显存分配失败。不要急着加卡,先查三个地方:--max-model-len是不是设得太大,--max-num-seqs是不是设得太高,--gpu-memory-utilization是不是太高导致碎片。绝大多数 OOM 是这三个参数的组合问题,而不是物理显存不够。
| 现象 | 常见原因 | 处理方式 |
|---|---|---|
| 启动即OOM | max-model-len过大 | 按P99限长,调低到业务真实水位 |
| 运行中OOM | 并发峰值超过KV Cache预算 | 降低max-num-seqs或扩容 |
| 偶发OOM | 显存碎片化 | gpu-memory-utilization降到0.85-0.9 |
我们的经验值是让 GPU 内存使用率保持在 0.85 到 0.9 之间,留出一点弹性。如果业务必须支持 64K 上下文,KV Cache 会陡然增加,这时再考虑 KV Cache 量化或单独拆一个长文本服务,而不是把生产实例的参数一起拉高。
6.2 推理速度慢、响应卡顿排查
请求一多就响应变慢,先看等待队列长度。如果排队请求数一直在涨,说明并发容量到顶了,要么扩容,要么调大max-num-seqs,但后者可能引发显存不足。如果队列不长但 TTFT 很高,问题多半出在 prefill 阶段,尤其是 RAG 请求把大量检索内容拼进 prompt,前缀很长,首 token 计算量大。
这时候前缀缓存的价值就体现出来了。把系统提示词、固定工具说明、知识库检索模板这些不变内容放在 prompt 前面,开启 prefix caching 后大量重复计算会被跳过。我们还遇到过一种情况:某个请求的输入特别长,把整批请求都拖慢了,因为 prefill 和 decode 混在一个批次里。后来在业务层面对超长输入做了限制和拆分,问题明显缓解。
6.3 长文本上下文与 KV Cache 爆炸
长文本是显存杀手。同一份显存,上下文长度从 8K 翻到 32K,KV Cache 本身涨四倍,各种临时激活值和调度开销也会同步上涨,整体显存压力会明显放大。所以生产环境一定要按业务真实分布去设置max-model-len,而不是照着一百多 K 的最大能力去配。
我们的做法是统计一段时间内的请求长度,画出分布曲线,取 P99 作为上限。剩余极少数超长请求走离线任务或降级通道。这样既保证绝大多数请求体验正常,又不会为了极少数大输入让所有人都承担显存成本。
6.4 多机集群的网卡与拓扑踩坑
最后说一个最容易忽视的坑:跨节点并行。我们一开始评估过双机 16 卡跑 BF16 权重,结果发现普通万兆网卡做张量并行根本扛不住节点间通信,每生成一个 token 都要跨节点同步多次,延迟增加非常明显。后来改成单机 8 卡 FP8,速度反而快了一截。
如果你不得不跨节点,建议优先考虑流水线并行或专家并行,而不是把同一层拆到两台机器上做张量并行。同一批 GPU 尽量保证在同一个高速互联域内。检查物理拓扑时,用显卡驱动自带的拓扑信息看一眼加速卡之间的互联方式,避免卡组里混着跨 PCIe 交换机的链路,那对吞吐的影响比想象中更大。
这次部署下来,我最大的感受是:MoE 大模型的企业级落地,本质不是把模型跑起来,而是把显存、带宽、并发和业务特征当成一个整体来设计。Qwen3.5-397B-A17B 给了很高的能力上限,但真正决定生产体验的,往往是max-model-len、max-num-seqs、gpu-memory-utilization这些不起眼的数字,以及你为故障场景留了多少余量。建议准备做类似部署的朋友,先把自己业务的请求长度分布、并发峰值和可接受延迟统计清楚再动手。别急着上 128K 上下文,也别把 GPU 利用率压到 99%,给系统留一点喘息的余地,企业级系统才能真正站得住。