推理框架与工程化:从选型到容量规划¶
本章导读 推理优化不只是“把模型跑起来”,还要在延迟、吞吐、成本、稳定性之间做可量化的取舍。 本文先对比主流推理框架的定位,再建立 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 的耗时:
\(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 的有效吞吐:
\(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 估算。
单卡或单副本最大并发为:
\(u\) 是目标显存利用率(常见 0.85 到 0.92),\(m_{kv}=2L n_{kv} d_{head} b_{kv}\) 是每 token KV 字节数,\(M_{overhead}\) 包含激活和工作区。所需 GPU 数取三个约束的最大值:
\(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 缓存按租户分区,避免侧信道泄露。
- 日志脱敏、加密、审计和保留期限要符合合规要求。
- 工具调用沙箱化,限制网络、文件和命令执行权限。
本文档为面试复习资料,公式与数字建议结合原始论文复核。