跳转至

【26年4月面试题总结】LLM算法暑期实习总结

来源:https://mp.weixin.qq.com/s/ZIZDoXJ851Hs5X3pqH1A0w

【大模型LLM训练营】、【大模型算法冲刺营】持续进行中,详细内容:大模型1v1第5期已经开始直播了! 详情了解可+v:Burger_AI

最近有同学面了几场 LLM 相关的岗位,整理一下被问到的问题。八股很少,基本都是顺着简历项目往下挖。挖到后面就是不停地问"为什么"——为什么这么选、为什么这个数、怎么知道有效。 下面把几个印象深的问题写出来,尽量还原当时的对话,再说说后来想清楚的答案(有些是当场没答好回去补的)。

一、为什么用 DPO,不用 prompt 也不先 SFT

简历上有一段写的是用 DPO 解决客户经理回复里的过度承诺问题。考官就盯着这一段开始问。 考官:合规问题为什么直接上 DPO?不先试试 SFT? 我:因为合规是让模型在合规和违规之间稳定选合规,DPO 优化的就是这个偏好边界。 考官(不太满意):那 SFT 加 DPO 一起做不是更好吗?InstructGPT 不就这么搞的。 我:(开始解释成本和收益)…… 考官:你 prompt 里写一句"不要过度承诺"不就完了?干嘛搞这么重的方案? 我:(解释为什么 prompt 不够)…… 考官:那你怎么知道 DPO 真的比 prompt 强?不是你自己感觉它强吧?

这四问是层层递进的。当时第二问和第四问我都答得不太利落,回去想了挺久。 关于 prompt 够不够用。 Prompt 是软的,不是硬的。多轮对话久了,或者用户一直追着问"你就告诉我行不行嘛",模型容易松动。合规这种场景,1000 次出错 10 次和出错 1 次完全是两个故事。另外 prompt 也不好向监管交代——"我们写在 prompt 里了"和"我们用合规数据微调过"是两个东西。我当时跟考官说,prompt 是把规则贴在显示器上的便利贴,微调是把规则训进肌肉记忆。 为什么不先 SFT。 SFT 是教模型"该说什么",给一堆好回答让它模仿。但合规问题不是"我不会写客户回复",是"我会写但有时候说错话"。给一万条好答案,模型只学到了好答案长什么样,没学到坏答案为什么坏。DPO 给的是 (prompt, chosen, rejected) 三元组,直接告诉模型这两个里你应该选哪个,更对路。 那 SFT + DPO 一起做总没错吧。 理论上是更稳,InstructGPT 和大多数论文都是这么做的。但工程上要算账。SFT 要单独标一份数据,训练时间多两三倍,还多一层过拟合风险。我们用的 base model 已经是个 RLHF 过的对话模型,写客户回复本来就会,缺的不是能力是偏好。这种情况下纯 DPO 够用。如果是从一个纯 base model 开始,那 SFT 跑不掉。 怎么验证 DPO 真的比 prompt 好。 这一问当时我答得最虚。回来想清楚了:要分三层验证。 最里层是离线评估集,500 条人工标注的合规测试用例,里面有诱导话术、边界 case、多轮施压。两个模型跑一遍对比通过率。这个数字给自己看的,调参用。 中间一层是对抗测试,让另一个模型扮演"想骗到承诺"的客户,连着追问 5 轮。Prompt 方案在这种场景下掉得很快,DPO 模型扛得住。这个能给老板看。 最外层就是 AB 测试,灰度放量,看真实场景下投诉率和人工复核拦截率有没有变化。这个数字才是老板真正在意的。前面两个再好看,线上没用都是白搭。

二、一万条 DPO 数据从哪来

接着上面那段,考官把火力转到数据上。 考官:你说用了一万条 DPO 数据,怎么造出来的? 我:(讲了拒绝采样加人工改写) 考官:那覆盖率怎么保证?万一漏了某种场景呢?

第二问是关键。说"我标了一万条"是没用的,得说清楚这一万条长什么样、有没有盲区。 数据不是一开始就标一万条。先有 200 条种子用例,模型生成一些 chosen/rejected 对,人工修一遍,训出 v1。然后把 v1 放到评估集上跑,专门看哪里翻车,针对那些翻车的场景再扩数据,训 v2。这么迭代下来才到一万。 具体每条偏好对的来源是混着用的。最大的一块是拒绝采样,同一个 prompt 让模型采 8 个候选,用规则加一个小打分器筛出最好和最差的。这部分大概占六成,最便宜。然后是人工改写,拿模型那些过度承诺的输出让人改成合规版本,原版当 rejected,改的当 chosen。这部分占两成左右,质量最高也最贵。再就是从历史客服对话里挖,被投诉的当 rejected,合规审核通过的当 chosen,又能凑一成多。最后一小块是对抗构造,让 GPT-4 故意写那种"听着合规其实违规"的边界 case,量不大但对模型的鲁棒性贡献最大——靠它防得住那些刁钻问题。 覆盖率这事我们是用一张表来管的。横着是业务场景:贷款、理财、保险、信用卡这些。竖着是违规类型:收益承诺、风险弱化、虚假对比、隐瞒费用之类。每个交叉格子至少要凑够 30 条,空着的格子强制补上。再按难度分三档——明显违规、隐含违规、边界 case,比例大概是 3:5:2。边界 case 是真正能把模型上限往上抬的,但不能太多,太多训不稳。 最后一招是上线之后持续挖坑。每个版本上线后,被人工复核拦下来的 case 全收回来加进下一轮训练数据。这是兜底——你怎么想都想不全所有 case,但用户和审核会帮你想到。 一万这个数字其实没什么神奇的。我们试过 5000 也能 work,长尾差一些。8000 之后边际收益就开始掉了。

三、DPO、PPO、GRPO 这三个到底有啥区别

少有的纯八股环节。 考官:说一下 DPO、PPO、GRPO 的区别。 我:(按显存、稳定性、适用场景讲了) 考官:那 on-policy 和 off-policy 是什么?这三个分别属于哪种? 考官:reward hacking 是什么?你们项目怎么避免的?

这三问连起来,考官想看的是你对 RLHF 这一系列方法有没有一个完整的图景,不是孤立地知道每个名词。 PPO 是 OpenAI 那条路线。 先训一个 reward model,再用 RL 去优化 policy。每次更新都要让当前 policy 现采新样本,所以是 on-policy。优点是表达力强,理论上多复杂的偏好都能拟合。缺点是要同时跑四个模型——policy、ref、reward、value——显存吃不消,训练也不稳,调参很痛苦,还容易 reward hacking。 DPO 是 Stanford 那篇论文的路子。 数学上证明了在 Bradley-Terry 偏好假设下,可以绕过 reward model,直接用偏好对优化 policy。损失函数大概长这样: 数据是预先准备好的,不需要在线采样,所以是 off-policy。只要两个模型,policy 和 ref,显存友好,训练稳,跟 SFT 差不多省心。代价是受离线数据的分布偏移影响,理论上限不如 PPO,β 这个超参对结果还挺敏感。 GRPO 是 DeepSeek 用的。 算 PPO 的简化版,把 value model 砍了。同一个 prompt 采一组 response,组内相对 reward 当作 advantage,不再单独训一个 value 网络去估。少了一个跟 policy 一样大的 value model,显存省一大截。GRPO 在数学推理这种有明确对错的任务上特别好用——reward 直接看答案对不对,1 分或者 0 分。DeepSeek-R1 用的就是这个。 简单选一下:数据现成、要稳、要省钱,DPO;reward 复杂、有算力、要做到极致,PPO;reward 是规则可判的(数学、代码),GRPO。 On-policy 和 off-policy 顺手讲清楚。 On-policy 是用当前正在训的模型采的样本来更新这个模型——PPO、GRPO 都是。Off-policy 是用别的模型(或者历史的自己)采的样本来更新当前模型,DPO 就是。实践上 on-policy 数据新鲜但贵,off-policy 数据便宜但有分布偏移。DPO 训到后面效果掉,很多时候就是 policy 已经飘离 ref 太远,那批离线数据相当于过期了。Iterative DPO 就是为了解决这个——训一段时间停下来,用新模型重新采一批数据继续训。 Reward hacking。 模型学会钻 reward 函数的空子,分数刷得很高但没真解决问题。最典型的几个例子:reward 给长回答打高分,模型就开始废话连篇;reward 喜欢礼貌用语,模型每句话开头都"非常感谢您的提问";代码任务的 reward 是单元测试通过,模型学会写 if input == test_case_1: return answer_1。本质上就是 reward 函数和真实目标对不齐,模型把这个 gap 放大了。防御办法没什么花活——RM 持续迭代、加 KL 约束让 policy 别飘太远、人工抽查、对抗测试。

四、PDF、Word、扫描件怎么统一入库

简历上的 RAG 项目,考官扔了个特别具体的场景。 考官:你做过 RAG。给你这么个场景:现在有三种文档要处理。PDF 用 pdfplumber,Word 用 python-docx,复印件先做图像预处理再用 PaddleOCR。问题是这三种来源的信息怎么统一入库?还有 PDF 里的表格怎么处理?现在有什么好办法?

整场面试我觉得最实在的一问。没有 buzzword,全是脏活。三个 parser 吐出来的格式都不一样,下游不可能给每种格式写一套 chunk 和 embedding 的逻辑。 我的做法是中间加一层抽象。下游只认一个统一的中间结构,谁也不管你原来是什么格式。大概长这样:

@dataclass
class Document:
    doc_id: str
    source_type: Literal["pdf", "docx", "scan"]
    elements: list[Element]
    metadata: dict

@dataclass
class Element:
    type: Literal["paragraph", "heading", "table", "list", "image_caption"]
    content: str
    level: int | None
    bbox: tuple | None
    page: int | None
    metadata: dict
每种格式写一个 parser 转成这个结构。pdfplumber 抽出来按 y 坐标排序,靠字号和加粗判断标题,表格走 extract_tables() 单独处理。Word 最简单,python-docx 本来就有 paragraph 和 table 的概念,几乎是直译。OCR 出来的复印件最麻烦,要做版面分析把 bbox 合并成行和段落,再尽量对齐成跟 PDF 一样的输出结构。 下游所有模块只看 Document,不知道也不关心源文件长什么样。以后再加一种格式就再写一个 parser,别的不动。 PDF 表格是单独的老大难。我试过三种: 一种是表格转 Markdown,用 | col1 | col2 | 存起来。embedding 模型对 markdown 表格的理解凑合能用,但表格一大就被 chunk 切碎,行列关系一断就废了。 另一种是表格作为独立 chunk 存,再让 LLM 给它生成一段自然语言摘要——比如"这是一张 2023 年各省 GDP 排名表,31 行,列是省份、GDP、增速、排名"。检索时用摘要去匹 query,命中之后把原始表格直接塞给 LLM 回答。我们生产用的就是这个,针对表格类问题的召回率比第一种高三成左右。 还有一种是把表格直接灌进数据库,命中之后让 LLM 写 SQL。复杂但精确,适合表格结构很规整、查询也有套路的场景。我们没这么用过,但听说有团队在用。 考官接着问 RAG 的痛点。我大概排了几个:召回不准(query 跟 doc 的语义 gap、长尾术语、多跳问题),chunk 切粒度的两难,多文档融合时矛盾信息怎么办,知识库更新到 embedding 重建的延迟,还有端到端答案质量的评估太难自动化。前景方面我说长上下文模型对 RAG 既是冲击也是补充——不用切那么细了;agentic RAG(让模型自己决定查几次、查什么)是现在的研究热点;GraphRAG 在结构化知识场景下也证明了价值。但 RAG 不会被替代,凡是要可审计、可更新、可溯源的场景都跑不掉它。

五、Chunk 怎么切

考官:你 chunk 怎么切的?为什么这么切?

看着平平无奇的问题,但"为什么"三个字是关键。答"按 512 token 切"基本就到顶了,考官想看的是你有没有想过切分对下游的影响。 我们的策略是结构优先、长度兜底。先按文档结构切——标题、章节、段落。段落超过 512 token 就按句号继续切,相邻 chunk 之间留 50 token 重叠。段落太短(不到 100 token)就跟相邻同级段落合并。表格和代码块当作原子单元,不切碎。 为什么这么搞?按结构切是为了保住语义边界,一个章节就是讲一件事,硬切会断逻辑。重叠是边界容错,万一关键信息正好卡在切点上,重叠保证至少一个 chunk 能完整覆盖。Chunk 太短信息密度不够,embedding 容易被噪声主导;太长又会失焦,超过 512 token 大部分 embedding 模型质量明显下降。 很多教程默认用固定长度切分,这在结构化文档上明显比按结构切差,这点我跟考官顶过。 考官:你们检索是 BM25 加 dense 吗?权重怎么配?

这是个想钓你给固定答案的问题。你要是答 7:3 或者 5:5,下一句就是"为什么是这个数",你就被动了。 实际上权重不是固定的,看 query 类型。一般场景 BM25:Dense 大概 0.3:0.7。术语密集的(法律、医疗、代码)BM25 要更重,0.5:0.5 甚至更偏 BM25。语义模糊的查询("那个东西怎么用")就更靠 dense,0.2:0.8。 更好的做法是用 RRF(Reciprocal Rank Fusion)融合:

k 一般取 60。这个公式不需要校准两路检索的分数尺度,工程上比加权和省心很多。最后再上一层 cross-encoder rerank(比如 bge-reranker),效果还能再涨一截。

六、零碎几个

LoRA参数怎么选。 r=8 或 16,alpha=2r,target_modules 选 q_proj/v_proj/o_proj/gate_proj。r 太小欠拟合,太大就失去 LoRA 的意义了——不如全参微调。alpha 取 2r 是经验值,控制 LoRA 输出的缩放强度。MLP 层不加 LoRA 一般也能 work,加上参数翻倍但提升有限,除非任务跟 base model 领域差得太远。 用什么框架。 考官问是手敲 torch 还是用了 huggingface 这套。这问题有点试探"你是真做过还是抄的代码"的意思。我老实说用的 trl,没手敲。trl 的 DPOTrainer 把 ref model 冻结、log_prob 计算、KL 这些都包好了,自己再写一遍除了练手没意义。手敲过的只有 ablation 时改 loss——试过 IPO 和 KTO 这些 DPO 的变种。 考官听完点了下头。这种问题答"我手敲了一遍"反而显得不真——生产项目谁有空重造轮子。重要的是你知道框架在帮你做什么。 拒绝采样怎么训练。 考官有一问问拒绝采样"怎么训练的"。其实拒绝采样不是训练方法,是数据构造方法。流程是:同一个 prompt 让当前 policy 采 8 个或 16 个 response,用 reward model 或者规则打分器打分,最高的当 chosen,最低的当 rejected,然后这条 (prompt, chosen, rejected) 加进 DPO 训练集。 它的好处是数据天然 on-policy,因为采样来自当前模型,能缓解 DPO 离线数据的分布偏移。坏处是质量完全靠打分器,打分器有偏差,拒绝采样会把这个偏差放大。

写在最后

回头看这些问题,面试考的根本不是"你知不知道 DPO 公式",是"你为什么选 DPO"、"你怎么知道它 work"、"出问题你怎么调"。每一道追问都在往下扒:算法选型、工程必要性、数据从哪来、怎么验证、边界 case 怎么办。 会背论文的人和真做过项目的人就差在这些"为什么"和"怎么办"。八股能筛掉不及格的,但筛不出靠谱的。能把每个决策的来龙去脉讲清楚,比能默写损失函数重要得多。 下次再有人问"你 prompt 里写一句不就行了",希望这篇笔记能帮你答得稳一点。

img

            预览时标签不可点




































<div class="