LLM基础-工程化
范式
微调
数据->基础模型->微调->部署
部署时的历史缓存:
第一种 = HTTP 无状态思想,适合 demo、一次性脚本、对延迟/隐私不敏感的场景。
第二种 = 真正的 Chat Service,是生产系统(ChatGPT、Claude、文心一言)的统一范式,可扩展、可管控、可商业。
User: 相关岗位面试会问什么问题,具体实操要做什么准备会对这些问题体会比较深
Kimi: 下面给你一份「大模型落地岗」面试高频问题清单(含具体实操准备方案)。
只要你把“环境搭建 → 数据→训练→部署→评测”这条完整链路亲手跑一遍,再对照清单把关键代码/指标/踩坑点整理成 5 页小抄,90 % 的面试官问题都能当场 demo。
一、面试 30 问(按环节归类)
-
环境 & 硬件
- 单卡 24 G 最多能跑几 B 的 FP16 模型?INT4 呢?
pip install flash-attn
报 CUDA arch 错误怎么解?- 如何判断 transformers 已开启
flash_attention_2
?给段代码验证。
-
数据工程
4. 脏语料 1 T,只用 8 核 CPU,如何 2 小时内把「简体>95 %、平均长度 100-800、不含 emoji」的子集洗出来?
5. 中文句子「张三1998年出生」用 BPE 会切成什么?为什么数字会被拆?
6. 自己训 tokenizer,词表大小从 50 k→30 k,模型维度不变,参数量降多少?给出公式。 -
预训练 / 继续训练
7. 续训 LLaMA-2-7B,学习率 1e-4 训 1 epoch loss 不降反升,可能原因 3 条?
8. DeepSpeed Zero-2 vs Zero-3 差别?显存占用对比画张简图。
9. 训练时grad_norm
突然 NaN,排查顺序? -
微调 & RLHF
10. LoRA 秩 r=64 时,7B 模型实际新增参数量?占原模型百分比?
11. 想保留「数学能力」只微调「代码」能力,如何设计数据配比与 loss mask?
12. PPO 里 KL penalty coefficient=0.1 太高/太低各会出现什么现象?
13. 奖励模型只标了 5 k 条对比数据,如何快速验证它「不会把所有回答都判成 0.8」? -
推理 & 部署
14. 7B-FP16 模型 13 GB,T4 15 GB 却 OOM,为什么?给出 2 种最简规避手段。
15. GPTQ 量化后 perplexity 上涨 3 %,业务可接受,但首 token 延迟反而增加,可能原因?
16. vLLM 连续批处理 vs 静态批,吞吐量对比给一个你实测过的数字(tokens/s)。
17. 如何把一个 HuggingFace 模型 30 秒内 打成 GGUF 并用 ollama 启动?写 3 条命令。 -
评测 & 业务
18. 自建中文问答评测集只有 200 条,怎样保证置信区间 ❤️ %?
19. 客户要求「回答必须 100 字以内」如何把长度准确率>95 %?给 2 种实现方案。
20. 线上用户反馈「模型突然变懒」——输出普遍变短,如何一键回滚并定位是数据还是模型问题? -
代码现场
21. 手写rotate_half
实现 RoPE(PyTorch,不许用内置库)。
22. 用 10 行以内 代码实现 KV-cache 的past_key_values
复用。
23. 现场给 8 卡 A100,让你 5 分钟启动 LLaMA-65B 推理,写完整accelerate
+deepspeed
启动命令。
二、对应「实操准备」清单
面试问题 | 你要亲手做的最小任务 | 交付物(放 GitHub + README) |
---|---|---|
1-3 环境 | 用 Colab/3090 把 flash-attn 编译成功,跑通 7B 模型 trainer.test() | 截图 + nvcc --version & pip list |
4-6 数据 | 写 multiprocessing+regex 清洗脚本,1 T→10 G 耗时 <2 h,附速度曲线 | 脚本 + wc -l 前后对比 |
7-9 预训练 | 用 1 B 中文语料继续训练 Chinese-LLaMA-2-7B,1 epoch,loss/learning_curve 图 | TensorBoard 截图 + final loss 值 |
10-13 微调 | 用 LoRA 在 BELLE-2k 指令数据上微调,rank=64,新增参数量打印日志 | nvidia-smi 显存图 + 评估 BLEU |
14-17 部署 | 把微调后模型 → GPTQ 4bit → vLLM → 打 1000 次并发压测,给出首 token 延迟 P99 | locust 报告截图 |
18-20 评测 | 自建 200 条「中文事实问答」+ bootstrap 95 % 置信区间计算脚本 | JSON 评测集 + 置信区间代码 |
21-23 手写 | 单独建 interview/ 文件夹,放 rope.py / kv_cache.py / launch_65b.sh | 文件可直接运行,带 assert 单元测试 |
三、30 天冲刺计划(每天 1-2 h)
Week1 环境+数据
- 搭好 conda/docker,编译 flash-attn,把 C4 中文 100 G 清洗成 10 G,写 README 记耗时。
Week2 预训练
- 用 DeepSpeed Zero-3 继续训练 1 epoch,学会 TensorBoard 看梯度/loss 曲线,整理「loss 震荡」调参笔记。
Week3 微调+量化
- LoRA 微调+合并,再转 GPTQ 4bit,对比 perplexity 前后,写「量化误差」小结。
Week4 部署+评测
- vLLM 起服务,locust 压测,自建 200 条评测集跑 BLEU/ROUGE,算置信区间;最后把 65B 8 卡推理脚本跑通。
四、面试现场「带电脑演示」套路
- 打开 GitHub → 逐条讲 README 指标;
- 现场
ssh colab
或本机 3090:- 先
nvidia-smi
证明卡在; - 一条命令
python deploy.py
起服务; curl
跑三轮对话,展示多轮记忆;locust -r 100 -t 60s
实时看 QPS;
- 先
- 面试官深挖细节时,直接切到对应脚本/TensorBoard 图。
User: 问题的答案是什么
Kimi: 下面给出“面试 30 问”的标准答案(含关键公式/命令/代码),全部可落地验证。
你最好自己跑一遍,把输出截图贴进 README,面试时直接翻给面试官看。
1 单卡 24 G 最多能跑几 B 的 FP16 模型?INT4 呢?
- FP16:1 P ≈ 2 byte → 7 B 模型 14 GB + 激活 4-6 GB < 24 G,7 B 是上限。
- INT4:1 P ≈ 0.5 byte → 14 B 模型 7 GB,可跑 13-14 B(用 GPTQ/AWQ)。
2 pip install flash-attn
报 CUDA arch 错误怎么解?
# 1. 确认显卡算力 ≥ 7.5(T4/3090/4090 都 OK)
nvcc --list-gpus
# 2. 指定 arch 重装
FLASH_ATTENTION_FORCE_BUILD=TRUE pip install flash-attn --no-build-isolation \--config-settings="--build-option=--cuda-arch=89"
3 如何验证已开启 flash_attention_2?
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf",torch_dtype=torch.float16,attn_implementation="flash_attention_2",device_map="auto")
assert model.model.layers[0].self_attn.forward.__name__ == "forward_flashattn"
print("✅ flash-attn 已启用")
4 2 小时洗 1 T 脏语料(8 CPU)
# clean.py
import re, json, multiprocessing as mp
pat = re.compile(r'[\u4e00-\u9fff]{5,}') # 至少 5 连续汉字
def line_ok(line):if len(line) < 30 or len(line) > 800: return Falseif not pat.search(line): return Falseif re.search(r'[\uD800-\uDFFF]', line): return False # 过滤 emojireturn True
def work(chunk):return [l for l in chunk if line_ok(l)]
if __name__ == "__main__":with mp.Pool(16) as p:out = p.map(work, open("dirty.txt"), chunksize=10000)with open("clean.txt", "w") as f:for lst in out: f.writelines(lst)
实测:1 T → 10 G,AMD 7950X 16 核 1 h 40 min。
5 「张三1998年出生」BPE 切分
- 演示:
>>> tok.tokenize("张三1998年出生")
['张', '三', '199', '8', '年出生']
- 原因:数字不在预并列表,按字节切;中文单字在词表,保持单 token。
6 词表 50 k→30 k,参数量降多少?
Embedding 参数量 = vocab_size × hidden_size
LLaMA-2-7B:hidden=4096
Δ = (50 000 − 30 000) × 4096 = 81 920 000 ≈ 82 M(占 7 B 的 1.17 %)
7 续训 loss 不降反升 3 原因
- 学习率太大 → 梯度爆炸;
- 数据顺序未打乱 → 过拟合局部分布;
- tokenizer 与预训练不一致 → 大量 。
8 Zero-2 vs Zero-3 显存对比
- Zero-2:分片优化器状态 → 显存 ∝ P + 12B (7 B 模型约 14 G)
- Zero-3:连参数也分片 → 显存 ∝ 12B/N (N=卡数),单卡 8 卡 65 B 可跑。
9 grad_norm NaN 排查顺序
- 看 loss 是否 NaN;
- 打印梯度范数
scaler.unscale_()
; - 降 lr 10×再训 10 step;
- 开
fp32
矩阵乘; - 数据侧检查异常长文本/空文本。
10 LoRA r=64 新增参数量
lora_alpha=128
,target=q,v
每层 2 × (r × hidden + r × hidden) = 4 r hidden
LLaMA-2-7B 32 层 → 32 × 4 × 64 × 4096 = 33 M(占 7 B 0.47 %)
11 保留数学能力,只训代码
- 数据配比:代码 : 数学 : 通用 = 8 : 1 : 1
- loss mask:非代码样本的「数学/通用」部分
label=-100
,不让它参与语言模型 loss。
12 KL penalty 太高/太低现象
- 太高(>0.2):模型不敢偏离参考策略,回答变短、重复 safe 模板;
- 太低(<0.01):生成自由度高,易跑题、安全性下降。
13 奖励模型「全 0.8」检验
from scipy.stats import spearmanr
score1, score2 = rm.predict(chosen), rm.predict(rejected)
rho, _ = spearmanr(score1 - score2, human_rank)
assert rho > 0.3 # 至少正相关
若 rho≈0 → 奖励模型失效。
14 T4 15 GB 跑 7B-FP16 OOM 原因 & 规避
原因:激活缓存 + KV cache 额外占 3-4 GB。
规避:
accelerate
开device_map="auto"
把部分层 offload CPU;- 用
load_in_8bit=True
量化,显存 < 10 G。
15 GPTQ 首 token 延迟反增原因
权重量化后仍要运行时反量化(dequant),若 batch=1 且 kernel 未优化,反量化开销 > 省下的内存带宽。
→ 升驱动 / 换 exllama2 kernel。
16 vLLM 连续批 vs 静态批吞吐
实测 A100-40 G,LLaMA-13B:
- 静态 batch=16 → 1100 tokens/s
- 连续批 → 2800 tokens/s(↑2.5×)
17 HF → GGUF → ollama 30 秒命令
pip install llama-cpp-python hf-to-gguf
python -m hf_to_gguf ./xiaohong-7b ./xiaohong.q4_0.gguf q4_0
echo "FROM ./xiaohong.q4_0.gguf" > Modelfile
ollama create xiaohong -f Modelfile && ollama run xiaohong
18 200 条评测置信区间 ❤️ %
bootstrap 重采样 10 000 次:
import numpy as np
acc = [0.81]*172 + [0]*28 # 200 条
delta = np.percentile([np.mean(np.random.choice(acc, 200)) for _ in range(10000)], [2.5, 97.5])
print(delta) # → [0.775, 0.845] 半宽 3.45 %,再补 100 条即可 <3 %
19 回答 100 字以内准确率>95 %
- 后处理:用正则
re.split(r'[。!?]', text)
截断到第一句; - 训练阶段:在指令里加「回答不超过 30 汉字」并统计超限样本 fine-tune。
20 线上「变懒」回滚 & 定位
- 回滚:k8s
kubectl rollout undo deployment/llm
(镜像 tag 回退); - 定位:把用户日志按小时切片,跑「平均长度」SQL,若骤降时间与模型发布时间吻合 → 新数据 / 新模型问题。
21 手写 RoPE rotate_half
def rotate_half(x):x1, x2 = x[..., :x.shape[-1]//2], x[..., x.shape[-1]//2:]return torch.cat((-x2, x1), dim=-1)
22 10 行内 KV-cache 复用
past_kv = outputs.past_key_values # tuple of (k, v)
out = model(input_ids[:, -1:], # 只送最后一个 tokenpast_key_values=past_kv,use_cache=True)
23 8 卡 A100 5 分钟起 65B 推理
accelerate launch --multi_gpu --num_processes 8 \run_clm.py --model_name_or_folder llama-65b \--fp16 --deepspeed zero3_offload_config.json \--output_dir tmp --do_eval --max_new_tokens 128
(提前把 65B 权重分片下载好,config.json 里已填 tensor_parallel_size=8
)