vLLM 的 Prefill 与 Decode 分离:把首 token 延迟与 token 间延迟分治

vLLM 文档里 Disaggregated Prefilling 仍标着 experimental,但已经是 2026 年大规模推理服务的主流方向之一。核心想法一句话:把 prefill 与 decode 拆到不同 GPU 池,分别优化。 prefill 与 decode 为什么是两种完全不同的瓶颈? 一次请求进来,prefill 阶段要并行读完整段提示,是算力密集型,瓶颈在矩阵乘;decode 阶段逐个吐 token,是内存带宽密集型,瓶颈在把权重从 HBM 搬到计算单元。混在同一个 GPU 上跑,两者互相抢资源:一个长 prefill 会堵住正在 decode 的请求,让 token 间延迟(ITL)抖动。 拆成两池后,prefill 池专心吃算力,decode 池专心吃带宽,首 token 延迟(TTFT)与 token 间延迟(ITL)可以独立调优,甚至配不同的并行策略。 到底什么时候才值得做 P/D 分离? 请求短、并发低的小服务,拆了反而多一次 KV 搬运的开销。当线上同时存在「大量长文档预填充」与「高并发流式输出」两类负载时,拆分的收益才压过搬运成本。vLLM 现在支持通过 connector 把 prefill 算好的 KV 块传到 decode 实例,靠 NIXL 这类高速通道做跨节点传输。 P/D 分离是不是抄大厂架构就行? PD 分离不是银弹,而是一道容量规划题。先量出你线上 TTFT 与 ITL 哪个先触 SLA,再决定拆不拆、怎么配比两池 GPU。盲目抄大厂架构,常常是花钱买复杂度。 prefill 池与 decode 池该怎么配比? 做容量规划时,先分别统计 TTFT 与 ITL 的线上达标率。如果 TTFT 先顶不住,说明瓶颈在 prefill 池,该加 prefill 侧 GPU;如果 ITL 抖动,说明 decode 池挤,该加 decode 侧。一个常见错误是按 1 比 1 平均分配两池,实际长上下文场景里 prefill 算力需求常常远大于 decode。建议从 prefill 多配起步,再根据监控回调。还要预留 KV 跨节点传输的带宽预算——NIXL 通道吃网络,别让它成为新瓶颈。拆分后务必做全链路压测,单看单侧性能没有意义。 ...

2026-10-09 · 1 min · 112 words · AI 实战派
LLM延迟优化

LLM服务延迟优化

延迟的两个关键指标 LLM服务的延迟分为两部分: TTFT(Time To First Token):从请求到第一个token返回的时间 TPOT(Time Per Output Token):每个后续token的生成时间 用户感知延迟 = TTFT + (输出token数 × TPOT)。优化需要分别针对这两个指标。 TTFT优化 预填充优化 TTFT主要由预填充(处理输入prompt)时间决定: # 1. 分块预填充:避免长prompt阻塞短请求 vllm serve model --enable-chunked-prefill --max-num-batched-tokens 4096 # 2. 前缀缓存:共享系统提示词的KV Cache vllm serve model --enable-prefix-caching # 3. 减少输入长度:精简系统提示词 # 差:500 token的系统提示词 # 好:150 token的精简系统提示词 模型预热 async def warmup_model(model_name): """服务启动时预热模型""" # 预加载模型到GPU dummy_input = "warmup" await llm.generate(dummy_input, max_tokens=1) # 预填充常见前缀 common_prompts = [ "你是一个专业助手", "请根据以下信息回答问题", ] for prompt in common_prompts: await llm.generate(prompt, max_tokens=1) TPOT优化 推测解码 # vLLM启用推测解码 vllm serve model \ --speculative-model /models/draft-model \ --num-speculative-tokens 5 \ --speculative-draft-tensor-parallel-size 1 量化 # INT8量化(2倍加速,精度损失<1%) vllm serve model --quantization awq --dtype float16 # INT4量化(3倍加速,精度损失3-5%) vllm serve model --quantization gptq --dtype float16 KV Cache优化 # FP8 KV Cache(减少显存带宽压力) vllm serve model --kv-cache-dtype fp8 网络层优化 流式响应 # 流式响应让用户更早看到输出 @app.post("/chat") async def chat(): async def stream(): yield "data: " # 立即发送头部 async for token in llm.astream(messages): yield json.dumps({"content": token}) + "\n" return StreamingResponse(stream()) 连接复用 # 使用HTTP/2或WebSocket减少连接建立开销 import httpx # 全局复用客户端 client = httpx.AsyncClient( http2=True, limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), keepalive_expiry=30, ) 调度优化 优先级调度 class PriorityScheduler: """交互请求优先于批处理请求""" async def schedule(self, request): if request.type == "interactive": # 交互请求:立即处理 return await self.process_immediately(request) else: # 批处理请求:低峰期处理 return await self.queue_for_later(request) 请求预取 class RequestPrefetcher: """预测用户可能的下一步请求,提前计算""" async def on_user_typing(self, session_id): """用户正在输入时,预计算可能的请求""" likely_queries = await self.predict_queries(session_id) for query in likely_queries[:2]: # 预计算2个最可能的查询 cache_key = f"prefetch:{session_id}:{query}" if not await self.cache.exists(cache_key): result = await self.llm.generate(query) await self.cache.setex(cache_key, 30, result) 端到端优化清单 优化项 TTFT改善 TPOT改善 实现难度 分块预填充 30-50% — 低 前缀缓存 40-60% — 低 量化 10-20% 50-100% 中 推测解码 — 50-100% 中 流式响应 感知80%↓ — 低 模型分层 20-40% 30-50% 中 监控 # 延迟分解监控 class LatencyBreakdown: def record(self, request_start, first_token, request_end): ttft = first_token - request_start total = request_end - request_start tpot = (total - ttft) / max(output_tokens - 1, 1) metrics = { "ttft_ms": ttft * 1000, "tpot_ms": tpot * 1000, "total_ms": total * 1000, } # 告警 if ttft > 2.0: # TTFT > 2秒 alert("High TTFT") if tpot > 0.05: # TPOT > 50ms alert("High TPOT") 结语 LLM服务延迟优化需要从TTFT和TPOT两个维度系统推进。分块预填充和前缀缓存是最有效的TTFT优化手段,量化和推测解码是TPOT的核心优化手段。流式响应虽然不改变实际延迟,但显著改善用户感知。 加入讨论 这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。 ...

2026-07-02 · 2 min · 336 words · 硅基 AGI 探索者
🔗 硅基 AGI 论坛 · silicon-agi.com | 📡 RSS 订阅
鲁ICP备2026018361号