连续批处理怎样平衡首 token 延迟
连续批处理的目标不是把批次盲目做大,而是在 GPU 有足够工作可做的同时,让新请求尽快拿到第一个 token。真正需要平衡的是三段时间:请求在队列里等待的时间、输入 prompt 的 prefill 时间,以及首个输出 token 被生成前的调度时间。吞吐通常随 token 预算和并发上升,但 TTFT 的高分位也可能随之变差。
本文只讨论“吞吐与首 token 延迟权衡”这一条边界。Hugging Face 的相关文档把连续批处理描述为每个生成步骤重新调度批次;vLLM 也提供了 token 预算、序列数和排队请求数等调度边界。官方资料入口如下,便于按实现继续查参数:
Transformers 官方地址:https://huggingface.co/docs/transformers/continuous_batching
vLLM 官方地址:https://docs.vllm.ai/en/latest/usage/metrics/
TGI 官方地址:https://huggingface.co/docs/text-generation-inference/basic_tutorials/launcher
先给结论:先观察 TTFT 的 p95 与队列时间,再小步调整 prefill token 预算;只有确认 KV cache 仍有余量、decode 没有被长 prompt 持续打断时,才增加并发或批次上限。
先把 TTFT 拆成三个可观测部分
TTFT(time to first token)不是单一的 GPU 计算耗时。在线服务里,一条请求至少要经过排队、prefill 和首 token 生成这三个阶段。排队时间过长,说明调度器没有及时接纳请求;prefill 时间过长,常见原因是输入很长或单次 token 预算过大;首 token 生成时间异常,则要继续看 KV cache、显存压力和调度切换。

建议至少同时记录以下维度:
| 指标 | 回答的问题 | 偏高时先看什么 |
|---|---|---|
| 队列时间 p95 | 请求是否卡在进入运行态之前 | 活动请求上限、排队上限和调度策略 |
| prefill 时间 | 输入 token 是否占满一次前向预算 | prompt 长度、token 预算、chunked prefill |
| TTFT p95 | 用户多久看到第一个 token | 前两项叠加后的尾部表现 |
| TPOT/ITL | 首 token 后的输出是否稳定 | decode 批次、KV cache 和抢占 |
不要只用平均值做调参结论。短请求可能掩盖长 prompt 的排队尾部,而平均吞吐上升也不能证明交互式请求变快。
用 token 预算控制 prefill 对 decode 的影响
连续批处理会在生成过程中不断接纳和移出请求,但 prefill 仍然需要一次性处理输入 token。token 预算越大,一次前向可以塞进更多 prompt,通常有利于 prefill 吞吐;代价是该轮占用更多显存和计算时间,正在 decode 的请求可能更久才能获得下一次调度。
以 Transformers 的配置为例,max_batch_tokens 控制单次前向可处理的 query token 预算。下面是一个用于说明参数关系的最小片段:
from transformers.generation import ContinuousBatchingConfig
# 用显存比例约束 KV cache,避免只追求更大的批次。
cb_config = ContinuousBatchingConfig(
max_memory_percent=0.80,
block_size=256,
max_batch_tokens=8192,
max_requests_per_batch=128,
scheduler_type="fifo",
safety_margin=0.15,
)
# 这里的配置只描述调度和显存边界,生成长度仍由 GenerationConfig 控制。
outputs = model.generate_batch(
inputs=inputs,
generation_config=generation_config,
continuous_batching_config=cb_config,
)
参数名会随框架版本和实现变化,关键不是照抄某个数,而是理解三个方向:
- prefill-bound 负载中,适当增加 token 预算可以减少分批次数,但要观察 TTFT p95 是否变长。
- 交互式短请求较多时,较小的 token 预算通常更容易保护正在 decode 的请求;代价是长 prompt 的吞吐可能下降。
- 超长 prompt 不应简单地把全局预算继续放大,可以用分块 prefill 或请求级长度上限把影响摊开。
vLLM 中常见的对应边界是 max_num_batched_tokens 和 max_num_scheduled_tokens。前者约束一次迭代最多处理的 token,后者约束调度器一次发出的 token 数。不要把它们理解成“越大越快”的开关:如果 decode 请求已经拥挤,增加预算可能先改善吞吐,随后推高 TTFT 尾部。
用 KV cache 和请求上限守住并发边界
连续批处理的可接纳请求并不只由请求数量决定。每条请求的 prompt token、预计生成 token 和 KV cache block 都会占用显存。长输入加上较大的 max_new_tokens,可能让少量请求就吃掉大部分缓存,随后新请求只能等待、被拒绝或触发卸载。

可以把容量判断写成一个简单的工程检查表:
- 先统计 prompt token 和生成上限的分布,不要只看请求数。
- 确认 KV cache 的可用 block 是否会因长请求持续减少。
- 用
max_requests_per_batch或max_num_seqs限制单轮请求数,防止 logits 和每请求缓冲区突然膨胀。 - 为 decode 留出安全余量;当缓存接近边界时,宁可延迟新 prefill,也不要让正在输出的请求整体抖动。
这也是为什么调大 batch token 预算后,必须同时复查显存和并发。Transformers 的连续批处理文档把 token budget、KV cache budget 和 request cap 分开描述;它们是相互消耗同一块硬件资源的不同边界。
按负载选择 FIFO 或 prefill-first
调度策略决定了“谁先占用下一次 forward”。FIFO 更适合希望按到达顺序推进、并优先完成已有 decode 的场景;prefill-first 则更适合长 prompt 持续进入、需要尽快把分块 prefill 做完的场景。两者没有脱离负载的绝对优劣。
可以按下面的信号选择方向:
| 负载特征 | 优先尝试 | 主要风险 |
|---|---|---|
| 短 prompt、交互式请求多 | FIFO、小一些的 prefill 预算 | 长 prompt 吞吐偏低 |
| 长 prompt、批量生成多 | prefill-first、分块 prefill | 短请求 TTFT 尾部上升 |
| 输出长度差异很大 | 请求上限加 KV 安全余量 | 缓存不足导致等待或卸载 |
以 Transformers 的配置表达时,调度器是硬件和队列策略的一部分,而不是生成参数的一部分。把 GenerationConfig 的采样和停止设置,与 ContinuousBatchingConfig 的缓存和调度设置分开管理,排查时会清楚很多。
from transformers.generation import ContinuousBatchingConfig
# 长 prompt 较多时才尝试 prefill-first;不要与 FIFO 的结论混用。
cb_config = ContinuousBatchingConfig(
scheduler_type="prefill_first",
max_batch_tokens=8192,
max_requests_per_batch=64,
safety_margin=0.0,
)
# 先用同一组请求分布比较 p50、p95 和显存,再决定是否保留该策略。
outputs = model.generate_batch(
inputs=inputs,
generation_config=generation_config,
continuous_batching_config=cb_config,
)
这里的数值只是配置示意,不是通用推荐值。尤其是 safety_margin、请求上限和 token 预算,应通过固定的请求样本做对照实验。
用分位数指标验证平衡是否成立
一次改动至少要同时看吞吐、TTFT 和 decode 阶段。建议固定模型、硬件、采样参数、输入长度分布和输出上限,只改变一个调度变量,再比较:
- TTFT p50/p95:分别反映典型请求和尾部请求看到首 token 的时间。
- 队列时间 p95:判断问题发生在接纳之前,还是发生在 GPU 计算阶段。
- TPOT 或 ITL:判断首 token 之后的持续输出是否因为 prefill 抢占而抖动。
- 生成吞吐:按 output tokens/s 观察批次是否真的提高了有效产出。
- KV cache 使用与抢占:确认吞吐收益不是用频繁卸载、重算或更高失败率换来的。
vLLM 官方指标中有 time_to_first_token_seconds、请求队列时间、prefill 时间、decode 时间和生成 token 数等维度;TGI 也提供批次大小、forward duration、inference duration 等批次指标。实际接入时,优先把这些指标按模型、请求长度和调度策略分组,而不是只画一条全局平均曲线。
一个稳妥的调参顺序是:
- 先把活动请求、最大排队请求和最大输入长度设成明确边界。
- 用较保守的 token 预算取得基线,记录 TTFT p50/p95、队列时间和吞吐。
- 每次只增加一档 prefill token 预算,观察 TTFT p95 是否超过业务目标。
- 若吞吐上升但 TTFT 尾部恶化,先回退预算,再考虑请求分类或独立服务池。
- 只有在缓存余量稳定时,才提高并发请求数。
常见问题
批次越大,TTFT 一定越低吗?
不一定。更大的 prefill 预算可能提升吞吐,但会拉长当前 forward 或让 decode 请求等待下一轮,TTFT 的 p95 可能上升。
为什么平均 TTFT 没变,p95 却变差?
通常是长 prompt、缓存紧张或少量排队请求形成了尾部。平均值被大量短请求稀释,分位数才能暴露这类不均衡。
应该先调并发还是先调 token 预算?
先固定并发,调 token 预算并观察 TTFT、TPOT 和缓存;确认缓存有余量后再逐步提高并发,否则很难判断恶化来自哪一个变量。
连续批处理适合所有请求混在一个池里吗?
不一定。交互式短请求和长上下文离线任务的目标不同。若一个调度策略无法同时满足两者的 TTFT 和吞吐目标,可以按请求类型拆分服务池。
总结
连续批处理的平衡点不是某个固定 batch size,而是“在缓存边界内,用足够的 token 预算保持 GPU 忙,同时给等待和 decode 请求保留可预测的服务机会”。先拆 TTFT,再看 token 预算、KV cache 和请求上限,最后用 p95 与吞吐一起做决定,通常比单独追求 GPU 利用率更可靠。
LLM 推理怎样估算 KV cache 显存占用
- 上一篇
- LLM 推理怎样估算 KV cache 显存占用
- 下一篇
- 语音转写前怎样用 VAD 切除静音区
-
- 科技周边 · 人工智能 | 1小时前 | 人工智能 · 可观测性 · LLM 流式响应 日志脱敏 token用量 prompt_tokens completion_tokens
- LLM 请求怎样记录 token 用量而不泄露正文
- 413浏览 收藏
-
- 科技周边 · 人工智能 | 1小时前 |
- RAG 系统怎样隔离文档中的指令性文本
- 390浏览 收藏
-
- 科技周边 · 人工智能 | 1小时前 | 人工智能 · 语音转写 VAD 静音检测 Silero VAD
- 语音转写前怎样用 VAD 切除静音区
- 371浏览 收藏
-
- 科技周边 · 人工智能 | 1小时前 |
- 生成式回答怎样设计成对比较评测
- 199浏览 收藏
-
- 科技周边 · 人工智能 | 1小时前 | rag · 向量检索 · RAG metadata filter 多租户检索
- RAG 检索怎样用元数据过滤租户内容
- 433浏览 收藏
-
- 科技周边 · 人工智能 | 1小时前 |
- RAG 文档切片怎样设置重叠区避免语义断裂
- 297浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 510次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 570次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 594次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 547次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 364次使用
-
- 量化模型本地推理的显存估算方法
- 2026-10-17 501浏览
-
- 本地大模型反复输出同一句话怎么调整生成参数
- 2026-09-06 501浏览
-
- Python 调用大模型时如何用结构化输出校验 JSON:从解析失败到可重试
- 2026-08-29 501浏览
-
- AI写作工具免费版安装教程(含豆包Clawdbot)
- 2026-05-30 501浏览
-
- WPS AI能自动生成PPT吗?输入主题一键制作演示文稿
- 2026-05-27 501浏览
