Skip to content

LLM 推理与服务优化

目录

1. 学习目标

  • 理解自回归生成、Prefill、Decode 和流式返回的完整数据流;
  • 能推导 Temperature、Top-k、Top-p 的概率变化和适用边界;
  • 能从张量维度和字节数计算 KV Cache 的显存,并解释 MHA/GQA/MQA 的差异;
  • 能区分单请求 KV Cache、跨请求 Prompt/Prefix Cache、应用侧 Prompt Bundle Cache 与答案缓存;
  • 能分析 Batching、Paged KV、量化和并行策略对 TTFT、逐 Token 延迟、吞吐与质量的影响;
  • 能设计带准入、限流、取消、超时、幂等、降级、监控和回滚的生产服务。

2. 面试结论

2.1 30 秒回答

LLM 推理分为 Prefill 和 Decode:Prefill 并行处理完整 Prompt 并建立各层 KV Cache,Decode 每次只生成一个 Token,用新 Query 读取历史 K/V。KV Cache 避免重复计算历史 K/V,但显存随层数、序列长度、KV 头数和并发线性增长。服务优化不能只看单请求速度,要同时管理 TTFT、逐 Token 延迟、吞吐、P95/P99、显存和质量;常用手段包括连续批处理、分页式 KV 管理、量化、长度感知调度、前缀缓存和并行,但每项都必须在固定模型、硬件、数据集与质量门槛下验证。

2.2 一分钟复述版

用户 Prompt 先 Tokenize,Prefill 一次前向得到首 Token Logits 和每层 K/V;之后每个 Decode 步把新 Token 作为输入,把新 K/V 追加到缓存,并对当前词表 Logits 做 Greedy 或 Temperature、Top-k、Top-p 采样。第一个可见 Token 的延迟是 TTFT,后续 Token 间延迟常用 TPOT/ITL 描述。标准 Attention 的 Prefill 随上下文存在平方项,Decode 单步读取长度为 t 的 Cache;KV Cache 元素数约为 2LBhkvtdh。连续批处理提升设备利用率,却可能增加排队和尾延迟;量化减少权重/KV 带宽与容量,却可能带来质量或算子兼容问题。生产系统必须做 Token/KV 准入预算、断连取消、重试幂等、过载降级、版本追踪和分场景质量回归。

3. 面试官为什么问

  • 算法理解:是否知道生成不是一次性输出整段文本,而是自回归循环;
  • 硬件意识:能否区分 Prefill 与 Decode 的计算/内存访问特征;
  • 容量规划:是否会计算权重、激活和 KV Cache,而不只报“显存不够”;
  • 系统设计:能否协调吞吐、交互延迟、公平性、质量和成本;
  • 故障处理:是否考虑断连、排队、OOM、重复计费、量化回归和版本不一致。

4. 概念与边界

小白先这样理解:爆满寿司店怎样一片片出餐

晚高峰时,后厨先一次读完整张订单,弄清口味和已点食材,并把之后会复用的备料放进带标签的货架。接着厨师每次只做下一片寿司,端出后再决定下一片。管理员还会把多张订单动态编成一组,尽量不让炉台空等。

生活角色 → 技术概念: 整张订单的首次处理是 Prefill,一片片出餐是逐 Token Decode,带标签的备料货架是 KV Cache,动态合并订单对应连续批处理,第一片等待时间类似 TTFT。

类比边界: KV Cache 保存的是各层历史 Key/Value 张量,不是预先写好的答案;它不能免掉 Prefill,且会持续占用显存。批处理提高吞吐也可能增加排队和单请求延迟,必须通过实测权衡。

4.1 推理阶段

阶段输入主要工作输出/状态
Tokenization文本编码、模板、截断input_ids、Mask
Prefill全部 Prompt Token并行前向、建立 K/V首步 Logits、KV Cache
Decode最新 Token + 历史 Cache单 Token 前向与采样新 Token、扩展 Cache
Detokenize/StreamToken ID增量解码与协议封装文本片段、结束原因

4.2 延迟与吞吐指标

  • TTFT(Time To First Token):请求到首个可见 Token,包含排队、Tokenize、Prefill、首步采样和网络;
  • ITL(Inter-Token Latency)/TPOT(Time Per Output Token):首 Token 后相邻输出 Token 的时间,具体口径应在团队内固定;
  • 端到端延迟:请求到完成,受输入长度、输出长度、停止条件与排队共同影响;
  • 吞吐:单位时间完成的请求或处理/生成的 Token,必须说明是输入、输出还是总 Token;
  • 并发:同时在队列、Prefill 或 Decode 的请求数,不等于批大小。

平均值会掩盖长尾,生产容量至少查看 P50/P95/P99,并按输入长度、输出长度、模型版本、租户和完成原因切片。

4.3 解码策略边界

  • Greedy 每步选最大概率,确定性强但不是全局最优;
  • Beam Search 维护多条高概率序列,常见于强调序列似然的任务,但开放式对话中可能增加重复和计算;
  • Temperature 调整分布尖锐程度;Top-k 限制候选数量;Top-p 选择累计概率质量最小集合;
  • 采样只能改变已存在的模型概率分布,不能补充模型不知道的事实或修复错误上下文;
  • 固定随机种子也未必跨硬件、内核、批处理与版本完全复现,应把“可复现”限定在明确环境内。

4.4 优化边界

  • KV Cache 省历史 K/V 重算,不省 Prefill 的完整上下文计算,也会消耗显存;
  • Batching 提升吞吐,不保证单请求延迟下降;
  • 量化降低数值位宽,不保证所有硬件上更快,也不保证质量不变;
  • 前缀缓存只在模型、适配器、Prompt Token、位置/Cache 语义一致时复用;
  • speculative decoding、并行和融合内核的收益依具体实现与接受率/通信开销,必须实测。

5. 原理剖析

5.1 自回归生成与采样公式

模型在第 t 步输出词表 Logits zRV。Temperature T>0 后:

pi=exp(zi/T)j=1Vexp(zj/T)
  • T<1 放大 Logit 差异,分布更尖;
  • T>1 缩小差异,分布更平;
  • 工程 API 常把“零温度”实现为 Greedy 特例,不能直接代入公式除以 0。

Top-k 只保留概率最高的 k 个候选后重新归一化。Top-p 将候选按概率降序排列,取满足累计概率首次达到 p 的最小前缀集合,再归一化采样。二者组合时顺序和重新归一化语义由具体框架规定,应查目标版本并用固定 Logits 测试。

5.2 Prefill、Decode 与 KV Cache 张量

对 Decoder-only Transformer 第 l 层,历史长度为 t

  • 新 Query:[B,hq,1,dh]
  • 缓存 Key/Value:各为 [B,hkv,t,dh]
  • Attention 分数在 MHA 情况下为 [B,hq,1,t];GQA/MQA 需要按组共享/广播 K/V 头;
  • 新一步只追加 [B,hkv,1,dh] 的 K 和 V。

对该层某个 Token 的隐藏状态 xt,可以把三种投影视为:

qt=xtWQ,kt=xtWK,vt=xtWV
  • Query(Q) 表示当前 Token 想从历史中查什么;
  • Key(K) 表示每个历史 Token 可以用什么特征被匹配;
  • Value(V) 表示匹配后真正参与加权汇总的信息。

生成下一个 Token 时会产生新的 Query,但历史 Token 的 K/V 在模型权重和位置语义不变时不会改变。因此系统缓存各层历史 K/V,让新 Query 直接读取;过去的 Query 已经完成了当时那一步查询,未来不会再次使用,所以通常不把历史 Q 作为自回归推理缓存的主体。这就是 KV Cache:它是模型中间张量缓存,不是原始 Prompt、数据库记录、长期记忆或最终答案。

忽略分配器碎片、元数据、对齐和其他状态,KV Cache 理论字节数约为:

MKV=2×L×B×hkv×t×dh×s

其中 2 表示 K 与 V,L 是层数,s 是每元素字节数。MHA 通常 hkv=hq,MQA 常令 hkv=1,GQA 介于两者之间,所以减少 KV 头数可以显著降低 Cache,但是否保持质量取决于模型训练和架构,不能在服务侧任意改头数。

5.3 为什么 Cache 能加速,为什么仍不免费

设初始 Prompt 长度为 P。若没有 Cache,朴素实现会在每个 Decode 步把不断增长的完整前缀重新送入模型,重复计算历史 Token 的投影和 Attention。使用 Cache 后只为新 Token 计算投影;生成第 j 个 Token 时,新 Query 与 P+j1 个历史 Key 做注意力,单层该步约为 O((P+j)d)。因此生成 T 个 Token 的 Decode Attention 累计约为:

O(j=1T(P+j)d)=O((PT+T2)d)

这还不包含 Prefill 的 O(P2d) Attention 计算。只有在忽略 P 或把它视为常量时,Decode 累计项才能简写为 O(T2d);Cache 消除了历史投影的重复计算,但没有把 Attention 变成常数时间。

同时,每个 Decode 步仍要读取大部分模型权重、执行新 Token 的线性层和 FFN,因此 Decode 常受显存带宽和小批次设备利用率限制。连续批处理把不同请求的 Decode 步组合起来,提高权重读取的复用和设备利用率,但会引入调度、公平性和排队权衡。

教学插图:KV Cache 的增量复用与持续读取

Prefill 写入历史 K/V,Decode 只追加新 K/V,但新 Query 仍读取全部历史

替代文本: Prefill 为提示词各 Token 计算并保存 K/V;Decode 每一步只计算并追加新 Token 的 K/V,新 Query 仍与全部历史 K 交互,并按权重聚合历史 V,缓存长度随生成过程持续增加。

读图结论: KV Cache 省掉的是历史 K/V 投影的重复计算,不是历史读取和 Attention 本身;它用持续增长的显存占用换取更快的增量解码。

图片只画出一层的逻辑关系,实际模型通常每层都有独立 Cache;Q 不作为历史 Cache 的核心内容,图中的连续货架也不代表物理显存一定连续,分页式实现可以通过块表映射非连续内存。

5.4 Prompt/Prefix Cache 如何跨请求复用前缀

这里的 Prompt Cache 通常指模型服务侧的 Prefix Cache(前缀缓存):服务第一次处理一段稳定前缀时,完成 Tokenize 和 Prefill,并缓存这段前缀在各层产生的 K/V 状态;后续请求若拥有完全兼容的相同前缀,就直接复用缓存,只计算新增后缀的 Prefill,再进入 Decode。

它缓存的不是自然语言答案,也不是让模型“永久记住 Prompt”。更准确地说,它把重复的前缀计算结果变成可复用的张量状态:

text
稳定前缀 = System Prompt + Tool Schema + 公共 Few-shot
动态后缀 = 用户问题 + RAG Context + 本轮工具结果

首次请求:稳定前缀 Prefill + 动态后缀 A Prefill + Decode
后续命中:复用稳定前缀 KV + 动态后缀 B Prefill + Decode

5.4.1 系统怎样识别“相同前缀”

系统一般不是拿两段自然语言做语义相似度比较,而是沿下面的精确匹配链路寻找 最长公共 Token 前缀(Longest Common Token Prefix)

  1. 按 Chat Template 序列化 System、Tools 和 Messages,再由固定 Tokenizer 转成 token_ids
  2. 构造隔离命名空间,至少包含模型/权重、Adapter、Tokenizer、模板、Cache 语义和租户或权限域指纹;
  3. 从第一个 Token 开始,使用 Token 前缀树/Radix Tree 逐段查找,或者把 Token 切成固定块并计算链式哈希;
  4. 连续命中的前缀块直接绑定到已缓存的 KV Page;遇到第一个未命中块就停止复用,从该位置继续 Prefill;
  5. 新计算出的完整块可以写回缓存,供后续兼容请求复用;显存压力、TTL 或淘汰策略可能让本来相同的前缀仍然 Miss。

固定块哈希可以抽象为:

Hi=Hash(namespace,Hi1,token_idsi)

其中 namespace 约束模型和安全边界,Hi1 把当前块与此前所有前缀绑定,token_ids_i 是当前 Token 块。因此系统命中的是“从开头连续一致的前缀”,不是在 Prompt 中间偶然找到一段相同文字。

下面是概念级伪代码,不代表某个具体引擎 API:

python
token_ids = tokenizer(apply_chat_template(messages))
parent_hash = namespace_fingerprint(model, adapter, tokenizer, tenant)
matched = 0

for block in split_into_blocks(token_ids):
    block_hash = hash(parent_hash, block)
    if block_hash not in prefix_cache:
        break
    reuse_kv_pages(prefix_cache[block_hash])
    matched += len(block)
    parent_hash = block_hash

prefill(token_ids[matched:])

例如,块大小假设为 4 Token:

text
请求 A:[S1 S2 S3 S4] [T1 T2 T3 T4] [用户问题 A ...]
请求 B:[S1 S2 S3 S4] [T1 T2 T3 T4] [用户问题 B ...]
                    命中第 1、2 块 ─────┘ 从第 3 块开始计算

如果请求 B 在 T2 就发生变化,按块缓存的实现通常只能安全复用变化点之前的完整块;具体是否支持更细粒度匹配取决于引擎的数据结构和块策略。肉眼相同的文本也不保证命中,因为角色标记、空白、工具顺序、模板或 Tokenizer 版本可能让最终 Token 序列不同;反过来,缓存命中只代表计算前缀兼容,不代表两个用户问题语义相同。

多轮提问还要区分两种情况:独立请求 System + Tools + 问题 A/B 通常只能共享稳定的 System + Tools;同一会话的第二轮输入一般是 System + 问题 A + 回答 A + 问题 B,它可能继续命中更长的历史前缀。但能否复用第一轮 Decode 期间生成的“回答 A”对应 K/V,取决于引擎是否把生成 Token 的 KV Page 持久化并纳入跨请求索引;不支持时仍需为这部分重新 Prefill。缓存只是一项可选性能优化,因此无论 Hit 还是 Miss,答案正确性都应相同。

因此它主要降低重复长前缀的 Prefill 计算、TTFT 和输入侧资源消耗;动态后缀和输出 Decode 仍需正常计算。某些托管 API 会根据缓存输入 Token 单独计费,但计费、最小可缓存长度、有效期和显式/自动缓存方式属于产品策略,不能从“支持 Prompt Cache”直接推导,接入时应核对目标模型与版本。

图:机制|Prompt/Prefix Cache 的跨请求复用边界

替代文本: 首次请求为稳定公共前缀执行 Prefill 并写入前缀 KV Cache;后续请求在模型、Tokenizer、模板、Token 序列和隔离域兼容时命中,只计算动态后缀;任一关键指纹变化都回退到完整 Prefill。

图表加载中…

读图结论: Prompt/Prefix Cache 跨请求复用的是稳定前缀的模型中间状态;它以严格的版本、Token 与安全隔离一致性换取 Prefill 加速,命中失败只是性能下降,错误命中则可能造成静默答案污染或越权风险。

一次可靠命中至少要约束以下维度:

  • 计算身份:模型、权重/量化制品、Adapter、Tokenizer、Chat Template 和推理 Cache 语义兼容;
  • 前缀身份:比较实际 Token ID 前缀及位置语义,不能只比较肉眼看起来相同的字符串;
  • 安全身份:租户、权限、数据域和敏感级别不得越界共享;公共前缀与私有上下文要有明确边界;
  • 生命周期:Prompt、工具 Schema 或模型升级后,通过版本指纹主动失效,而不是等待旧缓存自然过期;
  • 内容布局:稳定且可共享的内容尽量放在前面,时间戳、Request ID、用户数据、RAG 片段和工具结果放在后面。前部任一 Token 改动都可能使其后的长前缀无法命中。

四种常被混称为“Prompt 缓存”的机制应分开管理:

机制缓存内容复用范围主要收益主要风险
单请求 KV Cache当前请求已处理 Token 的各层 K/V同一次生成的 Decode 步避免每步重算历史 K/V显存随长度和并发增长
Prompt/Prefix Cache稳定前缀 Prefill 后的 K/V 状态多个兼容请求之间降低重复前缀 Prefill、TTFT 和输入计算错误命中、跨租户泄漏、版本污染
Prompt Bundle Cache应用从 Registry 解析出的 Prompt 文本、Schema、工具与模型策略配置应用实例或配置分发层减少配置读取并稳定运行版本缓存旧配置、运行中版本漂移
Response Cache完整请求对应的最终答案相同且允许复用的业务输入跳过整次模型调用时效错误、权限泄漏、非确定输出被误复用

Agent 中最常见的布局是把稳定的 System Prompt、工具定义和公共示例作为前缀,把会话消息、RAG 上下文和工具结果追加在后面。但不能为了提高命中率而削弱指令优先级、ACL 或工具权限;工具集合按请求动态装载时,还要接受前缀变化或按稳定工具集合分桶。

验证时不要只看总延迟,应同时记录 cache_hit_rate、缓存输入 Token 数、命中/未命中 TTFT、Prefill 时延、端到端成本和错误命中审计;回归测试至少覆盖合法命中的 Logits/答案一致性,以及跨模型、跨 Prompt 版本、跨工具版本、跨租户必须不命中的负例。

5.5 分页式 KV 与连续批处理

传统按最大长度预留连续 Cache 容易产生内部浪费,也难以处理动态增长。PagedAttention 的核心思想是把逻辑连续的 KV 序列映射到非连续固定大小块,由块表寻址,类似虚拟内存分页;这有利于减少碎片并支持共享/复制管理。代价是块表、调度器和内核复杂度,实际效果依工作负载。

连续批处理不等待整批请求全部结束:调度器在迭代边界移除完成/取消请求,加入新请求。它通常提升总体吞吐,但若 Prefill 和 Decode 不做隔离或预算,大 Prompt 可能阻塞交互式 Decode,造成 ITL 尾延迟。

5.6 量化原理与边界

线性量化把浮点权重近似为:

ws(qz)

其中 q 是低位整数,s 是 Scale,z 是 Zero Point。Scale 可以按张量、通道或 Group 计算:粒度越细通常误差越小,但元数据和内核更复杂。

  • Weight-only:权重量化,激活保留较高精度;适合权重带宽主导场景;
  • Weight + Activation:同时量化,可能进一步提高特定硬件吞吐,但校准和异常值处理更难;
  • KV Cache 量化:降低长上下文和并发的 Cache 占用/带宽,但需专门质量回归;
  • 量化是否加速取决于硬件是否有高效内核、反量化开销、批大小和瓶颈位置。

5.7 服务调用链可视化

图 1:生产 LLM 请求从准入到流式完成的调用链替代文本: 客户端请求先经过鉴权、配额与 Token/KV 预算,再由调度器执行 Prefill 和循环 Decode,流式网关处理断连与取消,指标链路记录版本、延迟、显存和结束原因。

图表加载中…

读图结论: 推理优化不是模型 Worker 单点问题;准入预算、调度、流式取消和可观测性共同决定容量、尾延迟和是否会浪费 GPU。

5.8 复杂度因果链

  • 输入长度增加 → Prefill Attention 平方项和 TTFT 上升 → 单个大请求更容易阻塞批次;
  • 输出长度增加 → Decode 步数与 KV Cache 线性增加 → 端到端延迟、占用时间和成本上升;
  • 并发增加 → KV 总量与调度队列增加 → 先出现显存或尾延迟瓶颈,而非必然提高吞吐;
  • 批次增大 → 权重读取摊薄、吞吐可能提高 → 单请求排队和 ITL 可能恶化;
  • 量化位宽降低 → 权重/KV 容量和带宽下降 → 质量、校准和内核兼容风险增加。

6. 实现与代码

6.1 最小可运行 Python 采样器

运行环境:Python 3.10+,仅使用标准库。示例展示 Greedy、Temperature、Top-k 与 Top-p 的候选过滤;它不包含真实模型。

python
import math
import random


def softmax(logits):
    largest = max(logits)
    exps = [math.exp(value - largest) for value in logits]
    total = sum(exps)
    return [value / total for value in exps]


def sample_token(logits, temperature=1.0, top_k=None, top_p=1.0, rng=None):
    if not logits:
        raise ValueError("logits 不能为空")
    if temperature < 0:
        raise ValueError("temperature 不能为负数")
    if temperature == 0:
        return max(range(len(logits)), key=logits.__getitem__)
    if not 0 < top_p <= 1:
        raise ValueError("top_p 必须位于 (0, 1]")

    candidate_ids = list(range(len(logits)))
    if top_k is not None:
        if top_k <= 0:
            raise ValueError("top_k 必须为正数")
        candidate_ids = sorted(candidate_ids, key=logits.__getitem__, reverse=True)[:top_k]

    scaled_logits = [logits[index] / temperature for index in candidate_ids]
    probabilities = softmax(scaled_logits)
    ranked = sorted(
        zip(candidate_ids, probabilities), key=lambda item: item[1], reverse=True
    )

    nucleus = []
    cumulative = 0.0
    for token_id, probability in ranked:
        nucleus.append((token_id, probability))  # 至少保留概率最高的一个
        cumulative += probability
        if cumulative >= top_p:
            break

    ids, weights = zip(*nucleus)
    rng = rng or random.Random()
    return rng.choices(ids, weights=weights, k=1)[0]


logits = [2.0, 1.8, 1.6, -0.5]
assert sample_token(logits, temperature=0) == 0
assert sample_token(logits, top_k=1, rng=random.Random(7)) == 0
experiment_rng = random.Random(7)
print("greedy:", sample_token(logits, temperature=0))
print(
    "repeatable sample sequence:",
    [
        sample_token(
            logits,
            temperature=0.8,
            top_k=3,
            top_p=0.9,
            rng=experiment_rng,
        )
        for _ in range(8)
    ],
)

6.2 关键实现说明

  1. Softmax 先减最大 Logit,防止指数溢出;
  2. temperature=0 作为 Greedy 分支处理,而不是执行除零;
  3. Top-k 后重新计算候选概率,再按累计概率构造 nucleus;
  4. 至少保留一个候选,避免极小 top_p 得到空集合;
  5. 重复采样必须复用同一个 RNG;如果函数内部每次用相同 Seed 新建 RNG,每次都会回到同一状态,经验分布实验就是假的;
  6. 真实框架还会处理重复惩罚、最小/最大长度、停止序列、无效值、随机数生成器和批处理,参数组合语义必须以目标版本文档与测试为准。

6.3 边界条件与验证

  • 对全相等 Logits、极大/极小 Logits、top_k>V、非法 Temperature/Top-p 写测试;
  • 固定 Logits 重复采样足够次数,比较不同 Temperature 下的经验分布,而不是只看单个样本;
  • 服务评测同时固定 Prompt、模型、Tokenizer、采样配置和随机环境;
  • 质量比较使用任务指标/人工评审与失败切片,不能用“输出更随机”替代质量证据;
  • KV Cache 优化要比较 Cache 与无 Cache 的逐步 Logits 容差,并覆盖长序列、批次和取消释放。

6.4 技术栈与横向选型

LLM 服务选型必须先固定模型、硬件、序列长度分布、并发和 SLO。下表是参考实现而非通用胜负结论;不同引擎版本的能力和 API 需在部署时重新核对。

技术点 ID技术点/环节类型采用方案链路职责版本/证据边界
TP-IS-01连续批处理与 KV Cache 调度推理服务vLLM 作通用 GPU 服务参考;TGI 作同层候选执行请求排队、Prefill/Decode、KV Cache 管理与流式输出吞吐与延迟受模型、硬件和流量形状影响;不以一次基准宣称普遍更快
TP-IS-02权重量化算法/库AWQ 作离线量化参考;GPTQ 作候选降低权重显存和带宽需求,生成带量化指纹的模型产物实际加速依赖 Kernel 与硬件;每个模型和质量切片都要回归
TP-IS-03客户端调用与流式协议协议对外 HTTP + SSE;受控内部链路可评估 gRPC承载请求、取消、流式 Token、错误码和版本指纹协议只解决传输,不替代准入、幂等、限流和模型路由
TP-IS-04跨请求前缀复用推理优化版本化 Prompt/Prefix Cache;无跨请求缓存作基线复用兼容公共前缀的 Prefill K/V,减少重复输入计算具体能力依模型服务版本;必须验证命中收益、隔离、失效与输出一致性
技术点 ID候选方案优点缺点/代价适用场景不适用场景选择结论与依据
TP-IS-01vLLM连续批处理和 KV Cache 管理面向高并发生成负载引擎、模型与量化支持随版本变化,需独立运维GPU 在线生成、长短请求混合、需 OpenAI 兼容服务的参考场景单请求离线实验或目标模型未经支持验证作默认基准,用真实长度分布测 TTFT、TPOT、吞吐和错误率
TP-IS-01Hugging Face TGI容器化服务链路完整,与 Hugging Face 模型生态结合同样存在模型、Kernel 与版本支持矩阵,切换有协议与运维成本团队已标准化 Hugging Face 部署与容器运维只因生态偏好即期待在任意硬件上更快与 vLLM 在相同模型、硬件和压测轨迹上对比后决策
TP-IS-02AWQ针对权重量化保留显著通道信息,常有现成推理集成需校准数据与兼容 Kernel,不同任务可能质量回归GPU 权重带宽或显存受限,引擎已验证支持高精度敏感任务或引擎缺少高效 Kernel作第一个离线候选,以分层质量和端到端延迟门禁决策
TP-IS-02GPTQ成熟的后训练量化路线,有多种工具与模型产物量化耗时、校准敏感,实际推理效率取决于引擎实现现有模型产物与部署引擎已完成兼容验证只比较文件大小、不做任务质量和 Kernel 基准作同层对照,不以量化格式名称替代实测
TP-IS-03HTTP + SSE浏览器和通用 SDK 友好,通过标准 HTTP 设施易集成双向控制和严格类型契约较弱,断连恢复需应用层设计对外文本生成 API、浏览器和多语言客户端高频内部二进制交互或复杂双向流对外默认参考,必须定义取消、重连、错误与版本语义
TP-IS-03gRPC StreamingProtobuf 契约严格,支持双向流与内部服务治理浏览器直连不便,网关、调试和客户端生成有额外成本受控内部服务、多语言强契约通信公网浏览器优先且团队无 gRPC 运维栈仅在内部类型契约与流控收益高于复杂度时采用
TP-IS-04不做跨请求前缀缓存实现简单,请求天然隔离,Prompt 更新不需额外失效重复长 System/Tools 前缀每次完整 Prefill前缀短、变化频繁、低复用或隔离风险高大量请求共享很长且稳定的公共前缀作为正确性和性能基线,先证明重复 Prefill 是实际瓶颈
TP-IS-04版本化 Prompt/Prefix Cache可降低高复用长前缀的 TTFT、输入计算和容量压力增加 Cache Key、显存/存储、隔离、逐出、失效和观测复杂度Agent 工具定义、公共规则和 Few-shot 稳定且重复率高前缀前部含时间戳/随机值,或不同租户私有内容无法安全共享仅在固定流量回放中同时通过收益、一致性和安全负例后启用

6.5 架构与技术调用流程

图:架构|LLM 在线推理服务组件边界

替代文本: 客户端经 HTTP/SSE 或内部 gRPC 进入网关,准入控制执行鉴权、配额和 Token/KV 预算,路由器选模型版本,调度器组批后调用推理引擎、权重与 KV Cache,流式网关返回结果,观测系统记录每阶段指标。

图表加载中…

读图结论: 推理引擎只是核心计算层,可用的在线服务还需要准入、版本路由、取消传播和分阶段观测。

架构图将协议、调度、权重优化与运行治理分层。如果只有平均端到端延迟,就无法判断瓶颈是排队、Prefill、Decode、网络还是客户端断连。

图:技术调用流程|生成请求的准入、流式与降级

替代文本: 请求先经鉴权和预算准入,超限时立即拒绝;通过后进入调度与推理,资源不足时只能在策略允许下路由到受验降级模型,否则返回可重试过载错误;成功时持续流式返回并传播取消。

图表加载中…

读图结论: 超额在准入层拒绝,过载只在有明确质量和合规边界时降级,客户端取消必须穿透到引擎释放计算与 KV Cache。

时序图表达的是用户可见语义,不承诺任意引擎的内部 API。压测必须同时验证正常、过载、断连和降级路径。

7. 实际项目案例

示例项目,非真实仓库实现;容量、延迟和成本数值必须在目标硬件实测。

7.1 背景、目标与约束

建设多租户企业 LLM Gateway,为聊天、文档摘要和结构化抽取提供流式推理。交互请求重视 TTFT/ITL,离线摘要重视吞吐;租户有不同配额,Prompt 长度差异大,GPU 显存固定,模型和 Adapter 需要版本化切换。

7.2 架构与调用链

  1. 网关鉴权、幂等键、租户限流和请求大小检查;
  2. Tokenizer 服务计算实际输入 Token,结合最大输出预算估算 KV;
  3. 准入器按模型池、优先级、显存和队列时限决定接收、排队或拒绝;
  4. 调度器分离/协调 Prefill 与 Decode,使用连续批处理并处理取消;
  5. Worker 加载固定模型、量化、Adapter 和 Tokenizer 制品,执行 Prefill/Decode;
  6. 流式层返回增量文本和明确 finish_reason
  7. 追踪记录模型/配置版本、队列、TTFT、ITL、Token、KV、批次、错误和计费事件。

7.3 方案选择与实现难点

真正困难的不是单独启用某个推理优化,而是让资源、调度、协议、质量和版本语义在同一条链路中保持一致:

技术难点难在哪里关键设计与权衡必须取得的验证证据
混合负载调度长 Prompt 的 Prefill、短对话的 Decode 和离线生成竞争同一计算资源;吞吐最优不等于交互体验最优分队列或做优先级/长度感知调度;必要时分块 Prefill,但要评估切换开销与公平性按输入/输出长度和请求类型切片的排队、TTFT、ITL、吞吐与饥饿时间
KV 容量与生命周期单请求 Cache 会随长度增长,取消、抢占、异常退出和块碎片都会让理论公式低估真实占用用 Token/KV 块而非仅用请求数做准入;为请求建立分配、追加、抢占、释放和对账状态请求级 KV 账本、块池高水位、断连释放时延、长短请求混合压测结果
流式协议与幂等首个片段发出后,请求已经产生外部可见结果;普通 HTTP 重试语义不再成立区分“未开始生成、已生成未发送、已流式发送、已完成记账”,只对明确可恢复阶段自动重试故障注入下的事件序列、唯一计费记录、客户端无重复拼接、明确 finish_reason
量化制品治理性能收益依赖硬件和内核,质量损失又可能只出现在长上下文、格式或安全切片把权重、激活、KV 量化作为独立制品;性能门槛与质量门槛同时发布和回滚固定硬件上的基准报告、分任务质量集、长上下文/结构化输出/安全回归及制品指纹
前缀缓存一致性文本相同不代表 Token、位置语义或 Adapter 相同,错误命中可能静默污染答案Cache Key 纳入模型、Adapter、Tokenizer、模板、Token ID、位置与 Cache 配置;版本切换主动失效跨租户、跨版本不命中测试;合法命中的 Logits 容差对比;命中率与错误命中审计

7.4 可验证的工程亮点与证据边界

下表是候选项目亮点,不是已经取得的成果。只有完成对应验证后,才能在项目复盘或面试中使用“实现了”“降低了”“避免了”等结果性表达。

候选亮点技术价值最小证据包表达边界
Token/KV 双预算准入在真正分配显存前识别长上下文与高并发风险预算公式与误差说明、请求级 KV 账本、极端长度压测、拒绝原因分布只能说明在已测模型、硬件、长度和并发范围内稳定,不能外推到任意负载
端到端取消与资源回收客户端断连后尽快停止无效 Decode 并释放 Cache网关到 Worker 的取消 Trace、活跃序列/KV 回落曲线、异常退出对账未覆盖进程崩溃和网络分区时,不能声称“资源绝不泄漏”
工作负载感知调度同时治理交互式尾延迟、离线吞吐和租户公平性固定到达分布的 A/B 压测、长度切片分位数、饥饿/抢占记录GPU 利用率上升不能单独证明用户体验改善
制品与 Cache 全链路指纹避免模型、Adapter、Tokenizer、模板和 Cache 语义混用每个 Trace 的版本字段、跨版本隔离测试、灰度与回滚记录缺少任一影响输出的版本字段时,只能称“部分可追踪”
性能—质量联合发布门禁防止吞吐优化以格式、长上下文或安全质量为代价同一制品的性能报告、固定回归集、失败切片、门禁与回滚演练没有代表性业务集和人工复核时,不能宣称“质量无损”

7.5 生产问题闭环演练

以下均为基于机制设计的故障演练,不代表本仓库或某个真实服务发生过这些事故。表中的“根因”是对应演练场景的设定,线上仍需以 Trace、指标、日志和制品版本确认。

问题现象与影响定位证据场景根因应急止损长期修复验证防复发
高并发 OOMWorker OOM/重启,在途请求失败,模型池容量进一步下降输入与最大输出 Token、活跃序列、KV 块/分配器水位、取消记录、OOM 前 Trace准入只看权重或请求数,未预算峰值 KV、碎片和延迟释放暂停长请求准入,降低并发/最大输出,摘除并排空异常 Worker,切换低容量模型请求级 KV 预算、水位限流、块对账、取消释放和 Worker 隔离长短请求混合阶梯压测下不崩溃;拒绝发生在预算边界且资源可回落容量矩阵纳入发布门禁;KV 水位与释放时延告警;定期对账
P99/ITL 突增平均延迟正常,但交互请求卡顿或中途停顿按长度/类型切片的排队、Prefill/Decode 时间、批次组成和抢占记录大 Prefill 阻塞 Decode,或等待组批/公平策略不合理限制超长同步输入,隔离离线队列,提高交互请求优先级分块 Prefill、长度感知与带老化的公平调度,分别设 TTFT/ITL 预算回放相同到达与长度分布,对比 P50/P95/P99、吞吐和饥饿时间固定混合负载基准;同时告警队列时间和计算时间,禁止只看平均值
断连后仍占 GPU客户端已离开,活跃序列与 KV 水位不下降,吞吐被无效任务占用网关断连时间、取消 Span、调度器序列状态、Worker 完成/释放事件取消只停在网关,或异常分支未触发 Cache 释放主动终止对应 Run,超时回收孤儿序列,必要时排空 Worker端到端取消令牌、幂等清理钩子、租约/心跳与请求—块对账注入断连、超时和 Worker 异常后,序列在预算时间内结束且 KV 回落取消延迟 SLI、孤儿序列告警、周期性资源对账与故障演练
重试后重复文本或计费客户端收到重复片段,或同一业务请求产生多条计费/完成记录幂等键、流式事件序号、Run 状态迁移、供应商调用 ID、计费唯一键流式开始后仍按无副作用请求自动重放,状态与记账未原子化关闭该错误类自动重试,按 Run ID 查询既有结果,冻结重复记账明确阶段状态机、事件序号/续传点、计费唯一约束和错误分类在首 Token 前后分别注入故障,确认只产生一个最终结果和一次记账重试策略契约测试;审计重复键;新增错误码必须声明可重试语义
量化后格式/能力回归吞吐可能改善,但 JSON 解析、长上下文、事实或安全切片失败增加制品指纹、任务/长度切片指标、解析错误、逐层或 Logits 对比校准集不代表业务,异常值或敏感层不适合当前量化粒度回滚全精度或已验证制品;关键任务临时路由高精度模型扩充校准与回归集,调整 Group/敏感层精度,对权重与 KV 量化分别评估同一数据、采样与硬件复测质量门槛和性能门槛,人工检查关键失败样本量化制品独立版本;质量—性能双门禁;新业务切片先影子评测
前缀 Cache 错命中Cache 命中率看似上升,但答案在版本/租户切换后静默异常Cache Key 展开值、模型/Adapter/Tokenizer/模板指纹、命中 Trace、Logits 对比Key 漏掉影响输出的版本、Token 或位置语义,或跨租户共享错误关闭可疑前缀缓存并清空相关命名空间,回退到正常 Prefill完整版本化 Key、租户隔离、发布失效协议和命中审计跨版本/租户必须不命中;合法命中与无 Cache 输出在约定容差内一致Cache Key 契约测试;版本字段变更评审;错误命中率和命名空间监控
流式输出乱码中英混合、Emoji 或组合字符出现替换符/残缺,客户端无法可靠拼接原始 Token ID、字节片段、增量解码器状态、客户端事件边界在任意字节或子词边界直接解码/截断,未保留增量状态暂停有问题的字节级拼接,改为安全缓冲或返回完整片段使用 Tokenizer 的状态化增量解码,协议明确事件编码与拼接规则覆盖中文、Emoji、组合字符、停止序列和任意分块的端到端回归流式字符集用例进入契约测试;协议版本化;解码异常指标与样本留存

7.6 监控、容量与验收

监控分三层:

  • 入口:请求率、Token 长度、拒绝/限流、队列等待、租户配额;
  • 调度/Cache:运行序列、批次 Token、KV 块使用率、碎片、抢占、取消释放时延;
  • Worker/结果:TTFT、ITL、吞吐、显存、内核错误、完成原因、模型版本、质量与安全回归。

验收必须在目标硬件、固定模型/精度、代表性长度分布和并发曲线下完成。报告原始配置、预热、测量窗口、分位数、质量门槛和失败样本;没有这些证据,不宣称“提升若干倍”。

8. 方案权衡与常见误区

8.1 优化手段与代价

手段主要收益主要代价/失效边界
KV Cache避免历史 K/V 重算显存随长度和并发增长
Continuous Batching提高设备利用率和吞吐调度复杂,可能增加等待与尾延迟
Paged KV降低连续预留和碎片问题块管理与内核复杂度
Prefix Cache复用公共前缀 Prefill命中率、隔离、安全和失效复杂
Weight Quantization减少权重容量/带宽质量与硬件内核兼容性
KV Quantization降低长上下文 Cache 成本Attention 质量和实现复杂度
Tensor Parallel单卡放不下或需更高计算并行每层通信与拓扑敏感
Speculative Decoding目标模型一次验证多个草稿 Token接受率、草稿成本和实现复杂度

8.2 常见错误回答

  • “KV Cache 让 Attention 变成 O(1)”:新 Query 仍读取长度 t 的历史 K/V;
  • “批越大延迟越低”:吞吐可能提高,但排队和单请求 ITL 可能恶化;
  • “INT4 一定比 FP16 快四倍”:位宽不是端到端速度的线性保证;
  • “Temperature 越低越准确”:它只改变采样分布,事实性还依模型和上下文;
  • “平均延迟合格即可”:交互体验和容量事故常由 P95/P99 与长度切片暴露;
  • “流断了重试就行”:若已生成/记账,重试需要幂等和续传语义。

8.3 生产风险与防线

  • 过载雪崩:有界队列、Token/KV 准入、租户限流、快速失败和降级模型;
  • 资源泄漏:取消传播、超时清理、请求状态机和 KV 块对账;
  • 质量回归:量化/内核/模型每个制品独立走 Golden、任务、安全和长上下文评测;
  • 版本混用:模型、Adapter、Tokenizer、采样默认值和 Cache Key 绑定发布;
  • 观测污染:统一 TTFT/ITL/Token 口径,区分排队、计算和网络时间;
  • 隐私泄漏:跨租户 Cache 严格隔离,Prompt/输出日志按数据分类脱敏与限时保存。

8.4 可复用的优化与排障经验

  1. 先固定实验清单,再谈优化收益:至少固定模型、制品哈希、Tokenizer、Prompt 模板、采样参数、硬件、驱动/内核、预热方式、长度分布、并发曲线和质量集;否则前后结果无法归因。
  2. 先拆排队、Prefill、Decode、网络,再定位“模型慢”:TTFT 变差不等于 Prefill 内核变慢,ITL 变差也可能来自调度抢占;Trace 必须能还原阶段时间。
  3. 容量单位优先使用 Token、KV 块和执行步,而非只用请求数:同样十个请求,长 Prompt、长输出和不同 KV 头数可能产生完全不同的资源压力。
  4. 先定义副作用与完成边界,再配置重试:流式片段、计费和业务回调一旦外部可见,就必须依赖幂等键、事件序号和状态机,而不是“失败就重试”。
  5. 性能优化与质量、安全共同发布:量化、Cache、调度、内核和模型升级都可能改变输出;每次只改变可追踪变量,并保留灰度、回滚和失败样本。
  6. 把经验固化为资产:长期保留基准测试清单、混合负载矩阵、容量预算表、故障注入用例、Cache Key 契约、发布门禁和故障 Runbook,避免经验只停留在个人判断中。

面试中应把亮点表达为“难点—决策—权衡—证据—边界”。例如可以说“我设计了基于 Token/KV 的准入,并用长短请求混合压测验证预算误差和资源回落”;没有压测记录时,只能说“设计了验证方案”,不能把预期收益说成已实现结果。

9. 面试题与参考答案

问题 1:Prefill 和 Decode 有什么区别?

  • 难度:基础;
  • 考察点:自回归推理阶段;
  • 合格答案要点:Prefill 并行处理完整 Prompt 并建立 Cache;Decode 每步处理新 Token、读取历史 Cache;
  • 优秀答案加分项:连接 TTFT、ITL、计算密集/带宽特征和调度;
  • 常见错误:认为首 Token 也只处理一个输入 Token;
  • 可继续追问:长 Prompt 和长输出分别压垮什么资源?

问题 2:KV Cache 显存如何估算?

  • 难度:中级;
  • 考察点:张量维度和容量规划;
  • 合格答案要点2LBhkvtdhs,说明 K/V、层、批、头、长度、头维和字节;
  • 优秀答案加分项:补充 GQA/MQA、块分配碎片、并发和其他内存;
  • 常见错误:只按参数量估算服务显存;
  • 可继续追问:为什么不能在已有 MHA 权重上直接把 KV 头改成 1?

问题 3:连续批处理为什么能提高吞吐,又可能伤害延迟?

  • 难度:中级;
  • 考察点:硬件利用率与排队论直觉;
  • 合格答案要点:动态加入/移除序列,摊薄权重读取;等待组批、大 Prefill 和公平调度会增加尾延迟;
  • 优秀答案加分项:提出 Prefill/Decode 分离、长度感知、公平性和 P99 切片;
  • 常见错误:只看 GPU 利用率判断用户体验;
  • 可继续追问:如何设计压测矩阵证明调度策略更好?

问题 4:量化后吞吐提高但业务质量下降,如何处理?

  • 难度:高级;
  • 考察点:性能—质量联合决策与回滚;
  • 合格答案要点:确认制品/配置,按任务和长度切片复现,对比 Logits/输出,调整粒度或敏感层精度并保留回滚;
  • 优秀答案加分项:区分权重、激活、KV 量化,说明校准集代表性和灰度门禁;
  • 常见错误:用平均自动指标掩盖安全/格式失败;
  • 可继续追问:什么证据可以支持只对部分层保留高精度?

问题 5:Prompt/Prefix Cache 与 KV Cache、答案缓存有什么区别?

可直接口述的参考回答: 我会先澄清 Prompt Cache 的口径。模型服务里的 Prompt 或 Prefix Cache,是跨请求复用相同稳定前缀 Prefill 后的 K/V 状态,主要减少重复输入计算和 TTFT;普通 KV Cache 则服务于同一个请求的逐 Token Decode。它们都不等于答案缓存,答案缓存会直接复用最终输出。Prefix Cache 命中必须同时满足模型、Tokenizer、模板、Token 前缀、位置语义和租户隔离一致,项目中我会用命中率、缓存 Token、命中/未命中 TTFT、输出一致性和跨版本/跨租户不命中测试验证,而不是只看平均延迟。

  • 难度:中级;
  • 考察点:推理阶段、缓存层次、版本治理与多租户安全;
  • 合格答案要点:区分单请求 Decode KV、跨请求 Prefix KV 和最终答案缓存,说明 Prefix Cache 省 Prefill 而不省动态后缀与 Decode;
  • 优秀答案加分项:说明实际 Token/位置匹配、版本指纹、租户隔离、稳定内容前置及命中/未命中对照指标;
  • 常见错误:认为缓存了 Prompt 文本或最终答案,或者只比较字符串就跨租户共享;
  • 可继续追问:为什么把当前时间写在 System Prompt 最前面会显著降低缓存收益?

10. 递进追问

  1. 基础概念:Greedy、Temperature、Top-k、Top-p 分别如何改变下一 Token 选择?
  2. 张量推导:Decode 第 t 步 Q、K、V 和 Attention 分数形状是什么?
  3. 容量计算:给定层数、KV 头、头维、dtype、长度和并发,计算理论 KV 字节并说明为什么实测更高;
  4. 复杂度边界:为什么 KV Cache 避免重复计算,却没有让长输出成本变成常数?
  5. 调度权衡:交互短请求和离线长摘要共享 GPU,如何兼顾吞吐、公平与 P99?
  6. 事故复盘:发布量化模型后出现 Cache 命中错误、重复计费和尾延迟上升,你如何止损、定位、修复并建立防回归门禁?

11. 实践任务

  • [ ] 采样实验:运行本文代码,用固定 Logits 重复采样,绘制不同 Temperature/Top-p 的经验频率;
  • [ ] KV 计算:为 MHA、GQA、MQA 分别计算相同长度和并发下的理论 Cache;
  • [ ] 基准设计:定义输入长度 × 输出长度 × 并发 × 精度的压测矩阵,记录 TTFT、ITL、吞吐、显存和质量;
  • [ ] 故障注入:模拟客户端断连、队列超时、Worker OOM 和流式后重试,验证取消、幂等和资源释放;
  • [ ] 量化回归:建立事实、格式、安全、长上下文和代码五类固定样本,对比全精度与量化制品;
  • [ ] 容量计划:根据业务长度分布而非单一最大长度,设计准入水位与降级策略;
  • [ ] 前缀缓存实验:固定模型与动态后缀,比较合法命中、Prompt 版本变化和跨租户负例的缓存 Token、TTFT、输出一致性与审计结果;
  • [ ] 面试口述:用一分钟讲清 Prefill → KV Cache → Decode → Continuous Batching 的因果链。

12. 相关知识与参考资料

12.1 相关知识

12.2 一手参考资料

以下资料均于 2026-07-10 访问。服务框架支持的后端、量化格式、Cache 类型和参数会变化,部署时必须重新核对锁定版本的官方文档与源码。

  1. Hugging Face Transformers, Generation strategies 官方文档
  2. Hugging Face Transformers, Cache strategies 官方文档
  3. Kwon et al., Efficient Memory Management for Large Language Model Serving with PagedAttention,vLLM/PagedAttention 论文;
  4. vLLM Project, 官方文档官方源码
  5. Frantar et al., GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers
  6. Lin et al., AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration
  7. Leviathan et al., Fast Inference from Transformers via Speculative Decoding
  8. Dao, FlashAttention-2,高效 Attention 内核论文。

13. 简明总结

一句话记忆: 单请求 KV Cache 加速 Decode,跨请求 Prompt/Prefix Cache 复用稳定前缀的 Prefill;服务优化是在正确性和隔离门槛下联合管理 TTFT、ITL、吞吐、显存和尾延迟。

  • 单请求 KV Cache 的理论字节约为 2LBhkvtdhs,它省重算但随长度和并发增长;Prompt/Prefix Cache 不缓存答案,只在模型、Token 前缀、位置和安全隔离兼容时跨请求复用前缀 K/V;
  • Temperature、Top-k、Top-p 只改变采样分布,不能修复知识和上下文错误;
  • 连续批处理、分页式 KV、量化和并行都有收益边界,必须在目标硬件与固定评测集上实测;
  • 项目最易踩坑的是 KV 超卖、长请求阻塞、断连资源泄漏、流式重试不幂等和跨版本 Cache 污染;
  • 面试应从张量与复杂度讲到准入、调度、监控、故障恢复和质量回滚,并用实验清单、故障注入和回滚记录界定亮点。