1000道算法工程师面试题(大模型)—— 第22部分
大模型推理与加速技术要点 本文总结了vLLM、SGLang、MindIE等框架的核心技术原理与实践经验。重点包括: 显存优化:PagedAttention通过分块管理KV Cache解决显存碎片问题 批处理优化:Continuous Batching动态调度提升GPU利用率 长文本处理:SGLang的Radix Attention优化共享前缀复用 硬件适配:昇腾卡部署时的算子兼容性解决方案 量化技
·
这是第二部分的参考答案。这部分内容涉及底层原理和工程实践,是体现你“是否真的在生产环境搞过大模型”的关键。
第二部分:大模型推理与加速(vLLM/SGLang/MindIE) (21-45)
21. 你简历提到了 vLLM,能不能通俗讲一下 PagedAttention 到底解决了什么问题?它是怎么减少显存碎片的?
答案:
- 核心问题: 显存碎片化(Fragmentation)。
- 在 PagedAttention 出现之前,框架必须按照 Max Context Length 为每个请求预分配连续显存。如果一个请求设了 2048 长度但只生成了 100 个词,剩下的显存就浪费了(内部碎片)。而且不同请求之间留下的空隙也塞不进新请求(外部碎片)。
- 解决方案: 借鉴了操作系统“虚拟内存分页”的思想。
- 它把 KV Cache 切分成固定大小的 Block(比如一块存 16 个 Token)。
- 逻辑上连续的 Token,在物理显存上可以是不连续的。
- 效果: 需要多少申请多少,极大消除了内部碎片,几乎杜绝了外部碎片,使得显存利用率接近 100%,从而能支持更大的 Batch Size。
22. 在 vLLM 里,Block Size 这个参数你是怎么调优的?设大设小对性能有什么具体影响?
答案:
- 调优经验: 通常默认值(16)或者 32 表现最好。
- 设太小(如 8): 显存利用率极高(碎片少),但寻址开销变大,Kernel 访存效率降低,导致推理变慢。
- 设太大(如 128): 寻址效率高,但尾部碎片(Internal Fragmentation)变多(最后一个 Block 没填满的部分),浪费显存,导致能跑的并发数(Batch Size)下降。
23. Continuous Batching(连续批处理)和传统的 Static Batching 区别在哪?为什么大模型推理必须上 Continuous Batching?
答案:
- Static Batching: 一个 Batch 里有 4 个请求,必须等最长的那个生成完,整个 Batch 才能结束。短的请求生成完了只能空转等待,GPU 利用率低。
- Continuous Batching (Iteration-level scheduling):
- 在每一次
Step(生成一个 Token)结束后,检测哪些请求结束了。 - 结束的请求立即移除(释放显存),立刻插入新的请求进来填补空位。
- 在每一次
- 必要性: LLM 生成长度方差极大(有的回答 “Yes”,有的写小作文),静态批处理会导致严重的 “Long-tail” 延迟问题。
24. 你用过 SGLang,它相比 vLLM 在长上下文(Long Context)场景下有什么优势?Radix Attention 是什么?
答案:
- 核心优势: 对 Shared Prefix(共享前缀) 的极致优化。
- Radix Attention:
- 它不仅像 vLLM 一样管理 KV Cache,还将 KV Cache 维护成一棵 Radix Tree(基数树)。
- 场景: 比如 Few-shot Prompting 或者 RAG 场景,系统提示词和例子都是一样的,只有最后的用户提问不同。
- SGLang 能自动识别这些公共前缀,直接复用显存里已有的 KV Cache,而不需要重新计算。这在多轮对话和 Agent 场景下能带来巨大的吞吐提升。
25. MindIE 是华为的推理框架吧?你在昇腾卡上部署的时候,有没有遇到算子不支持的情况?怎么解决的?
答案:
- 遇到过。 昇腾生态虽然在进步,但一些最新的激活函数或自定义算子可能还没通过
ACL适配。 - 解决思路:
- 查文档/算子库: 看 MindSpore 是否有等价的组合算子。
- Fallback 到 CPU: 极其影响性能,只作为调试手段。
- 自定义算子开发(TBE/TIK): 如果是瓶颈算子,会尝试写 TBE(Tensor Boost Engine),但这开发成本很高。
- 等待/反馈: 实际上最常用的是直接在华为社区提单,或者换用等价的标准算子(比如用 GeLU 替换 SwiGLU 的变体,如果精度损失可控)。
26. LMDeploy 的 TurboMind 引擎你了解吗?它在 int4 量化下的性能相比 vLLM 怎么样?
答案:
- 了解: 它是书生·浦语团队开源的,专门针对 NVIDIA GPU 做了极致优化的 C++ 推理引擎。
- 性能对比:
- 在早期,TurboMind 的 Int4 (W4A16) 实现通过 Persistent Batching 和手写的 Kernel,性能是明显优于 vLLM 的。
- 现在 vLLM 跟进很快(引入了 Marlin kernel 等),两者差距在缩小。但在单卡极致吞吐上,TurboMind 往往还是略胜一筹,特别是在处理 Llama 结构模型时。
27. 说说 KV Cache 吧,随着对话轮数增加,KV Cache 会越来越大,这块显存你们是怎么管理的?
答案:
- 物理层面: 靠 PagedAttention 分页管理。
- 逻辑层面(显存不够时):
- Swap-out: vLLM 会把暂时不活跃的请求的 KV Cache 搬到 CPU 内存 里,等轮到它时再搬回来(Swap-in)。
- Sliding Window(滑动窗口): 对于某些支持的模型(如 Mistral),只保留最近 N 个 Token 的 KV,旧的直接丢弃。
- Recomputation: 极端情况下丢弃,下次用的时候重新计算(以算力换显存)。
28. 假如现在有一个高并发场景,QPS 很高,你会选 vLLM 还是 TGI?理由是什么?
答案:
- 首选 vLLM。
- 理由: vLLM 的吞吐量(Throughput)通常更高,且对 Python 开发者更友好,方便魔改逻辑(比如加一些特定的 Logit Processor)。
- 何时选 TGI (Text Generation Inference):
- 如果追求极致的稳定性(Rust 后端),或者深度依赖 HuggingFace 的生态(不想转模型格式),且对 Tensor Parallel 有开箱即用的严格需求时,TGI 也是很好的选择。
29. 什么是 Speculative Decoding(投机采样)?在 vLLM 里怎么开启?它真的能加速吗?
答案:
- 原理: 用一个小模型(Draft Model)快速生成几个 Token,然后用大模型(Target Model)并行验证这些 Token 是否正确。如果猜对了就赚了,猜错了就回退。利用了验证比生成快的特性。
- 开启: vLLM 启动参数加上
--speculative-model [small_model_path]和--num-speculative-tokens 5。 - 加速效果: 看场景。
- 如果输入简单(如写代码补全、常见成语),命中率高,能加速 2-3 倍。
- 如果任务很难,小模型一直猜错,大模型一直回退,反而因为额外的开销变慢。
30. 在做推理加速时,Tensor Parallelism (TP) 和 Pipeline Parallelism (PP) 你是怎么选择的?单机 8 卡你会怎么切?
答案:
- 单机 8 卡(NVLink 环境): 全切 TP (TP=8)。
- 因为单机内 NVLink 带宽极高,TP 切分的是矩阵乘法,能降低单次推理延迟。
- 多机环境: 节点内 TP,节点间 PP。
- 跨机带宽低(Ethernet/Infiniband),跑 TP 通信太慢,所以用 PP 把模型分层切到不同机器上。
- PP 的缺点: 会有“气泡”(Bubble),且增加了 Latency,一般推理场景尽量避免用 PP,除非模型大到单机装不下。
31. 遇到过 vLLM 推理时首字延迟(TTFT)很高的问题吗?通常是什么原因导致的?
答案:
- 原因:
- Prefill 阶段计算量大: 输入 Prompt 很长,Attention 是 O ( N 2 ) O(N^2) O(N2) 复杂度,计算慢。
- 调度问题: 前面排队的 Request 正在做 Prefill,把计算资源占满了(Head-of-line blocking)。
- 解决(vLLM 新特性): Chunked Prefill。
- 把长的 Prompt 拆分成小块,和 Decode 阶段的 Token 一起 Batch 进去跑。这样不会因为一个长任务把整个 GPU 堵死,显著降低 TTFT。
32. 你们的模型支持多模态吗?比如 LLaVA 在 vLLM 上部署,图片特征提取那部分是怎么并行处理的?
答案:
- 支持。 vLLM 较新版本已经原生支持 LLaVA 等多模态模型。
- 处理流程:
- 图片 -> CLIP Vision Encoder -> Projector -> Image Embeddings。
- 这部分通常在 TP 组的 Rank 0 上串行执行(或者模型内部也支持切分),得到的 Embeddings 广播给其他卡,然后拼接在 Text Embeddings 里进入 LLM 部分。LLM 部分依然是正常的 TP 并行。
33. 关于量化,AWQ 和 GPTQ 有什么区别?在 vLLM 里加载 AWQ 模型需要注意什么?
答案:
- 区别:
- GPTQ: 基于二阶信息(Hessian 矩阵)逐层量化,侧重于调整权重以最小化误差。
- AWQ (Activation-aware Weight Quantization): 认为“不是所有权重都重要”,通过观察激活值(Activation),保留那 1% 的重要权重(Scaling)不量化或保护起来。AWQ 的泛化能力通常比 GPTQ 更好,且不依赖校准集的分布。
- vLLM 注意事项: 启动时指定
quantization="awq"。注意 Kernel 的兼容性,某些旧显卡可能跑 AWQ 的 GEMM kernel 效率不如 GPTQ。
34. MindIE 在 Ascend 910B 上跑 Llama3,性能大概能达到 A100 的百分之多少?有没有实测数据?
答案:
- (这个问题回答要谨慎且自信)
- 理论算力: 910B 的 FP16 算力是接近 A100 的。
- 实测性能:
- 如果是原生 PyTorch 跑,可能只有 50%-60%。
- 但是用了 MindIE + 算子融合 + FlashAttention 优化后,在 Llama3-70B 这种主流模型上,通常能达到 A100 的 80% - 90% 左右。
- 主要瓶颈有时不在算力,而在 HBM 带宽和部分特殊算子的实现效率上。
35. 很多推理框架都支持 Prefix Caching,这在 RAG 场景下有什么特别的用处?
答案:
- RAG 痛点: 每次请求都要带上一大堆检索到的文档(Documents)作为 Context,这些文档可能很长,导致每次都要重新计算 Prefill。
- Prefix Caching: 如果多条请求检索到了相同的文档(或者同一个文档被多次引用),框架会缓存这些文档对应的 KV Cache。
- 用处: 直接跳过 Prefill 阶段,把长文档的推理变成“查表”,TTFT 可能会从几秒降到几十毫秒。
36. TensorRT-LLM 你用过吗?它的构建 Engine 过程非常慢,你是怎么权衡构建时间和推理性能的?
答案:
- 权衡策略:
- 生产环境(Online): 必用 TRT-LLM。虽然 Build Engine 要半小时甚至更久,但一旦构建好,推理吞吐量提升显著。对于数月不换的模型,这个时间成本值得。
- 实验/开发环境(Offline/Dev): 不用 TRT-LLM,用 vLLM。迭代快,不用等编译。
- 技巧: 使用 Docker 缓存构建好的 Engine 文件;或者在 CI/CD 流水线里异步构建。
37. ONNX Runtime 在跑大模型时现在还常用吗?还是主要用来跑 BERT 这种小模型?
答案:
- 现状: 在 GPU 大模型(7B+) 领域,ONNX Runtime (ORT) 已经不是主流了,大家都在用 vLLM/TRT-LLM。
- 适用场景:
- CPU 推理: ORT 对 CPU 的量化和指令集优化依然是顶级的。
- 端侧/小模型: 跑 BERT、Embedding 模型或者在 Windows 本地部署(DirectML)时,ORT 依然很强。
- 微软推出了 ORT-GenAI 试图追赶,但在生态兼容性上目前还不如 vLLM。
38. 如果 SGLang 里的请求队列积压了,你会监控哪些指标来判断是显卡不够了还是 CPU 处理慢了?
答案:
- GPU 利用率 (Volatile-GPU-Util): 如果长期 100% 且显存满了,那是显卡不够,加卡。
- CPU 利用率 & Load Average: 如果 GPU 利用率不高(波浪形),但 CPU 爆满,说明是 Python 胶水代码、Tokenizer 或者 HTTP 处理在卡脖子。
- KV Cache Usage: 如果 KV Cache 满了导致频繁 Swap-out/Swap-in,也会导致队列积压。
39. 在昇腾上做推理,MindSpore Lite 和 MindIE Service 是一回事吗?它们的定位区别是什么?
答案:
- 不是一回事。
- MindSpore Lite: 侧重于 端侧/离线 推理(手机、IoT、嵌入式),或者简单的服务器端静态图推理。
- MindIE (Inference Engine): 对标 NVIDIA Triton + TensorRT-LLM。它是 服务端、高性能 推理框架,支持 Continuous Batching、PagedAttention 等高级特性,专门为了榨干 Ascend 910B 这种大芯片的性能而生。
40. 讲讲 vLLM 的调度策略,它是怎么决定哪个 Request 先跑,哪个被 Preempt(抢占)的?
答案:
- 基本策略: FCFS (First Come First Served)。
- 抢占逻辑:
- 当显存(KV Cache block)不足以容纳当前所有 Running 状态请求的新 Token 时。
- vLLM 会选择 最新加入 或者 优先级最低 的请求,将其状态改为 Preempted。
- 动作: 将其 KV Cache 换出到 CPU(Swap),腾出显存给前面的请求跑完。等显存充裕了再换回来继续跑。
41. 遇到过“生成重复内容”或者“死循环”的情况吗?在推理参数(Temperature, Top-P)上怎么调?
答案:
- 原因: 模型陷入局部最优,或者单纯是模型能力不行。
- 调参:
- 增加
frequency_penalty(频率惩罚): 这是一个硬指标,直接惩罚已经出现过的 Token 的概率,最有效。 - 提高
temperature: 增加随机性,让模型跳出局部循环。 - Top-P (Nucleus Sampling): 虽然有用,但如果模型非常确信那个重复词(概率极高),Top-P 截断了尾部也没用。建议优先调 Penalty。
- 增加
42. 如果要自己写一个简单的 Python 推理 Server,不用 vLLM,怎么实现流式输出(Streaming)?
答案:
- 核心机制: Python 的
yield生成器 + SSE (Server-Sent Events)。 - PyTorch 实现:
- 模型
generate()通常是阻塞的。需要使用TextIteratorStreamer(HuggingFace 提供的工具)。 - 开启一个 子线程 去跑
model.generate(..., streamer=streamer)。 - 主线程 循环读取
streamer里的内容,并yield出去。
- 模型
43. 显存只有 24G,想跑 70B 的模型,除了量化,还有什么办法能硬跑起来(比如 Offloading)?
答案:
- 硬跑方法: Layer-wise Inference(逐层推理)。
- 工具如
AirLLM或Accelerate的 offload。 - 原理: 显存里只放模型的一层(Layer),计算完这层,把结果存回内存,删除这层,加载下一层。
- 代价: 速度极其慢(龟速),完全受限于 PCIe 带宽,仅具备娱乐/调试价值,不可用于生产。
- 工具如
44. MindIE 支持动态 Shape 吗?在处理不同长度的输入时,会不会频繁重编译图?
答案:
- 早期痛点: 昇腾最怕动态 Shape,以前一变长度就 Recompile,卡几分钟。
- 现在: MindIE 支持得好多了。
- 采用了 分档(Bucketing) 机制,或者特定的 动态 Shape 算子。
- 对于范围内的长度变化,不需要重新编译图,可以直接执行。这是 MindIE 相比早期 MindSpore Lite 最大的进步之一。
45. 说一下 FlashAttention 的原理,它为什么能比标准 Attention 快?V2 和 V3 有啥区别?
答案:
- 核心原理: IO-Aware(IO 感知)。
- 标准 Attention 会频繁地在 HBM(显存,慢)和 SRAM(计算单元缓存,快)之间读写 N × N N \times N N×N 的矩阵。
- FlashAttention 使用 Tiling(分块) 技术,把 QKV 切成小块加载到 SRAM,在 SRAM 里一次性算完 Softmax 和 Score,减少了对 HBM 的读写次数。从 O ( N 2 ) O(N^2) O(N2) 降到了 O ( N ) O(N) O(N) 级别的 IO 复杂度。
- V2 改进: 优化了多线程并行策略(在 Sequence Length 维度并行),并减少了非矩阵乘法运算的开销。
- V3 改进: 主要是支持 Variable Length(变长序列)更高效,且支持 Hopping(跳跃访问),这对处理 Sparse Attention 或长上下文更有利。
更多推荐


所有评论(0)