在构建基于外部知识的问答系统时,用户的问题经常不是一句话能回答清楚的。比如询问某家公司收购对手后股价变化,就需要先确认收购对象、再查交易时间、最后比对前后股价。多跳检索正是为解决这类复合问题而设计,它把原始问题分解成若干子问题,每一跳利用上一跳的结果缩小搜索范围,最终拼出完整证据链。

为什么单轮检索处理不了复杂问题
传统检索增强生成做法会把用户问题直接向量化,再去知识库里找最相近的几段文本。这种方式在问题只依赖单一事实时表现不错,但面对隐含多个约束或需要推理的问题就会失效。例如提问“2020年营收最高的手机厂商,其创始人毕业于哪所大学”,这里至少包含两个实体抽取与两次文档定位,直接检索很容易只抓到营收排名而漏掉人物背景。
更关键的是,很多证据分布在异构来源中:一份财报提供营收数字,另一篇访谈提及创始人学历。单轮检索的相似度计算无法预判这种跨文档依赖,模型若只看到前者就会胡乱补全后者。多跳检索通过显式分解,让每一跳目标更单纯,检索器压力变小,召回精度自然提高。
从评价指标看,在公开多跳数据集上,单轮检索的答案为完全正确的比例常低于四成,而引入问题分解后可提升十五到二十个百分点。这证明分解动作本身就在降低语义歧义,使后续阅读器更容易抽取准确答案。
子问题生成与跳转逻辑的实现方式
分解复杂问题通常有两种路线。其一是基于提示工程,让大语言模型输出结构化子问题列表,并标注每个子问题依赖的前驱编号;其二是训练一个专门的分解网络,输入问题输出有向无环图。实际项目中,提示工程因成本低而被广泛采用,只要给定清晰示例,模型能稳定产生如“子问题1:A公司2020年营收是多少”“子问题2:A公司创始人是谁”这样的序列。
跳转逻辑决定下一跳拿什么去检索。最常见的是填充式:把上一跳答案嵌入到模板,形成新查询。比如子问题2实际发送给检索器的是“A公司创始人毕业于哪所大学”,其中A公司来自子问题1的答案。如果上一跳失败,则需要回退或换关键词重试,这部分可用简单规则或小规模分类器控制。
下面伪代码展示了一个基础循环。它先调用分解函数,再迭代执行检索与抽取,把累积上下文传给最终合成阶段。注意异常处理保证了某一跳为空时不直接崩溃,而是记录缺失并继续。
def multi_hop_answer(question, retriever, llm):
sub_questions = llm.decompose(question)
evidence = []
for sq in sub_questions:
if sq.depends_on:
sq.text = sq.template.format(*[evidence[i] for i in sq.depends_on])
docs = retriever.search(sq.text, top_k=3)
ans = llm.extract(docs, sq.text)
if ans is None:
evidence.append('')
continue
evidence.append(ans)
return llm.synthesize(question, evidence)
该实现虽简单,但揭示了多跳的核心:状态在跳与跳之间传递。生产环境可加入缓存避免重复检索相同子问题,也可并行无依赖的子问题以降延迟。无论怎么优化,分解质量决定了上限,因此需在提示或训练数据上多下功夫。
答案融合与误差传播的控制策略
多跳得到多个子答案后,如何合成最终响应直接影响用户体验。最简单是由模型把证据串起来写一段话,但若中间某跳错了,错误会被带进结论。为此可引入置信度评估:每跳抽取时让模型输出概率或支持句编号,融合阶段给低置信证据降权。
另一种策略是反向验证。得到最终答案后,再用答案反推是否能回答原问题,若不能则触发补充检索。这类似人类复查,能捕获因为分解遗漏导致的断链。下表对比两种常见融合思路的优劣:
| 策略 | 优点 | 缺点 |
|---|---|---|
| 直接拼接合成 | 延迟低,实现易 | 误差累积明显 |
| 置信加权加验证 | 准确率更高 | 计算开销大 |
在代码层,可把每跳结果存为带分数的字典,合成前按分数过滤。示例片段如下,展示如何丢弃低于阈值的证据:
def fuse(evidence_list, threshold=0.5):
kept = []
for item in evidence_list:
if item.get('score', 1.0) >= threshold and item['answer']:
kept.append(item['answer'])
if not kept:
return '无法从已有证据得出结论'
return ';'.join(kept)
控制误差还要从分解端入手。如果原问题被拆得过细,跳数多则出错机会倍增;拆得过粗又退化成单轮。经验上,把原问题转为不超过四跳、且每跳对应一个明确槽位填充,是较稳的配置。配合日志追踪每跳输入输出,团队能快速定位是检索器还是分解器的问题。
落地时的工程权衡与适用边界
多跳检索并非万能。对于简单事实型提问,强行分解反而增延迟且无收益。因此在入口处加一层路由分类器,判断问题类型再决定是否走多跳,是常见做法。分类器可用小模型,以准确率换整体效率。
知识库规模也影响收益。当文档量小时,单轮检索已能覆盖多数证据,多跳的提升有限;而在企业级海量文档、跨系统场景下,分解带来的路径引导价值放大。此外,若业务允许一定延时,可把多跳改为异步流水线,用消息队列解耦各跳,方便横向扩容。
最后要注意隐私与权限。每一跳检索都应携带用户上下文令牌,避免子问题拼接后越权访问。把权限校验放进检索器接口而非外层,能减少遗漏。综上,多跳检索是分解复杂问题的有效手段,但需结合路由、融合与工程管控,才能真正提升问答系统的可靠程度。
multi_hop_retrievalquestion_decompositionretrieval_augmented_generation修改时间:2026-08-17 10:20:36