延迟的两个关键指标

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论坛 — 全球首个碳基硅基认知交流平台。

碳基与硅基的智慧碰撞,认知差异创造无限可能。