首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >用 Python 实现查询分解提升多跳 RAG 检索召回

用 Python 实现查询分解提升多跳 RAG 检索召回

原创
作者头像
小凡geo用户12683298
发布2026-09-03 18:21:42
发布2026-09-03 18:21:42
650
举报

多跳问题需要组合多个文档片段才能回答,直接用原问题做向量检索容易漏掉关键子信息。查询分解先把复杂问题拆成若干子查询,分别检索后再合并,召回完整度明显提升。

一、为什么原查询检索会漏

向量检索比较查询向量与文档向量的相似度。问题"对比 A 和 B 的定价并给出选型建议"包含三个子意图:A 定价、B 定价、选型维度。单一向量只能逼近其中一个,其余子信息可能落在不同段落,直接检索会丢。

二、实现

python

代码语言:javascript
复制
# 依赖:pip install sentence-transformers==2.7.0 openai==1.30.0 numpy==1.26.4
import os
import numpy as np
from sentence_transformers import SentenceTransformer
from openai import OpenAI

client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
embedder = SentenceTransformer("BAAI/bge-small-zh")

docs = [
    "产品A定价每月 299 元,按年付八折。",
    "产品B定价每月 199 元,无年付折扣。",
    "选型建议:预算紧选 B,要稳定性选 A。",
    "产品A支持私有化部署,产品B仅SaaS。",
]

doc_vecs = embedder.encode(docs, normalize_embeddings=True)

def decompose(query: str):
    resp = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user",
                   "content": f"把下面问题拆成2~3个子查询,每行一个:{query}"}],
    )
    return [line.strip("- ").strip()
            for line in resp.choices[0].message.content.splitlines()
            if line.strip()]

def retrieve(sub_q: str, k: int = 2):
    qv = embedder.encode([sub_q], normalize_embeddings=True)
    scores = doc_vecs @ qv[0]
    return [docs[i] for i in np.argsort(-scores)[:k]]

if __name__ == "__main__":
    subs = decompose("对比产品A和B的定价并给选型建议")
    for s in subs:
        print("子查询:", s)
        print("召回:", retrieve(s))

三、输出样例

python

代码语言:javascript
复制
子查询: 产品A的定价是多少
召回: ['产品A定价每月 299 元,按年付八折。', '产品A支持私有化部署,产品B仅SaaS。']
子查询: 产品B的定价是多少
召回: ['产品B定价每月 199 元,无年付折扣。', '选型建议:预算紧选 B,要稳定性选 A。']
子查询: 如何根据定价做选型
召回: ['选型建议:预算紧选 B,要稳定性选 A。', '产品A支持私有化部署,产品B仅SaaS。']

原查询直接检索可能只召回到"选型建议"一条;分解后三个子查询分别召回到 A 定价、B 定价、选型维度,合并即得完整证据链。

四、关键参数

  1. 子查询数量:2~3 个。过多引入噪声,过少覆盖不全。
  2. 子查询生成模型:轻量模型(gpt-4o-mini)即可,不必用大模型,节省延迟与成本。
  3. 合并策略:各子查询 top-2 去重合并,再送进重排或大模型,避免片段冗余。

五、适用边界与工程注意

查询分解对单跳事实类问题增益有限,主要价值在多跳、对比、综述类问题。线上 serving 时,分解会增加一次大模型调用(约 300~800ms 额外延迟),可通过缓存高频问题的子查询模板缓解。落地前建议在固定多跳样本上对比原检索与分解检索的 context_recall 指标,确认提升后再接入。

将查询分解接入检索链路,RAG 系统可从"单向量匹配"演进为"多子问题并行召回",多跳问答的完整性上限随之提升。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、为什么原查询检索会漏
  • 二、实现
  • 三、输出样例
  • 四、关键参数
  • 五、适用边界与工程注意
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档