先分清两件事:首 token 延迟和吞吐
并发扛不住,多数时候不是卡不够,是参数没调对,或者指标看错了。上线前先把三个数约定好:TTFT(首 token 延迟,从请求发出到第一个 token 返回)、TPOT(后续每个 token 的间隔,决定“吐字”速度)、整体吞吐(tokens/s)。
不少团队只盯吞吐,把 batch 拉到 64、128,看板上 tokens/s 翻倍很开心,可 TTFT 从 200ms 涨到 3s。聊天类产品用户点完发送,两三秒没反应就以为卡死了;后面吐字再快,体验也是崩的。反过来,纯离线跑报表、批量翻译,你完全可以把 TTFT 放到几秒,去换更高的吞吐。两者策略相反,混在同一个实例上,总有一边难受。
| 指标 | 含义 | 什么场景该重点盯 |
|---|---|---|
| TTFT | 首 token 延迟,含排队 + prefill | 对话、语音、Copilot 类交互 |
| TPOT / ITL | 相邻 token 输出间隔 | 长文生成、代码补全 |
| 吞吐 tokens/s | 单位时间总产出 | 离线批处理、报表生成 |
| P95 / P99 | 尾部延迟 | 并发上来之后,平均值会骗人 |
第 1 步:量化与推理引擎,先算显存预算
先看什么指标:显存占用拆解、单卡能否装下目标上下文、量化前后的效果对比、TPOT。
显存要按「权重 + KV cache」一起算,别只看模型能不能放下。7B 模型 FP16 权重约 14GB,INT8 约 7GB,4bit 约 4GB;但 KV cache 不随权重量化等比缩小,上下文拉到 8k、16k 之后,KV cache 经常比权重还占地方。先把这笔记清楚,再谈能开几个实例。
量化的取舍:4bit(AWQ、GPTQ 这类)在通用问答上掉点通常不明显,但长上下文检索、数学推理、严格 JSON 输出这几类任务要单独测。用公开校准集量化的模型,换到你的垂直语料上可能就不好使了。稳妥做法是抽 200~500 条真实线上请求做对照,别看榜单决定生产配置。
引擎选择:vLLM 起步比较稳,continuous batching 成熟,社区问题好搜;SGLang 在前缀复用和结构化输出上更顺手;TensorRT-LLM 性能好,但编译流程和版本绑定成本高,适合模型固定、流量大的场景;llama.cpp / Ollama 适合单机低并发或边缘部署。选型时别一次换两个变量,先固定引擎再调参数。这部分细节可以对照我们的AI 推理部署方案。
第 2 步:批处理调优,别只把 batch 拉大
先看什么指标:GPU SM 利用率、batch size 与 TTFT 的曲线拐点、请求在队列里的等待时长。
continuous batching(in-flight batching)已经是基线能力,不是加分项。真正要调的是几个参数,顺序有讲究——先给 TTFT 定预算,比如 P95 不超过 800ms,然后往上加并发请求数,加到 TTFT 超标就回退一档,那才是安全水位。先定 batch 再抱怨延迟高,是常见的反着做。
| 参数 | 作用 | 调大的代价 |
|---|---|---|
| max_num_seqs | 同时在跑的请求数上限 | TTFT 涨、KV cache 涨,可能 OOM |
| max_num_batched_tokens | 单次前向的 token 预算 | 长 prompt 更慢,短请求被挤 |
| gpu_memory_utilization | 留给 KV cache 的显存比例 | 压太满会触发重算或直接崩 |
坑在长短请求混跑。一个 8k prompt 的请求进来,会把同一批里的短请求一起拖慢,因为 prefill 是算力密集的。两种解法:开 chunked prefill,把长 prompt 拆开插空跑;或者按 prompt 长度分流,长文本走单独实例。前者省机器,后者省心,团队小的话建议直接分流。
第 3 步:多实例扩容,加卡之前先找拐点
先看什么指标:单实例的吞吐-延迟拐点、排队长度、每百万 token 的算力成本。
单卡跑多实例,通常比单实例堆 batch 更容易保住 TTFT。比如 80G 卡上跑两个 7B 实例,各分 35G 左右,互相不抢 KV cache,一个实例撞上长请求也不会把另一个拖死。四卡机器上跑四个实例,故障域小,扩缩容也好切。
张量并行(TP)只在单个请求都放不下时才用。TP 每层都要走通信,对 TTFT 是负收益,8B 以下的模型基本用不上。别为了“看起来用满多卡”去开 TP。
网关层的坑更多。轮询分发遇到长尾请求会堆积,换成最少连接或按队列长度打分。流式 SSE 是长连接,注意负载均衡的空闲超时和连接数上限,别让网关把流式响应截断;重试策略也要收着点,否则用户会看到重复内容。扩缩容的触发条件用队列长度和 TTFT,不要用 GPU 利用率——利用率 70% 但 TTFT 平稳,说明还没到瓶颈,这时候加卡就是浪费。
实例位置会直接体现在 TTFT 上。用户在国内、机房放香港,链路上就能省掉几十毫秒,可以看香港 GPU 算力租赁的节点说明;需要横向扩规模时,GPU 服务器租用按小时起算,比一次性采购更适合验证阶段。
第 4 步:缓存与降级,把贵的那段省掉
先看什么指标:前缀缓存命中率、重复问题占比、超时率和被拒请求数。
Prefix caching 是性价比很高的一项。系统提示词、few-shot 示例、RAG 里固定的模板,在大量请求里是重复的,prefill 阶段可以直接复用 KV。前提是请求前半段字节级一致——模板里塞了时间戳、随机 ID,或者每次重新排序的 few-shot,命中率会掉到接近零。检查方法很土但有效:把同一用户的两次 prompt 前 500 字符 diff 一下。
语义缓存只建议用在 FAQ、客服这类问题集合有限的场景。相似度阈值调松会答非所问,而且错得隐蔽,宁可不命中。
降级链要提前写好顺序,别等崩了临时拍:请求超时 → 切小模型或量化版本 → 缩短 max_tokens → 转异步排队 → 限流返回排队提示。每一级都要在响应里带标记,前端才能提示“当前为快速模式”。用户能接受降级,不能接受莫名其妙变笨。
还有一点常被忽略:图片、JS、模型权重下载这些别让推理实例扛,交给 CDN,全球 CDN 加速能把这部分带宽和连接数从推理网关里摘出去,网关的并发数才干净。
按顺序自查一遍
- 把 TTFT、TPOT、吞吐、P95 打到看板上,交互流量和离线流量分开统计。
- 算清「权重 + KV cache」的显存账,再决定量化级别和实例数。
- 按 TTFT 预算反推 max_num_seqs,找到回退点。
- 单卡多实例先跑起来,找到拐点再横向加机器,别一步到位买大规格。
- 开前缀缓存、对齐模板,之后才考虑语义缓存和降级链。
首次上线按这个顺序走一遍,通常能在不加卡的前提下把可承载并发提一档。要具体参数建议,把模型、上下文长度、目标 QPS 和延迟预算发到 联系合作,或直接邮件 bd@319keji.com,我们按你的真实流量给配置,而不是丢一份通用模板。