1. 从一张显卡到一条产线:大模型部署到底在部署什么
很多人第一次接触“大模型服务器部署”,脑子里浮现的画面是:买张显卡,装个驱动,把模型文件拖进去,敲一行命令,然后浏览器里就能对话了。这个画面不能说错,但它只覆盖了整个部署工作的不到两成。真正让一个模型从“能跑”变成“能扛住业务”的,是后面那一长串没人愿意细讲的东西:显存怎么算、并发怎么控、请求怎么排队、模型怎么热更新、日志怎么留、成本怎么压。
我做过不少从零到一的推理服务落地,也接手过别人半途撂挑子的烂摊子。最常见的翻车现场不是模型跑不起来,而是跑起来之后:三个人同时提问,服务就卡死;跑了一周,显存悄悄涨满;老板问一句“这个月花了多少钱”,没人答得上来。所以这篇内容我想聊的不是“怎么把模型启动”,而是怎么把大模型部署成一条能持续运转、成本可控、出问题能查的生产线。
关键词里出现了推理框架、云服务、生产级流程,这三个词其实对应了部署工作的三个层次:框架决定单机效率,云服务决定资源形态,流程决定长期稳定性。三者缺一,系统就只能在演示阶段打转。这篇文章适合谁看?如果你是刚拿到一台带显卡的机器、想把开源模型跑起来的新手,前半部分能帮你少走弯路;如果你已经在维护线上推理服务,中间关于显存核算、并发压测、成本拆解的部分应该能对上你踩过的坑;如果你正在做企业私有化部署的选型,框架对比和云服务那两节可以直接拿去当评估清单。
下面我按实际落地的顺序来讲,从硬件和框架的匹配开始,一路走到监控、成本和安全边界。中间会穿插一些我自己踩过的坑,以及那些文档里不会写、但线上一定会遇到的情况。
2. 推理框架选型:别只看跑分,先看你的请求长什么样
选框架这件事,网上最多的是一张张吞吐量对比图,谁比谁快百分之几十。但我可以很负责任地说,脱离请求形态谈吞吐量,基本没有参考价值。你的请求是长输入短输出,还是短输入长输出?是单轮问答,还是多轮带历史?是同步等结果,还是流式吐字?这些差异会让同一个框架的表现天差地别。
2.1 主流框架的能力边界与适用场景
目前生产环境里出现频率最高的几类框架,大致可以这样划分。vLLM的核心优势是 PagedAttention 带来的显存利用率和连续批处理能力,适合请求量大、输入输出长度差异明显的在线服务,尤其是需要高并发流式输出的场景。TensorRT-LLM走的是编译优化路线,把模型图编译成针对特定显卡高度优化的引擎,单请求延迟能压得很低,但代价是编译过程繁琐、换模型要重新编译,适合模型固定、追求极致延迟的场景。Ollama的定位完全不同,它把模型下载、量化、运行打包成一条命令,适合本地开发、个人实验、小规模内部工具,但它的并发能力和调度策略不适合直接扛生产流量。TGI(Text Generation Inference)是另一套偏服务化的方案,对 HuggingFace 生态友好,连续批处理和流式输出都支持得不错,部署体验比 vLLM 早期版本要顺一些。
还有一类容易被忽略的:llama.cpp 系列。它靠 GGUF 量化格式,能在纯 CPU 甚至消费级显卡上跑起来,显存不够、预算有限、或者只是做离线批处理的时候,它是很务实的选择。我见过一些团队硬要用大框架跑一个小模型,结果资源浪费严重,其实换成量化后的轻量方案,效果差不多,成本降一大截。
| 框架 | 核心机制 | 最适合的场景 | 主要代价 |
|---|---|---|---|
| vLLM | PagedAttention + 连续批处理 | 高并发在线推理、流式输出 | 显存管理调参有门槛 |
| TensorRT-LLM | 图编译 + 内核融合 | 模型固定、极致低延迟 | 编译复杂、换模型成本高 |
| TGI | 连续批处理 + HF 生态 | 快速服务化、多模型切换 | 资源占用相对偏高 |
| Ollama | 量化 + 一键运行 | 本地开发、小规模内部使用 | 并发调度弱,不适合生产 |
| llama.cpp | GGUF 量化 + CPU 推理 | 低资源、离线批处理 | 吞吐上限受硬件限制 |
选型的时候我一般会问三个问题:第一,我的请求平均输入多少 token、输出多少 token?第二,峰值并发大概多少,能不能接受排队?第三,模型多久换一次?这三个答案基本就能把范围缩到一两个框架。比如输入两三千 token、输出几百 token 的文档问答,和输入几十 token、输出上千 token 的创作类任务,对批处理策略的要求完全不同。
2.2 量化精度怎么选:不是越低越好
量化是部署里绕不开的一环。FP16 是基准,INT8 能省一半显存,INT4 再省一半,但精度损失是累积的。我的经验是:通用对话和知识问答,INT8 基本无损感知;代码生成和数学推理,INT4 要谨慎,容易出现逻辑断裂;涉及结构化抽取和严格格式输出的任务,尽量别低于 INT8。量化不是免费的午餐,省下来的显存是用输出质量换的,而输出质量的问题往往在压测阶段看不出来,上线后用户投诉才暴露。
还有一个细节:不同框架对量化的支持程度不一样。有的框架只支持特定量化格式,有的需要自己转换。转换过程中如果校准数据选得不好,量化后的模型可能在某些领域突然变笨。我一般会准备一小批覆盖业务场景的测试问题,量化前后各跑一遍,对比输出,确认没有明显退化再上线。
2.3 显存核算:把账算在部署之前
显存不够是部署阶段最常见的硬门槛。一个粗略但实用的估算方式是:模型参数量乘以每参数字节数,再加上 KV Cache 和框架开销。FP16 下每参数 2 字节,INT8 是 1 字节,INT4 是 0.5 字节。比如一个 70 亿参数的模型,FP16 权重约 14GB,加上 KV Cache 和运行时开销,实际占用往往要到 18GB 以上。如果显卡是 24GB,留给并发的空间就很有限了。
KV Cache 的大小和序列长度、批大小直接相关。序列越长、并发越高,KV Cache 涨得越快。很多人只算了权重,没算 KV Cache,结果一上并发就 OOM。我的做法是:先按目标并发和最大序列长度估算 KV Cache,再倒推能选多大的模型和多高的量化精度。这个顺序不能反,否则就是先买鞋再量脚。
3. 云服务与资源形态:租卡、买卡还是混合
框架选完,下一个问题是算力从哪来。这个问题没有标准答案,取决于你的使用模式:是长期稳定负载,还是波动很大的实验性需求;是数据敏感必须私有,还是可以接受托管服务。
3.1 几种资源形态的真实成本结构
自建物理机适合长期高负载、数据不出内网的场景。一次性投入大,但单位算力成本随时间摊薄。缺点是扩容慢、运维重,显卡换代时资产贬值快。云上 GPU 实例灵活,按小时或按月计费,适合需求波动大、想快速验证的团队。但要注意,云厂商的 GPU 实例价格差异很大,而且网络存储、公网带宽这些周边费用经常被低估。托管推理服务最省心,按 token 或按调用次数计费,适合不想碰运维的团队,但单价通常更高,且对模型版本和参数的控制力有限。
我见过不少团队在“租还是买”上纠结很久,其实可以算一笔简单的账:把预期的月均 GPU 使用小时数乘以云实例单价,再和自建机器的月折旧加电费加运维人力对比。如果使用率长期低于某个阈值,租更划算;如果接近满载且持续一年以上,自建的优势才显现出来。这个阈值因地区和机型而异,但思路是通用的。
| 资源形态 | 适合的使用模式 | 隐性成本 | 控制力 |
|---|---|---|---|
| 自建物理机 | 长期满载、数据私有 | 运维人力、电费、折旧 | 最高 |
| 云 GPU 实例 | 波动负载、快速验证 | 存储、带宽、闲置计费 | 较高 |
| 托管推理服务 | 无运维团队、按量付费 | 单价高、版本受限 | 较低 |
3.2 网络与存储:最容易被忽略的两个瓶颈
模型文件动辄几十 GB,从对象存储拉取到本地磁盘的速度直接影响启动时间。如果每次重启都要重新下载,冷启动会非常痛苦。我的做法是把模型权重缓存在本地高速盘上,启动时只做校验不做下载。容器化部署时,把模型目录挂载成持久卷,避免每次重建容器都重新拉模型。
网络方面,推理服务的响应时间不只取决于 GPU,还取决于请求进出的链路。如果服务部署在公网可访问的实例上,入站流量和出站流量的带宽限制、安全组规则、负载均衡配置都会影响实际体验。内网部署相对简单,但要考虑跨可用区调用的延迟。我一般会把推理服务和调用方放在同一区域,能内网就内网,减少不必要的网络跳数。
3.3 弹性伸缩的边界在哪里
大模型推理的弹性伸缩比普通 Web 服务难得多。普通服务扩容就是多起几个实例,大模型扩容要等模型加载、显存分配、预热完成,冷启动可能几分钟甚至更久。这意味着基于 CPU 使用率的传统伸缩策略基本失效,等你触发扩容,请求早就超时了。
比较务实的做法是:保持一个最小常驻实例数,用队列长度或待处理请求数作为扩容信号,并且设置足够长的冷却时间。同时,把非实时任务(比如离线批量推理)和实时任务分开部署,避免批量任务把实时服务的资源挤占掉。如果业务允许,用请求排队加超时降级来平滑峰值,比盲目扩容更经济。
4. 生产级部署流程:从裸机到可观测服务
前面讲的是选型和资源,这一节讲具体怎么把服务搭起来并让它稳定运行。我把流程拆成几个阶段,每个阶段都有容易出问题的地方。
4.1 环境准备:驱动、容器与依赖锁定
环境准备阶段最大的坑是版本漂移。显卡驱动、CUDA 版本、框架版本、Python 依赖,任何一层不匹配都可能导致运行时报错,而且报错信息往往指向错误的方向。我的习惯是用容器把整个运行环境固化下来,基础镜像选官方提供的、经过验证的组合,然后在上面叠加自己的依赖。这样至少保证开发、测试、生产三套环境一致。
驱动层面,宿主机驱动版本要满足容器内 CUDA 运行时的最低要求。这个对应关系在官方文档里有矩阵表,部署前一定要查。我遇到过宿主机驱动偏旧、容器里 CUDA 版本偏新,结果框架加载时直接崩溃的情况,排查了大半天才发现是驱动不匹配。
依赖锁定方面,Python 包的版本冲突在大模型生态里特别常见。transformers、accelerate、tokenizers 这些库互相之间有版本约束,升级一个可能带崩另一个。用锁文件固定所有依赖版本,并且在 CI 里做一次干净环境的安装验证,能省掉大量“在我机器上是好的”这类问题。
4.2 模型加载与预热:别让第一个用户当小白鼠
模型加载完成不等于服务就绪。框架初始化、显存分配、CUDA 图捕获、量化反量化,这些操作在第一次推理时可能才真正触发。如果第一个请求进来才开始做这些,用户会等很久,甚至超时。
我的做法是在服务启动后主动跑几条预热请求,覆盖不同的输入长度和输出长度,让框架把该分配的资源都分配好、该编译的图都编译好,然后再把服务注册到负载均衡上。预热请求的内容可以从业务日志里采样,尽量贴近真实分布。这一步花几分钟,能避免上线初期的批量超时。
4.3 并发控制与请求队列
并发控制是生产部署的核心。GPU 是独占资源,同时处理的请求数超过显存和计算能力,要么 OOM,要么延迟飙升。连续批处理是主流框架的应对方式:把多个请求的动态批处理在一起,提高 GPU 利用率。但批大小不是越大越好,批太大时单个请求的延迟会明显上升。
我一般会设置一个最大批大小和最大等待时间,在吞吐和延迟之间找平衡。等待时间太短,批不起来,GPU 利用率低;等待时间太长,用户感知延迟高。这个参数需要根据实际压测结果调,没有万能值。另外,请求队列要有上限和超时,队列满了就快速失败,而不是无限堆积,否则雪崩是迟早的事。
4.4 监控指标:TPOT 和 TTFT 比 QPS 更有意义
大模型服务的监控,光看 QPS 和 GPU 利用率是不够的。真正反映用户体验的是两个指标:TTFT(Time To First Token,首 token 延迟)和TPOT(Time Per Output Token,每输出 token 耗时)。TTFT 决定用户觉得“服务有没有响应”,TPOT 决定用户觉得“输出快不快”。流式输出场景下,这两个指标比端到端延迟更能定位问题。
除了性能指标,还要监控显存使用趋势、请求队列长度、错误率、超时率。显存缓慢增长往往意味着有内存泄漏或缓存没有正确释放,早发现早处理。我习惯在监控面板上放一条显存使用曲线,正常应该是锯齿状波动,如果看到持续上升不回落,就要警惕了。
| 指标 | 含义 | 异常时的排查方向 |
|---|---|---|
| TTFT | 首 token 延迟 | 队列积压、批处理等待过长 |
| TPOT | 每 token 耗时 | 批太大、显存不足、计算瓶颈 |
| 显存使用 | 显存占用趋势 | 泄漏、缓存未释放、并发过高 |
| 队列长度 | 待处理请求数 | 扩容不足、处理能力下降 |
| 错误率 | 失败请求占比 | 超时、OOM、输入异常 |
4.5 日志与追踪:出问题时能查到人
生产环境出问题不可怕,可怕的是查不到原因。每个请求要有唯一标识,日志里记录请求标识、输入长度、输出长度、耗时、使用的模型版本。这样出问题时可以按请求追溯,也能做离线分析。日志量大的时候要注意采样和轮转,别让日志把磁盘写满。
追踪方面,如果服务链路比较长(比如前面有网关、后面有后处理),分布式追踪能帮上忙。但大模型推理本身耗时占比很高,追踪的重点往往在排队和调度环节,而不是模型计算本身。
5. 成本、安全与长期维护:部署之后的事
服务跑起来只是开始,后面还有成本、安全和维护三件事要持续投入。
5.1 成本拆解:钱花在哪里了
大模型推理的成本大头是 GPU 时间。但 GPU 时间不等于有效计算时间,空闲等待、批处理不满、显存浪费都是隐性成本。我一般会把成本拆成几块:GPU 租用或折旧、存储、网络、运维人力。其中 GPU 利用率是最容易优化的,通过合理的批处理和调度,同样的硬件能多扛不少请求。
另一个容易被忽略的是模型版本管理成本。同时维护多个模型版本会占用额外显存和存储,切换版本时的加载时间也是成本。如果业务允许,尽量收敛模型版本,减少并行运行的模型数量。
5.2 安全边界:输入输出都要管
大模型服务的安全不只是网络层面的。输入侧要防提示注入和恶意构造的请求,输出侧要防敏感信息泄露和不当内容。生产环境里,我一般会在推理服务前面加一层输入校验和输出过滤,虽然会增加一点延迟,但能挡掉大部分明显问题。
访问控制方面,推理接口要有鉴权和限流,避免被滥用。限流不仅防攻击,也防内部误用——某个脚本写错了疯狂发请求,把服务打挂的情况并不少见。
5.3 模型更新与回滚
模型更新是风险操作。新版本可能效果更好,也可能在某些场景下退化。我的做法是灰度发布:新版本先接一小部分流量,对比关键指标和输出质量,确认没问题再逐步放大。同时保留旧版本的快速回滚能力,一旦新版本出问题,能在几分钟内切回去。
回滚的前提是旧版本的模型文件和配置还在,所以不要在新版本上线后立刻删掉旧版本。存储成本相比回滚能力,是值得的。
6. 一些踩坑之后的个人体会
部署这件事,文档能教你的是一半,另一半是线上教你的。我印象比较深的一次是服务跑了一周后显存慢慢涨满,重启就好,但过几天又涨。查了很久才发现是某个缓存没有设置上限,长尾请求不断往里塞数据。这类问题压测阶段很难发现,只有长时间运行才暴露。所以上线后的持续观察比上线前的压测同样重要。
还有一次是并发一高就超时,查下来是批处理等待时间设得太长,请求都在队列里等批,单个请求的延迟被拉得很高。把等待时间调短之后,吞吐略降但延迟稳定了,用户体验反而更好。这让我意识到,吞吐和延迟的平衡点要根据业务来定,不能只看框架的默认值。
最后分享一个小习惯:我会给每个部署的服务写一份运行手册,记录启动命令、关键参数、监控地址、常见问题和处理方式。这份手册在半夜被叫起来处理故障的时候,价值比任何文档都高。部署不是一次性的活,它是一个需要持续照看的系统,把该记的记下来,后面会轻松很多。