跳转至

推理框架与工程化:从选型到容量规划

本章导读 推理优化不只是“把模型跑起来”,还要在延迟、吞吐、成本、稳定性之间做可量化的取舍。 本文先对比主流推理框架的定位,再建立 TTFT、TPOT、Goodput 等指标体系,最后落到容量规划与服务架构。 容量算例、GPU 价格和加速比均为量级/估算,真实项目必须用目标模型、目标硬件和真实流量压测。 框架版本迭代很快,涉及具体功能和性能的数字以官方文档与公开资料为准。

核心要点

  • vLLM 胜在生态与通用性,SGLang 强在前缀复用与结构化生成,TensorRT-LLM 追求 NVIDIA 平台极限性能。
  • llama.cpp 与 Ollama 面向本地和边缘,不要把 Ollama 直接当作高并发多租户生产网关。
  • TTFT 决定“首字快不快”,TPOT/ITL 决定“吐字顺不顺”,吞吐和 Goodput 决定“单位成本高不高”。
  • 容量规划的核心是权重、KV Cache、激活与碎片四本账,长上下文场景往往先耗尽 KV 而不是权重。
  • 负载均衡要感知队列和前缀缓存,轮询会把相同前缀打到不同副本,破坏缓存命中率。
  • 流式输出用 SSE,结构化输出靠语法约束解码,函数调用本质是模型生成受约束的 JSON 参数。
  • 可观测性要覆盖请求、token、队列、GPU 和成本五个维度,多租户还要处理配额与数据隔离。
  • 任何优化都要用端到端指标验证,单看 kernel 加速比或单看平均延迟都容易得出错误结论。

1. 推理框架对比

截至本文写作时(2026 年)的公开信息,主流框架都在快速迭代。下表给出定位级对比,具体版本能力以官方文档为准。

框架 定位 强项 局限 典型场景
vLLM 通用高吞吐推理引擎 PagedAttention、连续批处理、前缀缓存、chunked prefill、投机解码、多 LoRA 部分形状下不是极限性能,版本变化快 通用在线服务、私有化部署
SGLang 高性能服务与结构化生成 RadixAttention、压缩 FSM、DP attention、EPLB 生态相对小,部分优化绑定硬件 Agent、多轮、JSON/语法约束
TensorRT-LLM NVIDIA 平台深度优化 预编译 engine、in-flight batching、FP8/FP4、TP/PP/EP 构建复杂、硬件绑定、灵活性低 大规模 NVIDIA 集群、极致成本
llama.cpp 本地/边缘推理 GGUF、mmap、CPU/Metal/CUDA/Vulkan 高并发与分布式能力弱 笔记本、工作站、边缘盒子
Ollama 本地模型运行与管理 模型拉取、Modelfile、OpenAI 兼容接口 生产调度、观测、隔离能力有限 原型、个人开发、内部工具
HF TGI 生产级推理服务 Rust 服务、连续批处理、FlashAttention、流式、指标 功能覆盖和迭代速度不及头部框架 HuggingFace 模型托管、企业服务

vLLM 的核心贡献是把 PagedAttention 和连续批处理工程化:KV 切成固定块,用块表管理,降低显存碎片;调度器按迭代加入和退出请求,提高 GPU 利用率。它支持 TP/PP、多机、OpenAI 兼容接口、前缀缓存、chunked prefill、投机解码、多 LoRA 和 FP8/AWQ/GPTQ 量化,覆盖 NVIDIA、AMD、Intel 等硬件。弱点是不同模型结构、不同 GPU 上性能差异较大,自定义算子和极长上下文有时要等社区支持,生产环境应锁定版本并做回归。

SGLang 由前端语言和运行时组成:前端用 DSL 描述多步生成、分支、工具调用和结构化输出,运行时用 RadixAttention 把前缀组织成基数树跨请求复用 KV。它在多轮对话、Agent、批量 few-shot 等共享前缀场景命中率高;压缩有限状态机(compressed FSM)做语法约束解码,JSON Schema、正则、EBNF 的开销较低;还支持 DP attention、EPLB 等大规模 MoE 优化。弱点是生态和文档覆盖面较小,高级特性常依赖特定 GPU 或模型结构。

TensorRT-LLM 把模型编译成针对特定 GPU 和并行配置的 engine,融合自定义 kernel,使用 in-flight batching、FP8/FP4 和量化插件追求极限性能,通常通过 Triton 或自研服务层暴露接口。它在 NVIDIA 平台上往往有最高单卡吞吐,但 engine 与 GPU 型号、驱动、TensorRT 版本、权重和 TP/PP 配置绑定,换环境要重构建,调试和自定义模型改造门槛高,且只支持 NVIDIA。

llama.cpp 用 C/C++ 实现,支持 GGUF、mmap、CPU SIMD、Metal、CUDA、Vulkan,优势是“一个文件就能跑”,量化选项多、内存占用低、跨平台好。Ollama 在 llama.cpp 之上封装模型管理、Modelfile、REST API 和 OpenAI 兼容层,适合原型和个人开发,但默认调度、观测、配额和多租户隔离不是为大规模在线服务设计的。TGI 用 Rust 实现服务层,支持连续批处理、FlashAttention、流式、Prometheus 指标,与 HuggingFace 生态集成好,但功能覆盖和社区活跃度近年不如 vLLM、SGLang,选型应以当前版本实测为准。

选型清单:模型结构是否完整支持(含 MoE、多模态、自定义算子);目标硬件是否需要 FP8/FP4、NVLink、RDMA;是否需要前缀缓存、结构化输出、多 LoRA、投机解码、PD 分离;峰值吞吐、P99 延迟、冷启动和 engine 构建时间;社区活跃度、版本稳定性、许可证和商业支持;团队能否维护自定义 kernel 与分布式部署。

2. 关键指标与压测

TTFT(time to first token)是从请求到达到收到第一个输出 token 的时间,包含排队、prefill、首 token 采样和网络传输:\(\mathrm{TTFT}=T_{queue}+T_{prefill}+T_{first\_token}\)。TPOT(time per output token)是首 token 之后平均每个 token 的耗时:

\[ \mathrm{TPOT} = \frac{T_{last} - T_{first}}{O - 1} \]

\(T_{first}\) 是第一个 token 的时间,\(T_{last}\) 是最后一个 token 的时间,\(O\) 是输出 token 数。ITL(inter-token latency)是相邻 token 的时间间隔,关注抖动和长尾;TPOT 是平均值,ITL 的 P99 更能反映“卡顿感”。流式对话的端到端完成时间约为 \(\mathrm{TTFT}+\mathrm{TPOT}\times(O-1)\)。

吞吐要区分口径:token 吞吐是单位时间生成的 token 数,通常分开统计输入(prefill)和输出(decode);请求吞吐是单位时间完成的请求数(req/s 或 RPS);QPS(queries per second)与 RPS 类似,但“query”可能包含多次模型调用。P99 延迟表示 99% 请求不超过该值,比平均值更能暴露长尾。Goodput 是满足 SLO 的有效吞吐:

\[ \mathrm{Goodput} = \frac{1}{T}\sum_{i=1}^{N}\mathbf{1}\left[\mathrm{TTFT}_i \le S_{TTFT} \ \wedge\ \mathrm{TPOT}_i \le S_{TPOT}\right] \]

\(T\) 是观测窗口,\(N\) 是完成请求数,\(S_{TTFT}\)、\(S_{TPOT}\) 是 SLO 阈值,\(\mathbf{1}[\cdot]\) 是指示函数。每秒处理 1000 个请求但 40% 超时的系统,Goodput 可能不如每秒 600 个请求但 95% 达标的系统。

稳定系统中,Little's law 给出 \(N=\lambda W\):\(N\) 是在途请求数,\(\lambda\) 是到达率(req/s),\(W\) 是平均端到端延迟(s)。流式生成时 \(W \approx \mathrm{TTFT}+\mathrm{TPOT}\times(O-1)\)。它可用于由目标 RPS 和延迟估算并发,或由单副本并发估算副本数;突发流量和重试会破坏假设,需要留余量。

压测至少要做到:

  • 明确工作负载:输入/输出长度分布、模型、采样参数、并发数和到达过程。
  • 区分闭环(closed-loop)和开环(open-loop)。闭环收到响应才发下一个请求,容易掩盖排队;开环按固定速率或泊松过程发送,更接近真实流量。
  • 做 warmup,排除模型加载、CUDA Graph 捕获、缓存冷启动的影响;固定随机种子和输入分布,避免反复测同一段短 prompt。
  • 报告 P50、P90、P99,而不是只报平均;同时报告吞吐、错误率和 GPU 利用率。
  • 分别测前缀缓存命中/不命中、开启/关闭投机解码、不同 batch 上限。
  • 避免 coordinated omission:客户端不要在延迟升高时自动降低发送速率,否则会低估长尾。

常用工具包括 vLLM 自带 benchmark、NVIDIA genai-perf、Locust、k6、vegeta。压测机不能成为瓶颈,网络、TLS、日志和 JSON 解析都要计入。对话场景的 TTFT P99 常见目标是 0.5 到 2 秒,TPOT P99 约 30 到 80 毫秒(量级,按业务调整)。

3. 容量规划

显存由四部分组成:\(M_{total}=M_{weights}+M_{KV}+M_{act}+M_{workspace}\),其中 \(M_{weights}=P\cdot b_w\),\(M_{KV}=B\cdot S\cdot 2L n_{kv} d_{head} b_{kv}\)。\(P\) 是参数量,\(b_w\) 是每参数字节数(FP16 为 2,FP8 为 1,W4 约 0.5 加元数据),\(B\) 是并发序列数,\(S\) 是上下文长度,\(L\) 是层数,\(n_{kv}\) 是 KV 头数,\(d_{head}\) 是头维度,\(b_{kv}\) 是 KV 元素字节数;\(M_{act}\) 是激活,\(M_{workspace}\) 是 cuBLAS、通信、CUDA Graph 等缓冲,通常按 10% 到 20% 或固定 10 到 20 GB 估算。

单卡或单副本最大并发为:

\[ B_{max} = \left\lfloor \frac{M_{GPU} \cdot u - M_{weights} - M_{overhead}}{S \cdot m_{kv}} \right\rfloor \]

\(u\) 是目标显存利用率(常见 0.85 到 0.92),\(m_{kv}=2L n_{kv} d_{head} b_{kv}\) 是每 token KV 字节数,\(M_{overhead}\) 包含激活和工作区。所需 GPU 数取三个约束的最大值:

\[ N_{mem} = \left\lceil \frac{P b_w + B_{target} S m_{kv} + M_{overhead}}{M_{GPU} u} \right\rceil,\qquad N = \max\left(N_{mem},\ \left\lceil \frac{R_{target}}{R_{perGPU}} \right\rceil,\ N_{SLO}\right) \]

\(B_{target}\) 是目标并发,\(R_{target}\) 是目标 token 吞吐,\(R_{perGPU}\) 是单卡实测吞吐,\(N_{SLO}\) 是满足 P99 延迟所需副本数。最后再加 N+1 或 N+2 冗余和滚动升级余量。多卡 TP 时权重和 KV 近似按卡分摊,但每卡仍有自己的激活与通信缓冲,不能把单卡公式简单乘以卡数。

3.1 完整算例:70B 模型

假设模型 70B,FP16 权重约 140 GB,80 层,8 个 KV 头,头维 128,每 token KV 为 \(2\times80\times8\times128\times2=327{,}680\) 字节,约 0.3125 MiB;目标上下文 8K,并发 30,平均输出 500 token;硬件 H100 80GB,TP=4,显存利用率 0.9,固定开销 20 GB;SLO 为 TTFT 不超过 2 秒、TPOT 不超过 50 毫秒。

显存核算:

  • 4 卡总显存 320 GB,可用约 288 GB;权重 140 GB,开销 20 GB,KV 预算约 128 GB。
  • 单请求 8K KV 为 \(8192\times0.3125=2560\) MiB,约 2.7 GB(2.5 GiB)。
  • 最大并发约 \(128/2.684\approx47\);30 并发占用约 80 GB(75 GiB),总占用约 240 GB,能放下。

延迟核算:

  • 单步读取权重 140 GB 加 KV 约 80 GB(75 GiB),总流量约 220 GB;4 卡聚合带宽约 \(4\times3.35=13.4\) TB/s,理论单步约 16.4 ms。
  • 按 60% 带宽效率估算,单步约 27 ms,低于 50 ms 的 TPOT 目标。
  • 输出吞吐约 \(30/0.027\approx1100\) token/s(量级估算,未计调度和采样开销)。

prefill 核算:8K prompt 计算量约 \(2\times70\times10^9\times8192\approx1.15\times10^{15}\) FLOPs;4 卡 FP16 峰值约 3956 TFLOPS,按 40% MFU 约 1582 TFLOPS,prefill 约 0.73 秒,加上排队和首 token,TTFT 在 2 秒内可行。

结论:单副本 4 张 H100 可支撑约 30 并发、8K 上下文、1100 token/s 输出;要做 N+1 高可用,至少准备 8 张卡(两个 4 卡副本)。若并发升到 100,KV 约 268 GB(250 GiB),加权重和开销超过 288 GB,必须增加卡数、缩短上下文或做 KV 量化。

成本估算:按 H100 每小时 3 美元(量级)、满负载 1100 token/s,每小时产出约 396 万 token,单位成本约 \((4\times3)/3.96\times10^6\times10^6\approx3.0\) 美元/百万 token。这是满负载、只算输出 token 的理想值;平均利用率 30% 时约 10 美元/百万 token,实际还要算输入 token、网络、存储和运维。

3.2 完整算例:7B 模型与长上下文

7B 模型 FP16 权重 14 GB,MHA 配置每 token KV 约 0.5 MiB。L40S 48GB,显存利用率 0.9,开销 4 GB,KV 预算约 25 GB。

上下文 单请求 KV 最大并发(估算)
4K 2 GiB 12
8K 4 GiB 6
32K 16 GiB 1

即使是 7B 小模型,32K 上下文也会把并发压到个位数,长上下文服务的成本主要由 KV 决定。若改用 GQA(8 个 KV 头),每 token KV 降到 0.125 MiB,同样 32K 单请求只需 4 GiB,并发可提升约 4 倍。

3.3 容量计算代码

def kv_bytes_per_token(layers, n_kv, d_head, bytes_per_elem=2):
    return 2 * layers * n_kv * d_head * bytes_per_elem

def plan_capacity(gpu_mem_gb, num_gpus, util, params_b, weight_bytes,
                  layers, n_kv, d_head, ctx, overhead_gb=20, kv_bytes=2):
    total_mem = gpu_mem_gb * num_gpus * util
    weights = params_b * 1e9 * weight_bytes / 1e9
    kv_per_tok = kv_bytes_per_token(layers, n_kv, d_head, kv_bytes)
    kv_budget = total_mem - weights - overhead_gb
    per_req = kv_per_tok * ctx / 1e9
    return {"weights_gb": round(weights, 1), "kv_budget_gb": round(kv_budget, 1),
            "kv_per_request_gb": round(per_req, 2),
            "max_concurrency": max(0, int(kv_budget // per_req))}

print(plan_capacity(80, 4, 0.9, 70, 2, 80, 8, 128, 8192))

输出中的 max_concurrency 是纯显存约束,还要用实测吞吐和 P99 延迟校验。代码按十进制 GB 计算,与厂商标称一致;生产脚本还应加入碎片、块对齐和预留。

3.4 单位成本

成本公式为 \(\text{Cost}_{1M}=C_{GPU/hr}\times10^6/(R_{tok/s}\times3600\times U)\),\(C_{GPU/hr}\) 是单卡每小时成本,\(R_{tok/s}\) 是实测 token 吞吐,\(U\) 是平均利用率。它只算 GPU,不含 CPU、网络、存储和人力,可用于快速比较“更贵的快卡”和“更便宜的多卡”。

4. 服务架构

客户端
  -> DNS / TLS / CDN
  -> API 网关(认证、配额、限流、请求校验、日志)
  -> 模型路由(模型选择、租户策略、灰度、A/B)
  -> 推理副本池(每个副本含调度器与 GPU worker)
  -> KV 缓存层级(HBM -> CPU DRAM -> NVMe / 远端)
  -> 观测与计费(指标、trace、token 账单、告警)

网关负责横切能力:API Key 校验、租户识别、请求体大小限制、超时、重试策略、限流、审计。它不应做重的 token 级处理,否则会成为瓶颈。推理副本是无状态的,但 KV 缓存和前缀缓存有状态,负载均衡要尽量把同一会话或同一前缀送到同一副本,同时避免热点。

  • 轮询简单,但会让相同前缀落到不同副本,降低前缀缓存命中率。
  • 最少在途请求能感知副本压力,比轮询更适合长请求;队列感知进一步选择等待队列最短、预计完成最早的副本。
  • 前缀感知对 prompt 前缀做哈希,优先路由到已缓存该前缀的副本,命中率高时收益很大。
  • 多轮对话用 session id 做会话亲和,尽量复用 KV 和前缀;节点故障时要有重建机制。
  • 模型路由让简单分类、短问答走小模型,复杂推理走大模型;级联(cascade)先小后大,用置信度或校验决定是否升级。
  • 灰度发布先接 1% 到 5% 流量,比较 TTFT、错误率、任务指标和成本,异常自动回滚;影子流量不返回用户,只做对比。

限流分租户级、模型级、IP 级和全局级:令牌桶(token bucket)控制请求速率,并发信号量控制同时在途数,token 配额控制成本,超限返回 429 并带 Retry-After。降级可以缩短 max_tokens、关闭工具调用/视觉/结构化输出、路由到更小或量化模型、返回缓存答案,或排队但设置截止时间。缓存分为精确响应缓存(相同模型、相同 prompt、temperature=0,需 TTL 和版本号)、语义缓存(相似问题复用答案,可能答非所问,适合 FAQ)、前缀缓存(复用 KV,不改变输出)和会话 KV 缓存(注意隔离与失效)。

自动扩缩容不能只看 CPU:LLM 副本启动慢(模型加载、CUDA Graph 捕获、编译),要结合等待队列长度、TTFT/TPOT P99、GPU 显存与 KV 块使用率、每副本 token 吞吐和预测峰谷。缩容更保守,新副本先预热再接入流量。

5. API 设计

5.1 OpenAI 兼容接口

常见接口包括 GET /v1/models、POST /v1/chat/completions、POST /v1/completions 和 POST /v1/embeddings。对话请求的核心字段如下:

{
  "model": "llama-3-70b",
  "messages": [{"role": "user", "content": "解释 KV Cache。"}],
  "temperature": 0.7, "top_p": 0.9, "max_tokens": 512,
  "stream": true, "stream_options": {"include_usage": true}
}

响应要返回 id、object、created、model、choices、usage;usage 至少包含 prompt_tokens、completion_tokens、total_tokens,用于计费和观测。错误响应使用一致的 JSON 结构并带请求 id,方便排查。

5.2 流式输出与 SSE

流式输出通常用 Server-Sent Events(SSE),响应头为 Content-Type: text/event-stream,每个事件以 data: 开头、空行分隔:

data: {"id":"chatcmpl-1","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant"}}]}

data: {"id":"chatcmpl-1","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"KV"}}]}

data: {"id":"chatcmpl-1","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":20,"completion_tokens":8,"total_tokens":28}}

data: [DONE]

工程要点:设置心跳或注释行,防止代理层因空闲断开;客户端断开时取消后端请求,释放 KV 和 GPU;代理层关闭响应缓冲,Nginx 需 proxy_buffering off;最后一个 chunk 再带 usage,避免统计不完整。

5.3 结构化输出与函数调用

结构化输出把 JSON Schema、正则或语法编译成有限状态机,在每个解码步屏蔽不合法 token 的 logits。请求示例使用 response_format: {"type":"json_schema","json_schema":{"name":"person_company","strict":true,"schema":{"type":"object","properties":{"person":{"type":"string"},"company":{"type":"string"}},"required":["person","company"],"additionalProperties":false}}}。它只保证“格式合法”,不保证“内容正确”;复杂 schema 会增加编译时间和掩码开销;约束过强可能让模型无法表达“不知道”,要允许 null 或错误字段;生产环境要有解析失败的重试和降级。

函数调用(function calling / tool use)让模型输出工具名和参数:请求带 tools,每个工具用 JSON Schema 描述参数;模型返回 tool_calls,应用校验参数、执行工具,把结果以 role: "tool" 追加;再次调用模型生成最终回答。工具参数必须校验和限权,不能让模型直接拼接 SQL、Shell 或 URL;工具执行要有超时、沙箱、审计和速率限制;不可逆操作要求人工确认。并行工具调用能降低延迟,但增加结果合并和错误处理复杂度。

5.4 错误与重试

状态码 含义 处理建议
400 请求格式或参数错误 不重试,修正请求
401/403 认证或权限失败 刷新凭证,不重试
404 模型不存在 检查模型名与路由
429 限流或配额不足 退避重试,尊重 Retry-After
500 服务内部错误 有限次重试,记录 trace
503 过载或副本不可用 退避重试,切换副本
504 超时 根据幂等性决定是否重试

重试要用指数退避加随机抖动,避免惊群。流式请求一旦开始返回内容,重试可能造成重复输出,需要客户端去重或使用幂等键。

6. GPU 选型与成本

GPU 显存 带宽 FP16 稠密算力 FP8 互联 参考价格(量级) 适用场景
A100 80GB 80 GB 2.0 TB/s 312 TFLOPS 不支持 NVLink 600 GB/s 1.0 到 1.5 万美元;1 到 2 美元/小时 成熟训练/推理,生态好
H100 80GB 80 GB 3.35 TB/s 989 TFLOPS 1979 TFLOPS NVLink 900 GB/s 2.5 到 3.5 万美元;2 到 4 美元/小时 高吞吐、FP8、张量并行
H200 141GB 141 GB 4.8 TB/s 989 TFLOPS 1979 TFLOPS NVLink 900 GB/s 3 到 4 万美元;3 到 5 美元/小时 长上下文、大模型、大 KV
L40S 48GB 48 GB 864 GB/s 362 TFLOPS 733 TFLOPS PCIe 0.7 到 1 万美元;0.8 到 1.5 美元/小时 性价比推理、图形/多模态
RTX 4090 24GB 24 GB 1008 GB/s 330 TFLOPS 约 660 TFLOPS 无 NVLink 0.16 到 0.25 万美元;0.3 到 0.7 美元/小时 单机小模型、开发测试
RTX 6000 Ada 48GB 48 GB 960 GB/s 364 TFLOPS 约 728 TFLOPS 无 NVLink 0.6 到 0.8 万美元 工作站、48GB 单卡

价格与算力为公开资料量级估算,随市场、采购量和云厂商变化,务必以实际报价为准。

选型要点:显存容量优先,先看模型权重加 KV 能否放下,再看带宽和算力;decode 看带宽,prefill 看算力,70B 以上通常需要 TP,卡间互联很关键;H100/H200 的 FP8 能降低权重显存和提升吞吐,但需要框架和 kernel 支持;L40S 没有 NVLink,TP 通信走 PCIe,适合单卡或小规模 TP;RTX 4090 性价比高,但 24GB 显存、无 NVLink、消费级散热和可靠性限制生产适用性;云上按小时计费适合波动流量,自建适合稳定高利用率,要把闲置率和运维成本算进去。

7. 可观测性与安全

必须监控的指标:

  • 请求:QPS、并发数、错误率(按状态码)、超时率、限流次数。
  • 延迟:TTFT、TPOT、ITL、端到端延迟的 P50/P90/P99。
  • 队列:等待请求数、排队时间、抢占/换出次数。
  • 缓存:前缀缓存命中率、KV 块使用率、缓存淘汰数。
  • token 与成本:输入/输出 token 数、每请求 token 分布、每租户成本。
  • GPU:利用率、显存、SM occupancy、HBM 带宽、NVLink/PCIe 流量、功耗、温度。
  • 质量:结构化输出解析失败率、工具调用失败率、人工反馈。

日志要带 request id、tenant id、model、版本、token 数、采样参数、finish_reason 和延迟分解;默认不要记录完整 prompt,涉及隐私时要脱敏、采样或征得同意。trace 建议用 OpenTelemetry,把网关、路由、排队、prefill、decode、detokenize 拆成 span,高流量按 1% 到 10% 采样,错误请求全采样。告警基于 SLO:TTFT P99 超过阈值持续 5 分钟、错误率超过 1%、GPU 显存超过 90%、队列持续增长、副本不可用;告警要能关联模型版本和租户。

多租户隔离与安全:

  • 认证与授权:API Key 哈希存储、短期令牌、RBAC、租户级模型白名单。
  • 配额:按租户限制 RPM、TPM、并发数和每日 token 预算,防止 noisy neighbor。
  • 计算隔离:逻辑隔离(命名空间、优先级队列)成本低;强隔离可用 MIG 或独立 GPU 池。
  • 缓存隔离:前缀缓存可能通过命中时间泄露其他租户的 prompt 内容,生产上按租户分区或只共享公开系统提示。
  • 数据与工具:传输 TLS、静态加密、日志脱敏、保留期限、删除流程、跨境合规;工具调用最小权限、沙箱、超时和审计。
  • 提示注入与模型保护:把用户输入和系统指令分层,外部内容不直接当指令执行;限流、水印、输出过滤、防止模型窃取,权重文件访问最小化。

面试高频问题

1. vLLM、SGLang、TensorRT-LLM 怎么选?

参考回答要点:

  • vLLM 通用性和生态最好,模型覆盖广,适合大多数在线服务和私有化部署。
  • SGLang 在前缀复用、多轮 Agent 和结构化输出上强,适合共享前缀多的负载。
  • TensorRT-LLM 在 NVIDIA 平台上峰值性能最好,但 engine 与硬件/模型绑定,构建和调试成本高。
  • 选型要看模型支持、硬件、SLA、团队维护能力和版本稳定性,最好用真实流量做 A/B 压测。
  • 比较 Goodput 和单位 token 成本,而不是只看 benchmark 的峰值吞吐。

2. TTFT 和 TPOT 分别受什么影响?如何优化?

参考回答要点:

  • TTFT 包含排队、prefill、首 token 采样和网络,长 prompt 和排队是主要因素。
  • TPOT 主要由 decode 的权重/KV 带宽决定,批大小、上下文长度和投机解码会影响。
  • 优化 TTFT:chunked prefill、前缀缓存、减少排队、提高 prefill 算力、流式首包。
  • 优化 TPOT:KV 量化、GQA/MLA、减少批内干扰、投机解码、提高带宽利用率。
  • 两者会权衡:大 batch 提高吞吐但可能增加 TTFT 和 TPOT 的长尾。

3. 给定 70B 模型和 8K 上下文,如何估算需要多少 GPU?

参考回答要点:

  • 先算权重:70B FP16 约 140 GB,FP8 约 70 GB。
  • 再算每 token KV:\(2L n_{kv} d_h b_{kv}\),GQA 8 头、80 层、FP16 约 0.3125 MiB。
  • 8K 单请求约 2.5 GiB,乘以目标并发得到 KV 总量。
  • 加 10% 到 20% 的激活、碎片和 workspace,除以单卡可用显存,得到显存约束。
  • 再用实测吞吐和 P99 延迟校验,取显存、吞吐、SLO 三个约束的最大值,并加冗余。

4. 为什么平均延迟达标,用户仍然觉得卡?

参考回答要点:

  • 平均值掩盖长尾,P99 可能远高于均值,用户会记住最慢的几次。
  • 流式场景中 ITL 抖动比 TPOT 均值更影响体感,长 prefill 会阻塞 decode。
  • 排队、垃圾回收、缓存未命中、副本热点都会造成尖刺。
  • 要用 P99、ITL 分布和 Goodput 评估,而不是只看平均 tokens/s。
  • 优化手段包括 chunked prefill、队列感知调度、隔离长请求和容量预留。

5. 负载均衡为什么不能简单轮询?

参考回答要点:

  • LLM 请求时长差异大,轮询会把请求打到已经繁忙的副本,造成排队不均。
  • 前缀缓存有状态,轮询会破坏相同前缀的复用,降低命中率。
  • 更适合最少在途请求、队列感知或前缀感知路由。
  • 多轮对话需要会话亲和,但要有故障转移和缓存重建机制。
  • 要监控每副本的队列、TTFT 和缓存命中率,而不是只看连接数。

6. OpenAI 兼容 API 的关键点是什么?

参考回答要点:

  • 保持请求/响应字段兼容,包括 model、messages、temperature、max_tokens、stream、tools。
  • 流式用 SSE,事件以 data: 开头、空行分隔,最后发送 [DONE]。
  • 返回 usage,统计 prompt/completion/total token,支持计费和观测。
  • 错误码和错误结构要一致,429 带 Retry-After,5xx 可重试。
  • 客户端断开要取消后端生成,释放 KV 和 GPU 资源。

7. 结构化输出如何保证 JSON 合法?有什么局限?

参考回答要点:

  • 把 JSON Schema 或语法编译成有限状态机,在每个解码步屏蔽不合法 token。
  • 只保证语法合法,不保证字段内容真实或符合业务约束。
  • 复杂 schema、长枚举和递归结构会增加编译与掩码开销。
  • 约束过强可能让模型无法表达“不知道”,要允许 null 或错误字段。
  • 仍需要解析校验、重试和降级,不能把语法约束当成事实校验。

8. 函数调用的完整链路和安全风险是什么?

参考回答要点:

  • 请求带 tools schema,模型返回 tool_calls,应用校验参数并执行工具。
  • 工具结果以 tool role 回传,模型再生成最终回答。
  • 风险包括参数注入、越权访问、SSRF、命令执行和无限循环。
  • 工具要做最小权限、沙箱、超时、速率限制和审计。
  • 不可逆操作要人工确认,模型输出不能直接拼接 SQL 或 Shell。

9. GPU 选型只看算力对吗?如何比较成本?

参考回答要点:

  • 不对,decode 往往受带宽和显存容量限制,算力不是唯一指标。
  • 先看权重加 KV 能否放下,再看带宽、互联和 FP8 支持。
  • 用单位 token 成本比较:GPU 小时成本除以实测吞吐和利用率。
  • 考虑闲置率、网络、存储、运维和故障恢复成本。
  • 小规模或波动流量适合云上按需,稳定高利用率适合自建。

10. 多租户场景如何做隔离?

参考回答要点:

  • 认证、租户配额、RPM/TPM/并发限制,防止 noisy neighbor。
  • 逻辑隔离用命名空间和优先级队列,强隔离用 MIG 或独立 GPU 池。
  • 前缀缓存和 KV 缓存按租户分区,避免侧信道泄露。
  • 日志脱敏、加密、审计和保留期限要符合合规要求。
  • 工具调用沙箱化,限制网络、文件和命令执行权限。

本文档为面试复习资料,公式与数字建议结合原始论文复核。