Spring AI 系列之十 - RAG-进阶QuestionAnswerAdvisor

发布于:2025-07-15 ⋅ 阅读:(24) ⋅ 点赞:(0)

之前做个几个大模型的应用,都是使用Python语言,后来有一个项目使用了Java,并使用了Spring AI框架。随着Spring AI不断地完善,最近它发布了1.0正式版,意味着它已经能很好的作为企业级生产环境的使用。对于Java开发者来说真是一个福音,其功能已经能满足基于大模型开发企业级应用。借着这次机会,给大家分享一下Spring AI框架。

注意由于框架不同版本改造会有些使用的不同,因此本次系列中使用基本框架是 Spring AI-1.0.0,JDK版本使用的是19
代码参考: https://github.com/forever1986/springai-study

通过上一章对RAG的入门进行讲解,相信你对于RAG的场景其实已经比较熟悉,同时也了解到Spring AI对RAG有比较好的封装,这一章来讲一下Spring AI的RAG的实现底层原理

1 Spring AI的RAG实现

Spring AI 通过提供模块化架构来支持 RAG 技术,使用户能够自行构建自定义的 RAG 流程,或者使用内置的 RAG 流程通过 Advisor API 进行操作。其底层都是基于Advisors接口(注意:关于Advisors后续会讲一下这方面的原理,这里先知道RAG是基于Advisors实现即可

而基于Advisors接口上,实现了2个用于RAG的类,分别是QuestionAnswerAdvisorRetrievalAugmentationAdvisor

1.1 QuestionAnswerAdvisor源码分析

1)QuestionAnswerAdvisor类实现了BaseAdvisor接口,该BaseAdvisor接口主要有2个方法before和after,这个两个方法分别是调用Advisor的核心方法之前和之后执行的方法

2)QuestionAnswerAdvisor是相对简单的RAG,其主要实现都在before方法,如下图:

在这里插入图片描述

3)SearchRequest是一个封装的查询

在这里插入图片描述

说明:有几个参数需要关注
1)query:查询的问题
2)topK:返回前几个文档
3)similarityThreshold:相似度,大于等于这个值之上的相似度才会匹配
4)filterExpression:元数据的过滤条件,主要是过滤Document的metadata元数据属性

1.2 RetrievalAugmentationAdvisor

QuestionAnswerAdvisor对于RAG来说还是相对比较简单。如果看过本人之前写过《检索增强生成RAG系列》的文章,可以知道要做好一个RAG,需要做的内容还是比较多。一个好的RAG对于每一步都要做一些优化,比如问题优化、重排等功能。而RetrievalAugmentationAdvisor则比较好的将这些优化做个结构化步骤,关于Spring AI中的RetrievalAugmentationAdvisor内容,下章再讲。这一章先了解QuestionAnswerAdvisor,下面将演示QuestionAnswerAdvisor的一些常见用法和配置。

2 QuestionAnswerAdvisor示例演示

代码参考lesson11子模块下面的simple-advisor子模块

示例说明:通过设置查询条件,使用QuestionAnswerAdvisor实现文档存入,查询过滤,调用大模型回答用户问题

1)在lesson11子模块下,新建simple-advisor子模块,其pom引入如下:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-zhipuai</artifactId>
    </dependency>
    <!-- 引入向量数据库插件 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-advisors-vector-store</artifactId>
    </dependency>
</dependencies>

2)新建配置application.properties文件

# 聊天模型
spring.ai.zhipuai.api-key=你的智谱的API KEY
spring.ai.zhipuai.chat.options.model=GLM-4-Flash-250414
spring.ai.zhipuai.chat.options.temperature=0.7

3)创建向量数据库的配置VectorStoreConfig:

import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class VectorStoreConfig {

    /**
     * @param embeddingModel - 这里如果没有特殊配置,默认使用的是你引入model的embedding模型
     */
    @Bean
    public VectorStore vectorStore(EmbeddingModel embeddingModel){
        SimpleVectorStore simpleVectorStore = SimpleVectorStore.builder(embeddingModel).build();
        simpleVectorStore.add(getDocuments());
        return simpleVectorStore;
    }

    private static List<Document> getDocuments(){
        Document document1 = new Document("""
                ChatGLM3 是北京智谱华章科技有限公司和清华大学 KEG 实验室联合发布的对话预训练模型。ChatGLM3-6B 是 ChatGLM3 系列中的开源模型,在保留了前两代模型对话流畅、部署门槛低等众多优秀特性的基础上,ChatGLM3-6B 引入了更多的特性。\n
                北京智谱华章科技有限公司是一家来自中国的公司,致力于打造新一代认知智能大模型,专注于做大模型创新。
                """);
        document1.getMetadata().put("source", "官方网站");

        Document document2 = new Document("""
                OpenAI,是一家开放人工智能研究和部署公司,其使命是确保通用人工智能造福全人类。创立于2015年12月,总部位于美国旧金山。现由营利性公司OpenAI LP及非营利性母公司OpenAI Inc组成。
                """);
        document2.getMetadata().put("source", "官方网站");

        Document document3 = new Document("""
                ChatGLM3是由智谱清言开发的,是北京智谱华章科技有限公司推出的生成式AI助手,于2023年8月31日正式上线。 2024年8月29日,智谱清言APP支持视频通话功能。
                智谱清言基于智谱AI自主研发的中英双语对话模型还开发了ChatGLM、ChatGLM2、ChatGLM3、ChatGLM4等大模型。
                """);
        document3.getMetadata().put("source", "官方网站");

        Document document4 = new Document("""
                ChatGLM3 是由清华大学技术成果转化企业智谱AI研发的支持中英双语的对话机器人,基于千亿参数基座模型GLM架构开发。该模型通过多阶段训练流程形成通用对话能力,具备问答交互、代码生成、创意写作等功能,其开源版本ChatGLM-6B自2023年3月启动内测以来已形成广泛影响力。\n
                截至2024年3月,智谱AI通过该技术实现了2000多家生态合作伙伴的应用落地,并在多模态技术上持续突破,推出了视频生成等创新功能。清华大学是中国排名top2的学校。
                """);
        document4.getMetadata().put("source", "百度百科");

        List<Document> list = new ArrayList<>();
        list.add(document1);
        list.add(document2);
        list.add(document3);
        list.add(document4);
        return list;
    }
}

4)创建演示类RAGController :

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.filter.FilterExpressionBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RAGController {

    private ChatClient chatClient;

    public RAGController(ChatClient.Builder chatClientBuilder, VectorStore vectorStore) {
        PromptTemplate promptTemplate = PromptTemplate.builder()
                .template("""
                        {query}
                        参考信息如下,使用“---------------------”标识包裹在里面的为参考信息。
                        
                        ---------------------
                        {question_answer_context}
                        ---------------------
                        
                        鉴于当前的参考信息以及所提供的历史信息(而非任何先入为主的了解),请回复用户评论。如果答案不在上述背景信息中,告知用户您无法回答该问题。
                        """)
                .build();
        var b = new FilterExpressionBuilder().eq("source", "官方网站").build();
        QuestionAnswerAdvisor questionAnswerAdvisor = QuestionAnswerAdvisor.builder(vectorStore)
                .promptTemplate(promptTemplate)
                .searchRequest(SearchRequest.builder()
                        .similarityThreshold(0.2) //相似度阈值,只有大于等于该值才会被返回(取值范围:0-1),默认是0(没有相似度排除)
                        .topK(2) // 返回相似度排名前2的文档,默认是4
                        .filterExpression(b) // 通过文档的元数据过滤
                        .build())
                .build();
        this.chatClient = chatClientBuilder
                // 通过Advisors方式,对向量数据库进行封装
                .defaultAdvisors(questionAnswerAdvisor)
                .build();
    }

    /**
     * @param message 问题
     */
    @GetMapping("/ai/rag")
    public String rag(@RequestParam(value = "message", required = true, defaultValue = "ChatGLM3是哪个国家的大模型?") String message) {
        return this.chatClient.prompt()
                .user(message)
                .call()
                .content();
    }

}

5)新建启动类Lesson11SimpleApplication :

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Lesson11SimpleApplication {

    public static void main(String[] args) {
        SpringApplication.run(Lesson11SimpleApplication.class, args);
    }

}

6)演示结果:

http://localhost:8080/ai/rag

在这里插入图片描述

说明:这个示例主要是通过对QuestionAnswerAdvisor的一些设置进行验证
1)similarityThreshold设置0.2,这样对于一些极其不相关文档排除掉
2)topK设置2,只返回2份文档(如果不配置,这里会返回3份文档)
3)filterExpression设置过滤元数据,source=官方网站(如果这里不配置,会匹配到第4份文档)

7)通过debug查看,这里可以通过debug一下QuestionAnswerAdvisor的122行,可以看到如下只返回2份文档

在这里插入图片描述

结语:本章讲解的简单版RAG的实现QuestionAnswerAdvisor,并对其内部原理进行解析。但是对于一个真正的RAG来说,QuestionAnswerAdvisor还是远远没法满足条件。下一章将讲解RetrievalAugmentationAdvisor。


网站公告

今日签到

点亮在社区的每一天
去签到