在实际应用中,用户提出的问题往往不是单一、直接的简单问句,而是包含了多个隐含条件、需要对比分析或层层递进的复杂需求。例如,“公司今年在华东地区的销售策略调整了哪几个方面?与去年相比最大的不同是什么?”这个问题如果直接整体检索,很容易只召回其中一部分内容,甚至完全遗漏“去年策略”这个关键对比维度,导致回答片面或出现幻觉。
为什么需要子问题拆分
直接对复杂问题进行向量检索,存在两个天然局限:一是嵌入模型很难将多层次、多主题的意图压缩到一个稠密向量中而不丢失信息;二是整个知识库中可能根本不存在一段能同时覆盖所有子主题的文本,却分散在多个文档的不同章节。强行用原问题检索,往往只能命中其中一个角度。
将复杂问题拆解为多个更聚焦的子问题,分别进行检索,再汇总结果生成回答,可以从根本上提升召回率和答案的完整性。这一策略在需要多跳推理、比较分析、总结多个来源信息的场景中尤其有效。
拆解的基本方法
拆分的关键在于识别问题中的逻辑结构和隐含子任务。常见的拆分模式包括:
- 按实体拆分:如“请对比产品A和产品B的续航时间”,可拆为“产品A的续航参数”“产品B的续航参数”,分别检索后交叉对比。
- 按时间/版本拆分:如“今年和去年的退换货政策有什么变化?”,拆为“今年退换货政策”“去年退换货政策”,匹配后再提炼差异。
- 按条件/场景拆分:如“华东线下门店和线上渠道的会员积分规则有何区别?”,拆为“华东线下会员积分规则”“线上渠道会员积分规则”。
- 按推理步骤拆分:如“去年销量最高的区域,今年其主力产品线有调整吗?”,先拆出“去年各区域销量数据→找出最高区域”,再基于结果拆出“该区域今年产品线调整情况”。
拆分既可以由大模型在生成阶段前自动完成(比如用一个专用的提示要求模型把复杂问题分解为子问题列表),也可以预先人工梳理常见高频复杂问题模板。实践中,使用一个轻量级的LLM调用专门做“问题拆解”往往效果最好,生成的子问题更自然、覆盖面更全。
配合多路检索执行
获得子问题列表后,可以为每个子问题触发独立的检索请求,每条检索路径返回各自最相关的文档片段。最后将所有检索到的片段整合去重,作为统一的上下文喂给最终生成模型。为了避免上下文过长,通常会对多路检索结果按相关性做二次排序,并截取总 Token 上限内的最优内容。
实用示例
仍以公司内部助手为例。员工提问:“新产品线的性能提升体现在哪些方面?是否仍然兼容旧款接口?”
直接检索此问题可能会找到泛泛的产品介绍。采用拆分策略后,自动或手动拆为:
- “新产品线性能提升的具体指标和技术方案”
- “新产品与旧款接口的兼容性说明”
两路检索分别从《性能白皮书》和《技术规格兼容性列表》中召回精准片段。生成时综合这些信息,回答:“性能上,CPU算力提升了40%,内存带宽翻倍;兼容性方面,保留了旧版A/B接口,但C接口已替换为新一代标准。详见各自文档。”这样既准确又完整,避免了漏答。
注意点
- 子问题拆分并非越多越好,过多的检索路径可能引入噪声,甚至超出上下文窗口。通常根据问题复杂度控制在2-5个子问题,并保证每个子问题都可以独立被知识库回答。
- 子问题的表述要尽量与原文档术语对齐,避免用过于口语化的表达,以提升检索命中率。
- 最终生成时,需要提示模型明确区分信息来自不同路径,避免把不同语境下的碎片强行拼凑。
通过子问题拆分与多路检索的结合,RAG 系统能从简单的单点问答跃升为能处理多角度、多文档综合分析的高级助手,极大扩展了其在真实业务分析、报告生成等复杂场景下的可用性。