Skip to content

什么是上下文查询增强?它有什么作用?如何基于 Spring AI 实现上下文查询增强来处理无关问题? ​

  • 标签:后端、编程导航

🏛 业务架构师 ​

上下文查询增强:在检索前先判断"这个问题需不需要走知识库"——用模型对问题做一次轻量分析:与知识库主题相关才执行 RAG,无关(闲聊、通用常识、算术)则跳过检索直接让模型回答。

它解决的问题是个成本与体验的双重浪费:

  • 成本浪费:任何问题都检索一遍——"你好""帮我写个生日祝福"也去知识库捞一把,无意义的向量检索 + 塞进上下文的无关文档都是 token 白烧(尤其上下文按 token 计费,无关文档可能占几千 token);
  • 体验劣化:更糟的是无关文档污染上下文——模型被塞了一堆"请假制度"片段再回答祝福语,输出常常夹带莫名其妙的引用,检索来的噪声比没有检索更伤答案质量。

基于 Spring AI 的实现:Advisor before 阶段加一次分类判断(prompt:"判断该问题是否与[知识库主题]相关,输出 JSON {relevant: bool, reason}",结构化输出解析)——相关→注入 RAG 上下文;无关→透传。用小模型跑这个判断(分类任务不需要旗舰),延迟增加可控制在 200ms 内。

业务边界设计:判断不是二值开关——我的实现输出三档(强相关走 RAG / 弱相关走 RAG+提示"可能不相关" / 无关直答),宁可多检一次不可错杀(把该检索的判成闲聊=漏答,比多花一次检索贵)。

一句话:这是 RAG 管线的路由器——让知识检索用在刀刃上,每一分 token 成本都花在与知识相关的问题上。

🏗 系统架构师 ​

上下文查询增强 = 检索后对候选知识做"相关性判断与增强过滤":先判别"这个问题需不需要 RAG",再对检索到的内容做与问题的相关性校验/摘要压缩,最后拼装进上下文。专门解决无关问题污染上下文的问题。

作用:

  • 拒答脏检索:知识库里没有的问题(闲聊、超纲提问),硬拼一堆不相关 chunk 进 Prompt,模型容易被带偏("强行引用"幻觉)——增强层判断低相关就丢弃检索结果,让模型基于通用知识回答或明确说不知道;
  • 上下文预算控制:chunk 摘要压缩 + 去重,防止上下文爆 token。

Spring AI 实现思路(Advisor 内两阶段):

java
// 阶段1:路由判断——这个问题是否与知识库相关(结构化输出枚举)
Related related = chatClient.prompt()
    .user(question + " 判断该问题是否与[知识库主题]相关")
    .call().entity(Related.class);
if (!related.relevant()) { 直接走普通对话,跳过检索; }
// 阶段2:检索后过滤——对每个 chunk 做相关性打分(LLM 或交叉编码器)
// score < 阈值的丢弃;相关 chunk 按重要性排序、超限则摘要压缩

工程权衡:判断调用增加延迟(用轻量模型、可缓存高频问题判断结果);阈值要按验证集调(宁可少拼不可错拼——不相关上下文的伤害大于没有上下文)。这与网关的"请求校验"同构:入口处把不合规数据拦住,比下游消化它便宜。

💻 全栈开发专家 ​

上下文查询增强(我项目里叫"相关性门控")= 在 RAG 前先判断问题与知识库是否相关,无关问题直接走闲聊,不检索。

为什么需要:知识库助手上线后大量闲聊/无关问题("你好"、"帮我写周报")也会触发向量检索——浪费 token、拖慢响应,检索回来的无关片段还会污染 prompt 导致回答跑偏。

Spring AI 实现(两层判断):

java
public class ContextGateAdvisor implements CallAdvisor<...> {
    public ChatClient.ChatClientRequest adviseRequest(req, chain) {
        String q = req.prompt().getUserMessage().getText();
        // 层1:向量相似度门控——查一下 top1 分数
        List<Document> hits = vectorStore.similaritySearch(
            SearchRequest.builder().query(q).topK(1)
                .similarityThreshold(0.55).build());   // 阈值之下视为无关
        if (hits.isEmpty()) {
            // 标记跳过后续 RAG,直接普通对话模型回复
            req = req.mutate().context(ctx -> ctx.put("skip_rag", true)).build();
        }
        return chain.nextAdvice(req);
    }
}

层 2(可选,更准但更贵):小模型分类器判断意图(闲聊/知识问答/工具任务),路由到不同处理链。

实测数据:门控后约 35% 请求不再触发检索,平均响应时间降 20%,RAG 误检引起的答非所问工单明显减少。

踩坑:阈值 0.55 是用评估集调出来的(不同 embedding 模型分布不同,别照抄);门控要做成 Advisor 链最前面的"路由",失败时默认放行检索(宁可多查不能挡住正常问题)。