资讯详情

RAG Query理解模块全拆解:从意图识别到子查询分解

📅 2026/10/20 4:33:41 | 华诺云谱 👁 阅读
RAG Query理解模块全拆解:从意图识别到子查询分解
RAG面试题里能被面试官单独拎出来问的模块不多“Query理解”绝对算一个。我自己带项目时也常拿这个问题试探候选人有的人能把“理解模块”吹得天花乱坠但追问一句“具体怎么拆的”对方就只剩下“用大模型重新生成一下query”这种空话。这句话一出口基本就凉了。今天这篇就是针对这道高频面试题的完整拆解也是我从零做一个RAG检索系统时在query入口处真正落地过的方案包括子模块设计、工程实现、面试回答策略和踩坑记录。无论你是正在准备面试还是已经把RAG跑通但发现检索质量上不去这篇都可以当作业模板抄。1. Query理解在RAG链路中的定位与价值1.1 面试官真正想考察什么很多候选人默认RAG的流程就是“用户发来一段queryembedding模型向量化然后去向量库做相似度检索”。这个链路在demo里很顺畅但放到真实业务里基本跑不动原因多半是query本身不适合检索。什么叫“不适合检索”举个我实际遇到的例子用户问“Llama-2和Falcon哪个模型的参数量更大在A100上微调大概要多少显存”这句话里有两个模型实体、两个属性维度还夹着“对比”意图。如果直接把整句话embedding再检索向量检索大概率会召回一堆介绍这两个模型的泛泛文章而不是“参数对比”和“显存估算”这种精确内容。因为文档里很少有一句话同时覆盖两个模型的参数和显存。表达鸿沟就在这里。面试官问“你的Query理解模块怎么做的”其实是在同时考察三个层次第一你有没有意识到query和文档之间存在表达鸿沟第二你知不知道常规的解法有哪些以及每种方案的取舍是什么第三你有没有真的落地过知道什么场景该上什么手段而不是只会背概念。所以我建议的回答定位是不把Query理解当作一个孤立的“改写步骤”而是把它定义成RAG链路的入口质量闸门。它把用户原始的、口语化的、指代不清的、可能包含复合意图的query转换成语义清晰、可执行检索的结构化表示。这个定义一出来后面聊子模块就很顺理成章了。1.2 一个完整Query理解模块的设计思路完整模块通常拆成五件事指代消解、意图识别、实体抽取、查询改写、子查询分解。不是所有场景都需要全上比如纯单轮问答场景指代消解可以不做知识库主题很单一的话子查询分解也可以砍掉。但面试答题建议从全貌讲起再落回业务裁剪这会让面试官觉得你有整体思考而不是只见过自己那一亩三分地。模块之间的组织方式我推荐流水线加结构化输出。每个子模块接收上一个模块的结果同时保留原始query作为上下文避免信息在前置环节丢失。最后统一输出一个结构化对象典型字段包括intent、entities、sub_queries、constraints。下游检索器拿着这个对象决定是走常规向量检索、BM25检索还是走结构化字段过滤。我还想强调一点Query理解模块不是单纯的“前置处理”它其实承担了路由功能。比如检测到“代码问题”意图可以把query送到代码索引检测到“数值对比”意图可以并行触发结构化查询。这会让RAG整体从“一个向量库打天下”变成“多路检索协同”。2. 核心子模块拆解从意图到子查询2.1 意图识别先弄清楚用户想干什么意图识别的目标不是给query贴个标签就完事了而是要决定后续的检索策略。我一般会把意图分成咨询型、对比型、操作型、时效型和闲聊型。咨询型走普通知识检索对比型要触发子查询分解和并列召回操作型可能要去检索教程或代码库时效型要加上时间过滤条件闲聊型则直接不进RAG主链路。实现上常用的手段可以分成三档方案延迟成本泛化能力适用场景规则/关键词极低极低差依赖词表覆盖意图固定、表达规范的小场景小分类模型低中较好能覆盖模糊表达意图类别多、需要快速响应的主链路LLM few-shot高高最强边界情况也能处理低QPS复杂query、兜底纠偏实际项目里我很少只用一个方案。如果意图数量在5个以内用户表达相对规范用规则加关键词就够了意图类别超过8个或者用户说法千奇百怪建议上一个小的BERT分类模型来跑主链路LLM作为兜底只处理规则和小模型置信度低的情况。我这么做纯粹是成本和延迟考虑——主链路QPS一高每多一次LLM调用都是灾难但规则和小模型能把单次query理解控制在几十毫秒以内。一个具体例子“帮我对比下这两个大模型的训练推理速度然后写个总结。”意图识别模块输出comparison_task。这个标签会告诉下游可以拆子查询每个子查询分别检索“训练速度”和“推理速度”两类资料并且生成阶段最后要按对比结构输出。2.2 实体抽取与关键信息提取实体抽取解决的其实是“用户到底在说哪个东西”。RAG业务里经常遇到这种问题用户说“这个大模型支持多大上下文”这里的“这个”如果不带入上下文检索器根本不知道指哪个模型。我的做法是“词表匹配 正则 NER”三层结构。词表是性价比最高的手段比如某AI知识库的词表里有大量模型名、API名、论文名用最大匹配或AC自动机就能把“Llama-2”“Falcon”“DPO”“RLHF”这类词抽出来。难点在于词表更新以及实体变体比如大小写、缩写、版本号这些词表覆盖不了。正则就负责抓住那些规律性强的实体或数值比如“A100”“7B”“70B”。NER模型负责兜底识别词表和正则都覆盖不到的未登录实体。这里有个细节特别容易被忽略只抽实体不抽属性等于白做。还是用“Llama-2和Falcon哪个参数量更大”这个例子如果实体抽取结果只输出[Llama-2, Falcon]下游检索时仍然不知道用户要的是“参数量”相关资料。我踩过这个坑后来在实体抽取阶段直接把属性也抽出来每个实体附带attributes字段比如{entity: Llama-2, attributes: [参数量]}检索命中率明显上来了。这个细节在面试时讲出来很能体现你对检索的理解。2.3 查询改写与扩展的实用策略查询改写是大家认识Query理解第一步时最容易想到的它其实做的是两件事把口语化表达翻译成更规范、贴近知识库文风的书面表达把同义说法扩展成多个变体去检索提高召回覆盖率。口语转书面很好理解用户说“跑起来卡不卡”系统改写成“运行速度、延迟表现”。同义扩展也很常见比如把“大模型”扩展成“大模型/LLM/语言模型/foundation model”几个变体再分别检索。特别是在中英文混合场景下不同文档可能用不同语言称呼同一个概念扩展收益非常明显。但扩展不能无限发散。如果每个词都扩展比如把“A模型”扩成“A模型large language modelLLM大语言模型语言模型”最终向量会变成大杂烩语义被严重稀释。我的经验是同一语义维度最多保留3个变体并且用改写前后embedding的余弦相似度做校验相似度低于阈值的改写结果直接丢弃回到上一个稳定版本。这个校验逻辑成本很低但能挡住大多数改写跑偏的情况。2.4 子查询分解应对复杂多跳问题子查询分解是Query理解模块里最能体现水准的地方也是面试官最容易深挖的点。先说什么问题需要分解。一类是并列对比比如“A和B哪个参数量更大”它可以拆成“A参数量”和“B参数量”分别检索另一类是多跳组合比如“论文里提出的算法在B数据集上的效果”直接检索这一整句很难命中因为文档往往不会同时把算法和数据集效果写在一段里拆成“算法介绍”和“数据集 benchmark结果”分头再查命中率高很多。怎么判断需要分解我常用触发词表维护一组词“对比”“vs”“哪个”“区别”“为什么”等一旦命中就进入分解流程。分解出来的子查询数量我建议控制在2到4个。超过4个基本说明这个query不适合做成整句向量检索应该考虑结构化查询或者换更细的知识库切片方式。还要注意“属性透传”的问题。比如query是“Llama-2和Falcon在A100上微调需要多少显存”真正拆出来的子查询是“Llama-2在A100上微调显存需求”和“Falcon在A100上微调显存需求”。“A100”“微调”“显存”这几个约束条件必须在分解时透传给每个子查询否则子查询就变成了空心问题。这个细节特别容易漏我把它写出来给各位提个醒。3. 手把手实现一个Query理解模块3.1 技术选型规则、小模型还是LLM选型一句话没有标准答案取决于业务约束。如果业务QPS高、延迟敏感比如线上的客服搜索那么Query理解总耗时最好控制在20毫秒内这时候规则加小分类模型是主力LLM一个都不能放在主链路。如果是离线评测或者用户量不大、query却特别复杂的场景用LLM反而更省事因为它的泛化能力能处理大量长尾写法。一个成熟系统的架构通常不是单方案而是分级处理。我用文字描述一下这条链路先做query预处理接着规则匹配规则能处理的直接返回规则处理不了的小分类模型预测并记录置信度置信度低于某个阈值或预测类别很模糊的再交给LLM兜底。分级方案的好处是常规query成本极低复杂query虽然贵但数量占比小整体成本可控。3.2 工程实现以对比类Query为例我直接给一个简化但结构完整的代码骨架这个骨架是我在实际项目里的第一版原型改写的去掉了业务无关的细节保留了关键结构。from dataclasses import dataclass, field dataclass class ParsedQuery: intent: str # comparison / lookup / howto ... entities: list field(default_factorylist) sub_queries: list field(default_factorylist) constraints: dict field(default_factorydict) def preprocess(query: str, history: list[str]) - str: # 指代消解把“它”“这个模型”替换成历史实体 # 没有历史实体时宁可保留原句也不要乱猜 return query def classify_intent(query: str) - str: # 优先规则其次小模型 if any(w in query for w in [对比, vs, 哪个, 区别, 比较]): return comparison if any(w in query for w in [如何, 怎么, 步骤, 教程]): return howto return lookup def extract_entities(query: str, intent: str) - list[dict]: # 词表 正则 NER # 返回示例: [{entity: Llama-2, attributes: [参数量]}] return [] def decompose(query: str, intent: str, entities: list[dict]) - list[str]: # 对比类意图按实体切分并透传公共约束 if intent ! comparison: return [query] # 从query中抽取公共约束A100 / 微调 / 显存 constraints find_constraints(query) result [] for entity in entities: for attr in entity.get(attributes, []): result.append(f{entity[entity]} {attr} { .join(constraints)}) return result if result else [query] def rewrite_query(query: str, entities: list[dict]) - str: # 同义扩展 书面化改写 embedding相似度校验 return query def parse_query(raw_query: str, history: list[str] | None None) - ParsedQuery: query preprocess(raw_query, history or []) intent classify_intent(query) entities extract_entities(query, intent) sub_queries decompose(query, intent, entities) rewritten rewrite_query(query, entities) return ParsedQuery( intentintent, entitiesentities, sub_queriessub_queries, constraints{rewritten_query: rewritten} )这段骨架再次说明一件事每个环节都应该是独立函数方便替换、加缓存、加日志。我强烈建议在生产代码里给每个环节打日志否则排查“为什么某个query没触发子查询分解”会非常痛苦。3.3 与检索链路的衔接细节Query理解模块输出后下游检索怎么用对最终效果影响很大。我常用的衔接方式有三种。第一种是多路召回。把原始query、改写后的query、各个子查询分头送到embedding检索和BM25检索得到多路候选结果。原始query保留很重要因为改写可能失真保留原词兜底。第二种是结果合并去重。子查询之间召回内容重叠度通常很高特别是对比类query的两个子查询很可能召回到同一篇对比文章。合并时按文本相似度或文档ID去重保留和query相关度更高的那个来源还要控制给生成模块的总token数避免上下文爆炸。第三种是属性约束过滤。实体抽取结果和constraints可以转成检索的过滤条件。比如检测到“A100”和“微调显存”可以先按标签过滤出A100相关的页面再做向量检索。这个“先过滤再向量”的顺序能省掉大量无关chunk比纯向量检索快很多。这里还有一个容易忽略的衔接点用于检索的query和用于生成的query不一定是同一个。子查询“Llama-2参数量”只负责把材料捞回来但真正喂给生成模块的应该包含原始query、intent标签以及各子查询召回内容的汇总。如果不把intent传给生成模块生成结果就变成平铺直叙的文档照抄而不是用户要的“对比分析”。4. 面试回答框架与高频追问应对4.1 一套能拿高分的回答思路面试回答不要按教科书顺序背我建议按“目标—子任务—实现—取舍—效果”五段式来讲。第一段讲目标一句话概括Query理解是把用户的原始query转换成语义清晰、可执行检索的结构化表示。第二段列子任务指代消解、意图识别、实体抽取、查询改写、子查询分解并说明根据业务裁剪。第三段讲实现拿一个具体case演示比如“A模型和B模型对比”如何拆解成多个子查询。第四段讲取舍强调规则能覆盖的不用模型模型能覆盖的不轻易上LLM把延迟和成本的权衡讲清楚。第五段给效果如果项目里有量化结果最好没有就按合理估算给出命中率提升、延迟下降这类指标。还有一个面试加分点主动讲评估方法。如果你能说出“我们构建了400条评测集包含意图准确率、实体F1、子查询有效性以及端到端前5命中率”面试官对你的工程意识会有明显改观。因为大部分候选人都只停留在“我做了个模块”的层面能聊评估的人很少。4.2 高频追问及其背后的考察点我把面试中容易遇到的高频追问整理一下每个追问背后都有明确的考察意图。追问一“直接让LLM改写query不行吗为什么搞这么复杂”这个问题考察的是你对成本和可控性的理解。回答要点是LLM改写灵活但不可控可能引入幻觉而且延迟和成本都不适合QPS大的场景。纯LLM方案很难做回归测试prompt一改动行为可能大变规则加小模型则可以保证绝大多数query的低延迟和可测试性。追问二“改写后的query语义偏离原意怎么办”这个问题考察的是你有没有兜底意识。回答要点是用embedding相似度约束改写结果低于阈值的丢弃同时保留原query一起做多路召回让重排环节决定最终顺序。注意要把“相似度阈值”说成你们实际调过的东西别只说概念。追问三“怎么判断是query理解的问题还是向量检索的问题”这个问题考察的是定位问题的能力。回答要点是做一个白盒验证把解析出的sub_query直接输入检索器如果sub_query结果明显优于原query说明query理解模块在工作如果sub_query结果也不佳问题大概率在索引或切片策略。追问四“多轮对话场景怎么做query理解”这个问题考察的是工程经验。回答要点是先做指代消解和省略补全把当前query结合最近2到3轮对话整理成独立query再做后续处理。不要无限累加历史历史太长既费token又引入噪声。追问五“子查询分解后生成结果怎么拼装”这个问题考察的是链路串起来的思考。回答要点是子查询只服务检索喂给生成的文本必须还原成整体并把意图标签传给生成模块指导结构。如果检索到多个子答案让生成模块分别总结再合并而不是把所有chunk一股脑堆给它。5. 从实际项目踩过的坑与避坑指南5.1 Query改写导致语义偏移我在项目里踩过最普通的坑是把用户问句改写得太“学术”。曾经把“模型量化后精度损失大吗”改写成“模型int8量化的准确率退化问题研究”改写结果看起来像模像样但embedding检索回来的全是学术论文用户其实只想要一个简明结论。后来做了两层防护第一层改写结果和原query算余弦相似度低于0.82就放弃改写用原query召回第二层改写推荐贴近知识库实际文风的表达而不是通用书面语。教训是改写不是越高级越好而是越贴近目标文档的分布越好。5.2 数值对比类问题的检索失效纯向量检索很难回答“哪个更大”“差多少”“成本是多少”这类问题因为数值信息通常散落在文章不同角落单靠语义相似度匹配很难把两处信息同时召回。我后来在Query理解阶段加了一个数值属性识别检测到“参数量”“显存”“成本”“速度”这类属性词就转成结构化字段交给知识库里的属性表或图结构去查。结构化查询和向量检索并行最后合并结果效果比单向量好很多。如果你们的知识库没有属性表也可以用SPL查询或倒排索引覆盖这类需求。5.3 多轮对话指代消解真实客服场景里大量query是“它支持并发吗”“这个比刚才那个快多少”。如果Query理解模块不做指代消解后面所有环节都是白搭。我的做法是维护一个全局会话对象记录历史实体和最近一次讨论的主题当前query出现代词或省略时用模板补全再进入意图识别。但有一个原则没有历史实体时宁可不消解也不要乱猜否则会检索到完全错误的方向。简单加一句“您指的是哪个模型”也比直接乱补全强。5.4 子查询膨胀与性能权衡子查询数量不是越多越好。有一段时间我在对比类query上把每个属性都拆成独立子查询结果一个query带出8个检索请求检索服务直接被压垮。后来加了两个约束一是“子查询合并”相同主题的query合并成一个比如“训练速度”和“推理速度”拆开算两个但如果知识库内容粒度不够细就合并成“速度性能”一个查询二是数量超过4个的采用层级检索先跑一个概括性query再根据第一轮top结果做二轮细查。这个方案虽然多一次往返但整体召回质量反而稳定了。最后再分享一个自己的体会我最近连续做了几个RAG项目最大的感受是Query理解是整个链路里最容易被低估、但长期收益最明显的一环。很多人把精力花在换embedding模型、调重排模型上却忽略了入口的query质量。如果你正在准备面试建议把上面这套思路完整做成一个小demo不用多复杂规则模块、实体抽取、改写和分解跑通再记录几组前后命中率的对比数据面试基本能聊到别人聊不到的深度。这个模块后续还能扩展成路由模块把不同意图分给不同检索后端配合日志分析做持续迭代。先把“用户想干什么、要找什么”这件事想清楚后面的路自然就顺了。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑