1. 为什么你的 vLLM 推理服务需要一次可复现的性能评估
你已经在红帽 AI 推理服务上把 vLLM 跑起来了,模型能出字,接口能通,但这台机器到底能扛多少并发、首 token 要等多久、P99 延迟会不会在业务高峰期炸掉,这些问题不测一遍心里没底。LLM 推理服务和传统 Web 服务不一样,它的资源消耗跟输入长度、输出长度、并发数强相关,同一个模型在不同请求形态下吞吐能差好几倍。所以性能评估不是跑个脚本看个数字,而是要固定变量、可复现、能横向对比。
我这次要做的,是在红帽 AI 推理服务(vLLM)上,用 GuideLLM 这个专门为 LLM 部署设计的压测工具,完成一次从部署参数到压测配置再到结果解读的完整闭环。GuideLLM 和普通的 HTTP 压测工具最大的区别在于:它理解 token。它会按你指定的 prompt_tokens 和 output_tokens 去构造请求,统计 TTFT、ITL、TPOT 这些 LLM 专属指标,而不是只给你一个 QPS。这对做容量规划的人来说非常关键。
适合谁看:已经在用 vLLM 或红帽 AI 推理服务部署模型、需要给业务方一个「这台机器能撑多少 RPS」结论的工程师;正在做硬件选型、想知道「要达到 P99 TTFT < 80ms 需要几张卡」的架构同学;以及想把性能回归测试纳入 CI 的团队。读完你能拿到一套可以直接复制的 vLLM 启动参数、GuideLLM 压测命令,以及一份能对照排查报错的清单。
核心检索词先摆出来:红帽 AI 推理服务 vLLM 性能评估、GuideLLM 压测 LLM 吞吐延迟、vLLM 推理服务 TTFT ITL TPOT 指标。这三个词贯穿全文,你搜进来看到的就是这些内容。
在动手之前,先把几个关键指标的定义对齐,不然后面看报告会懵。RPS 是每秒请求数,衡量并发处理能力;Request Latency 是单请求从发出到结束的总时间,等于 TTFT 加生成时间;TTFT 是首 token 时间,面向用户的应用最在意这个;ITL 是 token 间延迟,不含首 token,反映生成流畅度;TPOT 是每个输出 token 的平均耗时,等于生成时间除以输出 token 总数,是吞吐效率指标。这几个指标里,TTFT 和 TPOT 是你要重点盯的,因为它们直接决定用户体验和单位成本。
2. 前置准备:红帽 AI 推理服务与 GuideLLM 环境搭建
这一节把地基打好。红帽 AI 推理服务本质上是把 vLLM 做了企业级封装,提供了运维、监控、多模型管理等能力,底层推理引擎还是 vLLM。所以你在红帽环境里验证过的 vLLM 参数,大部分可以直接迁移。如果你还没装好推理服务,先按官方入门文档把服务跑起来,确认vllm serve能正常加载模型。
先确认你的 Python 环境。建议用独立虚拟环境,避免和系统包打架:
python3 -m venv myenv source myenv/bin/activate pip install --upgrade pip然后安装 vLLM 和 GuideLLM。注意 GuideLLM 是 vLLM 项目下的独立工具包,安装命令就是pip install guidellm。同时把压测脚本需要的依赖也装上,因为 vLLM 自带的 benchmark_serving.py 会用到 pandas 和 datasets:
pip install vllm pandas datasets guidellm如果你只想用 GuideLLM,其实pip install guidellm就够了,它自带请求生成器,不依赖 datasets。但为了后面能对照 vLLM 原生脚本的结果,建议一起装。
模型方面,我用 RedHatAI/Llama-3.2-1B-Instruct-FP8 做演示,这个模型小、加载快、FP8 量化后显存占用低,适合在单卡上快速验证流程。你换成自己的模型也行,只要把后面的 model 参数替换掉。
启动 vLLM 服务。这里给一组我实测比较稳的参数,重点是--max-model-len要和你的压测输入输出长度匹配,--gpu-memory-utilization控制显存占用比例:
vllm serve RedHatAI/Llama-3.2-1B-Instruct-FP8 \ --host 0.0.0.0 \ --port 8000 \ --max-model-len 4096 \ --gpu-memory-utilization 0.90 \ --dtype auto \ --disable-log-requests--disable-log-requests在压测时很有用,否则每个请求都打日志,I/O 会成为瓶颈,测出来的吞吐偏低。等服务起来后,用 curl 确认接口通:
curl http://localhost:8000/v1/models返回模型列表就说明服务正常。这一步别跳过,后面 GuideLLM 报连接错误时,你能快速判断是服务没起还是压测配置写错了。
关于 TaoToken 的前置说明:如果你在本地做压测的同时,还想用云端 API 做对照测试,或者团队里有人用 Coding Plan 跑 Agent 任务,可以先把 key 准备好。TaoToken 的 API 地址是 https://taotoken.net/api,控制台在 https://taotoken.net/console,API Keys 管理页在 https://taotoken.net/api-keys。这些和本地 vLLM 压测是两条线,本地压测不依赖外部服务,但做模型效果对照时会用到。模型对话入口在 https://taotoken.net/model-chat,接入文档在 https://taotoken.net/doc,Coding Plan 在 https://taotoken.net/coding-plan。先把这些地址记下来,后面 CTA 会用到。
环境搭好后,建议先跑一次小规模请求确认端到端通,再上 GuideLLM。很多人一上来就 sweep,结果报错信息混在一起,排查成本高。
3. 可复制配置:vLLM 部署参数与 GuideLLM 压测文件
这一节是全文的核心操作区。我会给你三样东西:一份 vLLM 启动配置、一份 GuideLLM 的 YAML 压测配置、以及对应的命令行调用方式。你直接复制改路径就能用。
先说 vLLM 的启动配置。红帽 AI 推理服务支持用配置文件方式启动,我把它写成一个 TOML 片段,方便你纳入版本管理:
# vllm-service.toml [model] name = "RedHatAI/Llama-3.2-1B-Instruct-FP8" dtype = "auto" max_model_len = 4096 gpu_memory_utilization = 0.90 [server] host = "0.0.0.0" port = 8000 disable_log_requests = true [engine] enable_prefix_caching = true max_num_seqs = 256enable_prefix_caching对多轮对话或共享前缀的请求提升明显,压测时如果 prompt 有公共前缀,开启它能显著降低 TTFT。max_num_seqs控制同时调度的序列数,太小会限制并发,太大可能 OOM,256 是个保守起点。
接下来是 GuideLLM 的压测配置。GuideLLM 支持 YAML 配置文件,比纯命令行更好维护。我写一份guidellm-bench.yaml:
# guidellm-bench.yaml target: "http://localhost:8000" rate_type: sweep max_seconds: 30 data: prompt_tokens: 512 output_tokens: 256 profile: type: sweep strategies: - synchronous - throughput - constant constant_rates: [1.0, 2.0, 4.0, 8.0]这份配置的意思是:对 localhost:8000 做 sweep 压测,每个策略跑 30 秒,请求形态固定为输入 512 token、输出 256 token。sweep 会依次跑同步、吞吐、以及几个固定速率档位,帮你找到延迟开始劣化的拐点。constant_rates里的数字是 RPS,你可以根据自己机器的预期能力调整。
如果你不想用 YAML,等价的命令行是:
guidellm benchmark \ --target "http://localhost:8000" \ --rate-type sweep \ --max-seconds 30 \ --data "prompt_tokens=512,output_tokens=256"两种方式结果一致,YAML 适合反复跑和进 CI,命令行适合临时验证。
这里有个关键点:GuideLLM 默认走 OpenAI 兼容接口,也就是/v1/completions或/v1/chat/completions。vLLM 原生就兼容这套接口,所以不需要额外适配。但你要确认--target后面不要带/v1,GuideLLM 会自己拼路径。我见过有人写成http://localhost:8000/v1,结果 404,排查半天。
另外,如果你的服务开了鉴权,GuideLLM 支持传 authorization 头,在 YAML 里加:
backend: authorization: "Bearer your-token"本地压测一般不开鉴权,但红帽 AI 推理服务在生产环境通常会配,提前知道这个字段能省事。
配置写好后,先别急着跑全量 sweep。用--max-seconds 5跑个短测,确认没有连接错误、模型名对得上、请求能正常返回。短测通过后再跑 30 秒的正式压测。这个习惯能帮你把「配置错误」和「性能问题」分开。
4. 验证请求与结果解读:从 Benchmark 报告读出硬件需求
压测跑起来后,GuideLLM 会实时打印进度,结束后输出两大块:Benchmarks Info 和 Benchmarks Stats。Info 是每个策略的请求数、token 数统计,Stats 是延迟和吞吐指标。我拿一次实测结果来带你读。
先看 Info 部分。synchronous 策略下,30 秒完成 14 个请求,1 个未完成;throughput 策略下完成 161 个,510 个未完成。未完成不代表失败,而是压测时间到了请求还没返回,说明吞吐策略下系统被打满了。Err 列全是 0,说明没有报错请求,服务稳定。
再看 Stats 部分,这是重点。synchronous 策略下,Out Tok/sec 是 121.5,Req Latency mean 是 2.11ms,TTFT mean 24.7ms,ITL mean 8.2ms,TPOT mean 8.1ms。这个延迟非常低,因为同步策略一次只发一个请求,系统毫无压力。
随着 constant 速率从 1.09 升到 5.37,你能看到清晰的趋势:TTFT mean 从 21.6ms 涨到 37.3ms,ITL mean 从 8.8ms 涨到 11.9ms,TPOT 从 8.8ms 涨到 11.9ms。延迟在缓慢上升,但还没到崩溃点。throughput 策略下,并发冲到 141.45,TTFT mean 飙到 1713.3ms,P99 到 3793.7ms,这就是系统被打满后的表现。
现在做容量推算。假设业务要求 P99 TTFT 低于 80ms。看 constant 档位,constant@4.76 的 TTFT P99 是 75.3ms,constant@5.37 的 P99 是 90.7ms,已经超标。所以这台硬件在满足 P99 TTFT < 80ms 的前提下,能支撑的 RPS 大约是 4.76。如果业务需要 50 RPS,那 50 除以 4.76 约等于 10.5,向上取整需要 11 台同配置服务器。这个推算方法就是原文里提到的思路,我把它具体化了。
再验证一下请求是否真的成功。压测结束后,你可以单独发一个请求确认服务还在正常响应:
curl http://localhost:8000/v1/completions \ -H "Content-Type: application/json" \ -d '{ "model": "RedHatAI/Llama-3.2-1B-Instruct-FP8", "prompt": "Explain vLLM in one sentence.", "max_tokens": 64 }'返回里有choices字段和生成的文本,就说明服务健康。这一步是压测后的 sanity check,别省。
GuideLLM 还会把完整报告存成 JSON,默认路径在输出里会打印,比如/root/benchmarks.json。你可以用 jq 提取关键指标做对比:
jq '.benchmarks[] | {name: .name, ttft_p99: .stats.ttft.p99, tpot_mean: .stats.tpot.mean}' /root/benchmarks.json这样每次压测后能快速生成一张对比表,纳入回归测试。我试过把不同模型、不同量化版本的报告放一起对比,FP8 相比 FP16 在同等硬件上 TPOT 能降 20% 左右,但具体数字取决于模型和输入长度,你得自己测。
读报告时有个坑:mean 和 median 差距大说明分布偏斜,这时候要看 P99。比如 throughput 策略下 TTFT mean 1713ms、median 1608ms、P99 3793ms,P99 是 mean 的两倍多,说明有长尾请求。面向用户的应用必须盯 P99,不能只看均值。
5. 常见报错排查:401、连接失败与 choices 解析异常
压测过程中最容易撞上的几类错误,我按出现频率排一下,每个都给你定位方法。
第一类:401 Unauthorized。如果你在红帽 AI 推理服务上开了鉴权,GuideLLM 没带 token 就会 401。报错长这样:
Error: backend request failed with status 401: Unauthorized解决方法是确认服务端鉴权配置,然后在 GuideLLM 配置里加 authorization 字段。如果你用的是 TaoToken 的 API 做对照测试,key 要从 https://taotoken.net/api-keys 拿,Base URL 填 https://taotoken.net/api,Model ID 填你实际调用的模型名。这三件套缺一不可:Base URL、Key、Model ID。很多人只填了 URL 忘了 model,报 404 或 model not found。
第二类:local proxy failed 或 connection refused。报错类似:
Error: failed to connect to http://localhost:8000: Connection refused这说明 vLLM 服务没起来,或者端口不对。先curl http://localhost:8000/v1/models确认。如果服务在容器里,注意端口映射,--host 0.0.0.0不能少,否则只监听 127.0.0.1,容器外访问不到。
第三类:reading choices 相关错误。GuideLLM 解析响应时如果拿不到choices字段,会报:
Error: failed to parse response: missing 'choices' in response body这通常是接口路径不对。GuideLLM 默认走/v1/completions,如果你用的是 chat 模型且服务只开了/v1/chat/completions,就会解析失败。检查 vLLM 启动参数,或者确认模型是否支持 completions 接口。Llama-3.2-Instruct 系列建议走 chat 接口,在 GuideLLM 里可以指定路径。
第四类:OOM 或 CUDA out of memory。压测时并发一高,显存不够就崩。报错:
torch.cuda.OutOfMemoryError: CUDA out of memory解决方法是降--gpu-memory-utilization,或者降max_num_seqs,或者缩短max_model_len。压测的输入输出长度如果超过max_model_len,也会触发异常,确保prompt_tokens + output_tokens <= max_model_len。
第五类:OAuth 或 token 过期。如果你用云端 API 做对照,token 过期会报 401 或 403。重新生成 key 即可。本地 vLLM 不涉及这个问题。
排查顺序建议:先 curl 确认服务活着,再确认接口路径,再确认鉴权,最后看显存。这个顺序能覆盖 90% 的问题。每次改配置后重新跑 5 秒短测,别直接上 30 秒,省时间。
6. 把压测纳入日常:从一次评估到持续回归
一次压测只能告诉你「此刻这台机器能扛多少」,但模型更新、驱动升级、参数调整都会改变性能。所以真正有价值的做法是把这套流程固化成回归测试。
具体怎么做:把guidellm-bench.yaml和 vLLM 启动配置一起放进 Git,每次模型或环境变更后跑一次,把benchmarks.json存档,用脚本对比关键指标的波动。比如 TTFT P99 超过基线 20% 就告警。这样你能在性能劣化影响业务之前发现它。
如果你团队用 Coding Plan 跑长期 Agent 任务,压测数据还能帮你决定该用本地推理还是云端 API。本地推理在固定负载下单位成本低,但弹性差;云端 API 弹性好,但按 token 计费。用 GuideLLM 测出本地的 RPS 上限和延迟曲线后,你能算出本地能覆盖多少峰值流量,超出部分走云端,这个混合策略比拍脑袋靠谱。
最后给一个实用技巧:压测时把--max-seconds设成业务高峰的典型时长,比如 60 秒或 120 秒,短测容易低估长尾延迟。另外,warmup 很重要,vLLM 首次请求会触发编译和缓存填充,前几个请求延迟偏高,GuideLLM 支持 warmup 配置,正式测之前先跑几个请求把模型热起来。
这套流程我在不同硬件上跑过多次,最深的体会是:不要迷信单次结果,多跑几轮取稳定值;不要只看吞吐,延迟曲线才是容量规划的依据;不要跳过短测,配置错误和性能问题混在一起最难查。把这三条记住,你的 vLLM 性能评估就能做得又稳又可复现。