Spring AI 拦截器实现 RAG 检索的两种方式

文章目录

前言

在 Spring AI 中,Advisor API 本质上就是对话调用链上的拦截器。它位于用户 Prompt 和大模型调用之间,可以在请求发出前对 Prompt 做增强,也可以在响应返回后做处理。

用 Advisor 实现向量数据库的 RAG 检索,核心是 QuestionAnswerAdvisor。这个内置拦截器的工作方式很直接:拦截用户 Prompt,在绑定的 VectorStore 中执行相似度搜索,把检索到的文档片段拼进 Prompt 的 {question_answer_context} 占位符,再交给模型生成答案。

根据检索范围的固定还是动态 ,有两种实现方式。两者都通过 defaultAdvisors 注册,区别只在调用时是否额外传入过滤参数。

方式一:全局共用一份知识库

QuestionAnswerAdvisor 在构建时就绑定了 VectorStore,注册为 defaultAdvisors 后,每次对话自动走同一个检索逻辑,对整个向量库执行相似度搜索。

java 复制代码
@Configuration
public class RagConfig {

    @Bean
    public QuestionAnswerAdvisor questionAnswerAdvisor(VectorStore vectorStore) {
        return QuestionAnswerAdvisor.builder(vectorStore)
            .searchRequest(SearchRequest.builder()
                .topK(4)
                .similarityThreshold(0.8)
                .build())
            .build();
    }

    @Bean
    public ChatClient chatClient(ChatModel chatModel, 
                                 QuestionAnswerAdvisor questionAnswerAdvisor) {
        return ChatClient.builder(chatModel)
            .defaultAdvisors(questionAnswerAdvisor)   // 全局注册
            .build();
    }
}

调用时不需要在每次 prompt() 里重复指定任何东西:

java 复制代码
String answer = chatClient.prompt()
    .user("Spring AI 的 Advisor 是什么?")
    .call()
    .content();

topK 控制返回的文档片段数量,similarityThreshold 是相似度得分下限。两者的配合逻辑是:先按阈值过滤低质量候选,再取前 K 个 。similarityThreshold 设为 0.8 意味着只接受相似度 80 分以上的文档片段。

这种方式适合所有对话共享同一套知识的场景,配置最简单,但无法按用户或业务类型收窄检索范围。

方式二:每次对话动态过滤

同样注册为 defaultAdvisors,但允许在运行时通过 FILTER_EXPRESSION 参数 覆盖或细化检索范围。过滤表达式采用类似 SQL 的语法,可移植于所有 VectorStore 实现。

java 复制代码
@Bean
public ChatClient chatClient(ChatModel chatModel, VectorStore vectorStore) {
    QuestionAnswerAdvisor qaAdvisor = QuestionAnswerAdvisor.builder(vectorStore)
        .searchRequest(SearchRequest.builder()
            .topK(4)
            .build())
        .build();

    return ChatClient.builder(chatModel)
        .defaultAdvisors(qaAdvisor)   // 同样注册为默认 Advisor
        .build();
}

调用时传入过滤条件:

java 复制代码
String answer = chatClient.prompt()
    .user("我的订单有什么问题?")
    .advisors(a -> a.param(
        QuestionAnswerAdvisor.FILTER_EXPRESSION,
        "user_id == '12345' && type == 'order'"))
    .call()
    .content();

底层会先通过元数据字段缩小候选集,再在候选集内执行向量相似度计算。如果同时在 Advisor 构建时设置了基础过滤表达式,运行时传入的表达式优先级更高,会覆盖构建时的配置。

这种方式适合多租户、多业务线、需要权限隔离的场景,同一份向量库可以为不同对话提供不同范围的检索结果。

两种方式的核心区别

两种实现都使用了 defaultAdvisors ,QuestionAnswerAdvisor 都是通过 ChatClient.builder().defaultAdvisors(...) 注册的。区别只在于调用时是否额外传入运行时参数来收窄检索范围。

维度 方式一:全局共用 方式二:动态过滤
defaultAdvisors 有 有
检索范围 整个向量库 过滤后的子集
调用时的 advisors() 不传 传 FILTER_EXPRESSION
隔离能力 无 按用户/租户/业务类型隔离
适用场景 统一知识库问答 多租户、多业务线、权限控制

方式一是"注册后就固定",方式二是"注册后每次还能改"。

一个配置层面的细节

QuestionAnswerAdvisor 的默认 similarityThreshold 是 0.0,意味着接受所有匹配结果,不管相似度多低。在生产环境中,这通常不是想要的行为。设置一个合理的阈值,可以让模型在检索不到相关内容时更诚实地表示"不知道",而不是基于弱相关片段给出看似自信的错误回答。

阈值和 topK 的交互也需要留意:高阈值配高 topK,如果没有任何文档越过阈值线,模型会退回使用自己的知识库回答;阈值越低,越多的低质量匹配会进入 Prompt,可能干扰模型判断。


如需深入了解Agent核心架构设计、工具调用机制、记忆与上下文工程、多智能体协作模式、规划与推理策略、LangGraph状态图原理、中间件扩展体系、生产级Agent落地实践等内容,请持续关注本专栏《Agent智能体开发从入门到精通》系列文章。

相关推荐
南归北隐4 小时前
Spring AI Alibaba Graph框架实现RAG私有知识库问答
java·后端·spring·spring ai·java rag实现
EatFan15 小时前
2026 后端 AI 工程化:Spring AI 2.0、MCP 协议与 Agent 内嵌如何收进 Java 生产系统
java·人工智能·spring·agent·spring ai·spring boot 3·mcp
Sayai17 小时前
MCP Server 开发实战:Spring AI 把后端日志查询暴露给 AI Agent(7 条设计原则与踩坑实录)
java·人工智能·ai agent·spring ai·mcp
中间件XL2 天前
agent框架langgraph4j原理源码分析 图 III 执行图1原理分析
智能体·spring ai·langgraph4j·ai agent框架·图执行
海南java第二人3 天前
用 Redis 实现向量数据库:从原理到 Spring AI 实战
spring ai
EatFan4 天前
2026 后端 AI 集成三条落地路径:Spring AI 2.0、MCP 协议与旁路服务怎么选
java·人工智能·spring boot·spring·大模型·spring ai·mcp
EatFan7 天前
从云原生到AI原生:2026后端架构“三驾马车”(事件驱动、虚拟线程、AI Agent内嵌)演进解析
spring boot·云原生·架构·虚拟线程·ai-native·ai agent·spring ai
智码看视界11 天前
Day81-AI安全攻防:Prompt注入攻击与防御实践
ai安全·大模型安全·spring ai·越狱攻击·prompt注入·防御体系
南归北隐11 天前
Spring AI Alibaba Graph框架实现Tools工具调用
java·后端·spring·spring ai·spring ai tools