Q18: 介绍检索做的优化,具体追问子问题分解怎么做,有没有做意图识别?**
P2 · rag
🏷 标签:rag, retrieval, query-decomposition, intent-recognition, multi-hop
1️⃣ 考察意图
面试官想考察你对 RAG 检索优化的深度理解,尤其是从“简单召回”到“智能检索”的进阶能力。核心刁钻点在于:你是否只停留在罗列技术(如向量检索、重排序),还是能讲清楚“子问题分解”和“意图识别”这两个高级模块的工程落地细节。答好了能展示你对复杂查询(multi-hop、比较、推理)的处理能力,以及从系统设计角度平衡检索精度与延迟的硬实力。这属于系统设计 + 工程取舍型问题。
2️⃣ 标准答
检索优化通常分三层:索引层(如 HNSW 图索引、分片策略)、查询层(改写、分解、意图识别)、融合层(多路召回、重排序)。这里重点讲查询层的两个高级优化:子问题分解和意图识别。
子问题分解(Query Decomposition)
- 动机:用户查询可能是多跳的(如“特斯拉的电池供应商是谁,这家公司去年营收多少?”),直接检索一个 embedding 向量会丢失子问题间的逻辑关系,导致召回碎片化。
- 实现方法:用 LLM 将原问题拆成多个独立子问题。常用两种提示策略:Chain-of-Thought(CoT):让 LLM 先输出推理步骤,再生成子问题。例如:“问题:A 公司的 CEO 毕业于哪所大学?步骤:1. 找到 A 公司 CEO 是谁;2. 查该 CEO 的毕业院校。子问题:1. A 公司 CEO 是谁?2. [CEO 姓名] 毕业于哪所大学?”
- Few-Shot 示例:给 2-3 个分解示例,让 LLM 模仿。注意示例要覆盖不同复杂度(如单跳、双跳、比较型)。 质量控制:子问题生成后必须做两步过滤:
- 去重:用 embedding 相似度(如 cosine > 0.9)合并语义重复的子问题。
- 相关性校验:用一个小模型(如 BERT 分类器)判断子问题是否与原问题相关,过滤掉 LLM 幻觉产生的无关子问题。 结果合并:每个子问题独立检索 top-k 文档,然后用 LLM 融合。融合策略有两种 trade-off:
- 先合并再生成:将所有子问题的检索结果拼接成一个大上下文,让 LLM 统一回答。优点是信息完整,缺点是上下文过长可能超出模型窗口。
- 先生成再合并:每个子问题先让 LLM 生成中间答案,再让 LLM 基于这些中间答案生成最终答案。优点是节省 token,缺点是中间答案可能引入错误传播。
意图识别(Intent Recognition)
- 作用:不是所有查询都需要分解。意图识别决定“是否分解”以及“分解粒度”。
- 分类体系:通常分 4 类:事实查询(如“巴黎是哪个国家的首都?”):直接检索,不分解。
- 多跳推理(如“特斯拉的电池供应商是谁?”):需要分解。
- 比较查询(如“A 和 B 哪个更好?”):分解为两个独立子问题,再对比。
- 开放生成(如“写一篇关于 AI 的文章”):不检索或只做粗检索,依赖 LLM 生成。 实现方式:用一个小型分类器(如基于 RoBERTa 的 4 分类模型)或 LLM 的 few-shot 分类。工程取舍:分类器速度快(<10ms)但准确率略低(约 85%),LLM 分类准确率高(>95%)但延迟高(>200ms)。实际落地:对延迟敏感场景(如实时对话)用分类器,对离线或非实时场景用 LLM。实际坑:意图识别容易误判模糊查询(如“苹果怎么样?”——是问水果还是公司?)。解法:结合用户历史会话上下文(如之前聊过科技新闻)或使用 NER 提取实体后做消歧。
3️⃣ 答题模板(30 秒电梯版)
“这个问题我从三个层面回答:第一,检索优化总览,包括索引、查询、融合三层;第二,子问题分解的具体实现,包括 CoT 提示、质量控制、结果合并的 trade-off;第三,意图识别如何决定分解粒度,以及分类器 vs LLM 的工程取舍。总结一句:子问题分解解决多跳查询的召回碎片化,意图识别避免不必要的分解开销,两者结合才能实现智能检索。”
4️⃣ 高频追问 & 应对
追问 1:子问题分解时,如果 LLM 生成了 5 个子问题,但实际只需要 3 个,你怎么处理冗余?
用两步过滤:第一步,用 embedding 相似度去重,阈值设为 0.85(经验值),合并语义重复的子问题;第二步,用相关性分类器(如 BERT 微调)判断每个子问题是否与原问题直接相关,过滤掉无关的。如果过滤后子问题数仍过多,可以设置最大子问题数(如 3 个),按 LLM 输出的置信度排序后截断。注意:截断可能导致信息丢失,所以优先用去重和过滤。
追问 2:意图识别中,比较查询和推理查询的边界模糊,你怎么区分?
用规则 + 模型混合:先通过正则匹配关键词(如“vs”、“对比”、“哪个更好”)识别比较查询;对于无关键词的模糊查询,用分类器输出概率分布,如果比较类和推理类的概率接近(差值 < 0.1),则默认走推理分解(因为推理分解能覆盖比较场景,但反之不行)。实际落地中,比较查询的分解策略是生成两个独立子问题(如“A 的优缺点”和“B 的优缺点”),而推理查询需要生成有依赖关系的子问题。
追问 3:子问题分解的延迟很高,你怎么优化到实时可用?
三个优化点:第一,用异步并行检索,每个子问题独立检索,总延迟 = max(子问题延迟) 而非 sum;第二,子问题生成用蒸馏后的小模型(如 Llama-3.2-1B 替代 70B),延迟从 500ms 降到 50ms;第三,对高频简单查询(如单跳事实查询)跳过分解,直接用缓存或快速检索。整体上,意图识别前置可以过滤掉 60% 的不需要分解的查询,大幅降低平均延迟。
5️⃣ 避坑 · 常见错误答法
- ❌ 说“子问题分解就是让 LLM 把问题拆开,然后分别检索就行”,没有提到质量控制和结果合并的 trade-off。 → ✅ 必须强调去重、相关性校验、以及“先合并再生成” vs “先生成再合并”的取舍。
- ❌ 说“意图识别用 LLM 做分类就行,准确率最高”,忽略延迟成本。 → ✅ 必须区分场景:实时对话用分类器,离线场景用 LLM,并给出具体延迟数据(分类器 <10ms,LLM >200ms)。
- ❌ 说“检索优化就是加个重排序模型”,只停留在表面。 → ✅ 必须从查询层(分解、意图识别)和索引层(分片、HNSW 参数调优)展开,展示系统思维。
6️⃣ 简历呼应
- 如果你有 RAG 项目:从实际数据切入,比如“在 MultiHopQA 数据集上,子问题分解使 F1 提升 12%,但延迟增加 30%,所以用意图识别过滤了 40% 的简单查询,最终延迟只增加 5%”。
- 如果你只做过传统 NLP:用“查询改写”类比,比如“子问题分解类似于传统 IR 中的查询扩展,但更智能;意图识别类似于文本分类任务,可以用 BERT 微调实现”。
- 如果你是校招无项目:聚焦论文复现,比如“我复现了《Self-Ask》论文中的子问题分解方法,并在 WikiQA 上验证了效果,同时分析了 CoT 和 Few-Shot 的差异”。
- 《Self-Ask: Measuring and Narrowing the Compositionality Gap in Language Models》
- 《Query Decomposition for Multi-Hop Question Answering》
- 《REALM: Retrieval-Augmented Language Model Pre-Training》
- 《HNSW: Hierarchical Navigable Small World Graphs》
- 《RoBERTa: A Robustly Optimized BERT Pretraining Approach》