你可能已经跑通了 vLLM 或 llama.cpp,却发现两个人报的性能数字差好几倍——一个说吞吐上百,一个说单机就够用。问题通常不在框架本身,而在硬件、量化格式、并发数和上下文长度这四个变量没对齐。这篇不给你一个「谁更快」的结论,而是给一套可复现的对比方法:先明确你要优化的是首 token 延迟、单路输出速度还是总吞吐,再按硬件档位选择测量项,最后用同一份权重和同一组请求压出可比的数字。
你可能已经跑通了 vLLM 或 llama.cpp,却发现两个人报的性能数字差好几倍——一个说单机吞吐够用,一个说批量任务必须上调度框架。先别急着下结论说谁更快,大多数时候问题不在框架本身,而在硬件、量化格式、并发数和上下文长度这四个变量根本没对齐。对比之前先把这四个变量摆平,数字才有意义。
这篇不给你一个「谁更快」的固定答案,而是给一套能自己跑一遍的对比方法:先想清楚你要优化的是首 token 延迟、单路输出速度还是总吞吐,再按硬件档位挑测量项,最后用同一份权重和同一组请求压出可比的数字。下面按这个顺序讲。
为什么同一个模型,两个人的性能数字能差几倍
性能差异基本由四个主变量决定,任何一个没对齐,两个数字就没法放一起看。第一是硬件,消费卡、数据中心卡、统一内存设备、纯 CPU,四类机器上的瓶颈完全不是一回事;第二是量化格式,GGUF 和 safetensors 加 AWQ/GPTQ 走的根本不是同一条计算路径;第三是并发数,单请求和批量请求的曲线形状完全不同;第四是上下文长度,长上下文下 KV 缓存的压力会盖过权重本身。
- 硬件档位:显存容量与带宽决定了模型能不能完整驻留,驻留与否是数量级差别
- 量化格式:同一模型不同精度,权重体积、计算路径、质量损失都不同,不能混着比
- 并发数:单路快不代表批量快,批量快也不代表单路延迟低
- 上下文长度:短提示词测出来的吞吐,放到长上下文场景往往不成立
还有一个容易被忽略的点:vLLM 从设计上就是面向多并发批处理做调度的,llama.cpp 起家于单机单路和低资源设备,两者优化的目标函数本来就不一样。你拿 vLLM 的批量吞吐去比 llama.cpp 的单路延迟,等于让短跑选手和马拉松选手比同一件事,结论没有价值。所以第一步是先问自己:我要压的到底是延迟还是吞吐?问题问错了,后面测什么都白搭。
两条技术路线的差别:调度思路决定性能天花板
- 分页式 KV 缓存
- 把显存按固定大小的块分配,不同请求的缓存不再要求连续,碎片少了、浪费少了
- 连续批处理
- 新请求可以插进正在执行的批次里,不用等整批跑完,并发上来后吞吐上升明显
- 单路低延迟
- 请求排队和批处理开销小,一个请求进来就能开始算,首 token 时间通常更短
- 异构硬件覆盖
- 同一套代码能在 CPU、核显、独显、统一内存设备上跑起来,部署面更宽
vLLM 的核心是分页式 KV 缓存加连续批处理,显存按块分配,新请求能插进正在跑的批次,所以并发拉高之后总吞吐上升很快。代价是调度本身有开销,单请求场景下这个开销不一定划算。llama.cpp 反过来,它把权重和 KV 缓存尽量塞进有限的显存或内存里,单路延迟低、启动成本小,在显存紧张或只有 CPU、统一内存的机器上更实际。
多卡张量并行、多机扩展这类能力,vLLM 的做法更成熟;llama.cpp 的优势在端侧覆盖和部署简单。注意,如果窗口大小或并发规模变了,两边的相对位置会翻转,别把它们当成一条直线上的两个点。想知道两类路线在算子支持上的差异,可以到 /ai-dict/category/tech 翻术语条目对照。
按硬件分档:你的机器该重点看哪一项
不同硬件档位下,值得盯的指标不一样,挑错了指标等于测了个没用的数。下面按几类常见机器给判断标准,具体每档显存容量和卡数怎么对应你的模型规模,到 /compute/sizing 和 /models/deploy 按自己的参数量和精度算一遍。
| 硬件档位 | 优先看的指标 | 判断标准 |
|---|---|---|
| 消费级单卡,显存紧张 | 单路输出速度、能否完整驻留 | 量化档位的影响通常比框架选择更大 |
| 数据中心卡或多卡 | 并发吞吐、长上下文显存利用率 | 批处理调度能力会在这里被放大 |
| 统一内存设备 | 内存带宽、量化后能否放下 | 单路可用性比峰值吞吐更重要 |
| 纯 CPU 或低端核显 | 能否跑起来、单路延迟 | 先确认量化档位,再谈性能优化 |
数据中心卡场景下,别只测单请求。多卡张量并行开起来之后,通信开销会吃掉一部分收益,这时候要看的是并发扩容曲线,而不是单点峰值。统一内存设备是个例外:内存带宽是硬上限,加并发不会让带宽变多,所以关注点应该放在「能不能稳定跑起来、会不会爆内存」上。
要测什么指标:别只盯一个 token/s
token/s 是个被用烂了的指标,它不区分首 token 时间、单路速度和总吞吐,三个数里任何一个都能让你得出完全相反的结论。工程上至少要记三组数,再加一条并发扩容曲线,才算把性能摸清楚。
- 首 token 延迟:决定交互式应用的手感,长提示词下这个差距最明显
- 单路输出速度:决定单用户等待时间,量化格式和显存带宽是主导因素
- 总吞吐:每秒处理的总 token 数,决定批量任务和多人共用的成本,只看它会掩盖延迟恶化
- 并发扩容曲线:并发从低往上加,吞吐在哪开始持平、延迟在哪开始明显掉,这条拐点比任何单点数字都有用
- 显存占用峰值:它决定你下一档并发能不能再加,漏了这个数扩容就会翻车
测之前先量一遍链路基线。用 /tools/speed-test 跑一下网络和接口延迟,免得把网关排队、代理转发的耗时算到框架头上。做中转站或聚合服务的团队尤其容易踩这个坑,框架本身没问题,锅在链路。
可复现的对比步骤:照着做一遍就有自己的数字
- 固定权重与量化档位两个框架尽量用等价的精度,量化差异可以到 /ai-dict/category/tech 查各格式说明。精度不一致后面全白测
- 固定输入输出长度用同一批请求,提示词和生成长度写死;先跑单并发拿延迟基线,再按倍数往上加并发
- 记录三组数加峰值首 token 时间、单路 token/s、总吞吐三组都记,同时记下显存占用峰值,缺一项就没法解释异常
- 每档跑两轮第一轮当预热丢掉,第二轮才取数;抖动大的配置标注出来,别当稳定结果用
- 整理成表对比 SLA把结果和自己的服务等级目标对比,而不是和网上的数字对比,后者参考价值有限
这套流程跑下来,你手里会有一张自己的表:每档并发对应的三项指标加显存峰值。这张表比任何别人的结论都可靠,因为它是你自己机器、你自己模型、你自己请求分布下的数字。想省事的话,可以先用 /tools/speed-test 粗测一轮,确认链路没问题再上正式压测。
结果怎么看:什么时候 vLLM 明显占优,什么时候不适用
多用户、长输出、并发持续的在线服务场景,vLLM 的批处理调度优势通常会被放大,因为它的设计目标就是这个。反过来,单用户交互、显存吃紧、端侧或异构硬件场景,llama.cpp 的体积和部署成本优势更实际,强行上调度框架反而多一层开销。
| 你的场景特征 | 更可能占优的一方 | 原因 |
|---|---|---|
| 多人同时用、输出较长 | vLLM | 新请求可插入运行中的批次,并发越高吞吐越明显 |
| 单人交互、要求快响应 | llama.cpp | 单路调度开销小,首 token 通常更短 |
| 显存小、设备杂 | llama.cpp | 量化档位多,能在低资源设备上跑起来 |
| 多卡、要横向扩 | vLLM | 张量并行和多实例扩展的做法更成熟 |
不适用的情况也得说清楚。第一,模型权重或某些算子不被某个框架支持时,性能对比没有意义,先解决能不能跑的问题,再谈谁快。第二,量化档位降到很低时,输出质量损失可能盖过性能差异,快但答案变差等于没意义。第三,如果你的服务其实是低频调用,瓶颈在冷启动和模型加载时间上,推理速度根本不是主要矛盾。相关价目和规格口径可以到 /official-api 与 /compute/gpus 对照。
常见坑:这些做法会让对比结果失真
- 两边用了不同量化精度,或一边开了张量并行一边没开,结论直接作废
- 只测一轮、只测一个并发,把峰值当常态报出去
- 先后跑两个框架但没清缓存、没留足显存,前一个进程的影响会带进后一个
- 用短提示词测,却要上线长上下文场景,KV 缓存压力完全不是一回事
- 忽略服务包装层:上层工具会再叠一层调度,测出来不是纯框架表现
最后一个坑值得展开说:很多团队用的其实是包装过 llama.cpp 的上层工具,那测出来的数字里包含了包装层的排队和调度开销,不能直接拿去和裸 vLLM 比。同理,用网关或中转层做转发时,链路延迟也会被算进去。做对比前先确认你测的是哪一层,把这个写进报告的前提里。
下一步把你自己机器上的三组指标和并发拐点记下来,再和站内整理的中转与接口基准对照,就能判断问题出在框架、链路还是量化档位上。→常见问题
同样一张卡、同一个模型,为什么别人说 vLLM 快好几倍?
大概率是并发数不同。单路请求时两者差距不大,甚至 llama.cpp 更低延迟;并发上去后,vLLM 的连续批处理会把多路请求压进同一批计算,吞吐优势才出来。如果你想比的是一对一速度,先确认对方测的是单路还是批量,再对比才有意义。
显存不够的机器上还有必要试 vLLM 吗?
先算一下模型加 KV 缓存能不能放下。放不下时 vLLM 常见做法是降量化或做多卡切分,而 llama.cpp 本身就更擅长在显存紧张时把部分层放到内存或统一内存里。可以先用 /models/deploy 估一遍显存,再决定值不值得折腾。
量化档位不同还能对比两个框架的性能吗?
不建议。量化方式直接改变显存带宽占用和计算路径,GGUF 的不同档位和 safetensors 配 AWQ/GPTQ 本来就不是同一条实现。要对比框架就固定精度;要对比量化档位,就固定框架。混着比出来的数字没法归因。
只跑本地个人助手,需要关心吞吐吗?
通常不用。单用户场景真正影响体验的是首 token 延迟和单路输出速度,以及模型是否常驻显存。吞吐指标在多人共用或批量离线任务时才有意义。你要盯的是切换模型或提问时的等待时间,不是每秒能出多少 token。
测出来结果和官方文档里的数字差很远,是哪里错了?
多数是硬件、驱动版本、模型精度和测试参数四者之一不一致。官方的性能页通常标注了具体的卡型、批大小和序列长度,先对齐这几项;对不齐就以你自己的机器为准,把参数一起记下来,下次换配置时才有可比基线。