☰
大模型服务器部署全攻略:从框架选型到生产级实践
2026/10/1 19:01:22 网站建设 项目流程

年初我接到一个任务:把内部常用的 13B 模型从开发机搬到正式服务器,做成一个可供其他团队调用的 API 服务。我当时以为半天能搞定,结果前后折腾了接近一周。回头复盘,问题根本不在“把模型跑起来”,而在“用正确的方式跑起来”。这个正确,牵扯到框架选型、云服务器对比、显存预算、量化策略、服务化封装、压测验证等一系列决策。那篇帖子里我承诺过要写一份完整指南,今天就把这套大模型服务器部署的完整流程按 2026 年的现状整理出来,从框架选型讲到生产级流程,把我踩过的坑和最终沉淀下来的方案一并交代清楚。

无论你是刚接触大模型部署的新人,还是已经在本地跑过 demo、准备上生产的工程师,这篇文章都值得你花二十分钟读一遍。我尽量只讲实际操作和真实结论,不堆理论。

1. 部署一个模型,为什么比想象中复杂

1.1 “能跑”只是及格线

很多人第一次部署大模型,都是从“把模型跑起来”开始的。最简单的方式确实是下载一个 llama.cpp,加载一个 GGUF 文件,然后输入问题,看着终端一行行输出文字。那一刻感觉特别爽,但爽完之后面对的是一个很现实的问题:这个服务能不能给别人用?

一旦要给别人用,事情立刻变复杂。别人不会像你一样在终端里慢慢等输出,他们可能有几十个人甚至几百个人同时发起请求。每个请求的上下文长度不同,有的只有几百字,有的带几万字的历史记录。服务器响应慢了,调用方会认为是服务不可用;响应速度快了但结果乱码,调用方会质疑模型能力。这些都不是模型本身的问题,而是部署架构的问题。

所以我把“部署”这件事分成了四个层次:能跑、能用、能扛、能管。

能跑是最低标准,模型能加载、能推理、能出结果。能用是封装成标准接口,别人通过 HTTP 或 SDK 就能调用,不需要知道模型文件放在哪个目录。能扛是并发上来之后服务依然稳定,延迟在可接受范围内,不会动不动 OOM 或者排队排到超时。能管则是更上层的维度:监控指标、日志、告警、多副本扩缩、版本回滚,这些是一个生产系统必须具备的能力。

1.2 四个层次各自的门槛

能跑的阶段,最大的坑是框架不会用。你随便用transformers的pipeline跑一个 7B 模型,单条请求可能没问题,但吞吐量低到让人绝望。因为 transformers 默认的推理方式是逐个 token 生成,批处理能力几乎没有,GPU 利用率可能只有个位数百分比。

能用阶段,需要解决的是接口协议问题。现在社区基本已经把 OpenAI 兼容接口当成了事实标准,vLLM、SGLang、Triton 这些框架都提供了现成的 OpenAI 风格 API。你需要做的只是把模型路径、显存参数、端口配置好,然后往/v1/chat/completions上扔 JSON 请求。

能扛阶段,就要开始认真对待显存预算、KV Cache 占用、连续批处理参数、最大并发数、超时时间这些细节。我在后面的流程部分会给出具体的启动参数,以及每个参数的判断依据。

能管阶段,通常是团队协作的产物。至少要有一套监控面板,能看到 GPU 利用率、显存占用、请求延迟的 P50/P95/P99、每秒生成 token 数。还要有日志系统,能定位到具体一个请求是卡在 prefill 还是 decode。再往后才是 Kubernetes 编排、自动扩缩容、灰度发布这些重型武器。

1.3 一条可以复用的部署决策路径

我在踩过足够多的坑之后,逐渐固定了一套决策顺序:

  • 先确认模型规模:7B、13B、32B 还是 70B,直接决定你需要多大的显存。
  • 再确认流量画像:是内部几十人低频调用,还是面向高并发 API 场景,两者的框架选型和云服务器配置完全不同。
  • 接着确认延迟要求:内部工具允许 5 秒首 token,面对用户的产品可能要求 1 秒内出首字。
  • 然后选框架:vLLM 和 SGLang 是当前最主流的两个选择,后面会细说。
  • 再然后选云服务器:按需付费、包月、竞价实例各有适用场景。
  • 最后是服务化封装、压测、监控、上线。

这套顺序我后来基本没改过,只是在不同项目里权重不同。下面我按照这套路径逐步展开。

2. 2026 年框架选型:先看流量画像,再谈技术栈

2.1 主流推理框架的一页纸对比

走到 2026 年,大模型推理框架的竞争格局已经比较清晰了。vLLM 凭借生态和吞吐量稳坐第一梯队,SGLang 在共享前缀缓存和多模态场景上形成了差异化优势,TensorRT-LLM 在延迟敏感和极致性能场景依然有一席之地,llama.cpp 则继续担当轻量部署和本地实验的老黄牛。

我把自己实际用过的框架放在一起做了个对比:

框架核心机制最大优势主要短板最适合的场景
vLLMPagedAttention + 连续批处理生态成熟、吞吐高、API 兼容度好多轮共享前缀的缓存能力不如 SGLang通用高并发 API 服务
SGLangRadixAttention + 前缀树缓存多轮对话和共享文档前缀加速明显社区规模仍在追赶 vLLM长上下文、多轮对话、Agent 场景
TensorRT-LLMTensorRT 深度编译优化单卡延迟低、FP8 支持好、算子融合极致编译时间长、动态 shape 处理麻烦延迟敏感、shape 相对固定
llama.cppGGUF 量化 + 多平台支持部署简单、CPU 也能跑、跨平台高并发吞吐能力有限本地开发、边缘设备、临时演示
Triton Inference Server多模型管理 + 请求调度生产组件齐全、多模型共用配置学习成本高多模型网关、需要 A/B 测试的复杂生产环境

2.2 vLLM:吞吐优先场景的第一选择

如果让我给大多数人一个闭着眼睛不会太错的方案,我会选 vLLM。它过去两三年里迭代速度非常快,社区生态已经形成了事实标准。PagedAttention 把 KV Cache 切成分页,减少了显存碎片;连续批处理让新请求可以在当前 decode 批次中动态插入,不用等整个批次生成完就能加入,吞吐量提升非常明显。

实际使用中,vLLM 还有一个隐性优势:它大量兼容 OpenAI 接口格式,/v1/chat/completions、/v1/completions、/v1/embeddings这些端点都是现成的,接入业务方时几乎不需要写适配层。如果你的团队主要工作是做业务集成,而不是研究推理框架本身,vLLM 是最省事的选择。

vLLM 的缺点也很明确:它对前缀复用的优化不如 SGLang 激进。什么叫前缀复用?就是两个请求如果共享了一大段系统提示词或历史对话,理论上可以复用前面已经算过的 KV Cache,不用重新计算。vLLM 也有自动前缀缓存功能,但相对 SGLang 的 RadixAttention 在设计上更浅一些。如果你的场景是大量请求都带一个很长的公共 system prompt,SGLang 能吃到更多红利。

2.3 SGLang:多轮对话与长上下文场景的利器

SGLang 的核心理念是 RadixAttention,把前缀 KV Cache 构建成一颗基数树来共享。举个例子,如果系统提示词有 2000 个 token,一千个并发请求都带着这段提示词,SGLang 只需要真正计算一次公共前缀,剩下九百多次都能直接复用缓存。在多轮对话场景里,上一轮的计算结果也能被下一轮复用,首 token 延迟会明显下降。

我实际测试过一个 32B 模型,在模拟 50 个并发用户、每人带 3000 token 历史对话的压测场景里,SGLang 的 TTFT(首 token 延迟)比同一台机器上的 vLLM 低了大概 30%。但如果把公共前缀去掉,大家各自随机提问,两者的差距就没那么明显了。

所以我的建议是:如果业务形态是大量带固定 system prompt 的 Agent 应用,或者长文档问答,优先试一下 SGLang。如果只是标准的通用 API,用 vLLM 就行,别为了追求新东西给自己增加维护成本。

2.4 TensorRT-LLM:延迟敏感场景的另一个选项

TensorRT-LLM 是英伟达官方的推理优化方案,思路是把模型编译成高度优化的 TensorRT 引擎,算子融合、层融合、量化对齐都做得非常深。好处是同一个模型在三方框架下可能延迟是 50ms,TensorRT-LLM 能压到 35ms 甚至更低。

但代价也很现实:编译一次引擎可能要花几十分钟到几小时,而且对输入输出 shape 有要求,动态 shape 处理起来非常麻烦。如果你的 API 要接收不定长输入,引擎配置就要写得相当细致,每次改模型结构都要重新编译验证。

我个人的判断是:TensorRT-LLM 适合那种请求模式非常固定、性能要求极高的少数场景,比如在线游戏 AI、实时语音交互。大部分业务 API 的延迟瓶颈不在框架的算子级优化,而在显存不够导致的排队,这时候选 vLLM 或 SGLang 更务实。

2.5 llama.cpp 的不可替代性

别因为 llama.cpp 吞吐量不如 vLLM 就看不起它。在我这里,它有两个不可替代的价值:第一,GGUF 格式的量化模型非常省事,一个文件拷走就能跑,跨平台、跨设备;第二,它能在没有 NVIDIA GPU 的环境里靠 CPU 和 Apple Silicon 跑模型,对开发调试和边缘部署极其友好。

很多人在本地 Mac 上把模型跑通了,然后直接把同样的模型权重丢到服务器上,发现服务器环境一堆问题。如果你一开始就用 llama.cpp 跑 GGUF,那么从笔记本到小服务器之间几乎是无缝迁移。当然,生产环境我还是建议用 vLLM 或 SGLang,因为 GGUF 在高并发下的吞吐表现确实不够好。

2.6 我的选型经验

综合来看,我的选型决策可以压缩成三句话:内部高频 API 服务默认用 vLLM;大量共享前缀或长上下文场景用 SGLang,值得评估;延迟要求苛刻且请求模式固定,再考虑 TensorRT-LLM。llama.cpp 永远保留在工具箱里,用来快速验证模型和迁移环境。

有一个很容易被忽略的环节是:框架的版本和模型格式的匹配。每次升级框架大版本,最好先拿同一份模型权重做一次回归测试,确认输出质量和延迟没有退化。我在生产环境就碰到过 vLLM 升级之后某量化模型输出概率异常的情况,最后回退了版本才恢复正常。

3. 云服务器对比:GPU 实例的真实门槛

3.1 先算明白显存账

选择云服务器之前,第一步不是比价格,而是算清楚你的模型需要多少显存。以 FP16 精度为例,模型权重的大小大约是参数量乘 2 字节。一个 7B 模型就是 14GB 权重文件,一个 13B 模型就是约 26GB,一个 70B 模型大约 140GB。这还没算 KV Cache。

KV Cache 是个容易被新手忽略的大头。简单来说,生成过程中模型要缓存历史 token 的 key 和 value 张量,占用显存和你的max_model_len、层数、注意力头数成正比。一个 7B 模型在 8192 上下文长度下,KV Cache 可能额外占几个 GB;如果模型更大、上下文更长,十几个 GB 甚至几十个 GB 都正常。

所以我的经验法则是:7B 模型至少准备 24GB 显存的卡;13B 模型至少准备 40GB 左右的显存,或者上 48GB 的 L40S;32B 模型需要 80GB 级别,比如 A100/H100,或者用 AWQ/GPTQ 量化后塞进 48GB;70B 模型单卡基本放不下,要么两张 80GB 卡做张量并行,要么用量化方案配合多卡。

3.2 三种计费模式的分场景选择

云服务器厂商一般提供按量付费、包月包年和竞价实例三种计费方式,它们的适用场景差别很大。

按量付费适合开发和测试阶段。你只需要跑半天实验,用完就释放,不用为闲置时间买单。包月包年适合已经上线、流量稳定的服务,虽然单价贵,但按长期使用摊薄下来比按量便宜太多。竞价实例适合批处理、离线推理、可容错任务,价格可能只有按量的两三折,但随时可能被回收,不能用于核心在线服务。

我个人的习惯是:先按量付费把部署流程彻底跑通,压测结果满意之后再决定包月或者切竞价。很多人在测试阶段直接买了包月,结果框架参数都没配好,白白浪费一个月的费用。

3.3 主流云厂商 GPU 实例的横向视角

这里不点名推荐某一家,因为各个厂商的实例变化太快,但可以分享一个横向比较的框架:看卡型、看显存、看网络、看计费灵活性、看配套服务。

比较维度说明
卡型同一代型号下,A10/L4 适合 7B 级轻推理,L40S/A100 适合 13B~32B,H100/H200 适合 70B 和训练场景
显存24GB、48GB、80GB 三档决定你能否单卡部署
网络带宽GPU 实例如果带宽只有 1Gbps,大模型权重下载和模型更新会非常痛苦
计费灵活性是否支持按秒释放、竞价实例、包年折扣
配套服务对象存储、镜像仓库、日志服务是否顺手

如果你主要在国内云环境跑,通常要留意实例的可用区是否有目标卡型的库存,热门卡型在促销季经常一卡难求。如果你用海外云服务,则要重点考虑访问延迟和数据传输成本,GPU 实例本身便宜但跨区域流量可能很贵。

3.4 网络与数据面成本

模型部署之后,真正消耗成本的不只是 GPU 实例本身。一次模型权重的更新,可能是几十 GB 甚至上百 GB 的数据传输。如果云服务器和对象存储之间没有内网互通,走公网下载不光慢,流量费用也非常可观。

所以部署前一定要确认:模型文件放在对象存储的哪个区域,GPU 实例是否和存储在同一内网。举例来说,如果模型放在北京区域的存储,实例也在北京,就能走内网高速拉取;跨区域的话,下载速度和费用都不乐观。

另外一个容易忽略的点是出口带宽。模型 API 返回的 token 量虽然不大,但并发很高的情况下对带宽也有要求。我曾经在某个低带宽的实例上压测,发现 GPU 利用率还不到 30%,延迟就已经飙高,最后定位到是出口带宽被打满了。这个坑很隐蔽,排查成本高,最好在选型阶段就预留足够的带宽。

3.5 我的建议:先小后大,先按量后包月

操盘过几次 GPU 实例采购之后,我建议所有人在初期都采取“先小后大”的策略。先用最小可用的卡型把链路跑通,用最小的上下文长度验证接口逻辑,然后逐步放大。直接上顶配卡型看似省事,实际上你往往不知道哪些参数需要调,出了问题排查成本反而更高。

另外,每家公司对数据主权、日志合规、模型文件留存的规则不同,选地域的时候要提前确认。这个我不是在说玄学,而是很多正规项目上线评审时就会卡在这一环。部署层面尽早确认,免得服务已经跑起来了才发现地域不符合合规要求,被迫迁移。

4. 生产级部署流程:从权重文件到稳定 API

4.1 模型准备:下载、校验与格式确认

生产部署的第一步是把模型权重完整拿到服务器上。现在主流模型权重都托管在 Hugging Face 或国内的 ModelScope 上,官方 CLI 工具可以直接拉取。

我习惯用命令行指定目录下载,避免默认缓存目录造成混乱:

huggingface-cli download Qwen/Qwen2.5-7B-Instruct --local-dir /data/models/Qwen2.5-7B-Instruct

下载完成后做一个基础校验,至少确认关键文件大小和目录结构正确。safetensors 格式的权重比 PyTorch 的.bin更适合生产环境,因为它有明确的张量大小信息,加载更安全更稳定。现在多数新模型都默认提供 safetensors 文件,如果你的模型还停留在.bin,建议转换成 safetensors 再部署。

4.2 量化选型:FP16、FP8、AWQ、GPTQ 怎么选

框架选完之后,接下来要决定用什么精度部署。这个决定直接影响显存占用、生成质量和部署复杂度。

FP16 是最保真的选项,模型有多少显存需求就按多少给,不需要额外折腾。但如果显存不够,就需要量化。AWQ 和 GPTQ 是两类流行的权重量化方法,把权重压到 4bit 或 3bit,显存占用大幅下降,生成质量通常还能保持不错。FP8 则是更接近无损的量化方式,但需要 GPU 硬件支持,比如 H100、L40S 这一代卡基本都能很好地支持 FP8 推理。

我给的参考方案如下:

  • 显存充足,追求稳妥:FP16,省心。
  • 显存不够,模型 30GB 以内:首选 AWQ 4bit 或者 GPTQ 4bit,注意观察输出质量。
  • 硬件支持 FP8:优先考虑 FP8,在显存和精度之间平衡最好。
  • 本地或边缘设备:直接用 llama.cpp 做 GGUF 的 Q4_K_M / Q5_K_M 量化。

有一个经验教训:量化模型上线前一定要做一次“针对性回归”,把你业务中最常见的几种输入各跑一遍,对比量化前后的输出。不要只看 ppl(困惑度)指标,有些量化模型在复杂指令上的表现退化非常明显。

4.3 启动参数:vLLM 与 SGLang 的推荐配置

vLLM 启动一个大模型 API 服务,最简单的命令大概是:

python -m vllm.entrypoints.openai.api_server \ --model /data/models/Qwen2.5-14B-Instruct \ --tensor-parallel-size 1 \ --max-model-len 8192 \ --gpu-memory-utilization 0.90 \ --port 8000

几个关键参数的理解:

--tensor-parallel-size是张量并行度。单卡部署时设为 1;如果模型需要两张 80GB 卡才能放下,就设为 2。--max-model-len决定最大上下文长度,直接影响 KV Cache 预分配和单请求的显存占用。--gpu-memory-utilization告诉框架可以占用多少比例的 GPU 显存,我通常设 0.90,留出一点余量给 CUDA context 和碎片。

如果你用 SGLang,启动命令类似:

python -m sglang.launch_server \ --model-path /data/models/Qwen2.5-32B-Instruct \ --tensor-parallel-size 1 \ --max-total-tokens 16384 \ --port 30000

启动之后你会发现日志里会打印初始化完成、KV Cache 池大小等信息,这些输出记得保留,排查显存问题时非常有用。

4.4 服务化封装:OpenAI 兼容协议、鉴权与限流

框架启动后,默认就暴露了 HTTP 接口。以 vLLM 为例,直接可以用 curl 测试:

curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "Qwen2.5-14B-Instruct", "messages": [{"role": "user", "content": "你好,介绍一下你自己"}] }'

如果接口直接暴露在公司内网,至少要做两层保护:第一层是 API Key 鉴权,vLLM 启动时可以加--api-key参数,或者在外层网关统一校验;第二层是限流,防止某个调用方把 GPU 资源全部打满。限流可以在 Nginx 层做,也可以在 API 网关层做,按 IP、按用户、按服务维度分别配置 QPS 限额。

4.5 部署形态:systemd、容器与 Kubernetes 的取舍

部署形态这个选择,取决于你的运维基础设施。

如果只有一台服务器,我推荐直接用 systemd 托管推理进程,简单可靠。写一个 service 文件,设置Restart=on-failure,进程崩溃能自动拉起,日志交给 journald 管理。不少团队在这里用 Docker,但说实话在单机场景下 Docker 的优势并不明显,反而增加了一层镜像构建和卷挂载的心智负担。

如果服务要横向扩展到多台服务器,就得考虑容器化加 Kubernetes。vLLM 这类无状态推理服务非常适合 Kubernetes,你可以按照 GPU 资源声明来调度,配合 HorizontalPodAutoscaler 做自动扩缩。不过,Kubernetes 的调度器对 GPU 资源的分配有自己的规则,需要设置好显存资源的 requests 与 limits,否则会出现“一台机器上两个 pod 都申请了整张卡,实际只有一个 pod 在用”的尴尬局面。

4.6 多副本与自动扩缩:从单卡到集群

当单卡实例的吞吐量扛不住业务流量时,最简单的扩容方式是开多副本,前面挂一个负载均衡。推理框架的多副本不需要像数据库那样考虑数据一致性,模型权重是只读的,副本之间完全独立,扩容起来非常轻松。

我推荐的做法是:每个副本独立部署一套 vLLM 或 SGLang 服务,通过负载均衡把请求分发到不同实例。Kubernetes 环境下用 Service 加 Deployment 天然支持,云厂商也有托管的负载均衡服务。如果你的请求量波动很大,可以基于 QPS 或 GPU 利用率设置自动扩缩规则。

这里要注意:自动扩缩有个延迟,模型服务启动加载权重可能需要一两分钟,直接落在 K8s 的默认扩缩策略上会导致扩容滞后。更好的方式是根据流量预测提前扩容,或者设置一个较高的 CPU 利用率阈值但配合实例预热。

5. 实战踩坑:部署过程中最疼的五个教训

5.1 GPU 显存碎片导致随机 OOM:一次完整的排查链路

有一次我部署一个 13B 模型,上线初期一切正常,跑了几天之后开始随机会报 CUDA out of memory。重启之后又恢复一阵子,然后再次出现。刚开始以为是并发太高,于是调低了并发限制,但问题依旧。

后来我把 vLLM 日志拉出来,发现 OOM 时单个张量申请的显存其实很小,可能只有几十 MB,但就是分配不出来。我用nvidia-smi看显存占用,发现进程占用的显存里有大量零散空洞,这就是显存碎片化。

最终解决思路不是压缩模型,而是给 KV Cache 池留出更合理的余量。我把--gpu-memory-utilization从 0.95 降到 0.88,给框架更多缓冲空间,同时显式限制了每个请求的最大 token 数,避免单请求把 cache 池撑破。调完之后跑了两个星期,没再出现随机 OOM。

这个坑给我的教训是:显存利用率不是越高越好,尤其在生产环境,留出 10% 到 15% 的缓冲非常必要。

5.2 并发一高 P99 就爆:只测平均延迟的恶果

另一个让我印象深刻的坑是压测时只看平均延迟。当时服务用的是 vLLM,单请求首 token 延迟大约 400ms,看起来很健康。但并发加到 30 之后,整体平均延迟还是 1.2 秒左右,感觉还能接受,可一上线就有用户反馈“卡死了”。

我后来把监控粒度切到百分位才看明白:P95 延迟到了 4 秒,P99 更是飙升到了 8 秒。平均数被大量快速请求平均掉了,真正在排队等 GPU 计算的慢请求完全被掩盖。从此之后,我所有项目的监控指标第一个看的就是 P99,而不是平均值。

大模型推理的延迟天然具有长尾特征,因为输入长度和输出长度变化极大,极端场景下某个请求可能比其他请求慢一个数量级。如果不用百分位指标,前端用户拿到的真实体验很容易失真。

5.3 容器启动后反复退出:退出码 137 和 110 的区分

有段时间我们用 Kubernetes 部署推理服务,发现 Pod 启动后反复重启。排查时看到退出码是 137,第一反应是 OOMKilled,也就是内存超了。但检查容器内存配置后,发现限制并不小。后来仔细看才知道,Kubernetes 里 137 除了内存限制,还有可能是被外部 kill,而真正的原因其实是另一个问题:启动命令里没有指定正确的模型目录,服务启动失败,但由于探针配置错误,Pod 一直处于未就绪状态,不断被健康检查杀掉,表现也是反复重启。

这里的排查经验是:不要只盯着退出码,要把事件、日志、健康检查探针三者结合起来看。退出码 137 代表进程被 kill,但被谁 kill、为什么 kill,要靠事件和日志来定位。后来我统一在 Deployment 里加了清晰的 startupProbe,给足模型加载时间,再配合 livenessProbe 做崩溃恢复,这个问题才算根治。

5.4 输出乱码与历史对话错乱:tokenizer 版本不匹配

有一次我把模型从测试环境复制到生产环境,用的是同一个目录名,但生产环境加载之后对话结果明显异常,中英混杂,甚至出现了连续生成同一个 token 的怪象。一开始怀疑 GPU 有问题,换了卡还是不行。

后来我对比两个环境的tokenizer_config.json和vocab.json,发现文件 hash 不一致。原因是测试环境用的模型目录是旧的,生产环境重新下载时模型版本已经更新,权重和 tokenizer 混用了。大模型的权重要和 tokenizer 严格绑定,哪怕 tokenizer 少一个特殊 token,都会导致乱码和采样分布异常。

这件事之后,我养成了两个习惯:第一,模型目录默认带版本号,比如Qwen2.5-14B-0421,避免新旧权重互相覆盖;第二,每次部署前用固定脚本对模型目录做完整性校验,对比关键文件的 hash 值。

5.5 压测工具选错:单线程 curl 造成的虚假瓶颈

最早我给同事写压测方案,图省事直接写了一个 shell 循环,用 curl 不断请求接口。结果测出来最大 QPS 只有 5,同事直接说服务太垃圾。我当时也很困惑,后来才发现问题根本不在服务,而在压测工具本身。

一个串行 curl 循环意味着:第一个请求返回之后才发第二个请求,网络连接也没有复用来,每次都要重新建 TCP 连接,这测出来的完全是“串行请求 + 建连开销”,和真实并发场景没有任何关系。要模拟真实生产流量,至少要用支持并发、连接复用的压测工具。

前面说的这些坑,我只是挑了几个最痛的,实际上还有鉴权配置错误、日志没配导致排障抓瞎、模型路径硬编码导致迁移失败等等。经验就是教训换来的,别看每个坑都细碎,踩多了真的会让人怀疑人生。

6. 上线前的压测与调优:让服务扛住真实流量

6.1 构造贴近真实场景的压测脚本

压测不是随便打一堆请求,而是要尽量还原真实流量。大模型的请求特征和传统接口完全不同:它带长文本、输出也是流式的、不同请求的输入长度差异巨大。

我压测时通常准备三类请求模板:短问题,模拟一般聊天场景;长系统提示词加短用户问题,模拟 Agent 场景;带多轮历史对话的请求,模拟真实业务。三类请求按一定比例混在一起,并发用户数和请求速率也按业务预估来设。

工具层面,我偏好用 Locust 或者自定义 Python 脚本。因为大模型 API 的压测要记录每个请求的输入长度、输出长度、首 token 延迟、总延迟,这些信息比单纯统计 QPS 有价值得多。我甚至会把压测期间的 GPU 利用率、显存占用、KV Cache 使用率同步采集出来,方便后续一起分析。

6.2 必须盯住的五个数字

大模型推理服务有别于传统 Web 服务,核心指标也更细致。我每次压测和上线后盯的指标就是这五类:

指标含义我关注的原因
QPS每秒完成的请求数服务容量的直接表现
TTFT首个 token 的延迟用户感受到的“响应速度”
TPOT每个输出 token 的平均生成时间决定整个回复要多长时间
GPU 利用率GPU 计算资源忙闲程度判断瓶颈是算力还是排队
KV Cache 使用率显存中的缓存池占用比例判断是否接近容量上限

vLLM 暴露了/metrics端点,SGLang 也有类似的监控输出,Prometheus 直接抓取就行。我在仪表盘里优先展示这几项,而不是默认的 CPU 和内存指标。

6.3 常见瓶颈与调优方向

根据我的压测经验,大模型服务的结果通常落在三种情况:

第一种,GPU 利用率打满,TTFT 和 TPOT 都偏高。说明算力确实是瓶颈,调参能改善的空间有限,要么上更强的卡,要么开多副本。

第二种,GPU 利用率不高,但 TTFT 偏高。这说明请求在排队但不是因为计算排队,很可能在框架的调度层卡住了。这时候可以检查max_num_seqs是否太小,连续批处理是否没生效,模型加载参数是否需要调整。

第三种,KV Cache 使用率长期接近 1.0,同时频繁出现超时。这就是显存池太小,要么降低max-model-len,要么开更大的显存卡,要么考虑量化模型降低单请求缓存占用。

调优时我还有一个习惯:先做单请求延迟基线测试,再做并发压测。单请求延迟能定位到模型和框架层面的问题,并发压测能定位到调度和容量层面,两者不能混在一起看。

7. 长期实践留下的几个部署习惯

内容写到最后,我想分享几个长期踩坑后养成的部署习惯,每个习惯都对应着一次真实教训。

第一个习惯是模型目录永远带版本号,并且部署脚本里要做文件校验。这能避开权重和 tokenizer 不一致的问题,也能让多版本模型并存、快速回退。

第二个习惯是启动参数集中管理。我把max_model_len、gpu_memory_utilization、max_num_seqs、tensor_parallel_size这些参数统一放到一个配置文件里,每次调整都留记录。这样出了性能问题可以快速还原当时的配置,而不是靠记忆去猜。

第三个习惯是日志默认带上请求级别信息,包括输入 token 数、输出 token 数、TTFT 和总耗时。有了这些日志,线上反馈“某个请求很慢”的时候,我能直接定位到是输入太长、排队太久还是生成太多,而不是两眼一抹黑。

第四个习惯是每次调整架构或框架版本之后,一定做一次小规模回归压测。哪怕只是从 vLLM 0.6 升到 0.7,行为也可能发生变化。推理框架版本迭代很快,并不是越新越稳。

最后一个习惯,是对监控报警的 P99 阈值做动态调整。大模型服务的延迟天然波动,固定阈值容易误报,我会根据近一周的延迟分布自动更新基线。报警的价值不在多,而在准。

部署大模型这门手艺,说到底是把模型能力、硬件资源、框架特性、业务流量四者匹配起来的过程。没有一组固定参数能通吃所有场景,但只要理解了显存、吞吐、延迟和成本这四本账,按这套流程走一遍,至少不会出大方向上的错误。希望这篇指南能帮你少踩几个我踩过的坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询