当前位置:首页 > 文章列表 > 科技周边 > 人工智能 > 连续批处理怎样平衡首 token 延迟

连续批处理怎样平衡首 token 延迟

来源:17golang原创 2026-10-17 23:42:27 0浏览 收藏

连续批处理的目标不是把批次盲目做大,而是在 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、显存压力和调度切换。

连续批处理把请求、等待队列、prefill、KV cache、首 token 和 decode 组织成三个观测分组的静态说明图
图1:TTFT 的静态分解说明图,展示请求、队列、prefill、KV cache、首 token 与 decode 的关系,不是运行截图或性能证据。

建议至少同时记录以下维度:

指标回答的问题偏高时先看什么
队列时间 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,可能让少量请求就吃掉大部分缓存,随后新请求只能等待、被拒绝或触发卸载。

连续批处理中 token 预算、请求上限、KV cache 与等待请求之间的静态关系说明图
图2:输入预算、调度边界和显存资源的关系说明图,用于理解容量取舍,不表示某次真实压测结果。

可以把容量判断写成一个简单的工程检查表:

  1. 先统计 prompt token 和生成上限的分布,不要只看请求数。
  2. 确认 KV cache 的可用 block 是否会因长请求持续减少。
  3. 用 max_requests_per_batch 或 max_num_seqs 限制单轮请求数,防止 logits 和每请求缓冲区突然膨胀。
  4. 为 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 等批次指标。实际接入时,优先把这些指标按模型、请求长度和调度策略分组,而不是只画一条全局平均曲线。

一个稳妥的调参顺序是:

  1. 先把活动请求、最大排队请求和最大输入长度设成明确边界。
  2. 用较保守的 token 预算取得基线,记录 TTFT p50/p95、队列时间和吞吐。
  3. 每次只增加一档 prefill token 预算,观察 TTFT p95 是否超过业务目标。
  4. 若吞吐上升但 TTFT 尾部恶化,先回退预算,再考虑请求分类或独立服务池。
  5. 只有在缓存余量稳定时,才提高并发请求数。

常见问题

批次越大,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 利用率更可靠。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
LLM 推理怎样估算 KV cache 显存占用LLM 推理怎样估算 KV cache 显存占用
上一篇
LLM 推理怎样估算 KV cache 显存占用
语音转写前怎样用 VAD 切除静音区
下一篇
语音转写前怎样用 VAD 切除静音区
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    510次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    570次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    594次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    547次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    364次使用