乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • Spring AI 学习路径
  • 第1章 Spring AI 概述与核心理念

    • 章节导读
    • Spring AI 概述与可移植 API
    • 核心模块与依赖关系
  • 第2章 快速入门与第一个AI应用

    • 章节导读
    • 环境准备与配置
    • 第一个 AI 对话应用
  • 第3章 聊天模型与ChatClient

    • 章节导读
    • ChatClient 详解
    • ChatModel 底层抽象
    • 多轮对话与 ChatMemory
  • 第4章 提示词管理与模板

    • 章节导读
    • Prompt 与 Message 体系
    • 提示词模板与动态构建
  • 第5章 输出解析与结构化响应

    • 章节导读
    • 输出解析器与 BeanOutputConverter
  • 第6章 嵌入模型与向量存储

    • 章节导读
    • EmbeddingModel 与文本向量化
    • ETL 数据注入流水线
    • 向量存储抽象与配置
  • 第7章 检索增强生成(RAG)

    • 章节导读
    • RAG 核心机制与流程
    • QuestionAnswerAdvisor 详解
    • RAG 实战案例
  • 第8章 函数调用(Function Calling)

    • 章节导读
    • Tool 注解与函数声明
    • 函数调用实战
  • 第9章 多模态

    • 章节导读
    • 图像输入与视觉模型
    • 图像生成
  • 第10章 Advisor拦截器链

    • 章节导读
    • Advisor 链与内置拦截器
  • 第11章 MCP 协议与跨语言工具集成

    • 章节导读
    • MCP 协议深入
  • 第12章 可观测性测试与最佳实践

    • 章节导读
    • 可观测性与指标监控
    • 测试策略与 Mock 实践
    • 最佳实践与面试考点汇总

小崔看完上节手动 RAG 代码后吐槽:"每个查询都要写四步,这也太麻烦了。"白歌笑了笑:"所以说框架存在的意义就是消灭样板代码——一个 Advisor 搞定全部。"

QuestionAnswerAdvisor 详解

定义与作用

QuestionAnswerAdvisor 是 Spring AI 内置的 RAG Advisor,自动完成"检索 → 拼上下文 → 注入 Prompt"全流程。只需将 VectorStore 传入构造器并注册到 ChatClient,每次调用自动执行 RAG。

new QuestionAnswerAdvisor(vectorStore)
    // 一行代码启动 RAG,背后是三阶段自动化

对比手动实现:

维度手动 RAGQuestionAnswerAdvisor
检索手动调 VectorStore自动执行
Prompt 拼接手写字符串模板内置默认模板 + 可自定义
上下文注入手动 String.format()Advisor 链中自动注入
与 Advisors 配合需手动管理顺序自然融入 Advisor 洋葱模型

核心原理:自动注入流程

图释:QuestionAnswerAdvisor 在 adviseRequest 阶段拦截请求,自动检索 VectorStore → 拼接上下文 → 注入 Prompt,然后交给 ChatModel 生成回答。

完整示例一:最简 RAG 实现

场景说明

孔蓝要求"在现有聊天接口上加上公司知识库,不要改太多代码"。

关键代码

@Configuration
public class RagConfig {

    @Bean
    public ChatClient chatClient(ChatClient.Builder builder,
                                  VectorStore vectorStore) {
        return builder
                .defaultAdvisors(new QuestionAnswerAdvisor(vectorStore))
                .build();
    }
}
@RestController
public class StudentSystemController {

    private final ChatClient chatClient;

    public StudentSystemController(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    // 一句代码接入 RAG
    @GetMapping("/ask")
    public String ask(@RequestParam String question) {
        return chatClient.prompt()
                .user(question)
                .call()
                .content();
    }
}

运行结果

GET /ask?question=飞翔科技的办公时间是几点到几点?

响应:
「根据飞翔科技员工手册第二章:
 - 标准办公时间:9:00 - 18:00(午休 12:00 - 13:30)
 - 弹性工作制部门:核心时段 10:00 - 16:00 需在岗
 - 加班需提前报备并由部门主管审批」

关键观察:Controller 代码与普通的 ChatClient 调用没有任何区别,但回答却基于了公司内部文档——这就是 Advisor 无侵入集成的优势。

完整示例二:自定义 RAG Prompt 模板

场景说明

高英发现默认 Prompt 模板不符合运营场景的需求——她需要 AI 回复时附带文档页码来源。

关键代码

@Configuration
public class CustomRagConfig {

    @Bean
    public ChatClient chatClient(ChatClient.Builder builder,
                                  VectorStore vectorStore) {
        QuestionAnswerAdvisor advisor = new QuestionAnswerAdvisor(vectorStore);
        
        // 自定义 Prompt 模板
        advisor.setPromptTemplate("""
                你是飞翔科技的管理助手。
                
                【必须严格遵守以下规则】
                1. 仅基于以下文档片段回答问题
                2. 每条回答末尾标注来源页码(如 [员工手册-P23])
                3. 如果文档中没有相关信息,回复「此问题超出我的知识范围」
                
                相关文档:
                {context}
                
                用户问题:{question}
                
                回答:
                """);
        
        return builder
                .defaultAdvisors(advisor)
                .build();
    }
}

运行结果

GET /ask?question=怎么申请报销?

响应:
「报销流程如下:
 1. 填写《费用报销单》并附发票原件
 2. 直属主管签字审批
 3. 财务部审核(3 个工作日内)
 4. 金额 >5000 元需副总加签
 [员工手册-P47]」
 ↑ 附带页码来源,高英可以直接验证

易错场景与面试考点

易错场景一:VectorStore 为 null 导致 NPE

// ❌ 错误:VectorStore 未配置,注入为 null
@Bean
public ChatClient chatClient(ChatClient.Builder builder) {
    return builder
            .defaultAdvisors(new QuestionAnswerAdvisor(null))  // NPE!
            .build();
}

问题分析

VectorStore 需要通过 PGVector 等具体实现来提供。如果不引入 spring-ai-pgvector-store-spring-boot-starter 依赖或未配置连接,VectorStore Bean 不会创建。

// ✅ 正确:先确保 PGVector 配置正确
// application.yml
spring:
  ai:
    vectorstore:
      pgvector:
        index-type: HNSW
        distance-type: COSINE_DISTANCE
        dimensions: 1536
        initialize-schema: true
  datasource:
    url: jdbc:postgresql://localhost:5432/vectordb
    username: postgres
    password: ${PG_PASSWORD}

面试高频题

Q1:QuestionAnswerAdvisor 与 Advisor 链的协作方式是什么?

QuestionAnswerAdvisor 实现了 RequestResponseAdvisor 接口,在 adviseRequest 阶段从 VectorStore 检索文档并注入 Prompt。它可以与其他 Advisor(如 ChatMemoryAdvisor)组合使用,执行顺序由注册顺序决定。

Q2:如何自定义 RAG Prompt 模板中的占位符?

默认模板使用 {context} 和 {question} 两个占位符。通过 advisor.setPromptTemplate() 传入自定义模板字符串,框架会自动将检索结果填充到 {context},将用户问题填充到 {question}。

本章小结

  • QuestionAnswerAdvisor 自动完成 RAG 三步:检索 → 拼接 → 注入
  • 通过 defaultAdvisors 注册后,所有请求自动 RAG 增强
  • 支持自定义 Prompt 模板(含 {context} 和 {question} 占位符)
  • 务必确保 VectorStore 已正确配置,否则抛出 NPE
上一页
RAG 核心机制与流程
下一页
RAG 实战案例