跳到主要内容

技术答题框架

用"先定义、再分析、后总结"的三段式结构,把每道技术题答出深度和条理


通用答题方法论

三段式答题框架

每一道技术题都按以下三段式回答:

  1. 定义层(30 秒):用一句话概括核心概念,展示你"懂本质"
  2. 分析层(60-90 秒):分层次展开原理、方案对比、适用场景
  3. 总结层(15-30 秒):给出具体数据、实践经验或个人观点

用数据支撑回答

回答中尽量带入具体数字,以下是一组参考基准值:

指标典型值说明
7B 模型 FP16 显存~14 GB单卡 A100-80G 可部署
70B 模型 FP16 显存~140 GB需要 2-4 卡 A100-80G(TP)
INT8 量化显存压缩约 50%精度损失通常 < 1%
INT4 量化显存压缩约 75%精度损失约 1-3%
vLLP vs TGI 吞吐提升 2-4xContinuous Batching + PagedAttention
P99 延迟(7B)200-500ms取决于输入长度和 batch size
GPU 利用率(优化前)30-50%传统部署
GPU 利用率(优化后)70-85%量化 + Continuous Batching

FDE 面试高频技术问题 Top 15

Q1:解释 vLLM 的 PagedAttention 机制

定义:把 KV Cache 按固定大小的 block 分页管理,借鉴操作系统虚拟内存思想。

分析:
- 问题:传统推理引擎的 KV Cache 连续分配,导致显存碎片化(浪费 30-40%)
- 方案:将 KV Cache 切分为固定大小的 block(如 16 tokens/block),按需分配
- 核心机制:block table 动态映射、非连续存储、自动 GC 回收
- 效果:显存碎片率从 40% 降到接近 0,整体利用率从 60% 提升到 95%

总结:在我的实践中,开启 PagedAttention 后,同样一张 A100 能服务的并发请求数提升了 2.5 倍。

Q2:Continuous Batching 解决了什么问题?

定义:在批次级别动态替换已完成的序列,而不是等整个 batch 都完成再出下一批。

分析:
- 传统 Static Batching 的问题:短序列等长序列,GPU 空转
- Continuous Batching 的做法:一个序列生成完毕立即从 batch 中移除,新序列补充进来
- 实现依赖:PagedAttention 提供的非连续 KV Cache 存储
- 效果:吞吐提升 2-4 倍,尤其在请求长度差异大的场景下效果显著

总结:生产环境中请求长度方差通常很大(CV 约 0.6-0.8),Continuous Batching 的价值更加突出。

Q3:INT8 量化和 FP8 量化怎么选?

定义:INT8 使用 8bit 整数表示权重/激活,FP8 使用 8bit 浮点数(E4M3/E5M2 格式)。

分析:
- 精度:FP8 > INT8(因为浮点有动态范围)
- 速度:两者接近,都依赖硬件支持(Hopper 架构原生支持 FP8)
- 兼容性:INT8 更广泛,FP8 需要 H100 或更新 GPU
- 实践建议:
- 有 H100 → 优先 FP8,精度更好
- 有 A100 → INT8 是唯一选择
- 70B 以上大模型 → 更推荐 FP8,精度损失更可控

总结:我们在 A100 上用 INT8 量化 70B 模型,精度损失 < 0.5%,显存降低约 50%。

Q4:70B 模型如何在有限 GPU 下部署?

定义:通过量化 + 分布式并行 + 推理优化的组合方案,在资源约束下部署大模型。

分析:
- 方案一:INT8 量化 + Tensor Parallel(2-4 卡),显存从 140GB 降到 70GB
- 方案二:INT4 量化 + 单卡,显存降到 35GB,但精度损失更大
- 方案三:CPU offload(推理慢,适合离线场景)
- 推荐方案:如果有多卡,TP2 + INT8 是性价比最高的选择
- 额外优化:启用 Prefix Caching(相同前缀只计算一次)

总结:我们采用 TP2 + INT8 部署 70B 模型,2 张 A100-80G,
P99 延迟约 400ms,GPU 利用率 75%。

Q5:如何优化推理延迟?

定义:从 prefill(首 token 延迟)和 decode(逐 token 生成延迟)两个阶段分别优化。

分析:
- Prefill 阶段优化:
- Flash Attention 2(减少 IO 复杂度)
- 增大 prefill batch size(提高并行度)
- Decode 阶段优化:
- Continuous Batching(减少空闲等待)
- 量化(降低计算量)
- KV Cache 优化(PagedAttention、Prefix Caching)
- 系统级优化:
- 模型并行度(TP/PP)选择
- GPU 通信优化(NCCL 调参)

总结:我们的综合优化路径是 FlashAttention2 + Continuous Batching + INT8,
TTFT 从 600ms 降到 200ms,解码吞吐提升 3 倍。

Q6:流量翻 10 倍怎么扛?

定义:从垂直扩展、水平扩展、架构优化三个层次应对流量激增。

分析:
- 第一层(立即生效):
- 调大 batch size,提升单实例吞吐
- 开启所有优化开关(Continuous Batching、Prefix Caching)
- 第二层(短期,小时级):
- 水平扩展:K8s HPA 自动加实例
- 负载均衡:根据模型/请求类型分流
- 第三层(中期,天级):
- 架构优化:换更高效的推理引擎
- 模型蒸馏:用 7B 蒸馏模型替代 13B
- 引入缓存:高频问题直接返回缓存结果
- 第四层(降级策略):
- 限流:保护核心业务
- 优雅降级:降低生成长度或切换到更小模型

总结:关键是提前做好容量规划,建立 auto-scaling 体系,
而不是临时手忙脚乱。

Q7:线上 P99 延迟突然升高怎么排查?

定义:按"监控 → 定位 → 分析 → 解决"四步法进行线上延迟排查。

分析:
- 第一步:看监控大盘
- 是单个实例问题还是全局问题?
- 延迟升高发生在 prefill 还是 decode?
- 是否有请求量突增?
- 第二步:定位瓶颈
- GPU 利用率:如果低于预期,说明有瓶颈
- KV Cache 使用率:接近 100% 说明显存是瓶颈
- 网络 IO:是否有数据传输瓶颈
- 第三步:profiling 分析
- 用 nsight / py-spy 做 profile
- 定位 hotspot(计算还是 IO)
- 第四步:解决
- 如果是请求量突增 → 触发扩容
- 如果是显存瓶颈 → 降低 batch size 或启用量化
- 如果是长尾请求 → 检查是否有超长输入

总结:我们遇到过一次线上延迟升高,最终定位到是某个业务线
突然发了大量超长 prompt,通过启用 prompt 长度限制和前缀缓存解决。

Q8:Transformer 中 Self-Attention 的时间复杂度和空间复杂度?

定义:Attention 的计算复杂度是 O(n²d),其中 n 是序列长度,d 是隐藏层维度。

分析:
- 时间复杂度:
- Q·K^T 矩阵乘法:O(n²d)
- softmax:O(n²)
- attention·V:O(n²d)
- 总体 O(n²d),序列长度是主导因素
- 空间复杂度:
- attention score 矩阵:O(n²)
- KV Cache:O(n·d),每生成一个 token 需要缓存
- 优化方向:
- Flash Attention:IO 感知算法,将复杂度从 O(n²d) 优化到更高效的实现
- 稀疏 Attention:减少 n² 计算
- MQA / GQA:减少 KV head 数量,降低 KV Cache 压力

总结:GQA 是近期最实用的优化,Llama 3 从 MHA 改成了 GQA,
KV Cache 内存减少了 8 倍(head 从 32 降到 4)。

Q9:解释 Flash Attention 的核心思想

定义:一种 IO 感知的 Attention 算法,通过分块计算(tiling)和重计算(recomputation)
减少 HBM 和 SRAM 之间的数据搬运。

分析:
- 传统 Attention 的瓶颈:中间矩阵 O(n²) 需要反复读写 HBM
- Flash Attention 的做法:
1. Tiling:把 Q、K、V 切分为 block,在 SRAM 内完成计算
2. Recomputation:不存储完整的 attention score 矩阵,需要时重算
3. 在线 softmax:避免额外的归一化 pass
- 效果:理论复杂度仍是 O(n²d),但常数项大幅降低,实际加速 2-4 倍

总结:Flash Attention 2 进一步优化了计算顺序,
在我们的 70B 模型上,TTFT 缩短了约 30%。

Q10:Speculative Decoding 是什么?

定义:用一个小模型(或草稿模型)预生成多个 token,然后用大模型并行验证的加速方法。

分析:
- 原理:小模型生成 N 个草稿 token → 大模型一次验证 N 个 token
- 加速条件:小模型的猜测准确率越高,加速效果越好
- 典型配置:1B 草稿 + 70B 验证,加速 1.5-2.5 倍
- 适用场景:生成式任务中,当输出有一定可预测性时效果最好

总结:在我们的代码生成场景中(输出模式相对固定),
Speculative Decoding 带来了约 1.8 倍的吞吐提升。

Q11:Tensor Parallel 和 Pipeline Parallel 的区别?

定义:两种不同的模型分布式并行策略。

分析:
- Tensor Parallel(TP):
- 方式:把每一层的权重矩阵切分到多卡上
- 通信:每层都需要 all-reduce,通信量大
- 延迟:单层延迟低,但通信开销随卡数增加
- 适用:小模型多卡部署(如 70B 在 2-4 卡)
- Pipeline Parallel(PP):
- 方式:把模型按层切分到不同卡上
- 通信:只在层间传递激活,通信量小
- 延迟:存在 bubble(空闲时间),需要 micro-batching 优化
- 适用:超大模型部署(如 175B 以上)

总结:我们部署 70B 模型时用 TP2,通信开销在可接受范围内;
如果模型更大,会考虑 TP + PP 混合并行。

Q12:如何评估量化后的模型精度?

定义:通过 benchmark 测试量化前后模型在目标任务上的表现差异。

分析:
- 通用评估:
- Perplexity(PPL):在 WikiText / C4 等数据集上计算
- PPL 增长 < 5% 通常可接受
- 任务评估:
- 用具体任务(如代码生成、问答)对比 FP16 和量化的输出
- 可以用 LLM-as-judge 做自动评估
- 实践方法:
- 先选一小部分代表性数据做快速评估
- 确认精度后再全量部署
- 线上持续监控用户反馈

总结:我们量化 70B 模型时,PPL 从 6.2 升到 6.5(增长 4.8%),
线上 AB 测试显示用户满意度无显著差异。

Q13:vLLM 的 Scheduler 是怎么工作的?

定义:vLLM 的调度器负责在 prefill 和 decode 之间分配 GPU 资源。

分析:
- 核心策略:
- 优先调度 prefill(减少 TTFT)
- 但当显存不足时,优先保证 decode 完成(避免中断已开始的生成)
- 调度算法:
- 基于 block 的显存管理
- 支持 chunked prefill(大 prompt 分段处理)
- 动态调整 batch 组成
- 关键参数:
- max_num_seqs:最大并发序列数
- max_num_batched_tokens:最大批处理 token 数

总结:理解 Scheduler 的工作机制对线上调参非常关键,
我们调整 max_num_seqs 参数后,在高并发场景下吞吐提升了 30%。

Q14:Prefix Caching 的原理和适用场景?

定义:对相同或相似前缀的 prompt 共享 KV Cache 计算结果,避免重复计算。

分析:
- 原理:
- 计算 prompt 的 KV Cache 并缓存
- 新请求到来时,匹配前缀,复用已计算的 KV Cache
- 只需计算新增部分
- 适用场景:
- System prompt 很长且重复(如 role-playing 场景)
- Multi-turn 对话(历史对话可复用)
- 相同 prompt 不同后缀的场景
- 效果:
- 在 multi-turn 场景下,TTFT 可降低 50-80%

总结:我们的客服场景中,system prompt 有 2000+ token,
开启 Prefix Caching 后 TTFT 从 800ms 降到 150ms。

Q15:MoE 模型部署的挑战和应对方案?

定义:MoE(Mixture of Experts)模型通过激活部分 expert 实现高效推理,但部署有特殊挑战。

分析:
- 挑战一:显存占用大(expert 数量多,如 Mixtral 8x7B 总参数量 47B)
- 应对:只加载激活的 expert,但需要 expert 级别的调度
- 挑战二:负载不均衡(不同 expert 的计算量不同)
- 应对:动态路由 + 负载均衡策略
- 挑战三:通信开销(expert 分布在多卡上时)
- 应对:expert 级别的 TP + 合理的 expert 放置策略

总结:MoE 已在 2025-2026 年大规模生产部署(DeepSeek V3、Kimi K2 1T 参数),
核心挑战从"能不能部署"转向"如何高效部署"——Expert 通信优化和负载均衡是关键。

不会的问题怎么回答

"坦诚 + 分析思路"框架

遇到不会的问题,不要用以下方式应对:

  • ❌ 瞎编答案(容易被追问揭穿)
  • ❌ 直接说"不会"就结束
  • ❌ 转移话题

正确的做法:

1. 坦诚边界:"这个问题我没有深入研究过"
2. 展示思路:"但如果让我来分析,我会从这几个角度考虑..."
3. 关联已知:"这和我熟悉的 [某个相关领域] 有相似之处..."
4. 表达学习意愿:"面试结束后我会去深入了解这个方向"

示例

面试官:"你对 Triton 的 kernel 优化有了解吗?"

回答:"Triton 的 kernel 编程我没有亲手写过,但我知道它的核心思想是
用 Python 级别的 DSL 描述 GPU kernel,编译器自动处理 block 切分和
内存优化。如果让我来优化一个 Attention kernel,我会先从
Flash Attention 的分块策略入手,用 Triton 重写出来对比性能。
这个方向我一直想实践,面试结束后我会深入研究。"

技术深度追问的应对策略

防御性回答策略

面试官经常会对你的回答进行追问("为什么选 INT8 而不是 FP8?"),这是好事——说明对你感兴趣。应对策略:

  1. 预留钩子:主动回答中埋下 1-2 个"钩子",引导面试官追问你擅长的方向

    • "我们对比过 INT8 和 FP8,最终选了 INT8,原因有两个..."
    • (引导追问:为什么选 INT8?)
  2. 分层回答:先给中层回答,观察面试官反应再决定是否深入

    • 第一层:概念解释(所有面试官都满意)
    • 第二层:实践经验(大部分面试官满意)
    • 第三层:源码级理解(只有追问时才展开)
  3. 用项目佐证:每个理论观点都配一个项目案例,增强可信度

被问住后的补救

如果某个问题确实没答好:

"这个问题我刚才回答得不够深入。实际上在 [项目] 中我遇到过类似场景,
当时的做法是 [简述]。从这个经验来看,我认为关键点在于 [总结]。"

面试视角:回答的加分项

  1. 主动画图:能白板画架构图的候选人极少
  2. 给 benchmark 数据:有对比实验数据的回答比纯理论描述更有说服力
  3. 提及踩坑:真实的踩坑经历证明你有实践经验
  4. 展示思考过程:不只是"做了什么",更重要的是"为什么这样做"
  5. 诚实面对不确定性:"这个数据我记不太清了,但大致范围是..." 比瞎编一个精确数字更好

下一节:项目故事