Yihui’s Blog

RAG 系统中如何处理多跳问答(Multi-hop QA)?

日期:2026-09-27
标签:#面试 #AI应用开发 #RAG #多跳问答
难度:困难
原题:牛面题目详情

一句话答案

多跳问答要找齐相互依赖的证据:把复杂问题拆成子问题,按依赖顺序检索并验证每一跳,再基于完整证据链作答和引用;证据不足时继续检索或拒答。

面试口语版(约 60 秒)

普通 RAG 用原问题检索一次,适合答案直接出现在某段文档中的场景。多跳问题则要把分散的事实连起来。例如问“项目 A 的负责人属于哪个部门”,第一跳先找负责人是谁,第二跳再用这个人名查所属部门。实现时,我会先识别问题中的依赖关系,再逐跳检索并保留每条证据的文档 ID、位置和版本;每一跳校验实体是否一致,避免把同名的人或过期记录串起来。最后只基于已验证的证据作答并附引用。评估时除答案正确率,还要看整条证据链是否都被召回,以及额外检索带来的延迟和成本。

原理拆解

为什么一次检索容易失效? 第二跳的检索词可能还不存在于原问题中,要先读到第一跳的答案才能构造下一次查询。IRCoT 论文将检索与中间推理步骤交替进行,展示了“已获得的信息决定下一步检索内容”的思路。这是一种实现路径,并非每道多跳题都必须使用链式思维提示。

以下是虚构的内部知识库示例:

步骤子问题或结论所需证据
原问题项目 A 的负责人属于哪个部门?需要两条事实
第 1 跳项目 A 的负责人是谁?→ 张敏项目负责人记录
第 2 跳张敏属于哪个部门?→ 搜索平台组人员部门记录,且确认为同一人
最终回答项目 A 的负责人张敏属于搜索平台组同时引用两条记录

子问题可以预先规划,也可以边检索边生成。若子问题互不依赖,可并行检索;上例的第二跳依赖第一跳的人名,必须顺序执行。知识图谱可按实体和关系遍历;纯文本知识库则可用迭代检索。两者都要保留原始出处,不能把模型生成的中间结论当成外部证据。

两份文档通过同一员工实体形成完整证据链

示意图使用虚构数据;DOC-01 与 DOC-02 表示两份必须同时引用的来源。

Mermaid 图解

flowchart TD
  Q[复杂问题] --> P[识别子问题和依赖]
  P --> R1[检索第 1 跳]
  R1 --> V1{证据与实体明确?}
  V1 -->|否| F[补检索或拒答]
  V1 -->|是| R2[用中间实体检索下一跳]
  R2 --> V2{证据链完整且无冲突?}
  V2 -->|否| F
  V2 -->|是| A[基于证据作答并逐条引用]

图中的证据校验需要结合来源、时效、权限、实体对齐与内容一致性;模型本身不能保证事实真实。

伪代码:带证据链的迭代检索

function answer_multihop(question, user_scope, max_hops, budget):
    plan = decompose_into_dependent_subquestions(question)
    evidence_chain = []
    known_facts = {}

    for subquestion in topological_order(plan):
        if len(evidence_chain) >= max_hops or budget.exhausted():
            return abstain("预算内未形成完整证据链")

        query = fill_dependencies(subquestion, known_facts)
        candidates = retrieve(query, filter=user_scope)
        ranked = rerank(query, candidates)
        fact, source = extract_fact_with_source(ranked)

        if source is None or not entity_matches(fact, known_facts):
            return abstain("某一跳缺少可验证证据")
        if conflicts_with_existing(fact, evidence_chain):
            return abstain("证据冲突,需要补检索或人工核验")

        evidence_chain.append(source.document_id_and_span)
        known_facts.update(fact)

    if not covers_all_required_hops(plan, evidence_chain):
        return abstain("证据链不完整")
    return generate_grounded_answer(question, known_facts, evidence_chain)

这是用于解释控制流程的伪代码。实际系统还需处理检索超时、重试、跨文档版本一致性,以及一个实体对应多条候选记录的情况。

关键细节与工程取舍

  • 证据完整性:命中其中一段不代表问题已回答;应检查每个必要跳数的 supporting facts。HotpotQA 论文介绍了句级 supporting facts,可用于评估。
  • 实体消歧:同名人、别名、历史名称可能让第二跳接错实体。优先使用稳定实体 ID、文档元数据或明确的上下文约束。
  • 权限与时效:每跳检索都带租户或用户权限过滤;记录文档版本和生效时间,避免引用无权访问或过期证据。
  • 错误传播:前一跳答错会改变后续查询。对低置信或冲突事实保留多个候选,必要时补检索;超过预算则拒答。
  • 成本与延迟:逐跳调用检索器和模型会增加时延。可以先做单跳基线,只对识别出的复杂问题启用多跳;限制最大跳数、候选数和 token 预算。EfficientRAG 论文研究了减少逐轮大模型调用的迭代检索方案。

如何评估

  1. 为每个问题标注最终答案、每一跳的子问题、所需证据和文档版本。
  2. 检索:统计每跳证据召回率,以及“所有必要证据都被召回”的完整链召回率;单个 Top-K 命中会掩盖缺失的跳数。
  3. 生成:检查答案正确性、引用是否真正支持结论、证据不足时的拒答是否合理。
  4. 系统:记录平均与尾部延迟、检索和模型调用次数、token 消耗,并与单跳 RAG 基线比较。

面试官追问

  1. 什么问题需要多跳,什么问题一次检索就够?
  2. 子问题是预先拆好,还是根据上一跳结果动态生成?
  3. 第一跳召回两个同名实体,第二跳如何避免串错?
  4. 只召回一半证据时,为什么不能让模型补全另一半?
  5. 多跳检索比单跳准确,但延迟超标,你会从哪里优化?

常见错误说法

  • “多检索几次就等于多跳。”——关键是后续查询依赖前面的证据,最终还要检查完整证据链。
  • “模型写出了推理过程,证据就齐了。”——推理文本不是外部证据;每个事实仍需对应来源。
  • “有一条引用就够了。”——结论跨越两条事实时,两条都需要可追溯的出处。

参考论文、数据集与社区项目

以下链接于 2026-09-27 核对;代码 API 和项目维护状态以后以仓库文档为准。

资料用来学什么
IRCoT 论文 / 官方代码检索与中间推理交替;看每跳如何构造查询
EfficientRAG 论文 / 官方代码迭代检索中的成本与效率设计
HotpotQA 论文 / 数据集主页多跳问题与 supporting facts 的标注和评测
LlamaIndex SubQuestionQueryEngine 源码观察子问题生成、分发和答案合成的框架抽象;具体依赖顺序仍需按场景设计

学习清单

  • 不看笔记,用 60 秒讲清“先找负责人,再找部门”的两跳流程。
  • 手写一个两跳样例,给两条证据都标注来源与版本。
  • 解释为什么完整链召回率比单段命中更能暴露多跳失败。
  • 比较预规划、动态迭代和图谱遍历各适合什么数据。
  • 用一个证据缺失或同名实体的反例说明何时拒答。
维护与整理 · Yihui在 GitHub 上编辑

继续阅读

浏览全部文章

题目模板:把用户提问写成面试与学习笔记

复制本文件的结构到对应题目文件,替换提示文字;没有解释价值的小节可以删去。不要把待填提示或未经核验的事实当作答案发布。 (填写题目原文) 日期:YYYY-MM-DD 标签:#面试 #AI应用开发 #RAG #知识工程 难度:(按题目实际难度填写) 来源:(若改写已有题目,填原题直达链接;自拟题写“用户提问”,不要…

阅读全文