我做了几年算法工程师,也断断续续参与过几十场面试。见得最多的现象是:候选人带着三四百道刷题记录来,挂在看似无关紧要的一问上;也有人项目经验并不亮眼,却因为肯把细节讲透,拿到了更高的评级。说白了,人工智能算法工程师面试题背后没有标准题库,只有一套能力画像。这篇文章我换个角度,从面试官和候选人两个视角,把校招和社招里反复出现的考点、追问背后的意图、以及真正能拉开差距的备考方法拆开讲一遍。
内容会覆盖数学基础、机器学习和深度学习常考题、手撕代码的答辩节奏、项目深挖与系统设计、行为面试与薪资谈判。不为凑题数,只为说清楚每类题在考什么、怎么答才算答到点上,以及哪些坑是我亲眼见过并且希望你能提前避开的。
1. 面试官到底在找什么:从一句追问拆穿背题者说起
1.1 一个典型追问背后的能力画像
先还原一个真实场景。面试官问:"讲讲BERT里CLS向量能不能代表整个句子的语义。"背过面经的候选人大概率会答"可以"或者"理论上可以"。这时只要加一句追问——"你在实际任务里验证过吗?换别的池化方式结果差多少?"——真假立刻见分晓。
这个问题看似在考察Transformer,实际上考察的是三件事:第一,你有没有真的跑过模型、看过数据;第二,你遇到一个方案时会不会质疑它;第三,你能否把"效果差异"讲成可以量化的结论。面试官想要的是一个能独立思考的工程师,不是一台只会复述结论的留声机。
所以我一直建议,复习面试题时不要只看"标准答案",要看答案背后的"可验证性"。你说CLS能代表句子语义,就要能补一句"在我跑的文本分类任务里,CLS向量做平均池化的F1比直接取CLS高0.7个百分点"。哪怕这个数字是粗略的,也比干巴巴的理论强十倍。因为面试官从这句话里读到的信息是:你做过实验、你敢给结论、你愿意用数据说话。
1.2 校招与社招的考察权重差异
校招和社招虽然共用一套知识体系,但筛选逻辑差别很大。我把常见维度的权重列成下面这张表,方便你对照自己的准备重心。
| 考察维度 | 校招权重 | 社招权重 | 校招关注点 | 社招关注点 |
|---|---|---|---|---|
| 理论基础 | 高 | 中 | 公式推导是否流畅、概念是否清晰 | 能否结合实际场景解释理论 |
| 算法与数据结构 | 高 | 中 | 常见题型的熟练度、边界处理 | 复杂度分析、工程化取舍 |
| 项目深挖 | 低 | 高 | 只要做过就加分,有无闭环 | 业务理解、难点攻坚、产出量化 |
| 系统设计 | 低 | 高 | 了解流程即可 | 环节取舍、扩展性、故障预案 |
| 行为面试 | 中 | 高 | 学习能力、沟通协作 | 抗压能力、冲突处理、带人潜力 |
一句话总结:校招看的是"你会不会",社招看的是"你做过没有、做成了没有、能不能讲清楚"。这也是为什么我经常跟准备社招的朋友说,简历上每一个数字都要能扛住三层追问。第一层问背景,第二层问做法,第三层问结果和代价。能扛住三层追问的项目,才是真正属于你的项目。
2. 基础关怎么准备:数学、机器学习、深度学习的高频考点与推导逻辑
2.1 数学三件套:够用不是背题,是能现场推理
很多候选人一听到数学就头疼,觉得面试官故意刁难。其实面试官考数学的目标非常明确:验证你对模型的理解天花板。你连最大似然估计都说不清楚,凭什么说自己能改损失函数?所以数学复习的核心不是刷完一整本习题集,而是把"模型为什么这样设计"回归到数学源头。
高频考点里,最大似然估计是最常被手推的。面试官会问"为什么分类任务常用交叉熵做损失函数",本质就是在问"交叉熵和最大似然是什么关系"。你如果能当场写出:给定数据集 D,模型参数 θ 的似然函数是 Π p(y_i|x_i; θ),取负对数后就得到交叉熵形式的损失,这就把数学和工程打通了。
另一个高频点是 L1 和 L2 正则的区别。L2 是让权重整体变小,它的解是连续收缩的;L1 因为在零点不可导,解更容易落在坐标轴上,所以产生稀疏解。我建议准备时用几何视角再解释一遍:L1 约束是个菱形,L2 约束是个圆,椭圆等高线和菱形相交时更容易交在顶点上,也就是某些维度被压成 0。能讲出这一层,面试官大概率不会再追问。
贝叶斯公式、朴素贝叶斯分类器的假设、SVM 的对偶与核函数、SVD 在降维中的应用、拉格朗日乘子法,这些都属于"出现频率很高但不需要死记硬背"的考点。复习策略是每个点都自己上手推一遍,推完关上笔记默写一遍。记住,面试现场的手推能力是"肌肉记忆",不是"看了就会"。
2.2 机器学习常考题:过拟合、评估指标和样本不均衡
机器学习部分常见的三类题,我分别说下答题思路。
第一类,过拟合。面试官喜欢问"模型过拟合怎么办",表面在问方法,实际在问你有没有体系化思维。参考答案要分三层展开:数据层加样本、做数据增强;模型层降低复杂度、加正则、加 Dropout、Early Stopping;验证层做交叉验证、观察训练集和验证集的差距。重要的是补一句"我会先确认是偏差问题还是方差问题",这句话能体现你的诊断能力,而不是一上来就堆方案。
第二类,评估指标。二分类问题里,准确率什么时候会骗人?样本不均衡的时候。这时要讲清楚 Precision、Recall、F1、AUC、PR 曲线的适用场景。比如正样本极少时,AUC 仍然可能虚高,而 PR 曲线对正样本更敏感。我建议准备一个具体场景:"CTR 预估里正样本点击率只有千分之几,我会用 AUC 看排序能力,同时用 GAUC 分用户群体评估。"这种结合实际场景的回答,比背定义高出一个档次。
第三类,样本不均衡的解决手段。从数据层面说:欠采样、过采样、SMOTE;从算法层面说:代价敏感学习、调整 class_weight;从评价层面说:换评估指标,不做硬分类,输出概率再校准阈值。应对追问时,你需要能说清"过采样会不会引入噪声""SMOTE 的合成样本在特征空间里是否合理""阈值怎么选——在验证集上遍历不同阈值找平衡点"。每一条都要展开成一个三句话的小论证,而不是只报菜名。
2.3 深度学习三块基石:反向传播、梯度消失与Transformer
深度学习面试题基本围绕三个基石:反向传播、梯度消失问题、Transformer 结构。
反向传播里最经典的推导是 softmax 加交叉熵。很多人能背出公式,但现场一推就出错。我建议你完整推一遍:设 z 是 logits,p = softmax(z),y 是 one-hot 标签,交叉熵损失 L = -Σ y_i log p_i。先证明 softmax 的雅可比有特殊形式,再代入链式法则,最后得到极其简洁的结果:∂L/∂z_i = p_i - y_i。这个结果你可以用一个小脚本验证,我当年就是这么干的:
import torch z = torch.randn(3, requires_grad=True) y = torch.tensor([1.0, 0.0, 0.0]) p = torch.softmax(z, dim=0) loss = -(y * torch.log(p)).sum() loss.backward() # 理论上 grad = p - y,即 [p0-1, p1, p2] print(z.grad) print(p.detach() - y)能亲手验证一次,你才算真正理解了"为什么深度学习框架里 softmax 的梯度这么简单"。
梯度消失问题的高频问法有两个方向。一是"为什么 sigmoid 容易梯度消失",你要答出饱和区的导数趋近于 0,多层连乘后梯度指数级衰减;二是"为什么 ResNet 能缓解",你要答出恒等映射让梯度可以跨层传回,同时补充 BatchNorm 为什么有帮助。注意,现在面试官对 BN 的理解要求变高了,只会背"归一化到均值 0 方差 1"远远不够。更准确的说法是:BN 让每层输入的分布相对稳定,同时让损失曲面变得更平滑,从而允许更大的学习率。能讲到这一层,就是加分项。
Transformer 几乎场场必考。最核心的手写题是:Attention(Q,K,V) = softmax(QK^T / √d_k) V。面试官会追问为什么要除以 √d_k。你要答出:当 d_k 很大时,QK^T 内积的方差变大,softmax 的输入会落到梯度饱和区,除以 √d_k 可以把方差拉回接近 1 的水平。接下来通常还会连环问位置编码怎么加、为什么不用 RNN、Decoder 的 Mask 机制是做什么的、推理时 KV Cache 省了什么计算。社招面试里 KV Cache 出现频率很高,你要能说清楚:生成第 n 个 token 时 Query 只需要和缓存的 K、V 做 attention,不用重新计算前面的所有 Key、Value。
3. 代码环节怎么练:刷题策略、高频题模型与面试答辩节奏
3.1 刷题数量不是关键,题型结构才是
候选人经常问我:"LeetCode 刷多少题够?"我的回答是:按题型刷,把高频模型吃透,200 题的有效覆盖率远大于 500 题的盲目刷。这里说的"有效",是每道题做完之后能回答三个问题:暴力解是什么、最优解是什么、两者复杂度差在哪。
我个人推荐的题型雷达图是:数组与哈希表、双指针与滑动窗口、二叉树遍历与变体、DFS/BFS 图搜索、动态规划、贪心、堆与 TopK、链表操作。这八个类别基本覆盖了算法岗面试里九成的代码题。动态规划又是重中之重,因为这一题最考验"状态定义"能力,恰好也是算法工程师日常最需要的建模能力。
有一个非常实用的刷题法:把每道题按"题目链接、我的第一反应、最优解思路、复杂度、边界条件、能不能变形"记成卡片。不要只写答案,要写"我当时卡在哪"。大部分人的薄弱点其实集中在少数几个思维定式上,比如看到最值就想贪心、看到子串就无脑双指针。把卡的环节记录下来,针对性突破,比盲目刷新题效率高得多。
3.2 三类高频题模型:TopK、链表环、动态规划
高频题不需要刷几千道,把几种"题根"吃透,变式都能应对。我举三个典型。
第一个是 TopK 问题。求一个数组里最大的 K 个数,有三种主流解法:最小堆维护 K 个元素、快速排序的 partition 思想、BFPRT 严格线性选择。面试官一般会让你先写堆的版本,然后追问"堆的复杂度是多少,建堆为什么是 O(K)、每次调整为什么是 O(logK)",再追问"partition 版本的最坏情况是什么,为什么会退化"。你要能答出:快速选择平均 O(N),最坏 O(N²),随机化可以降低退化概率。如果还能补一句"海量数据场景下堆比全量排序更省内存",这一题就能拿高分。
import heapq def top_k(nums, k): if k <= 0: return [] heap = [] for x in nums: if len(heap) < k: heapq.heappush(heap, x) elif x > heap[0]: heapq.heapreplace(heap, x) return heap第二个是链表环检测。经典解法是快慢指针,面试官一定会追问"为什么快指针走两步、慢指针走一步就一定能相遇"。你要答出:如果存在环,进入环后快指针每次比慢指针多走一步,相当于在环上做差为 1 的追及,一定能追上。反之如果快指针走了三步,"步长差为 2"时则可能跳过相遇点,这也是为什么快慢指针最稳妥的组合是 2 和 1。
第三个是动态规划。面试官最爱拿"最长递增子序列""编辑距离""股票买卖"来考。这类题的关键不在背公式,而在把"状态定义"讲清楚。比如编辑距离里的 dp[i][j] 表示"字符串 A 的前 i 个字符转换成 B 的前 j 个字符所需的最小编辑次数",然后讨论最后一个字符相等时直接继承、不等时取插入/删除/替换的最小值加一。你要在写代码之前,先把状态转移方程用自然语言讲出来,再落成代码。面试官更看重你的推演过程,而不是最终代码是否一次通过。
3.3 面试写码的三个隐形要求:边界、复杂度、沟通
代码题不是"写对就行",整个互动过程都在被考察。我总结了三个隐形要求。
第一,动手前先确认边界。面试官给你题目后,你先不要急着写。问清楚输入范围、是否含负数、是否可能为空、数组长度量级。这不只是礼貌,它能帮你确定选哪种算法。比如数据量是 10^9 就不能用 O(N²);只有 100 个元素时甚至可以暴力解。
第二,写的过程中口头说思路。边写边讲"我准备用双指针,左指针负责遍历起点,右指针负责扩展窗口",让面试官随时知道你在做什么。最忌讳的是闷头写十分钟,写完发现思路偏了。算法面试本质是一场结对编程演练,沟通节奏决定体验。
第三,写完必须自己跑测试。这里的"跑测试"不是指上机,而是口头过一遍边界用例:空输入、单元素、正序、倒序、重复元素。一小段自测过程能暴露大部分 bug,也能让面试官看到你工程习惯好。我见过不少候选人代码能写对,但跑完不验证,最后被追问才意识到漏了边界,非常可惜。
我还见过一个高频扣分点:复杂度分析说不准。堆 TopK 说成 O(N log N),或者矩阵 DP 说成 O(N)。建议每写完一题,主动把"时间复杂度和空间复杂度"报一遍。如果算错了,宁可停下来想清楚再说,也不要随口给一个错的。
4. 项目深挖与系统设计:社招的分水岭、校招的加分项
4.1 STAR讲项目:把做过的事讲成可验证的证据
项目深挖是社招面试里占比最大、也最容易翻车的环节。翻车原因通常不是没做过事,而是讲法不对。很多人喜欢按时间线流水账:"我们做了一个系统,用了 BERT,效果不错。"听完之后面试官脑子里没有任何有效信息。
更有效的讲法是 STAR 四步法,但关键不在 STAR 本身,而在每个字母的落地。我拿一个模拟项目举例:某推荐系统的排序优化。
- Situation:原有排序模型是 LR,特征以统计类特征为主,新用户场景下 AUC 只有 0.72。
- Task:希望把排序 AUC 提升到 0.75 以上,同时不增加线上推理耗时。
- Action:先做特征工程改造,把用户实时行为序列压缩成可更新的 embedding;再对比 LR、GBDT、简单深度网络三类模型;发现深度网络离线 AUC 最高,但线上推理耗时超预算,所以最终采用"GBDT 做特征交叉 + 轻量 DNN 做最终打分"的组合结构。
- Result:离线 AUC 从 0.72 提升到 0.755,线上 A/B 实验 CTR 相对提升 6.3%,推理耗时增加 4%。
这个案例里最重要的是 Result 中出现了"离线指标、在线指标、工程代价"三个维度。面试官最在意的就是你能不能同时看到这三个方面。很多人只讲了"效果提升",漏掉了"代价",一追问就露馅。所以你在准备项目时,务必为每一个"动作"准备一句话代价说明。
面试官通常会连环追问:"你为什么选这个模型不选另一个?特征怎么做的?负样本怎么采的?线上服务怎么部署?模型多久更新一次?遇到 badcase 怎么反馈?"每一问都要用"我当时做了什么 + 结果是什么 + 如果重来哪里会改"的结构来回答。尤其是最后一句,非常加分,因为它能体现复盘能力。
4.2 系统设计题的通法:约束、离线、在线、评估
系统设计题在校招里出现频率逐渐变高,在社招里几乎必考。很多候选人一听到"设计一个新闻推荐系统"就慌,其实这类题有非常清晰的四步万能框架。
第一步,明确约束。先问清楚系统规模、用户量、item 量、延迟要求。比如模拟项目X:日活用户 1000 万,新闻总量 500 万并持续增长,推荐接口 p99 要求在 200ms 以内。约束决定选型,这是很多人会跳过的一步。
第二步,离线方案。推荐系统的离线核心是特征、样本、模型。特征分成 user 特征和 item 特征,user 特征包括历史点击序列、人口属性、兴趣向量;item 特征包括类目、关键词、embedding。样本来自曝光日志和点击日志,注意负样本通常要采样,否则模型会严重偏向"不点击"类别。模型分召回和排序两段:召回用双塔模型输出几十到几百个候选,排序用更复杂的深度模型精排。
第三步,在线链路。用户请求进来后,先基于 userId 查用户特征,用召回模型从 500 万新闻里捞出一个候选集,再经过粗排、精排、多样性打散,最后返回 Top20。系统设计里最关键的其实是冷启动:新用户没有足够行为序列,常见的方案是"热榜兜底 + 内容画像 + 少量探索流量",而不是硬套个性化模型。
第四步,评估与迭代。离线看 AUC、召回率,在线做 A/B 实验。你要能说清楚 A/B 实验怎么分流、实验周期设多长、关注哪些指标(CTR、人均时长、留存),以及怎么把 badcase 闭环回到训练数据里。
你要注意,系统设计没有唯一正确答案,面试官考察的是你能不能在自己设定的约束下自洽地做出取舍。选双塔做召回,就要说出双塔的假设是"user 和 item 的交互只通过内积建模",而这种方式在高阶特征交叉上能力不足,所以精排要用更强的模型。这种"选型理由 + 代价说明"的结构,就是系统设计题的答题核心。
5. 行为面试与offer谈判:从面得好到拿得值
5.1 行为面试:用STAR讲好三件事
行为面试看起来漫无边际,实际上围绕三个固定问题:讲一个你遇到过的困难、讲一次你与他人发生冲突的经历、讲一次你失败的事。这类题没有标准答案,但有一个通用雷区:只讲过程不讲结果。
用 STAR 结构时要特别注意 Result 必须是"你学到了什么"而不仅是"问题解决了"。比如你讲一个模型上线失败的案例:背景是模型的离线指标涨了但线上效果降了;你的行动是排查数据分布差异、发现问题来自样本穿越;结果是最终修正了样本生成的逻辑,同时沉淀了一条"离线在线一致性"的 check 规范。这个回答既体现了排查能力,又体现了沉淀能力,属于行为面试里的高分答案。
另一个雷区是贬低他人。候选人讲冲突时容易把对方描述成"不配合的同事",这会让面试官担心你的协作能力。正确做法是"立场不同"而不是"人有问题":你可以说对方优先保证业务按时上线,而你想先修复数据质量,最后通过约定一个数据修复小周期同时满足了双方目标。这类回答既客观又有建设性。
5.2 薪资谈判与offer比较:目标锚定与结构拆解
面得好不一定拿得值,薪资谈判是很多人的盲区。我见过不少人因为不敢谈、不会谈,入职后才发现自己的薪资结构比同期候选人差一截。这里有两个实用技巧。
第一,锚定区间而不是报底价。被问期望薪资时,不要只报一个数字,给出一个上下浮动区间,并说明你的依据是什么:当前职级带宽、手上已有 offer 的水平、你能带来的差异化价值。同一岗位给到不同候选人的薪资可以差很多,关键是你有没有把自己的差异化价值讲清楚。比如"我在上一段项目里完整负责过模型从训练到上线的闭环"就是一句话锚点,它能帮你从普通执行者池子里跳出来。
第二,谈"结构"而不只谈 base。薪资构成包括 base、绩效奖金、期权或股票、签字费、年假天数、调薪机制。很多人只盯着 base,忽略了大头可能在绩效或长期激励。面试谈薪时要问清楚:绩效怎么评、调薪频率多久一次、期权兑现条件是什么。报价时可以这样表态:"我的核心诉求是总包处于目标区间下沿的偏上水平,但我更在意的是业务方向和成长空间。"这种回答既理性又不容易被压价。
最后是 offer 比较。不要只看 base 高低,要把业务成熟度、团队技术氛围、数据体量、加班强度、岗位发展路径放在一起看。我的经验是:第一份工作宁可选"数据多、事杂、有人带"的岗位,也不要去"名头响、但无人指导、只能维护旧代码"的岗位。算法工程师是经验型职业,真实的数据场景和高质量的反馈是成长最快的燃料。
6. 挂科复盘与最后提醒:面试中那些"隐形雷区"
6.1 我见过的高频挂因清单
面试挂掉的原因五花八门,但高频的其实就那么几种。我按出现概率排个序。
第一种是背题痕迹明显。问概念答得丝滑,追问一句细节就宕机。这类候选人通常准备了很多"八股文",但缺乏实验和项目支撑。解决方法是复习时给每个知识点配一个真实案例,哪怕是模拟项目里的也行,关键要有"我用过、我验证过"的语言。
第二种是代码题卡住后不换思路。很多人死磕一道题,写了删删了写,最后时间耗尽。正确做法是:卡住 5 分钟后主动说出自己的想法,请面试官给个提示方向。这并不丢人,反而能让对方看到你的沟通能力。面试官优先考察的一定是你的思路过程,然后才是结果。
第三种是项目讲成一团浆糊。候选人做了很多事,但讲不出优先级、说不清自己贡献、也答不出 "为什么这样做"。这种情况下面试官会默认你没有独立思考和抽象能力。为了避开这个坑,建议准备项目时列一张"项目一页纸":背景、目标、我的角色、三个关键动作、两个量化结果、一个复盘改进。
第四种是过度包装。简历上写"精通 Transformer",被追问到位置编码实现细节就答不上来。包装可以有,但必须建立在真实掌握的基础上。每写一个关键词,就要预设三个相关追问,自己先答一遍。
6.2 面试后48小时复盘与offer选择建议
面试结束不代表事情结束。我自己的习惯是,面完当天就把被追问的问题记下来,48 小时内整理成知识卡片。因为面试里被追问的问题,往往就是你知识体系里最薄弱的位置,值得花整块时间补齐。这些卡片积累起来,就是你下一轮的专属面经,比任何公开题库都更有针对性。
收到多个 offer 时,建议做一个简单的对比表:业务成长性、数据量、技术栈匹配度、团队氛围、薪资总包结构。不要被某一个维度的优势冲昏头。实际经验里最常见的后悔来源是:只因为薪资高 15% 选了纯业务外包性质强的团队,进去后做的是重复性调参工作,两年后竞争力不升反降。判断团队能不能成长,看两件事:一是你们有没有足够的离线数据做实验,而不是只能在线上试错;二是 leader 会不会在周会上做技术复盘,还是只盯业务数字。
如果你还能提前做一件事,我建议找一位朋友扮演面试官,用模拟问法对你进行压力测试。把你准备的项目和每道高频题讲一遍录下来,回听时你会惊讶地发现:语速过快、逻辑跳跃、口头禅这些毛病,在自信状态下根本意识不到。这是我从候选人身上学到的经验,也是我自己后期带模拟面试时最常用的一招。
面试归根到底是一趟"证据交换"——你用知识、项目、沟通向对方证明你能解决问题,对方用团队、数据、发展空间向你证明这里值得加入。如果你只能记住这一条,我希望是:在简历里为每一个数字都准备一个能被追问到第三层的故事。做到这一点,校招和社招都只是一场水到渠成的验证而已。