Skip to content

面试题库

本页速览 推理加速岗面试全景与高频真题解析:十类轮次、28 道题覆盖性能指标、量化、KV cache、批处理、算子、服务编排、投机解码、分布式、硬件与系统设计,附手撕 KV cache 草稿与「不知道」话术和 1 周/1 个月冲刺清单。

本页含时效性内容,数据截止于 2026-08;引擎版本、性能榜单、产品功能等信息可能已变化,引用前请核对原始出处。

面试题库

先记住本页的一句话:面试不是考知识,是考"你会不会用知识解决没做过的问题"。 单靠背题不可能通过推理部署岗的面试,但完全不看题就上考场是浪费机会——本文给的是两样东西:题目背后的考察逻辑,以及你回答时该走的框架。刷题的目的是把高频考点变成条件反射,而不是押中原文。

本页是 career 模块四步流水线的最后一步「证明自己」,前面三步(看清市场能力地图简历打磨)做完,再来这里。时间紧张时请按第九节 面试准备计划 的清单执行。

一、面试结构全景:一轮一轮在考什么

推理部署岗的面试大体由五到七轮组成,多数公司一天内完成 2–4 轮。每一轮有它自己的通过标准,不要用"我上一轮答得很好"来替代"这一轮该怎么答"。

推理部署岗典型面试流程(大厂 / 中厂通用)
┌─────────────┬─────────────────────────────┬──────────────────────────────┐
│ 轮次         │ 现场形式                     │ 通过标准(面试官心里打分)     │
├─────────────┼─────────────────────────────┼──────────────────────────────┤
│ ① 自我介绍  │ 3–5 分钟口头                  │ 表达逻辑、定位清晰、和岗位匹配 │
│ ② 系统基础  │ Python/C++/Linux 问答         │ 工程底子扎实、能讲 GIL/RAII   │
│ ③ 引擎与调度│ vLLM/TensorRT/PagedAttention  │ 源码理解、能讲权衡、能定位瓶颈│
│ ④ 算子与量化│ CUDA/Triton/INT8/FP8 问答     │ 知道机制、能讲 bank conflict  │
│ ⑤ 项目深挖  │ 围绕简历项目连环追问          │ 真实做过、有性能数字、能扛追问│
│ ⑥ 系统设计  │ 设计 1000 QPS LLM 服务        │ 有框架、有取舍、有边界意识     │
│ ⑦ 手撕代码  │ KV cache 草稿 / reduction    │ 正确性 + 复杂度 + 沟通          │
│ ⑧ HR 面    │ 聊天式                        │ 稳定性、动机、软素质            │
└─────────────┴─────────────────────────────┴──────────────────────────────┘

各轮真正的考察点拆开说:

  • ① 自我介绍:不是复述简历。面试官要的是**"你是谁 → 你做过什么 → 为什么适合这个岗位"三句话骨架**。30 秒讲背景,2 分钟讲 1–2 个有性能数字的项目,30 秒讲动机。结尾抛一个钩子("我最近在给 vLLM 提 PR 加 chunked prefill,正好对应你们 JD 里的长上下文优化"),把节奏引向你准备好的领域。
  • ② 系统基础:考察工程底子是否扎实。Python GIL / asyncio、C++ RAII / 智能指针、Linux 性能分析是高频三连。这一轮不通过的话后面再亮也救不回来。
  • ③ 引擎与调度:推理部署岗的"承重轮"。vLLM 的 Scheduler 怎么工作、PagedAttention 的 block table 长什么样、continuous batching 与 in-flight batching 的差异——这些问题考的是"你是看过文档还是读过源码"。
  • ④ 算子与量化:考察能否下到 CUDA / Triton 层。FlashAttention 为什么快、bank conflict 怎么避免、INT8 vs FP8 选型——这一轮是引擎岗与系统岗的分水岭。
  • ⑤ 项目深挖:面试官用连环追问检验项目真实性——"真的做过"和"看过别人的项目"在追问 3 层之后立刻暴露。细节问题包括 vLLM 的 --gpu-memory-utilization 你设多少、为什么;Nsight 报告里你看到哪几个指标;benchmark 时 batch 与 seq_len 怎么选。详见第六节
  • ⑥ 系统设计:给开放问题("设计一个支持 1000 QPS 的 LLM 服务""设计一个多模型推理平台")。评分标准不是"标准答案",而是你是否有一套从需求 → 引擎选型 → 部署架构 → 监控告警 → 容量规划的思维框架,以及能否在延迟、成本、可用性约束下做取舍。
  • ⑦ 手撕代码:通用算法题(排序 / 二分 / DP)+ 推理相关手写题(KV cache 草稿、reduction kernel)。通过标准是跑得对、复杂度说得清、过程中会沟通。不会做时先讲暴力解再说优化,比闷头写强得多。
  • ⑧ HR 面:考察稳定性(为什么离职 / 为什么选我们)、动机、团队协作与抗压。核心原则:正面、具体、不抱怨前东家。薪资谈崩多发生在"我期望 X 万"给出绝对数字时,正确做法是报区间并反问对方预算。

一条贯穿所有轮次的原则:STAR 法

项目、行为、设计问题全部可以用 STAR 组织回答:Situation(背景)→ Task(任务)→ Action(你做了什么,突出你的决策)→ Result(数字化的结果)。面试官对"我们当时有个推理服务慢"的回答印象为零,对"vLLM --max-num-batched-tokens 从 2048 调到 4096,TTFT 从 1.8s 降到 0.6s、吞吐 +120%"的回答印象深刻。

二、性能与指标题(4 题)

1. TTFT 与 TPOT 的区别?分别受什么影响?

  • 考察点:推理部署岗的元概念,必考题。
  • 参考答案
    • TTFT(Time To First Token):从用户发送请求到收到第一个 token 的时间。受 prefill 阶段主导——计算量随 prompt 长度平方级增长,受 GPU 算力、KV cache 显存分配、batch 内调度策略影响。
    • TPOT(Time Per Output Token):生成阶段每个 token 的平均时间。受 decode 阶段主导——每生成一个 token 都要做一次 forward,但 batch 内只有 1 个 token,是 memory-bound,受 HBM 带宽、KV cache 大小、batch size 影响最大。
    • 优化方向不同:TTFT 优化靠 chunked prefill、prefix caching、更快的 attention kernel(FlashAttention);TPOT 优化靠 continuous batching 提高并行度、KV cache 量化减小访存、投机解码减少 forward 次数。
  • 加分回答
    • "线上业务侧其实更关心 P99 而非均值,TTFT 与 TPOT 都要按 P50/P99 上报";
    • "TTFT 与 TPOT 之间有'权衡':开 chunked prefill 会增加 TPOT 但降 TTFT,需要按业务侧权重调参"。
  • 本站对应延迟与吞吐批处理与调度基准测试

2. memory-bound 与 compute-bound 怎么判断?

  • 考察点:Roofline 模型的直觉理解。
  • 参考答案
    • Roofline 模型判断:横轴是算术强度(FLOPs / Byte),纵轴是吞吐(FLOP/s)。某算子的性能上限 = min(峰值算力,HBM 带宽 × 算术强度)。
    • 如果算子落在"带宽斜线"上 → memory-bound,瓶颈是 HBM 带宽;
    • 如果落在"算力水平线"上 → compute-bound,瓶颈是 Tensor Core 算力。
    • LLM 推理的特征:decode 阶段几乎总是 memory-bound(每生成 1 token 只算 batch×hidden 维度的小矩阵乘,但要把整个权重从 HBM 读出来,算术强度极低);prefill 阶段在长 prompt 下趋于 compute-bound。
    • 实测方法:用 Nsight Compute 看每个 kernel 的 Achieved OccupancyDRAM Throughput,前者低且后者满 → memory-bound。
  • 加分回答:"Llama-70B decode 的算术强度约 0.5 FLOP/Byte,A100 HBM 带宽 2TB/s × 0.5 = 1 TFLOP/s,远低于 312 TFLOP/s 的峰值算力,所以是 memory-bound。这就是为什么 weight-only 量化能线性加速 decode——降带宽 = 提速。"详见内存与带宽Roofline 模型
  • 本站对应Roofline 模型内存与带宽GPU 优化原理

3. LLM 推理的延迟瓶颈通常在哪?怎么定位?

  • 考察点:性能调优实战经验。
  • 参考答案:按"调度 → prefill → decode → 通信"四层排查:
    • 调度层:vLLM 的 Waiting / Running 队列长度、是否因 max_num_seqs 卡住;Triton 的 dynamic_batching 队列;
    • prefill 层:长 prompt 触发 chunked prefill 不足、KV cache 显存分配失败;
    • decode 层:batch 不足导致 memory-bound 没填满 HBM 带宽、attention kernel 走了非 FlashAttention 路径;
    • 通信层:跨节点 TP 的 all-reduce 占 forward 时间 > 30%、NCCL 走 PCIe 而非 NVLink/RDMA。
    • 定位工具链:Nsight Systems 看 forward 内部各阶段比例;PyTorch Profiler 看 forward 内每个 kernel 的开销;vLLM 的 --profile 模式生成 trace。
  • 加分回答:"70B 跨 2 节点 TP=16 时,我曾定位到 NCCL all-reduce 占 forward 38%,调 NCCL_NET_GDR_LEVEL=5 走 RDMA 后降到 15%。这个值在 nsys trace 上是 nccl-allreduce 这一段。"
  • 本站对应延迟与吞吐分布式推理调优实践

4. 为什么 LLM 推理的 batch size 不能无限大?

  • 考察点:调度与显存的权衡理解。
  • 参考答案:三个约束:
    • 显存约束:KV cache 随 batch×seq 线性增长,max_num_seqs × max_num_batched_tokens × 2 × num_layers × hidden_size × dtype_size ≤ 可用显存
    • 延迟约束:batch 越大,每个 forward 算的算子越大,单次 forward 时间变长;decode 阶段 batch 越大 TPOT 越高(因为算术强度上升但延迟变长);
    • 调度约束:vLLM 的 continuous batching 会在 batch 中请求完成时立即换入新请求,batch 太大换入频次降低,反而吞吐下降。
    • 最优 batch size 通常在 32–256 之间,需要按硬件 + 模型 + SLO 实测。--max-num-seqs--max-num-batched-tokens 是 vLLM 调度的两个核心参数。
  • 加分回答:"我做过一个实测:Llama-70B 在 A100 80G 上,batch 从 8 到 64 时吞吐线性上升,64 到 128 时吞吐基本持平,128+ 时因 KV cache 不足触发 evict,吞吐反而下降。"
  • 本站对应批处理与调度内存与带宽基准测试

三、量化题(4 题)

1. GPTQ vs AWQ 区别?分别适合什么场景?

  • 考察点:量化方法选型,推理优化岗必考。
  • 参考答案
    • GPTQ:基于二阶 Hessian 信息的权重量化方法,逐列求解权重更新使输出误差最小。需要校准数据(128 条左右),量化后精度损失通常 < 1%。适合 精度敏感场景(如 chat 模型、指令跟随任务)。
    • AWQ:基于"权重重要性"的量化——只对 outlier 通道(激活大的)保留高精度,其余 INT4 量化。不需要二阶信息,速度快、内存友好。适合 资源受限 / 快速量化场景
    • 机制差异:GPTQ 用反向传播式的方法最小化输出误差(用预激活值校准),AWQ 直接按激活幅值识别"重要权重"并保护。
    • 实测对比:在 Llama-70B 上,GPTQ perplexity 上升 0.3%,AWQ 上升 0.4%,但 AWQ 量化速度快 3 倍。
  • 加分回答:"SmoothQuant 是另一种思路——通过平滑激活的 outlier,让 weight 和 activation 都能量化到 INT8。LLM 推理主推 weight-only(GPTQ / AWQ),原因是 decode 阶段 memory-bound,weight 量化直接降带宽;activation 量化在 LLM 上掉点严重。"
  • 本站对应量化权重-激活混合精度

2. 权重量化为何在 LLM 推理上效果显著?

  • 考察点:量化的"为什么",深入理解。
  • 参考答案:两个原因:
    • decode 阶段是 memory-bound:算术强度约 0.5 FLOP/Byte,瓶颈是 HBM 带宽。权重占显存大头(Llama-70B FP16 = 140GB),INT4 weight-only 把权重压到 35GB,直接 4× 减少 HBM 访问 → 线性加速 decode
    • 权重的"列方向 outlier"稀疏:LLM 权重存在少量 outlier 通道,但 outlier 是结构性的(同一通道在不同 token 上都是 outlier),可以用 group-wise 量化或 AWQ 的"重要通道保护"机制处理,整体精度损失小。
    • 对比:activation 量化在 LLM 上掉点严重——激活的 outlier 是 token-level 的(不同 token outlier 位置不同),INT8 量化时被 outlier 主导,整体精度崩坏。这就是 LLM 主推 weight-only 的根本原因。
  • 加分回答:"INT4 weight-only 把 Llama-70B 从 140GB 压到 35GB,单卡 H100 80G 就能跑——而 FP16 必须 2 卡 TP。这是量化解决'装不下'的硬件问题,不只是加速问题。"
  • 本站对应量化权重-激活混合精度内存与带宽

3. INT4 量化的精度损失来源?

  • 考察点:量化精度问题的深入理解。
  • 参考答案:四个来源:
    • outlier 通道量化饱和:少数 outlier 通道幅值远大于其他,4bit 范围只有 16 个值,outlier 被压到 max → 精度损失集中在 outlier 通道。AWQ 通过保留 outlier 通道 FP16 来缓解。
    • group-wise 量化误差:group_size 越大,组内 outlier 与非 outlier 差异越大,量化误差越大;group_size=128 是经验平衡点。
    • 零点偏移不准:对称量化(zero_point=0)在权重分布偏移时误差大,非对称量化需要校准 zero_point。
    • KV cache 量化叠加:如果同时开 INT4 weight + INT8 KV cache,误差会累积,需要分别评估。
    • 通常 INT4 group-wise 量化在 Llama 系列上 perplexity 上升 0.3–0.6%,业务侧盲测基本无感知差异。
  • 加分回答:"我用 AWQ group_size=32 在 Llama-3-8B 上跑过:group_size=128 perplexity +0.4%,group_size=32 +0.2%,但 group_size=8 显存反而增加(scale 与 zero_point 元数据多)——32 是性价比甜点。"
  • 本站对应量化权重-激活混合精度

4. FP8 与 INT8 的区别?H100 上 FP8 为什么快?

  • 考察点:新硬件与精度格式的结合。
  • 参考答案
    • 格式差异:INT8 是 8bit 整数(-128 到 127),需要 scale 与 zero_point;FP8 有 E4M3(4 位指数 + 3 位尾数)与 E5M2(5 位指数 + 2 位尾数)两种格式,是浮点数,无需 scale 但有动态范围。
    • 精度差异:FP8 在 LLM 上的精度损失通常 < INT8(因为权重与激活的 outlier 用浮点格式更安全);INT8 weight-only 在 LLM 上仍是主流,FP8 weight + activation 在 H100 上是新趋势。
    • H100 上 FP8 为什么快:H100 引入 Transformer Engine + FP8 Tensor Core,FP8 矩阵乘吞吐相对 FP16 翻倍(1979 TFLOP/s vs 989 TFLOP/s)。同时 FP8 不需要量化 / 反量化的转换开销(与 INT8 的 dequantize kernel 对比),减少 kernel launch 与访存。
    • 何时不用 FP8:A100 与之前硬件不支持 FP8 Tensor Core;精度敏感场景(如 RLHF 训练)仍主推 BF16;端侧与 CPU 推理 INT8 更通用。
  • 加分回答:"FP8 在 H100 上不只是快,更重要的是 NVIDIA 把 Transformer Engine 与 FP8 深度集成——FP8 量化、scale 管理、loss scaling 都在硬件层做,软件栈(TransformerEngine、TensorRT-LLM、vLLM 0.8+)已经原生支持。"
  • 本站对应量化GPU 优化原理硬件入门

四、KV cache 与 batching 题(4 题)

1. KV cache 大小怎么算?

  • 考察点:基本功,几乎必考。

  • 参考答案:公式:

    KV cache (bytes) = 2 (K and V) × num_layers × batch_size × seq_len × head_dim × num_kv_heads × dtype_size
    • 2:K 与 V 两个 cache;
    • num_layers:Transformer 层数;
    • batch_size × seq_len:每个 token 都要存一对 K、V;
    • head_dim × num_kv_heads:每个 KV head 的维度与 KV head 数量;
    • dtype_size:FP16 = 2 bytes,INT8 = 1 byte。

    例子:Llama-70B(80 layers, 64 heads, 8 KV heads, head_dim=128, FP16),batch=8, seq=2048: 2 × 80 × 8 × 2048 × 128 × 8 × 2 = 5.37GB

    MQA / GQA 的影响:num_kv_heads 从 num_heads 降到 1(MQA)或 num_heads/8(GQA),KV cache 直接降到 1/8 或 1/8。这是 GQA 在 LLM 上如此重要的原因。

  • 加分回答:"算 KV cache 大小是调 vLLM --gpu-memory-utilization 的前提:可用显存 = 总显存 - 权重显存 - 临时 buffer - KV cache。我之前调 70B 在 A100 80G 单卡时,先算 FP16 权重 140GB 装不下 → INT4 权重 35GB → 剩 45GB 给 KV cache → 算出 batch×seq 上限。"

  • 本站对应内存与带宽批处理与调度量化

2. continuous batching 怎么工作?解决了什么问题?

  • 考察点:vLLM 与 TensorRT-LLM 的核心机制。
  • 参考答案
    • static batching 的问题:batch 内请求长度不同,短请求完成后要等长请求,GPU 空转;新请求要等整个 batch 完成才能进,延迟堆积。
    • continuous batching:在每次 forward 的边界(一个 step),调度器检查哪些请求已完成,把它们换出,把队列里的新请求换入,开始下一 step。整个过程对未完成请求的 KV cache 透明。
    • 关键数据结构:PagedAttention 的 block table——KV cache 不是连续分配的,而是按 block(如 16 个 token 一块)分页管理,请求可以共享空闲 block,避免显存碎片。
    • 效果:吞吐相对 static batching 提升 2–10×,相对无 batching 提升 10×+。vLLM 的 continuous batching 与 TensorRT-LLM 的 in-flight batching 本质相同,实现细节不同。
  • 加分回答:"continuous batching 限制:每 step 的 forward 是 batch 内所有 token 一起算,但短请求完成后换入新请求时,新请求的 prefill 计算与老请求的 decode 计算混在同一个 batch——这就是 chunked prefill 要解决的问题,把长 prompt 的 prefill 切块,避免它占用整个 forward 预算。"
  • 本站对应批处理与调度vLLMTensorRT-LLM

3. PagedAttention 解决了什么问题?

  • 考察点:vLLM 的招牌机制。
  • 参考答案
    • 问题:传统 KV cache 按"请求连续分配"——请求一来就申请 max_seq_len 大小的连续显存,导致两个问题:①显存碎片:短请求完成后留下小碎片,长请求装不下;②预留 max_seq_len 浪费:实际生成长度通常远小于 max_seq_len,预留部分浪费。
    • PagedAttention 的解:借鉴 OS 的虚拟内存——KV cache 按 block(如 16 token / block)分页存储,逻辑上连续、物理上离散。block table 记录每个请求的逻辑 block → 物理 block 的映射。请求完成后 block 直接归还 free pool,无碎片。
    • 关键机制:①block table:每个请求一个,记录 KV cache 的物理位置;②copy-on-write:beam search 等多分支场景共享 block,需要修改时再复制;③prefix sharing:相同 prefix 的请求(如相同 system prompt)共享 KV block,省重算。
    • 效果:显存利用率从 30–50% 提升到 90%+;吞吐相对 static batching 提升 2–24×(vLLM 论文数据)。
  • 加分回答:"PagedAttention 的副作用是 attention kernel 要按 block table 索引访问 KV,相比连续访问有性能损失(cache miss)。vLLM 0.8 之前 block_size=16,0.8 后调到 16 仍是默认——这是性能与显存利用率的权衡。block_size 越大越接近连续访存,但显存利用率越低。"
  • 本站对应批处理与调度vLLM内存与带宽

4. chunked prefill 是什么?为什么 vLLM 0.8 引入?

  • 考察点:vLLM 演进的理解,区分用过与读过源码。
  • 参考答案
    • 问题:continuous batching 在引入新请求时,新请求的 prefill 计算量随 prompt 长度平方级增长,长 prompt 会占满 forward 预算,老请求的 decode 等待时间飙长,TPOT 抖动。
    • chunked prefill 的解:把长 prompt 的 prefill 切成多块(每块 N 个 token),每 step 只算一块,与老请求的 decode 混在同一个 forward。这样长 prompt 不会"霸占"forward 预算,老请求 decode 延迟稳定。
    • 关键参数--max-num-batched-tokens 控制每 step 总 token 数预算(如 4096)。设小了 → 长 prompt 切太细,prefill 阶段长;设大了 → 老 decode 等待久。需要按业务调。
    • 何时该用:业务里有长 prompt(> 4k token)混合短 prompt 时必开;纯短 prompt 业务可以关掉省调度开销。
  • 加分回答:"chunked prefill 与 TTFT / TPOT 的关系:开 chunked prefill → TTFT 升(prefill 切块后整体变慢)但 TPOT 降(老 decode 不被阻塞)。这是一个典型的延迟-延迟权衡。"
  • 本站对应批处理与调度vLLM延迟与吞吐

五、算子题(3 题)

1. FlashAttention 为什么快?

  • 考察点:算子优化必考,考察对机制而非名字的理解。
  • 参考答案:三个机制贡献:
    • Tiling:把 Q、K、V 切块到 SRAM(shared memory),避免 HBM 反复读写。原始 attention 的 S = QKᵀ 是 O(N²) 中间结果,要写回 HBM 再读回来算 softmax;FlashAttention 把整个 softmax 融合到 tiling 内,中间结果不落 HBM。
    • Recompute:反向传播时不存中间 attention 矩阵,前向只存 Q、K、V 与 softmax 归一化系数,反向重算 attention。这是"用算力换显存"。
    • IO-aware:精确地不是减少 FLOPs(其实 FLOPs 略增),而是减少 HBM 访问—— Roofline 视角下 attention 是 memory-bound,减 HBM 访问 = 加速。
    • 效果:FlashAttention-1 在 A100 上把 attention 速度从 2.3× 提升到 4×(小 seq)/ 7×(长 seq);FlashAttention-2 优化 GPU 线程调度,再快 2×;FlashAttention-3 在 H100 上用 TMA + FP8,再快 1.5–2×。
  • 加分回答:"FlashAttention 的核心不是'算法快'而是'IO 少'。看 Nsight Compute 报告,原始 attention 的瓶颈是 DRAM throughput 飙满;FlashAttention 后 DRAM 利用率降到 30%,瓶颈转到 SM Compute。"详见算子融合内存与带宽
  • 本站对应算子融合内存与带宽GPU 优化原理

2. 算子融合的边界在哪?什么时候不要融合?

  • 考察点:算子优化的判断能力。
  • 参考答案:融合的收益与边界:
    • 收益:①减少 HBM 访问(中间结果在 SRAM 流转);②减少 kernel launch 开销(一次 launch 跑一组算子);③减少显存占用(中间 tensor 不分配)。
    • 边界
      • 算子形状差异大:Conv(N,C,H,W)与 MatMul(M,K,N)融合需要数据布局转换,转换成本可能超过融合收益;
      • 算子语义复杂:含 if/else 分支、动态 shape 的算子融合难度高(如 padding mask),编译器常放弃;
      • reduction 跨 block:跨 block 的 reduction(如全 layer norm)需要 atomic op 或两阶段 kernel,融合反而慢;
      • Shape 静态:动态 shape 时融合的 tile 大小无法预测,性能反而差。
    • 什么时候不要融合:单个 kernel 已经接近峰值性能(如 cuBLAS GEMM 在大矩阵下已经 95% 峰值);融合需要写自定义 kernel 但维护成本高(PyTorch eager 直接调更稳定)。
  • 加分回答:"Linear+ReLU+Linear 这种"邻接融合"是显然的;但 Transformer 里 attention 之所以要 FlashAttention 单独写,是因为融合需要算法级改造(recompute + tiling),不是简单的 kernel 串联。这就是为什么 fusion 的真正高阶形式需要"算法+硬件协同设计"。"
  • 本站对应算子融合图优化GPU 优化原理

3. CUDA 里 bank conflict 是什么?怎么避免?

  • 考察点:CUDA 基础,算子工程师必考。
  • 参考答案
    • bank conflict:shared memory 被分成 32 个 bank(每 bank 4 字节宽,可独立访问)。一个 warp 内 32 个 thread 同时访问 shared memory,如果两个或以上 thread 访问同一 bank 的不同地址 → 串行化 → 性能下降。
    • 类型:①2-way bank conflict:2 个 thread 同 bank → 2 倍延迟;②32-way bank conflict:32 个 thread 同 bank → 32 倍延迟(最严重);
    • 避免方法:①padding:在数据布局上加一列 padding(如 33 列而非 32 列),错开 bank;②swizzle:调整 thread 到数据的映射(如把 thread (i,j) 映射到 (j, i ⊕ j) 的位置),让连续 thread 访问不同 bank;③__ldmatrix 指令(Hopper):硬件层支持 ldmatrix 指令,自动避免 bank conflict;
    • 检测方法:Nsight Compute 的 L1/Histogram Shared Bank 指标,看到 32-way conflict 就是 bug。
  • 加分回答:"CUTLASS 里 GEMM kernel 的 swizzle 是经典案例——thread 到 tile 的映射用 XOR swizzle,让同一 warp 在不同迭代访问不同 bank。读懂 CUTLASS 的 swizzle 比写一个能跑的 GEMM 更难,是真正区分'会写 CUDA'与'懂 CUTLASS'的分水岭。"
  • 本站对应GPU 优化原理算子融合

六、项目深挖题(8 题)

项目轮是推理部署岗淘汰率最高的一轮,因为简历造假与"挂名项目"在这一轮无所遁形。策略只有一个:项目是自己真实做过的,然后按"背景 → 我的决策 → 性能数据 → 复盘"组织。下面是高频问题的回答框架。

1. 讲一个你最得意的推理优化项目

  • 回答框架:用 STAR,且刻意突出**"我做的决策"而非"我们做的事"**。结构:一句话背景(业务问题 + 模型 + 硬件)→ 我的三步动作(引擎选型、参数调整、kernel 改写,为什么这么选)→ 硬指标结果(TTFT、TPOT、QPS、GPU 利用率前后对比数字)→ 一句复盘(如果再让我做一次,哪一步会不同)。控制在 2–3 分钟,留出让面试官追问的空间。
  • 常见错误:全程讲团队不突出个人;只讲成功不讲权衡;无性能数字。
  • 追问应对:准备三个"被深挖点"——①引擎源码细节(你改了哪个文件、哪一行);②性能数字口径(benchmark 怎么跑的、预热了吗、取 P50 还是 P99);③踩过的坑(什么参数调错了、什么版本升级出过 bug)。

2. 你为什么选 vLLM 而不是 TensorRT-LLM?不用别的?

  • 回答框架:对比决策三件套——模型类型(开源 LLM 还是闭源)、业务约束(成本、可维护性、生态)、团队栈(Python 优先还是 C++ 优先)。例:"业务是内部 Llama-70B 助手 + Python 栈优先,选 vLLM 0.8 因为:①开源生态活跃,问题能社区求助;②Python 主导,团队上手快;③chunked prefill 与 prefix caching 是 0.8 后新加的,正好对应我们长 prompt 场景。TensorRT-LLM 性能确实强 10–15%,但 build 链路复杂、版本升级痛,团队 C++ 资源不足,权衡下来 vLLM 是更现实的选择。"
  • 考察点:不是选得对,而是有明确的决策逻辑——能说出"为什么不选 X"比"为什么选 Y"更值钱。

3. 线上推理 P99 突然飙到 8 秒,你会怎么排查?

  • 回答框架:按"流量 → 调度 → 引擎 → 算子 → 硬件"五层排查:
    • 流量层:QPS 是否突然上涨?长 prompt 比例是否飙升?看 Grafana 看板确认。
    • 调度层:vLLM Waiting 队列长度是否堆积?max_num_seqs 是否达上限?max_num_batched_tokens 是否过小?
    • 引擎层:vLLM 版本是否最近升级?某条 prompt 触发了非 FlashAttention 路径?prefix caching 是否失效?
    • 算子层:Nsight Systems trace 看 forward 内哪个 kernel 时间飙长;NCCL all-reduce 是否占 forward > 30%?
    • 硬件层:GPU 利用率是否下降(说明 I/O 卡了)?显存是否快满(KV cache evict 严重)?跨节点 NVLink 是否断了?
  • 考察点:工程排查思维,答出"先怀疑流量、再怀疑调度、再怀疑引擎、最后才怀疑硬件"的排序非常加分。

4. 上线后效果慢慢变差,怎么办?

  • 回答框架:这是分布漂移与 KV cache 碎片的混合场景。动作清单:
    • ①建立监控:TTFT、TPOT、queue length、GPU 利用率、KV cache evict 率五线监控,报警阈值提前定好;
    • ②定位漂移类型:用户 prompt 长度分布是否变化(业务高峰期长 prompt 多)?模型是否切换了版本?
    • ③对策:a) 定期重启实例清理 KV cache 碎片(vLLM 0.8 之后有 PrefixCaching 缓解,但仍需定期重启);b) 调整 max_num_seqs:业务变化后旧参数不再最优;c) 多副本灰度:新参数先在 10% 副本试。
    • 同时回答"如何防":上线前就设计监控看板,TTFT P99 > 阈值自动告警。
  • 考察点:是否理解"推理服务是易腐商品",以及监控 / 调度闭环的 MLOps 意识。详见模型服务常见陷阱

5. 你在这个项目里踩过最大的坑是什么?

  • 回答框架:诚实 + 完整闭环:坑是什么 → 怎么发现的 → 怎么解决的 → 沉淀了什么。最好选技术坑而非甩锅给他人。经典优质素材:
    • chunked prefill 参数踩坑max_num_batched_tokens 设过大导致老 decode 等待;
    • NCCL 通信走 PCIe 而非 NVLink:跨节点 TP 慢得离谱,调 NCCL_NET_GDR_LEVEL 解决;
    • vLLM 升级回归:0.6 → 0.8 prefix caching 行为变化,导致 cache 命中率从 80% 降到 30%;
    • 量化精度掉点:INT4 group_size=128 在某业务场景 perplexity 暴涨,发现是 outlier 分布异常,改 group_size=32 解决。
  • 考察点:真实性与复盘能力。面试官知道项目不会一帆风顺,"没踩过坑"本身才是危险信号

6. 你的 benchmark 是怎么跑的?口径可信吗?

  • 回答框架:把 benchmark 当成一个独立工程讲:
    • 预热:先跑 10 次预热,让 KV cache、CUDA 上下文稳定,再开始计时;
    • 采样:跑 1000 次取 P50/P90/P99,不要取平均(长尾分布会让平均无意义);
    • 固定变量:模型版本、batch、seq_len、硬件、并发数都要写死,只改一个变量才能归因;
    • 对照组:每次都要有对照(旧版本、另一引擎、另一参数),否则绝对数字无意义;
    • 复现性:脚本与 prompt 集发到 GitHub,让面试官能 clone 下来复现。
  • 考察点:是否真的做过基准测试,还是临时拼了个数字。详见基准测试

7. 你是怎么给 vLLM 提 PR 的?讲讲 review 过程

  • 回答框架:讲三件事:
    • 动机:业务场景碰到什么问题 → 读源码发现什么 bug 或性能瓶颈 → 改了什么;
    • 方案:为什么这么改,对比过哪些方案,benchmark 证明多少提升;
    • review 过程:maintainer 提了什么意见 → 你怎么改 → 最终怎么合并 → 后续版本有没有延续你的方案。
  • 加分点:讲出"被要求加测试"或"被要求改 API 设计"等具体 review 反馈,证明你真的经历过开源协作。一个合并到主线的 PR 比五个项目经历都值钱

8. 如果给你两个月,你打算怎么把这个项目重做一遍?

  • 回答框架:展示反思与优先级
    • ①先复盘原项目最大的短板(性能数字口径不清 / 没有监控告警 / 未做跨节点 TP / 未做投机解码),用 30% 时间补;
    • ②监控与基准先行(监控口径错了,后面全错);
    • ③按"基线 → 增量"迭代,每个增量都有 benchmark 与灰度;
    • ④预留 1–2 周做投机解码 / 量化 / 端侧适配的实验。
    • 回答里出现"我会先做一次完整 benchmark 与监控基线,再谈优化"是高分信号。
  • 考察点:项目复盘 + 工程方法论 + 时间规划能力。

七、系统设计与综合题(4 题)

1. 设计一个支持 1000 QPS 的 LLM 推理服务

  • 考察点:综合能力,常见系统设计题。
  • 参考答案框架
    • 需求澄清:1000 QPS 是峰值还是平均?prompt 平均长度?生成长度?TTFT / TPOT 的 SLO?预算?
    • 容量估算:假设 prompt 1k tokens、生成 500 tokens,单请求消耗 1500 token 推理。1000 QPS × 1500 = 150 万 token/s。Llama-70B 在 H100 80G 上单卡吞吐约 2000 token/s(INT4 weight + continuous batching),需要 750 张 H100——这显然不可接受。要么换更小模型(8B 单卡 10000+ token/s)、要么量化更狠(INT4 group-wise)、要么 batch 更大。
    • 架构设计
      • 入口层:Nginx / Envoy + 限流(按 prompt 长度路由);
      • 调度层:vLLM 副本池 + 动态路由(按 prompt 长度分到长上下文 / 短上下文副本组);
      • 推理层:单副本 vLLM + chunked prefill + prefix caching;长上下文副本组开 chunked prefill,短上下文副本关掉省调度开销;
      • 监控层:Prometheus + Grafana,TTFT / TPOT / queue / GPU 利用率五指标打点;
      • 弹性层:K8s HPA + GPU 资源池;
      • 故障层:副本健康检查 + 自动重启 + 流量切换。
    • 取舍:要不要做多模型调度(多模型副本占用 GPU 资源,但可按需路由)?要不要投机解码(吞吐 +30–50%,但代码复杂)?要不要跨节点 TP(单模型装不下时必选,否则不必)?
    • 反思:1000 QPS 的瓶颈通常不是算力而是 KV cache 显存——可以靠 INT8 KV cache 量化 + GQA 模型解决。这是面试官想听的关键洞察。
  • 加分回答:"我会先做容量规划再谈架构:1000 QPS 在 70B 上不现实,在 8B 上完全可行。模型选择本身就是架构决策的一部分。"
  • 本站对应模型服务批处理与调度分布式推理基准测试

2. 设计一个多模型推理平台,支持 200+ 模型版本

  • 考察点:MLOps 视角的系统设计。
  • 参考答案框架
    • 模型仓库:每个模型版本一份 metadata(路径、版本、SLO、依赖硬件、量化方案);
    • 路由层:按 model_id 路由到对应副本组,按 prompt 长度 / 用户优先级二次路由;
    • 部署策略:a) 长驻副本(高频模型);b) 按需加载(低频模型,用 vLLM --load-format 与权重缓存);c) Serverless(极少调用的模型,启动开销大但成本最低);
    • 版本管理:灰度发布(5% 流量灰度 30 分钟,无回归才全量)、A/B 测试、回滚机制;
    • 成本与配额:按团队计费、按 token 配额、超额限流。
    • 这是 ML Infra / MLOps 工程师的核心考察题。详见模型服务
  • 本站对应模型服务Triton 推理服务

3. 投机解码为何无损?Medusa vs EAGLE 区别?

  • 考察点:投机解码原理。
  • 参考答案
    • 为何无损:投机解码用一个小模型(draft model)先生成 k 个候选 token,大模型一次 forward 验证这 k 个 token(因为验证比生成便宜——一次 forward 算 k 个 token 的 logit)。被接受的 token 按大模型的概率分布保留,被拒绝的从拒绝点重新采样。关键在于:接受 / 拒绝的判断按大模型概率分布,所以最终输出分布与大模型直接采样完全等价 → 无损。
    • Medusa:在 LLM 的 hidden state 上接多个"medusa head",每个 head 预测下一个 token。优势是不需要单独的 draft model,缺点是接受率较短。
    • EAGLE:用一个 autoregressive 的 draft model,输入是 LLM 的 hidden state + 上一 token,输出下一个 token。优势是接受率高(0.6+),延迟加速比 2–3×。
    • 何时不用:①接受率低(draft 模型与 target 模型差异大);②prompt 极长(draft 也要跑完整 prompt,prefill 阶段无加速);③strict mode 业务(必须严格按 target 模型输出,draft 偏差不可接受)。
  • 加分回答:"投机解码的实际加速比取决于接受率与 k 的乘积。EAGLE 在 Llama-70B 上接受率 0.6、k=4,实际加速 2.2× 左右。代价是显存与算力增加(draft model 也要装下)——资源紧张时不值。"
  • 本站对应投机解码vLLM延迟与吞吐

4. Tensor Parallel vs Pipeline Parallel,通信代价?

  • 考察点:分布式推理必考。
  • 参考答案
    • TP(Tensor Parallel):把单层的权重切到多卡,每次 forward 都要 all-reduce。通信量 = batch × seq × hidden × 2 bytes(FP16)。在机内 NVLink 上(NVSwitch 900GB/s)通信开销小,跨节点(IB 200GB/s)通信占比可达 30%+。
    • PP(Pipeline Parallel):把不同层切到不同卡,只在层边界传 activation。通信量 = batch × seq × hidden × 2 bytes(每次只传一次)。但 PP 有 bubble 问题——前面的卡在等后面的卡完成才能进下一 micro-batch,bubble 比例 = (N-1) / (N+M-1),N 是 stage 数、M 是 micro-batch 数。
    • 何时选:①单层装不下(70B 单层权重 > 单卡显存)→ 必选 TP;②整模型装不下但单层能装下 → PP;③通常 TP+PP 组合,机内 TP=8,跨节点 PP。
    • MoE 推理:用 EP(Expert Parallel),把不同专家切到不同卡,token 按路由发到对应专家。EP 与 DP 的区别:DP 是每卡有完整模型副本,EP 是每卡只有部分专家。
  • 加分回答:"跨节点 TP 慢的原因不是 NVLink vs IB 带宽差异(NVSwitch 900 vs IB 200),而是 NCCL 在跨节点时会 fall back 到 P2P 而非 RDMA,除非显式调 NCCL_NET_GDR_LEVEL。这是一个踩过坑才知道的细节。"
  • 本站对应分布式推理硬件入门

八、手撕代码题(5 题)

推理部署岗的手撕分两类:通用算法(笔试 / 在线,见准备计划)与 推理相关手写题(现场问答 + 写核心代码)。这里给推理相关题的高频清单与参考实现。

1. 实现一个简单 KV cache 类

  • 考察点:推理数据结构基本功。
  • 参考实现
python
import torch

class KVCache:
    def __init__(self, num_layers, num_kv_heads, head_dim, max_batch, max_seq, dtype=torch.float16, device="cuda"):
        self.num_layers = num_layers
        self.num_kv_heads = num_kv_heads
        self.head_dim = head_dim
        self.max_batch = max_batch
        self.max_seq = max_seq
        # 预分配 (num_layers, max_batch, max_seq, num_kv_heads, head_dim)
        self.k = torch.zeros(num_layers, max_batch, max_seq, num_kv_heads, head_dim, dtype=dtype, device=device)
        self.v = torch.zeros_like(self.k)
        # 当前每个 batch 已写入的长度
        self.lengths = [0] * max_batch

    def append(self, layer_idx, batch_idx, new_k, new_v):
        # new_k, new_v: (new_seq, num_kv_heads, head_dim)
        start = self.lengths[batch_idx]
        end = start + new_k.shape[0]
        self.k[layer_idx, batch_idx, start:end] = new_k
        self.v[layer_idx, batch_idx, start:end] = new_v
        self.lengths[batch_idx] = end

    def get(self, layer_idx, batch_idx):
        return self.k[layer_idx, batch_idx, :self.lengths[batch_idx]], \
               self.v[layer_idx, batch_idx, :self.lengths[batch_idx]]
  • 追问:"这个实现有什么问题?"——①浪费显存(预分配 max_seq),实际用 PagedAttention 分块;②batch 维度无法动态扩缩(continuous batching 要换入换出请求);③无 prefix sharing。
  • 本站对应批处理与调度vLLM

2. PagedAttention 草稿:block table 与 block pool

  • 考察点:PagedAttention 机制理解。
  • 参考实现
python
import torch

class PagedKVCache:
    def __init__(self, num_layers, num_kv_heads, head_dim, block_size, num_blocks, dtype=torch.float16, device="cuda"):
        self.block_size = block_size  # 如 16 token / block
        self.num_blocks = num_blocks
        # 物理存储:(num_layers, num_blocks, block_size, num_kv_heads, head_dim)
        self.k_blocks = torch.zeros(num_layers, num_blocks, block_size, num_kv_heads, head_dim, dtype=dtype, device=device)
        self.v_blocks = torch.zeros_like(self.k_blocks)
        # block pool:空闲物理 block 编号
        self.free_blocks = list(range(num_blocks))
        # 每个请求的逻辑 → 物理 block 映射
        self.block_tables = {}  # request_id -> list of physical block ids

    def allocate(self, request_id, num_tokens_needed):
        # 按需分配若干 block
        n_blocks_needed = (num_tokens_needed + self.block_size - 1) // self.block_size
        if n_blocks_needed > len(self.free_blocks):
            raise RuntimeError("OOM: no free blocks")
        blocks = [self.free_blocks.pop() for _ in range(n_blocks_needed)]
        self.block_tables[request_id] = blocks

    def free(self, request_id):
        # 请求完成,归还 block
        for b in self.block_tables[request_id]:
            self.free_blocks.append(b)
        del self.block_tables[request_id]
  • 追问:"这跟真实 vLLM 的实现差什么?"——①真实实现用 C++ 与自定义 allocator;②有 copy-on-write 支持 beam search;③有 prefix sharing(相同 prefix 共享 block,写时复制)。详见vLLM
  • 本站对应批处理与调度vLLM内存与带宽

3. 手写 reduction kernel(CUDA 草稿)

  • 考察点:CUDA 基础。
  • 参考实现
cuda
__global__ void reduce_sum(const float* input, float* output, int n) {
    __shared__ float sdata[256];
    int tid = threadIdx.x;
    int i = blockIdx.x * blockDim.x + tid;
    // 每个线程取一个元素(更通用的版本要 strided 循环)
    sdata[tid] = (i < n) ? input[i] : 0.0f;
    __syncthreads();
    // 树状 reduction
    for (int s = blockDim.x / 2; s > 0; s >>= 1) {
        if (tid < s) {
            sdata[tid] += sdata[tid + s];
        }
        __syncthreads();
    }
    if (tid == 0) {
        atomicAdd(output, sdata[0]);
    }
}
  • 追问:"这个版本有什么 bank conflict?"——shared memory 访问 sdata[tid]sdata[tid + s],s=128 时跨 128 个 float = 512 字节 = 128 bank,无 bank conflict;s=1 时是相邻访问,无冲突。 stride 访问在某些 s 下会冲突,更优版本用 warp shuffle(__shfl_down_sync)。
  • 本站对应GPU 优化原理算子融合

4. 用 Triton 写一个简单 fused matmul + bias + relu kernel 草稿

  • 考察点:Triton DSL 入门。
  • 参考实现
python
import triton
import triton.language as tl

@triton.jit
def matmul_bias_relu_kernel(
    a_ptr, b_ptr, bias_ptr, c_ptr,
    M, N, K,
    stride_am, stride_ak,
    stride_bk, stride_bn,
    stride_cm, stride_cn,
    BLOCK_M: tl.constexpr, BLOCK_N: tl.constexpr, BLOCK_K: tl.constexpr,
):
    pid_m = tl.program_id(0)
    pid_n = tl.program_id(1)
    offs_m = pid_m * BLOCK_M + tl.arange(0, BLOCK_M)
    offs_n = pid_n * BLOCK_N + tl.arange(0, BLOCK_N)
    offs_k = tl.arange(0, BLOCK_K)
    acc = tl.zeros((BLOCK_M, BLOCK_N), dtype=tl.float32)
    for k in range(0, tl.cdiv(K, BLOCK_K)):
        a = tl.load(a_ptr + offs_m[:, None] * stride_am + offs_k[None, :] * stride_ak,
                    mask=(offs_m[:, None] < M) & (offs_k[None, :] < K + k * BLOCK_K), other=0.0)
        b = tl.load(b_ptr + offs_k[:, None] * stride_bk + offs_n[None, :] * stride_bn,
                    mask=(offs_k[:, None] < K) & (offs_n[None, :] < N), other=0.0)
        acc += tl.dot(a, b)
    bias = tl.load(bias_ptr + offs_n, mask=offs_n < N, other=0.0)
    acc += bias[None, :]
    acc = tl.maximum(acc, 0.0)  # ReLU
    tl.store(c_ptr + offs_m[:, None] * stride_cm + offs_n[None, :] * stride_cn,
             acc, mask=(offs_m[:, None] < M) & (offs_n[None, :] < N))
  • 追问:"这个 kernel 的 TILE 大小怎么选?"——BLOCK_M / BLOCK_N / BLOCK_K 取决于 SRAM 大小,A100 上常用 128×128×32;过大会溢出 SRAM,过小会浪费并行度。
  • 本站对应算子融合GPU 优化原理

5. 通用算法手撕的练习范围

  • 考察点:是否"刷得动题",高频范围比全刷重要。
  • 参考清单
    • 二分查找与变种:在有序数组找第一个 >= target 的元素、找峰值;
    • 排序:快排、归并、堆排;
    • DP:最长上升子序列、背包问题、编辑距离;
    • :BFS / DFS、拓扑排序、Dijkstra;
    • 链表:反转、环检测、合并有序链表;
    • 栈 / 队列:单调栈、滑动窗口最大值。
  • 练习顺序:先暴力解能跑,再优化到面试官认可的最优复杂度;每题说清时间 / 空间复杂度,这是最重要的隐性评分项。常见坑与编码规范见常见陷阱

九、如何回答"不知道"的题

被问住不可怕,答得难看才可怕。面试官也在观察你的临场反应——这本身就是一道软素质题。原则与话术:

  • 原则 1:绝不装懂硬编。面试官问的深度通常远超你能覆盖的范围,编造的后果是被追问当场戳穿,评分直接崩盘,且失去"诚实"印象分。正确姿势是明确边界 + 展示思考路径
  • 原则 2:分层响应。不是所有"不知道"都值得直接承认,先判断层次:完全没听过(领域外)→ 听过不会推导(原理缺失)→ 会一部分(记忆模糊)。
  • 原则 3:把"不知道"变成"会学习"的证据

三套话术模板:

模板一(完全陌生,最诚实路线):
"这个概念我确实没系统学过。不过按我的理解,它可能和 X 相关(给出相邻知识),
如果是解决 Y 问题(从问题反推),我的初步思路是……。面试后我会去补一下这个方向。"

模板二(听过、不会推导):
"我在论文/博客里见过这个,能说出它大概解决什么问题(一两句),
但具体的推导细节我现在讲不完整。可以的话,你能提示一下它的前提假设吗?
或者我换成用例子描述我对它的理解——我判断它和 A、B 有关联……"

模板三(记忆模糊,引导式):
"我记得它和 PagedAttention 的关系,但具体 block table 的索引细节不确定。
我先把确定的部分讲清楚:……。不确定的部分我宁可直说,不想误导你。
如果你给我一个具体场景,我可以现场推理一下它的作用机制。"

配套的三个加分层动作:

  • 主动暴露学习路径:"我最近正在刷 FlashAttention-3 的源码,虽然今天没答好 TMA 的细节,但这个方向我下个月能讲清楚"——把"不会"变成"成长中"。
  • 用类比兜底:听不懂术语时,用"我理解它大概是在做……,就像……"让面试官看到你的类比能力。
  • 反客为主提问:在不熟悉的领域问一个具体且不冒犯的问题("这个机制在你们的推理服务里是 vLLM 实现的还是 TensorRT-LLM 实现的?"),既拖时间又展示参与度。不要问"能给我点提示吗"这种白嫖题。

一个必须避免的回答

"这个我没学过,能跳过吗"——直接消耗一题分数并暴露学习意愿差。 正确姿态永远是:承认边界 + 给出部分理解 + 表态会补。面试官不期待你全会,期待你"会的东西讲得透,不会的东西不丢分"。

十、面试准备计划(1 周与 1 个月清单)

求职冲刺线的以终为始原则设计:先弄清目标岗位的 JD 考什么,再对着清单查漏。两个版本都默认你已经完成了能力地图的自评。

1 个月版(标准节奏,每天 2–3 小时)

主线任务每天 30 分钟固定动作
第 1 周L1 基础 + 性能指标:Python GIL / C++ RAII / Nsight / TTFT-TPOT——配合延迟与吞吐GPU 优化原理手撕 1 道通用算法题
第 2 周L2 引擎 + 量化:vLLM 源码精读 / PagedAttention / continuous batching / GPTQ vs AWQ——配合vLLM量化口述 1 道概念题(录音回听)
第 3 周L3 算子 + 分布式:FlashAttention / CUDA reduction / TP-PP-EP——配合算子融合分布式推理每天自问"我项目里这个决策为什么这么做"
第 4 周全真模拟:按第七节话术模拟"不知道"场景;预约 2 场模拟面试;整理错题本复习前三周错题与口述录音

1 周版(紧急冲刺,每天 4–6 小时)

第 1–2 天  基础快扫:性能指标 4 题、量化 4 题(第二节)先自答再看答案,
           不会的当天解决;配 latancy-throughput / quantization 两篇
第 3 天    引擎与调度:精读 vLLM Scheduler / PagedAttention 源码、
           手推 KV cache 大小公式、写一遍 PagedAttention 草稿(第八节)
第 4 天    算子 + 分布式:FlashAttention 原理 / CUDA reduction 手写 / TP-PP 通信开销
第 5 天    项目深挖:STAR 重写简历项目,预演第六节 1、3、5、6 题;
           把"不知道"话术背熟
第 6 天    模拟面试 2 场(找朋友/录像),重点练自我介绍与项目讲述
第 7 天    错题总复习 + 轻松复盘,不再学新内容

三个贯穿全程的建议

  1. 录音回听自己的口头回答——90% 的"当时觉得很好"在回放时都暴露逻辑断裂,这是成本最低的提升手段。
  2. 建立"一句话定义"清单:每个高频概念能用一句话 + 一个数字讲清(如"TTFT 是 prefill 阶段的延迟、Llama-70B 在 H100 上 2k prompt 约 600ms"),这比能背长文有用得多。
  3. 术语统一:回答中主动使用规范术语(PagedAttention、continuous batching、TP、EP、TTFT、TPOT),并随时查术语表校准——术语使用是面试官判断"科班感"的隐形信号。

十一、延伸阅读

参考资料