百度 AI Infra 二面
Q: RAG系统中知识库数据如何清洗和构造?数据质量参差不齐会产生哪些影响?
清洗流程(按优先级):
- 去重:文档级去重(SimHash/MinHash)和段落级去重,避免重复内容污染检索结果
- 格式标准化:统一编码、去除HTML标签/特殊字符、标准化日期/数字格式
- 噪声过滤:去除广告、导航栏、页头页脚等无关内容(基于规则或分类器)
- 质量打分:用语言模型对文档打分(困惑度、信息密度),过滤低质量内容
- 实体对齐:统一同一实体的不同称呼(如”北大”=”北京大学”)
构造策略:建立丰富的元数据(来源、时间戳、类别标签、可信度评分)便于检索时过滤和排序。对结构化数据(表格/知识图谱)和非结构化数据分别建索引。
数据质量差的影响链:
- 检索阶段:噪声文档与真实文档语义接近时干扰 top-k 排序,降低召回精度
- 生成阶段:矛盾信息(同一问题不同来源答案不一致)导致模型产生幻觉或输出不确定
- 系统效率:低质量文档膨胀向量库体积,增加检索延迟和存储成本
- 长期维护:错误知识被持续引用,形成”错误强化”效应
Q: 文档切分策略如何设计?chunk size和overlap如何影响召回质量和生成效果?
切分策略(由简到优):
- 固定长度切分:按字符数/token数切分,简单但可能截断语义
- 基于分隔符:按段落/换行/句号切分,保持句子完整性
- 递归切分:优先按标题层级(H1>H2>段落>句子)递归,保持语义单元完整
- 语义切分:用 embedding 相似度检测语义边界,相邻句子相似度骤降处切分
Chunk Size 影响:
- 过大(>1024 token):召回精度下降(一个 chunk 混入无关信息),但上下文完整性好
- 过小(<128 token):语义不完整(一个概念被拆散),但召回精度高
- 实践最优:256-512 token,具体取决于文档类型(技术文档偏大,FAQ 偏小)
Overlap 作用:
- 避免关键信息恰好被截断在两个 chunk 的边界处
- 典型值:50-100 token(约 chunk size 的 10-20%)
- 过大的 overlap 导致索引膨胀和重复检索
经验法则:embedding 模型的最大输入长度通常是 chunk size 的上限(如 512 token for sentence-transformers)。
Q: 用户问题在知识库中存在但未召回正确文档,如何排查?
系统性排查思路(从检索管道逐步定位):
Embedding 质量:计算 query 和目标文档的 embedding 余弦相似度。若相似度低于阈值(如 <0.7),说明 embedding 模型对该领域的语义理解不足,考虑 fine-tune embedding 模型或换用领域 embedding。
切分问题:关键信息可能被拆散到多个 chunk 中,单个 chunk 语义不完整导致相似度不够。解决:增大 chunk size、增加 overlap、或使用 parent-child 索引(检索子 chunk 但返回父 chunk)。
Query 与文档表述差异:用户用口语化/简写方式提问,而文档是正式表述。解决:
- Query 改写/扩展(HyDE:先让 LLM 生成假设答案再用来检索)
- 多路召回:同时用原始 query 和改写后的 query 检索
检索策略单一:纯向量检索对关键词匹配不敏感。解决:引入混合检索(向量检索 + BM25 关键词检索),RRF(Reciprocal Rank Fusion)合并结果。
Top-K 设置过小:目标文档排在第 K+1 位。解决:增大 K 后配合 Reranker 精排,既保证召回率又不牺牲精度。
Q: 检索到的文档正确但模型生成答案错误,如何定位问题?
排查层级(从简单到深入):
上下文长度溢出:检查拼接后的 prompt+documents 是否超出模型最大 context length。超出会导致截断丢失关键信息。解决:压缩文档、只保留最相关片段。
Prompt 设计缺陷:是否明确指示模型”仅基于以下文档回答”?若无此约束,模型可能依赖预训练记忆产生幻觉。添加 system prompt 如”If the answer cannot be found in the context, say ‘I don’t know’.”
Lost in the Middle 现象:LLM 对长文本中间位置的信息关注度显著低于开头和结尾。解决:将最相关文档放在 prompt 开头或结尾;使用 MAP-based reordering。
模型推理能力不足:需要多跳推理或数值计算时,小模型可能力不从心。解决:换用更强模型(如 GPT-4 替代 GPT-3.5)、添加 CoT 提示。
Few-shot 引导:在 prompt 中添加 1-2 个”文档->正确答案”的示例,引导模型学会从文档中提取信息的模式。
Q: 召回结果语义相似但事实不相关,如何优化检索模块?
这是 RAG 系统中典型的”语义漂移”问题——embedding 空间中的相似不等于事实相关。
优化方案(效果递增):
引入 Reranker(Cross-Encoder)精排:初始召回 top-50 后用 Cross-Encoder(如 bge-reranker)对 query-doc 对精细打分重排。Cross-Encoder 比 Bi-Encoder 准确率高 5-10%,但推理慢(不能预计算),适合精排少量候选。
混合检索:向量检索捕获语义,BM25 捕获精确关键词匹配。两者互补可显著减少语义相似但事实不相关的问题。
元数据过滤:在向量检索前用时间/类别/来源等元数据预过滤,缩小候选空间。如用户问”2024年的政策”,先过滤出 2024 年的文档再向量检索。
Fine-tune Embedding 模型:用领域内的正负样本对微调 embedding,拉开”语义相似但不相关”的距离。需要构造 hard negative(语义相似但答案错误的样本对)。
Hard Negative Mining:从当前系统的 false positive 中挖掘困难负样本,加入训练集迭代优化 embedding 和 reranker。
Q: 跨多个文档的问题,RAG系统如何处理?
跨文档问题(如”A 和 B 的区别是什么?”需同时找到 A 和 B 的信息)是 RAG 的重大挑战。
解决方案:
问题拆解(Query Decomposition):将复合问题拆为子问题(”A是什么?””B是什么?”),分别检索后合并上下文交给 LLM 综合回答。可用 LLM 自动拆解。
增大 Top-K:简单增加召回数量提高覆盖率,配合 reranker 保证相关性。但上下文长度是瓶颈。
迭代式 RAG(Multi-hop RAG):第一轮检索回答部分问题,发现信息不足时自动生成追加查询,进行第二轮检索。类似 Agent 的循环检索。
知识图谱辅助:建立实体间关系图,当检索到 A 时,通过图关系找到关联的 B 文档。适合结构化强的领域。
长上下文模型:使用 128K+ 上下文的模型,一次性输入多个完整文档让模型自行整合。简单有效但 token 成本高。
Q: RAG系统中如何判断问题出在检索模块还是生成模块?
经典诊断方法——“Oracle Document”测试:
将 ground truth 文档(人工确认的正确文档)直接作为上下文喂给生成模块:
- 生成正确 -> 问题在检索模块(未能召回正确文档)
- 生成仍然错误 -> 问题在生成模块(模型能力不足或 prompt 有问题)
量化评估指标:
- 检索模块:Recall@K(正确文档是否在 top-K 中)、MRR(正确文档排在第几位)、NDCG
- 生成模块:Faithfulness(答案是否基于给定文档)、Answer Relevancy(答案是否回答了问题)、Correctness(与 ground truth 的一致性)
工具:RAGAS 框架可自动计算这些指标,帮助定位问题组件。实践中建议建立 golden set(100-500 条 query+正确文档+正确答案),定期回归测试。
Q: Transformer从输入token到输出logits的完整计算流程?
完整的前向传播流程(以 Decoder-only LLM 为例):
1. Token Embedding:token ID 经过 Embedding 层查表得到 d_model 维向量。词表大小 V 通常 32K-128K,embedding 维度如 4096。
2. 位置编码:注入序列位置信息。RoPE(旋转位置编码)在 Q/K 投影之后施加,将绝对位置编码为旋转角度使内积天然包含相对位置。
3. Transformer Block(重复 N 层):
- RMSNorm(Pre-Norm):归一化输入
- Multi-Head Attention:输入 x 经线性投影得到 Q/K/V(各 d_model -> n_heads * head_dim)-> 对 Q/K 施加 RoPE -> 计算 attention:softmax(QK^T/sqrt(d_k)) * V -> 多头拼接 -> 输出投影 O_proj
- 残差连接:x = x + Attention(x)
- RMSNorm
- FFN(SwiGLU):gate = SiLU(x * W_gate),up = x * W_up,output = (gate * up) * W_down。升维比通常为 8/3 * d_model。
- 残差连接:x = x + FFN(x)
4. 最终输出:
- RMSNorm 归一化
- LM Head:线性映射 d_model -> V(词表大小),输出 logits
- 推理时对 logits 做 temperature/top-k/top-p 采样得到下一个 token
Q: FFN层为什么采用”先升维再降维”的结构?
这是一个信息瓶颈(Information Bottleneck)设计,具有深刻的理论动机:
1. 高维空间的表达能力:低维空间中线性不可分的特征组合,映射到高维后可以变得线性可分(类似 SVM 的核方法思想)。升维后的激活函数(ReLU/SiLU/GELU)能在高维中实现更丰富的非线性选择性。
2. 稀疏激活与特征选择:研究表明 FFN 高维空间中只有少量神经元被激活(稀疏性),不同神经元对应不同的语义”知识点”(knowledge neurons)。升维提供足够多的”槽位”来编码不同知识模式。
3. 信息压缩:升维-激活-降维的过程可理解为”展开-选择-压缩”:展开到高维后选择有用信息,再压缩回原始维度。这比直接在低维做变换表达能力强得多。
4. 典型比例:标准 Transformer 升维 4x(如 4096 -> 16384 -> 4096)。LLaMA 使用 SwiGLU 结构时升维约 8/3 x(约 2.67x)来补偿门控带来的参数减少。
5. MoE 的启示:MoE 模型将 FFN 换成多个专家,进一步说明 FFN 层是”知识存储器”的角色——不同输入路由到不同专家(子 FFN)处理。
Q: MHA、MQA、GQA在推理阶段的KV Cache占用和计算效率差异?
三者的核心区别在于 K/V 头的共享策略,直接影响推理时的 KV Cache 显存和带宽压力:
| 方案 | KV头数 | KV Cache大小 | 推理速度 | 生成质量 |
|---|---|---|---|---|
| MHA | n_heads 个独立 KV | 基准(100%) | 基准 | 最优 |
| MQA | 1 组共享 KV | 1/n_heads(如 1/32) | 最快 | 略有下降 |
| GQA | g 组共享 KV | g/n_heads(如 8/32=25%) | 快 | 接近 MHA |
具体计算(以 LLaMA-2 70B 为例,n_heads=64, n_layers=80, d_head=128, seq_len=4096):
- MHA KV Cache = 2 * 80 * 64 * 128 * 4096 * 2B = 167 GB(不可行)
- GQA(8组) KV Cache = 2 * 80 * 8 * 128 * 4096 * 2B = 20.9 GB
- MQA KV Cache = 2 * 80 * 1 * 128 * 4096 * 2B = 2.6 GB
为什么 GQA 是主流选择:MQA 的质量损失在大模型上明显(所有头共享一组 KV 限制了注意力的多样性),GQA 以少量额外 Cache 代价(相比 MQA 大 g 倍)换回接近 MHA 的质量。LLaMA-2/3、Mistral 等主流模型均采用 GQA。
Q: 为什么推理阶段KV Cache只缓存K和V,不缓存Q?
根本原因在于自回归解码的计算模式:
每一步 decoding 只生成一个新 token,其对应的 Q 向量是当前步特有的、全新的,没有复用价值。而 Attention 的计算需要当前 Q 与所有历史位置的 K 做点积、再对所有历史位置的 V 加权求和:
1 | Attention = softmax(q_new * [K_1, K_2, ..., K_t]^T) * [V_1, V_2, ..., V_t] |
- K 和 V:需要包含位置 1 到 t 的所有历史信息,如果不缓存就得对整个前缀重新计算 QKV 投影,时间复杂度从 O(d) 变成 O(t*d)
- Q:每步只有一个新 token 的 Q(维度 1 * d_head),计算量极小,且下一步的 Q 完全不同,缓存无意义
补充:Prefill 阶段一次性计算整个输入序列的 K/V 并存入 Cache;Decode 阶段每步只追加一行新的 K/V 到 Cache 中。
Q: RoPE的核心原理是什么?长上下文场景下有什么问题?
核心原理:
RoPE(Rotary Position Embedding)将位置信息编码为旋转操作。对 Q/K 向量按维度两两分组,每组施加不同频率的 2D 旋转矩阵:
1 | R(m) = diag(R_1(m*theta_1), R_2(m*theta_2), ..., R_{d/2}(m*theta_{d/2})) |
其中 theta_i = 10000^(-2i/d) 是不同维度对应的基础频率。
关键性质:经过旋转编码后,Q_m 和 K_n 的内积只依赖相对位置 (m-n):
1 | <R(m)q, R(n)k> = <R(m-n)q, k> |
这使得模型自然学到相对位置关系,且对绝对位置有泛化能力。
长上下文问题:
- 训练时序列长度有限(如 4K),推理时遇到超出训练长度的位置编码值会导致注意力分数异常(外推性差)
- 高频分量(小 i 对应的维度)在长距离时旋转过多圈,模型未见过这些角度
解决方案:
- Position Interpolation(PI):将位置缩放到训练范围内(如 8K 位置压缩为 4K),牺牲精度换外推
- NTK-aware 插值:调整频率基数,对低频维度插值多、高频维度插值少,保持局部精度
- YaRN:结合 NTK 插值和注意力温度缩放,用少量数据微调即可扩展到 128K+
- Dynamic NTK:推理时根据实际序列长度动态调整频率基数
Q: Instruction tuning中多轮对话训练时loss mask如何设计?
核心原则:只对 assistant 回复部分计算 loss,对 system prompt 和所有 user 输入部分 mask 掉(loss weight = 0)。
具体设计(以多轮对话为例):
1 | [System Prompt] -> mask (不计算loss) |
为什么这样设计:
- 模型学习的目标是”给定上下文如何回答”,而非记忆输入本身
- 对 user 输入计算 loss 会让模型学习”复述用户问题”的能力,这不是我们想要的
- System prompt 是固定模板,学习它会浪费模型容量
实现细节:
- 需要 attention mask 仍然是 causal(assistant 可以看到前面所有内容)
- 只是 loss 的计算通过 labels 中设置 -100(ignore_index)来跳过
- 多轮中每一轮 assistant 开头的 BOS token 通常也 mask 掉(它的预测无意义)
注意事项:如果 mask 设计错误(如误将 assistant 的部分 mask 了),模型会”不知道该在哪里说话”,表现为格式混乱或输出空白。
Q: SFT后特定任务增强但通用能力下降,如何解决?
这是灾难性遗忘(Catastrophic Forgetting)的典型表现,预训练获得的通用知识在微调过程中被覆盖。
解决方案(按实践常用程度排列):
混合训练数据:在 SFT 数据中混入通用对话数据(如 ShareGPT、Open-Assistant),比例通常为特定任务:通用 = 7:3 到 5:5。这是最简单有效的方法。
LoRA/QLoRA 参数高效微调:冻结预训练主体权重,只训练低秩适配器。主体能力天然保留,适配器学习新任务。推理时可按任务加载不同 adapter。
降低学习率:使用远小于预训练的学习率(如 1e-5 到 5e-6),减少对预训练权重的破坏幅度。配合 cosine decay 和 warmup。
正则化方法:
- L2 正则化:惩罚参数偏离预训练值的幅度
- EWC(Elastic Weight Consolidation):对”重要”参数(Fisher 信息量大的参数)施加更强约束
- 知识蒸馏:用原始预训练模型的输出作为正则信号
数据配比调优:逐步增加特定任务数据比例,监控通用 benchmark(MMLU、HellaSwag 等)确保不掉点。
Q: LoRA的低秩分解为什么能逼近全参数微调效果?
理论基础——内在维度(Intrinsic Dimensionality):
研究表明预训练模型的微调过程中,权重更新矩阵 ΔW 具有很低的内在维度。也就是说,ΔW 的信息主要集中在前几个奇异值对应的主成分上,其余方向的更新量接近零。
直观理解:
- 预训练已经学到了丰富的通用表示,微调只需要在这个基础上做小幅度调整
- 这些调整往往是低秩的:例如让模型学会新的指令格式,可能只需要调整注意力投影的几个主方向
- 实验证据:7B 模型全参微调的 ΔW 做 SVD 分解后,rank 8-64 就能捕获 >90% 的信息量
LoRA 的数学形式:W_new = W_frozen + B * A,其中 B ∈ R^{d×r}, A ∈ R^{r×d}, r << d。
- A 捕获输入空间的关键方向(哪些输入特征需要调整)
- B 将这些调整映射回输出空间
- r 的大小决定了能捕获多少独立的调整方向
实践验证:在大多数 NLP 任务上,LoRA rank=16-64 即可达到全参微调 95%+ 的效果,同时只训练 0.1-1% 的参数。
Q: LoRA的rank设置不合理会出现什么现象?
| Rank 设置 | 现象 | 原因 |
|---|---|---|
| 过小(r=1-4) | 欠拟合,任务指标提升有限 | 表达能力不足,无法捕获微调所需的复杂调整方向 |
| 过大(r=256+) | 过拟合(小数据集),或效率优势丧失 | 参数量接近全参微调,且小数据集无法提供足够信号训练这么多参数 |
| 合理范围 | rank=8-64,任务效果好且效率高 | 恰好覆盖了ΔW的主要奇异值方向 |
选择策略:
- 简单任务(格式调整、分类):rank=8-16 足够
- 中等任务(对话、摘要):rank=32-64
- 复杂任务(多领域知识注入):rank=64-128
- 如果增大 rank 后验证集指标不再提升,说明当前 rank 已足够
其他关键超参:
- alpha:缩放因子,通常设为 rank 的 1-2 倍。实际缩放为 alpha/rank,所以 alpha=rank 时等效学习率不变
- target_modules:通常选择 attention 的 QKV 和 O 投影,FFN 按需添加
Q: DPO训练后模型输出明显变长,如何处理?
根因分析:DPO 训练时,如果 chosen 样本普遍比 rejected 样本长,模型会隐式学到”长=好”的 spurious correlation(虚假相关)。因为 DPO 的 loss 基于序列总 log probability,长序列天然有更大的绝对值差异。
解决方案:
训练数据控制(最根本):确保 chosen/rejected 对的长度分布相近。过滤掉长度差异过大的样本对(如 |len(chosen)-len(rejected)| > threshold)。
长度归一化(算法层面):
- 使用平均 token log probability 而非总 log probability:r(x,y) = (1/|y|) * sum(log P(y_t|x,y_{<t}))
- SimPO 方法直接采用此归一化,无需参考模型
- R-DPO:在 reward 中显式减去长度惩罚项
推理时控制:
- 设置合理的 max_tokens
- 使用 length_penalty < 1.0 惩罚长输出
- Repetition penalty 避免冗余重复
后处理:对异常长的输出做截断或重生成(如检测到重复模式时停止)。
Q: 对齐后模型过于保守频繁拒绝回答,如何调整?
这是”过度对齐(Over-alignment)”问题——模型在安全训练中学到了过于宽泛的拒绝模式。
调整策略:
减少拒绝样本比例:审计训练数据中”拒绝回答”类样本的比例。如果超过 20-30%,模型容易学到”拒绝是安全的默认策略”。
细粒度安全标注:区分”真正有害”(暴力/犯罪指导)和”边界/敏感但可回答”(医疗咨询/历史事件讨论)。对后者标注为应该回答而非拒绝。
调整 KL 惩罚系数(DPO 的 beta):降低 beta 允许策略偏离参考模型更远,增加 helpfulness。但过低会导致不稳定或安全性下降。典型范围 0.01-0.5,过保守可从 0.1 降到 0.05。
增加 Helpfulness 信号:在偏好数据中增加”有帮助的回答 > 无用的拒绝”这类样本对,让模型学到”能回答时不该拒绝”。
红队测试 + 迭代修正:用红队数据集测试过度拒绝的 case,将其标注为 chosen(应回答),加入训练集进行迭代对齐。
Q: 大模型出现复读机现象由哪些因素导致?
“复读机”现象(repetition/degeneration)是 LLM 的常见问题,成因是多方面的:
数据层面:
- 训练数据重复:如果训练集中存在大量重复模式(如网页模板、法律条款),模型学到这些重复是”正常的”
- 模板化 SFT 数据:固定格式的指令数据导致模型学到固定输出模式
模型/架构层面:
3. 注意力退化:长序列中 attention weight 过于集中在近邻 token(recency bias),形成局部循环。随序列变长,早期信息的影响衰减,模型”忘记”了前面已经说过什么
4. 位置编码外推不足:超出训练长度时位置编码失效,模型无法区分”新位置”和”旧位置”
解码策略层面:
5. Greedy/Beam Search:确定性解码容易陷入高概率循环(一旦进入重复模式,重复的下一个 token 概率更高,形成正反馈)
6. Temperature 过低:使分布过于尖锐,只有少数 token 被选择
解决方法:
- 训练阶段:数据去重、添加多样性正则
- 解码阶段:repetition_penalty(对已出现 token 降低概率)、frequency/presence penalty、nucleus sampling (top-p)
- 架构:增加 attention sink tokens、使用更好的位置编码