ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

LLM岗位面试必问的8个核心问题:从Tokenization到推理部署

LLM岗位面试必问的8个核心问题:从Tokenization到推理部署

1. 为什么这8个问题成了LLM岗位的硬门槛

面过LLM方向的人大概都有体会:面试官不太爱问“介绍一下Transformer”这种能背出来的题,而是喜欢在你讲完项目后突然插一句——“你刚才说用了RAG,那Embedding那一步你是怎么选模型的?”或者“Function Calling的schema你手写过吗,参数校验放在哪一层?”这类问题没有标准答案,但答不上来基本就凉了。原因很简单:LLM工程落地的坑,八成集中在Tokenization、Embedding、注意力机制、Function Calling、上下文管理、评测、微调数据、推理部署这八个环节上,而这些环节恰恰是“用过API”和“真正做过系统”之间的分水岭。

我自己带过几轮面试,也作为候选人和不少团队聊过。一个很直观的感受是:能把这8个问题讲清楚的人,未必是算法大牛,但一定是能把系统跑起来、出了问题能定位的人。反过来,简历上写满“精通大模型”,一问Token怎么切、Embedding维度怎么定、Function Calling失败怎么兜底就卡壳的,基本第一轮就出局了。这篇文章我按面试官的真实提问逻辑,把这8个问题逐个拆开,讲清楚每个问题背后到底在考什么、怎么答才算过关、以及我踩过的那些坑。适合准备LLM岗位面试的人,也适合正在做LLM应用、想自查知识盲区的工程师。

需要先说明一点:下面涉及的具体参数、模型选型、代码片段,都是基于当前主流工程实践的合理补充,不同团队的技术栈会有差异,重点是理解背后的判断逻辑,而不是死记某个数字。

2. 问题一:Tokenization到底在切什么,为什么它会影响成本和效果

2.1 面试官真正想听的:不是BPE的定义,而是你对“切分粒度”的直觉

很多人一被问Tokenization就开始背“Byte Pair Encoding,把高频字节对合并”。这没错,但面试官想听的是:你知道Token不是字符、不是单词,而是一种子词单元,并且这个切分方式直接决定了三件事——计费、上下文长度、模型对中文/代码/特殊符号的处理能力。

举个最直观的例子。英文里“tokenization”这个词,在GPT系列的BPE词表里大概率被切成“token”+“ization”两个token;而中文如果按UTF-8字节切,一个汉字可能占2到3个token。这就是为什么同样一段话,中文的token数往往比英文多,成本也更高。我实测过一段约500字的中文技术描述,用某主流模型的tokenizer算下来接近700个token,而对应的英文翻译只有约400个。这个差异在长文档场景下会被放大到很夸张的程度。

2.2 实操中怎么验证和优化Tokenization

面试时如果被追问“你怎么知道自己的输入有多少token”,别只说“用tiktoken”。可以这样答:先用官方tokenizer做离线统计,把历史请求的token分布拉出来,看P50和P95,再决定上下文窗口留多少余量。下面是一段我常用的统计脚本思路:

import tiktoken enc = tiktoken.get_encoding("cl100k_base") def count_tokens(text): return len(enc.encode(text)) samples = ["你的历史请求文本1", "你的历史请求文本2"] counts = [count_tokens(s) for s in samples] counts.sort() print("P50:", counts[len(counts)//2]) print("P95:", counts[int(len(counts)*0.95)])

这里有个经验:不要用字符数除以某个固定系数去估算token,中文、英文、代码、JSON的切分比例完全不同。JSON因为大量括号和引号,token膨胀特别明显,一个看起来不大的function schema可能就吃掉几百token。我见过有人把整个工具定义塞进system prompt,结果还没开始对话上下文就满了。

注意:不同模型的tokenizer不通用。用A模型的tokenizer去估B模型的token数,误差可能到20%以上。做成本预估时一定要用目标模型自己的tokenizer。

2.3 中文场景下的一个坑

中文里有个容易被忽略的问题:生僻字和emoji。有些tokenizer对生僻字会退化成按字节切,一个字的token数暴涨。如果你的应用要处理用户昵称、地址这类含生僻字的内容,最好在预处理阶段做一次token数检查,超限的直接截断或提示,而不是等请求发出去被服务端拒绝。这个细节面试时提一句,面试官会觉得你真的处理过线上问题。

3. 问题二:Embedding模型怎么选,维度越高越好吗

3.1 选型的三条硬标准

被问到Embedding,面试官通常不是让你背排行榜,而是想看你的选型逻辑。我一般从三个维度答:语言覆盖、维度与成本、领域适配。

语言覆盖很好理解,做中文为主的RAG,就得选中文语义空间训练充分的模型,否则“苹果”和“iPhone”的相似度可能还不如“苹果”和“水果”。维度方面,常见的有384、768、1024、1536、3072等。维度高不代表一定好——高维能表达更细的语义,但存储和检索成本线性上升。100万条向量,1536维用float32存就是约6GB,3072维直接翻倍。如果只是做FAQ匹配,768维往往够用。

领域适配是最容易被忽略的。通用Embedding模型在医疗、法律、代码这些垂直领域表现会明显下降。我做过一个代码检索的小实验,通用模型对“这个函数是干嘛的”和函数实现的匹配度,明显不如专门在代码语料上训练的模型。所以选型时如果有垂直领域模型,优先试。

3.2 一个可复现的选型对比方法

别只看排行榜,自己造一批领域内的query-doc对来测。方法很简单:从你的业务数据里挑50到100个真实问题,人工标注每个问题对应的正确文档,然后算Recall@K。下面是我常用的对比表格模板:

模型维度中文Recall@5单条推理耗时存储成本(百万条)
模型A7680.8212ms约3GB
模型B15360.8625ms约6GB
模型C10240.8418ms约4GB

这张表一摆出来,选型就不是拍脑袋了。面试时如果你能说出“我测过Recall@5,最后选了性价比最高的那个”,比说“我用了某某排行榜第一”有说服力得多。

3.3 归一化和相似度计算的细节

Embedding出来之后,要不要做L2归一化、用余弦还是点积,这两个问题经常被追问。结论是:如果向量已经归一化,余弦相似度和点积等价,用点积更快;如果没归一化,必须用余弦。很多向量库默认帮你归一化,但换库的时候容易踩坑。我遇到过一次,从A库迁到B库后检索结果全乱,排查半天发现是B库没自动归一化,而索引是按点积建的。这个坑面试时讲出来,很加分。

4. 问题三:Transformer的注意力机制,别只背公式

4.1 从“为什么需要注意力”讲起

面试官问Transformer,最烦听到一上来就默写Softmax(QK^T/√d)V。更好的切入点是:RNN按顺序处理,长距离依赖会衰减,注意力让每个位置直接看到所有位置。这个“直接看到”就是核心。然后再说Q、K、V的直觉——Query是“我在找什么”,Key是“我有什么”,Value是“我实际提供什么”。用检索来类比,Query是搜索词,Key是文档标题,Value是文档内容,注意力权重就是匹配分数。

4.2 复杂度和你需要知道的工程含义

标准自注意力的复杂度是O(n²·d),n是序列长度。这意味着序列翻倍,计算量翻四倍。这就是为什么长上下文那么贵。面试时如果能主动提到“所以有了各种稀疏注意力、滑动窗口、线性注意力的变体”,说明你关注的是工程约束而不只是理论。

我手写过一版最简注意力,用来给新人讲原理:

import torch import torch.nn.functional as F def attention(Q, K, V, mask=None): d_k = Q.size(-1) scores = torch.matmul(Q, K.transpose(-2, -1)) / (d_k ** 0.5) if mask is not None: scores = scores.masked_fill(mask == 0, -1e9) weights = F.softmax(scores, dim=-1) return torch.matmul(weights, V)

这段代码里有两个细节值得在面试时点出来:除以√d是为了防止点积过大导致softmax梯度消失;mask用-1e9而不是-inf是为了数值稳定。能说出这两点,说明你不是只抄过代码。

4.3 多头注意力的“头”到底在干嘛

常见追问是“多头有什么用”。标准答案是“让模型在不同子空间关注不同信息”。但更实在的解释是:单个注意力头只能输出一种加权组合,多头相当于并行做多次“检索”,有的头关注语法、有的关注指代、有的关注位置。不过要注意,头与头的分工并不是人工设计的,而是训练出来的,而且很多头其实是冗余的,这也是后来各种头剪枝研究的动机。面试时提一句“有研究显示部分头可以剪掉而不明显掉点”,会显得你读过论文而不只是背概念。

5. 问题四:Function Calling的schema设计和失败兜底

5.1 这不是“调个API”那么简单

Function Calling是LLM应用里最容易出线上事故的地方。面试官问这个,基本是在筛“有没有真正让模型调用过外部工具”的人。核心考点有三个:schema怎么设计、参数怎么校验、调用失败怎么兜底。

schema设计的第一原则是让模型容易填对。参数名要语义清晰,枚举值要穷举,必填项要明确。我见过有人把参数设计成嵌套三层的对象,结果模型十次有八次填错。能扁平就扁平,能用枚举就别用自由文本。

5.2 参数校验必须放在服务端

这是血泪教训。永远不要相信模型返回的参数。模型可能返回不存在的枚举值、超出范围的数字、格式错误的日期。校验层要独立于模型,做类型检查、范围检查、枚举检查。下面是一个校验思路:

def validate_args(args, schema): for field, rule in schema.items(): if rule.get("required") and field not in args: raise ValueError(f"缺少必填参数: {field}") if field in args and "enum" in rule: if args[field] not in rule["enum"]: raise ValueError(f"参数{field}取值非法") return True

5.3 失败兜底的三层策略

我的经验是分三层:第一层重试,把错误信息回传给模型让它重新生成参数,通常一次重试能解决大部分格式问题;第二层降级,如果重试还失败,走规则兜底或直接问用户澄清;第三层熔断,连续失败达到阈值就停止调用,避免无限循环烧钱。这个三层结构面试时讲出来,基本能证明你做过生产系统。

注意:重试时一定要把“上次错在哪”明确告诉模型,否则它很可能原样再错一遍。我试过只回传“参数错误”,模型改了半天还是错的;改成“参数date格式应为YYYY-MM-DD,你返回的是YYYY/MM/DD”之后,一次就对了。

6. 问题五:上下文窗口管理,塞满就完事了吗

6.1 上下文不是越多越好

很多人以为上下文窗口越大越好,塞满就行。实际上塞得越多,模型越容易“迷失在中间”,关键信息如果落在长上下文的中段,被利用的概率会下降。而且token就是钱,塞无关内容纯属浪费。面试时如果被问“你怎么管理上下文”,答“按相关性裁剪+摘要压缩”比答“尽量塞满”高一个档次。

6.2 我常用的上下文组装策略

具体做法分四步:系统提示固定在最前,放角色和硬约束;最近几轮对话保留原文,保证连贯性;较早的对话做摘要,用一个小模型或规则压缩成要点;检索到的文档按相关性排序,只保留Top-K,并且把最相关的放在靠近用户问题的位置。这个“位置”很关键,因为模型对开头和结尾的信息利用更好。

内容类型处理方式保留策略
系统提示原文始终保留
最近3轮对话原文始终保留
更早对话摘要压缩到200字内
检索文档排序截断Top-5,按相关性

6.3 一个容易忽略的成本细节

上下文管理还要考虑缓存。很多模型服务对相同前缀有缓存计费优惠,如果你每次请求的system prompt都一样,就能省一笔。所以组装上下文时,把不变的部分放前面,变化的部分放后面,能提高缓存命中率。这个细节面试时提出来,面试官会觉得你不仅懂技术还懂成本。

7. 问题六:怎么评测一个LLM应用,别只说“感觉还行”

7.1 评测是区分“玩过”和“做过”的分水岭

面试官问评测,基本是在筛有没有工程思维的人。因为“感觉模型回答得不错”不是评测。真正的评测要有数据集、指标、基线、回归。我一般分三层讲:离线评测、在线评测、人工评测。

离线评测用固定数据集,指标可以是准确率、召回率、BLEU、ROUGE,或者用另一个LLM做裁判。在线评测看真实用户的点击、采纳、追问率。人工评测抽样打分,校准自动指标。三层结合才靠谱。

7.2 LLM-as-Judge的坑

用LLM做裁判很方便,但有几个坑:位置偏见(倾向于选第一个答案)、长度偏见(倾向于选长的)、自我偏好(倾向于选自己生成的)。缓解方法是交换答案顺序各评一次取平均,或者用多个裁判模型投票。我实测过,单裁判的评分和人工评分相关性只有0.6左右,多裁判投票能提到0.75以上。

7.3 回归测试不能省

每次改prompt、换模型、调参数,都要跑一遍回归测试。我见过太多“改了一个词,别的场景全崩”的案例。回归集不用大,几十条覆盖核心场景就够,但必须每次跑。这个习惯面试时讲出来,比任何理论都有说服力。

8. 问题七:微调数据怎么准备,标注有什么讲究

8.1 数据质量远比数量重要

被问微调,面试官想听的不是“我用了多少条数据”,而是“你怎么保证数据质量”。我的经验是:1000条高质量数据胜过10万条噪声数据。高质量的标准是:指令清晰、回答准确、格式统一、覆盖多样。尤其是格式,如果训练数据里回答格式五花八门,模型学出来的输出也会不稳定。

8.2 标注流程的实操细节

标注不是随便找人写答案。我的流程是:先写标注规范,明确什么算好答案、边界情况怎么处理;再做小批量试标,几个人标同一批,算一致性,不一致就讨论修订规范;然后正式标注,定期抽检;最后做数据清洗,去重、去敏感、去格式错误。这个流程里,试标和一致性检查是最容易被跳过但最重要的环节。

8.3 一个关于数据泄露的提醒

微调数据里如果混入了评测集,评测结果会虚高,上线就露馅。所以训练集和评测集必须严格隔离,最好在数据管理阶段就用不同的来源或做去重。我见过一个团队,微调后评测分数很高,上线效果却很差,排查发现训练数据里混了评测题。这个坑面试时讲出来,面试官会印象深刻。

9. 问题八:推理部署和成本控制,你算过账吗

9.1 延迟、吞吐、成本的三方博弈

面试官问部署,核心是看你有没有“算账”的意识。延迟、吞吐、成本三者互相制约。批处理能提吞吐但增延迟,量化能降成本但可能掉点,缓存能省重复计算但占内存。我一般会讲清楚自己的场景优先级:如果是对话应用,延迟优先;如果是离线批处理,吞吐优先。

9.2 量化的取舍

量化是最常见的降本手段。从float16到int8,显存和带宽需求大致减半,但精度损失因模型而异。我的做法是先在小批量上对比量化前后的输出差异,如果关键指标掉点超过阈值就放弃。不要盲目上int4,有些模型int4之后输出会明显退化。

9.3 一个真实的成本估算

假设每次请求平均消耗2000 token输入、500 token输出,每天1万次请求。按某主流模型的定价粗算,输入和输出分别计价,一天的成本是可以算出来的。面试时如果你能当场把这个账算出来,并说出“所以我把system prompt压缩了30%,每月省下多少”,面试官基本会认定你是个能落地的人。

优化手段延迟影响成本影响适用场景
前缀缓存降低降低system prompt固定
量化略降明显降低显存受限
批处理增加降低离线任务
上下文裁剪降低降低长对话

10. 面试时怎么把这些串起来讲

单独答对8个问题是一回事,能把它们串成一个完整的项目故事是另一回事。我的建议是:准备一个自己深度参与的项目,把8个考点自然嵌进去。比如讲一个RAG系统,从Tokenization的成本控制讲到Embedding选型,从Function Calling的工具调用讲到上下文管理,从评测讲到部署成本。面试官顺着你的故事追问,你每个点都有细节,这比被动答题强太多。

还有一点:不会的就说不确定,但给出你的排查思路。面试官不怕你不会,怕的是你瞎编。我面过一个候选人,被问到某个Embedding模型的维度,他直接说“具体数字我记不清了,但选型时我会对比Recall和成本”,这种回答反而加分。

最后分享一个我自己的体会:这8个问题之所以成为必问,不是因为它们难,而是因为它们覆盖了LLM应用从输入到输出的完整链路。能把这条链路讲通的人,才是团队真正需要的人。准备面试的时候,别只背答案,动手把每个环节跑一遍,哪怕是最小的demo,跑过和没跑过,回答的底气完全不一样。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进