1. 为什么这8个问题能决定面试生死
面过几十场大模型岗位之后,我越来越确信一件事:LLM 面试和传统后端面试的筛选逻辑完全不同。传统后端你可以靠刷题、背八股混过前两轮,但 LLM 岗位的面试官往往只问八个左右的问题,就能判断出你是"真做过"还是"只读过论文"。原因很简单——这个领域太新,网上能背的标准答案太少,而工程落地中踩过的坑又太多,一个人有没有真正训过模型、调过推理、接过业务,几句话就能露馅。
我见过不少候选人,简历上写着"熟悉 Transformer、了解 RAG、做过 Agent 项目",结果第一个问题"你能手推一下 self-attention 的计算复杂度吗"就卡住了。也见过反过来,学历一般但每个问题都能讲到具体数字和踩坑细节的人,直接拿到 offer。这八个问题之所以"答不上来直接淘汰",不是因为它们有多难,而是因为它们覆盖了 LLM 工程链路上最核心的八个能力点:Transformer 原理、Tokenization、位置编码、注意力机制变体、推理优化、Function Calling、Agent 设计、评测与容错。任何一个点答不上来,都意味着你在真实项目里大概率是个"调包侠",无法独立定位问题。
这篇文章我不打算给你一份标准答案背诵手册——那种东西网上太多了,面试官一听就知道你在背。我要做的是把这八个问题拆开,讲清楚面试官到底想听什么、每个问题背后的考察意图、以及一个真正做过项目的人应该怎么回答。同时我会补充大量工程实践中的细节,比如 KV Cache 到底省了多少显存、Function Calling 的 schema 设计有哪些坑、Agent 容错怎么做才不会雪崩。这些内容你在任何八股文里都找不到,但恰恰是面试官最想听到的东西。
适合谁看?如果你正在准备大模型算法岗、AI 应用开发岗、AIGC 产品岗的面试,这篇文章能帮你把零散的知识点串成一条工程主线。如果你已经在大模型团队里,也可以拿它当一次自查清单,看看自己是不是在某些环节上一直是"黑盒使用者"。
2. Transformer 原理:面试官真正想听的不是公式
2.1 self-attention 的计算复杂度和显存账
几乎每场 LLM 面试都会从 Transformer 开始,但问法差别很大。初级问法是"讲一下 self-attention 的公式",这种问题背一背就过了。真正能筛人的问法是:"self-attention 的时间和空间复杂度是多少?序列长度翻倍会怎样?"
标准答案是 O(n²·d) 的时间复杂度和 O(n²) 的空间复杂度,其中 n 是序列长度,d 是维度。但光说这个不够,面试官想听的是你有没有算过账。我给你一个具体的数字:假设 batch size 为 1,序列长度 4096,head 数为 32,每个 head 维度 128,那么注意力矩阵的大小是 32 × 4096 × 4096,约 5.4 亿个元素。如果用 fp16 存储,光注意力分数就要占 1GB 显存。序列长度翻到 8192,这个数字直接变成 4GB。这就是为什么长上下文这么贵——不是模型参数大,而是注意力矩阵随长度平方增长。
一个做过项目的人会接着补充:实际推理时,真正吃显存的往往不是注意力矩阵本身,而是KV Cache。KV Cache 的大小是 2 × batch × n × d_model × layers × 精度字节数。以 LLaMA-7B 为例,32 层、hidden size 4096、fp16,序列长度 4096、batch 1 时,KV Cache 约 2 × 1 × 4096 × 4096 × 32 × 2 字节 ≈ 2GB。这还只是 7B 模型,70B 模型直接乘以 10。所以面试官问复杂度,本质是在问你有没有被显存爆过。
2.2 为什么是 scaled dot-product 而不是普通点积
这个问题很多人答不上来。标准解释是:当 d_k 很大时,query 和 key 的点积方差会随维度线性增长,导致 softmax 的输入值过大,梯度趋近于零,训练不稳定。除以 √d_k 就是把方差拉回到 1 附近。
但面试官更想听的是你有没有直观理解。你可以这样解释:softmax 对输入值的尺度非常敏感,如果 logits 都在 ±50 这个量级,softmax 输出会变成接近 one-hot 的分布,梯度几乎消失;如果都在 ±0.1,输出又太均匀,模型学不到区分度。除以 √d_k 就是让 logits 保持在一个"既不饱和也不太平"的区间。这个解释比背公式更能体现你理解背后的数值稳定性问题。
2.3 多头注意力到底"多"在哪里
很多人以为多头就是把一个大矩阵切成几块分别算,这个理解对但不完整。关键在于:每个 head 有自己的 Q、K、V 投影矩阵,也就是说不同 head 是在不同的子空间里做注意力。这带来的好处是模型可以同时关注不同类型的关系——有的 head 关注语法依赖,有的关注指代关系,有的关注位置邻近。
工程上有个细节值得提:多头注意力的总计算量和单头(维度相同)其实差不多,因为每个 head 的维度是 d_model / num_heads。所以多头不是靠增加计算量换性能,而是靠增加表达的子空间多样性。这也是为什么 head 数不是越多越好——head 太多,每个 head 维度太小,反而学不到有效特征。实践中 32 到 128 个 head 比较常见,head 维度一般保持在 64 到 128 之间。
2.4 位置编码:从正弦到 RoPE 的演进逻辑
位置编码是 Transformer 面试的高频深水区。正弦位置编码的问题在于它是绝对位置且外推能力差——训练时见过 2048 长度,推理时给 4096,模型就懵了。RoPE(旋转位置编码)的核心思想是把位置信息编码成旋转操作,作用在 Q 和 K 上,使得注意力分数天然只依赖相对位置差。
RoPE 为什么现在几乎成了标配?因为它有两个关键优势:一是相对位置感知,注意力分数只和 token 之间的相对距离有关,符合语言直觉;二是一定的外推能力,配合 NTK 插值或者 YaRN 这类方法,可以把训练时的 4K 上下文扩展到 32K 甚至更长。面试时如果你能说出"RoPE 通过旋转矩阵实现相对位置编码,配合 NTK-aware 插值可以扩展上下文长度",基本就能证明你不是只读过综述。
3. Tokenization:最容易被忽视却最能暴露功底
3.1 BPE、WordPiece、SentencePiece 的区别与选型
Tokenization 是 LLM 面试里最容易被低估的环节。很多人觉得这就是个分词,没什么好讲的。但面试官问这个,是想看你有没有处理过多语言、特殊字符、代码这些真实场景。
BPE(Byte Pair Encoding)的核心是从字符开始,不断合并最高频的相邻对。它的优点是简单、可逆,缺点是合并规则依赖训练语料,对未见过的语言可能切得很碎。WordPiece 是 BERT 用的方案,和 BPE 类似,但合并时用的是似然增益而不是频率,效果上更偏向保留常见词。SentencePiece 则把空格也当成普通字符处理,不依赖预分词,对中文、日文这种没有空格的语言特别友好。
选型逻辑很直接:多语言场景优先 SentencePiece,纯英文可以 BPE,需要和 BERT 生态兼容就用 WordPiece。但真正的坑在于词表大小。词表太小,一个中文词被切成四五个 token,序列变长、推理变慢;词表太大,embedding 层参数暴涨,低频 token 训练不充分。实践中 32K 到 128K 是比较常见的区间,LLaMA 用的是 32K,Qwen 用的是 150K 左右。
3.2 中文 tokenization 的坑:一个汉字几个 token
这是中文场景面试的必问题。很多英文模型(比如早期的 GPT-2)对中文极不友好,一个汉字可能被切成 2 到 3 个 byte-level token,导致同样一段中文,token 数是英文的三倍以上。这直接带来两个后果:上下文利用率低和推理成本高。
解决办法是在训练 tokenizer 时加入足够的中文语料,让常见汉字和词组成为独立 token。你可以现场给面试官算一笔账:一段 500 字的中文,如果每个字平均 1.5 个 token,就是 750 个 token;如果优化到平均 0.7 个 token,就只要 350 个。按现在 API 的定价,成本直接砍半。这种"算账式回答"比背概念有说服力得多。
3.3 特殊 token 和 padding 的工程细节
面试里经常被忽略但实际很致命的是特殊 token 的处理。比如[PAD]、[CLS]、[SEP]、<|endoftext|>这些 token 的 id 是多少、在什么位置加、loss 计算时要不要 mask 掉。我踩过的坑是:padding token 的 loss 没有 mask,导致模型学会了预测 padding,训练 loss 看着很低,实际生成质量很差。
还有一个细节是tokenizer 和模型必须配套。我见过有人用 LLaMA 的 tokenizer 去加载 Qwen 的模型,结果 token id 全错位,生成出来全是乱码。面试时如果你能主动提到"tokenizer 的 vocab 必须和模型的 embedding 层严格对齐",面试官会知道你至少真正部署过模型。
4. 注意力机制变体与推理优化:区分调包侠和工程师的分水岭
4.1 MHA、MQA、GQA 的取舍
标准多头注意力(MHA)每个 head 都有独立的 K、V 投影,KV Cache 很大。Multi-Query Attention(MQA)让所有 head 共享一份 K、V,KV Cache 直接降到 1/num_heads,但效果会掉。Grouped-Query Attention(GQA)是折中方案:把 head 分成若干组,每组共享一份 K、V。
面试官想听的是你怎么选。我的经验是:7B 以下模型用 MQA 问题不大,13B 以上建议 GQA,组数一般取 head 数的 1/4 到 1/8。LLaMA-2 70B 用的就是 GQA,8 组 KV。这样 KV Cache 降到原来的 1/8,推理吞吐提升明显,而效果损失在可接受范围内。如果你能说出"GQA 是在推理成本和模型质量之间的帕累托最优选择",基本就到位了。
4.2 KV Cache 的原理和显存优化
KV Cache 的本质是用空间换时间:自回归生成时,每个新 token 都要和之前所有 token 做注意力,如果不缓存,就要重复计算前面所有 token 的 K、V。缓存之后,每步只需计算新 token 的 Q、K、V,然后和缓存的 K、V 拼接。
但 KV Cache 的显存占用随序列长度线性增长,长对话场景下会成为瓶颈。优化手段有几个:PagedAttention(vLLM 的核心)把 KV Cache 分成固定大小的 block,按需分配,减少碎片;量化 KV Cache把 fp16 降到 int8,显存减半;滑动窗口注意力只保留最近 N 个 token 的 KV。面试时能说出 PagedAttention 解决的是"显存碎片和动态分配"问题,而不是简单说"vLLM 更快",层次就上去了。
4.3 量化、蒸馏、剪枝:推理加速的三板斧
量化是最常用的手段。GPTQ、AWQ、GGUF这几个名词面试官很爱问。简单说:GPTQ 是训练后量化,用校准数据逐层最小化量化误差;AWQ 认为不是所有权重都同等重要,对激活值大的通道保留更高精度;GGUF 是 llama.cpp 用的格式,支持 CPU 推理和多种量化等级(Q4_K_M、Q5_K_M 等)。
蒸馏是用大模型教小模型,核心是软标签——学生模型不仅学正确答案,还学老师模型的概率分布。剪枝则是去掉不重要的权重或结构。面试时如果被问"怎么把一个 70B 模型部署到单卡",一个完整的回答应该是:先量化到 4bit(显存降到约 35GB),再用 GQA 减少 KV Cache,配合 PagedAttention 管理显存,最后用连续批处理提升吞吐。这种端到端的回答,比单独讲某个技术点更能体现工程能力。
5. Function Calling:从"能调用"到"调得对"的距离
5.1 Function Calling 的本质是结构化输出
很多人把 Function Calling 理解成某种魔法,其实它的本质是让模型输出符合特定 schema 的 JSON。模型本身不执行函数,它只是生成一个结构化的调用请求,由外部代码解析并执行。理解这一点,很多问题就通了。
面试官常问:"模型怎么知道有哪些函数可以调用?"答案是通过 system prompt 或专门的 tools 参数把函数定义注入上下文。函数定义包括 name、description、parameters(JSON Schema 格式)。模型根据用户意图,决定是否调用、调用哪个、传什么参数。
5.2 schema 设计的坑:description 写不好,模型就乱调
这是实战中最容易翻车的地方。我踩过的坑:两个函数功能相近,description 写得太模糊,模型经常调错。比如search_flights和search_trains,如果 description 只写"搜索交通工具",模型就会乱选。正确做法是在 description 里写清楚适用场景、参数含义、甚至反例。
参数设计也有讲究。必填参数和可选参数要分清,枚举值要列全,日期格式要明确(是2024-01-01还是2024/01/01)。我一般会在 description 里加一句"如果用户没有提供日期,默认使用今天",这样模型就不会因为缺参数而卡住。还有一个技巧:给参数加示例值,比如"date": "2024-01-01 (格式 YYYY-MM-DD)",模型填充的准确率会明显提升。
5.3 并行调用、错误处理和幂等性
进阶问题是:"如果用户一句话需要调用多个函数怎么办?"现代模型支持并行 Function Calling,一次返回多个调用请求。但工程上要处理的是依赖关系——如果第二个函数的参数依赖第一个函数的返回结果,就不能并行,必须串行。
错误处理是另一个重点。函数执行失败时,要把错误信息以模型能理解的形式返回给它,让它决定是重试、换参数还是告诉用户失败。我通常会把错误包装成{"error": "城市名无效,请使用标准城市名", "retryable": true}这样的结构。幂等性也很关键——搜索类函数天然幂等,但下单、支付类函数必须做幂等设计,否则模型重试会导致重复下单。
6. Agent 设计:自主容错才是真正的门槛
6.1 ReAct、Plan-and-Execute、Reflection 的适用场景
Agent 面试现在越来越硬核。ReAct 是"思考-行动-观察"的循环,适合步骤不多、需要动态调整的任务。Plan-and-Execute 是先规划再执行,适合步骤明确、可以提前拆解的任务。Reflection 是让 Agent 回顾自己的输出并改进,适合对质量要求高的场景。
面试官想听的是你怎么选。我的经验:简单工具调用用 ReAct,复杂多步任务用 Plan-and-Execute,质量敏感场景加 Reflection。但要注意,Reflection 会显著增加 token 消耗和延迟,不是所有场景都值得。我一般只在最终输出质量要求高、且对延迟不敏感的场景才加。
6.2 自主容错:Agent 挂了怎么不雪崩
这是标题里"自主容错控制"的核心。Agent 的容错分几层:工具层要处理超时、限流、返回格式错误;规划层要处理子任务失败后的重规划;执行层要处理死循环和无限重试。
我踩过最惨的坑是:Agent 调用一个搜索工具,工具返回空结果,Agent 没识别出来,继续用空结果往下走,最后生成了一堆幻觉内容。解决办法是在每个工具返回后加一个校验步骤,判断结果是否有效、是否为空、是否符合预期格式。如果无效,就让 Agent 重新规划或者直接返回"无法完成"。
还有一个关键设计是最大步数限制和超时控制。没有这个,Agent 可能陷入死循环,烧光 token 还不产出结果。我一般设置最大 10 到 15 步,超过就强制终止并返回当前最优结果。同时每一步都要记录日志,方便事后排查是哪一步出的问题。
6.3 多 Agent 协作的通信和冲突解决
多 Agent 系统听起来很酷,但工程上很容易变成"三个和尚没水喝"。核心问题是通信协议和冲突解决。Agent 之间怎么传递信息?用共享内存、消息队列还是直接函数调用?如果两个 Agent 给出矛盾结论,谁来仲裁?
我的实践是:用一个 Orchestrator Agent 做调度和仲裁,其他 Agent 只负责各自领域的子任务。Orchestrator 负责拆解任务、分配、收集结果、解决冲突。这样结构清晰,也便于加容错逻辑。如果让 Agent 之间自由通信,很容易出现信息不一致和死锁。
7. 评测与容错:怎么证明你的 LLM 系统是可靠的
7.1 离线评测和在线评测的指标设计
面试官问"你怎么评估一个 LLM 应用的效果",很多人只会说"看准确率"。这远远不够。离线评测要分任务级指标(准确率、F1、BLEU、ROUGE)和系统级指标(延迟、吞吐、成本)。在线评测要看用户反馈(点赞、采纳率、重试率)和业务指标(转化率、解决率)。
关键是评测集的设计。我一般会构建三类测试集:常规 case覆盖主要场景,边界 case覆盖极端输入,对抗 case覆盖容易出错的输入。每类都要有明确的通过标准。没有评测集的 LLM 应用就是裸奔,上线后出问题只能靠用户投诉发现。
7.2 幻觉检测和事实性校验
幻觉是 LLM 应用的头号敌人。检测手段有几种:基于检索的校验(把生成内容和知识库比对)、基于模型的校验(用另一个模型判断是否有事实错误)、基于规则的校验(检查数字、日期、专有名词是否和输入一致)。
工程上最实用的是引用溯源:让模型生成内容时同时给出引用来源,然后校验引用是否真实存在、是否支持结论。RAG 场景下这个特别有效。如果模型说"根据文档 A 第 3 段",你就去检查文档 A 第 3 段是不是真的支持这个结论。不支持就是幻觉。
7.3 降级策略和兜底方案
任何 LLM 系统都要有兜底。模型超时了怎么办?返回格式错了怎么办?置信度低怎么办?我的做法是分级降级:一级降级是重试(换个 prompt 或换个模型),二级降级是返回缓存或默认答案,三级降级是转人工或明确告知用户"暂时无法回答"。
关键是不要让用户看到原始错误。模型返回的 JSON 解析失败,不能直接把异常抛给用户,而要包装成友好的提示。同时所有降级都要打点上报,方便监控降级率。如果某个降级路径频繁触发,说明上游有问题,需要优化。
8. 面试现场:怎么把八股答成工程故事
8.1 用数字和踩坑细节建立可信度
面试时最忌讳的是"泛泛而谈"。说"我做过 RAG 项目"不如说"我做过一个法律问答的 RAG 系统,文档 5 万份,用 bge-large 做 embedding,召回 top 20 再重排到 top 5,准确率从 62% 提升到 81%"。数字和具体技术选型会让面试官相信你真的做过。
踩坑细节更是加分项。比如"我们一开始用固定长度切分文档,结果法律条款被切断,后来改成按条款结构切分,召回率提升了 15 个百分点"。这种细节编不出来,只有真做过的人才知道。
8.2 遇到不会的问题怎么答
面试中一定会遇到不会的问题。这时候不要硬编,面试官一听就知道。正确的做法是:先说出你知道的部分,然后说明你的思路,最后坦诚不知道的部分。比如被问到某个没听过的技术,你可以说"这个我没直接用过,但根据名字我猜测它是解决 XX 问题的,如果是我,我会从 XX 角度去验证"。
这种回答展示的是解决问题的思路,比背答案更有价值。面试官招的是能干活的人,不是题库。
8.3 反问环节:问什么能加分
反问环节是很多人浪费的机会。问"公司福利怎么样"不会加分,问"你们现在的 LLM 应用最大的技术挑战是什么"会。好的反问能展示你的思考深度,也能帮你判断这个团队值不值得去。
我一般会问三个问题:当前系统的瓶颈在哪里、团队怎么做评测、未来半年的技术规划。这三个问题覆盖了现状、方法和方向,面试官也能感受到你是认真考虑加入的。
最后分享一个我自己的体会:LLM 面试的八个问题,表面考的是知识点,实际考的是你有没有把知识变成过产品。背八股能过初筛,但过不了终面。真正拉开差距的,是那些只有踩过坑才知道的细节——KV Cache 到底占多少显存、Function Calling 的 description 怎么写才不翻车、Agent 死循环怎么破。这些东西没有捷径,只能靠真做项目积累。如果你现在还在准备阶段,我的建议是:找一个真实场景,从数据准备到部署上线完整走一遍,哪怕规模很小。走完之后再回头看这八个问题,你会发现答案都在过程里。