掘金 人工智能 06月18日 10:22
Spring AI 基于 RAG 构建本地知识库问答助手
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文介绍了如何使用 Spring AI 在 Java 环境下构建 RAG(Retrieval-Augmented Generation)系统,实现对私有知识库的问答。通过 Spring AI 提供的便捷封装,开发者能够轻松地集成文档解析、Embedding、向量存储和检索等功能,并结合 OpenAI 的 GPT-4.1 模型进行问答。文章详细阐述了 RAG 的核心流程,包括私有知识的准备、Spring Boot 项目的搭建,以及关键代码的实现,最终完成一个可运行的 RAG 系统。

💡 RAG 是一种通过检索增强来提升大模型性能的技术,它通过结合私有知识库,减少大模型的幻觉,提高回答的准确性。

📚 Spring AI 为 Java 开发者提供了 RAG 的便捷实现,它封装了 DocumentReader、TextSplitter 等组件,支持多种文件格式和向量库,简化了 RAG 的构建过程。

🛠️ Spring AI RAG 的实现流程包括:文档解析、Embedding、向量存储和检索、以及结合 OpenAI 的 GPT-4.1 模型进行问答。文章详细介绍了如何使用 Tika 解析文档,并使用 OpenAI 的 text-embedding-3-small 模型进行 Embedding。

💾 本文使用 Milvus 作为向量数据库,并提供了 Spring Boot 项目的依赖配置和代码示例,展示了如何将解析后的文档持久化到 Milvus 中。

💬 文章还展示了如何构建问答服务,通过 ChatClient 和 QuestionAnswerAdvisor 实现对私有知识库的问答功能,并提供了一个测试 Controller 作为入口。

 

一、Spring AI & RAG

RAG 检索增强,最常见的实现方式便是向量检索增强,通过分析读取本地私有化知识内容,Embedding 后存储至VectorStore 中做为知识库。当用户发起提问时,通过向量余弦距离相似度等方式,召回知识库中的相似内容作为上下文背景组装至 Prompt 中,达到动态扩充大模型对私有知识感知的能力,减少大模型的幻觉。

在 JAVA 体系下 Spring AI 针对RAG的实现,也类似 LangChain 做了很多的封装和支持,基本上做到使用较少的代码即可实现 RAG 的过程。

例如:官方提供了多种格式的 DocumentReader 封装,包括:JSONTextHTMLMarkdownPDF、以及万能文件解析神器 Tika 。针对文本内容拆分,Spring AI 也提供了 TextSplitter 和 TokenTextSplitter 两种方式。对于向量库的支持,也是几乎涵盖了市面上所有类型的向量库可供选择。

更多的细节可以参考官方的文档:

docs.spring.io/spring-ai/r…

本次实现的RAG流程如下所示:

模型使用 OpenAI 的 GPT-4.1, Embedding模型采用 OpenAI 的 text-embedding-3-small ,向量库使用 Milvus ,实验前请确保安装好 Milvus 环境。

二、私有知识准备

对于实验的私有知识,我这里随便制造了一些内容,包括,xlsxpdfdocx 格式,你可以使用真实的私有知识进行实验,内容示例如下:

Excel:

PDF:

Docx:

三、Spring AI RAG 流程搭建

新建 SpringBoot 项目,在 pom 中修改如下依赖:

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>    <groupId>com.example</groupId>    <artifactId>rag</artifactId>    <version>0.0.1-SNAPSHOT</version>    <name>rag</name>    <description>rag</description>    <properties>        <java.version>17</java.version>        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>        <spring-boot.version>3.3.0</spring-boot.version>        <spring-ai.version>1.0.0-SNAPSHOT</spring-ai.version>    </properties>    <dependencies>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-test</artifactId>            <scope>test</scope>        </dependency>        <dependency>            <groupId>org.springframework.ai</groupId>            <artifactId>spring-ai-starter-model-openai</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.ai</groupId>            <artifactId>spring-ai-starter-vector-store-milvus</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.ai</groupId>            <artifactId>spring-ai-advisors-vector-store</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.ai</groupId>            <artifactId>spring-ai-tika-document-reader</artifactId>        </dependency>                <dependency>            <groupId>org.projectlombok</groupId>            <artifactId>lombok</artifactId>        </dependency>    </dependencies>    <dependencyManagement>        <dependencies>            <dependency>                <groupId>org.springframework.boot</groupId>                <artifactId>spring-boot-dependencies</artifactId>                <version>${spring-boot.version}</version>                <type>pom</type>                <scope>import</scope>            </dependency>            <dependency>                <groupId>org.springframework.ai</groupId>                <artifactId>spring-ai-bom</artifactId>                <version>${spring-ai.version}</version>                <type>pom</type>                <scope>import</scope>            </dependency>        </dependencies>    </dependencyManagement>    <repositories>        <repository>            <name>Central Portal Snapshots</name>            <id>central-portal-snapshots</id>            <url>https://central.sonatype.com/repository/maven-snapshots/</url>            <releases>                <enabled>false</enabled>            </releases>            <snapshots>                <enabled>true</enabled>            </snapshots>        </repository>        <repository>            <id>spring-milestones</id>            <name>Spring Milestones</name>            <url>https://repo.spring.io/milestone</url>            <snapshots>                <enabled>false</enabled>            </snapshots>        </repository>        <repository>            <id>spring-snapshots</id>            <name>Spring Snapshots</name>            <url>https://repo.spring.io/snapshot</url>            <releases>                <enabled>false</enabled>            </releases>        </repository>    </repositories>    <build>        <plugins>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-compiler-plugin</artifactId>                <version>3.8.1</version>                <configuration>                    <source>17</source>                    <target>17</target>                    <encoding>UTF-8</encoding>                </configuration>            </plugin>            <plugin>                <groupId>org.springframework.boot</groupId>                <artifactId>spring-boot-maven-plugin</artifactId>                <version>${spring-boot.version}</version>                <configuration>                    <mainClass>com.example.rag.RagApplication</mainClass>                </configuration>                <executions>                    <execution>                        <id>repackage</id>                        <goals>                            <goal>repackage</goal>                        </goals>                    </execution>                </executions>            </plugin>        </plugins>    </build></project>

修改 application.yml 文件,加入如下配置:

server:  port:8080spring:ai:    openai:      base-url:https://api.openai.com      api-key: {your_openai_key}      chat:        options:          model:gpt-4.1      embedding:        options:          model:text-embedding-3-small    vectorstore:      milvus:        client:          host:127.0.0.1          port:19530          username:"root"          password:"milvus"        databaseName:"default"        collectionName:"vector_rag"        embeddingDimension:1536# text-embedding-3-small 模型向量维度的大小        indexType:IVF_FLAT        metricType:COSINE        initialize-schema: true

实现文档解析、Embedding、持久化至向量库逻辑,其中文档解析这里使用 Tika 来实现,这里为了演示效果直接递归读取了本机目录下的文件,对于文件的管理你在实际应用时应该考虑使用文件系统进行统一管理:

public interface PersistenceVectorService {    // 加载解析文件知识,并存储至向量库中    void load(String path);}
@Slf4j@ServicepublicclassPersistenceVectorServiceImplimplementsPersistenceVectorService {    privatefinal VectorStore vectorStore;    publicPersistenceVectorServiceImpl(VectorStore vectorStore) {        this.vectorStore = vectorStore;    }    @Override    publicvoidload(String path) {        List<Resource> listnewArrayList<>();        recursionAllFiles(list, newFile(path));        log.info("找到{}个文件。", list.size());        list.stream().filter(Objects::nonNull)                .map(r -> newTikaDocumentReader(r).get())                .map(d -> newTokenTextSplitter().apply(d))                .forEach(vectorStore::add);        log.info("持久化至vectorStore完成。");    }    privatevoidrecursionAllFiles(List<Resource> list, File file) {        if (file.isDirectory()) {            Arrays.stream(Objects.requireNonNull(file.listFiles())).filter(Objects::nonNull).forEach(f -> {                recursionAllFiles(list, f);            });        } else {            list.add(newFileSystemResource(file));        }    }}

执行逻辑,处理上面准备的文档:

@SpringBootTestclass RagApplicationTests {    @Resource    private PersistenceVectorService etlService;    @Test    void contextLoads() {        etlService.load("D:/rag");    }}

运行后,可以在 Milvus 中看到自动创建的 Collection :

接着实现问答的过程:

public interface QAService {    // 知识问答    String qa(String question);}
@Slf4j@ServicepublicclassQAServiceImplimplementsQAService {    privatefinal ChatClient chatClient;    publicQAServiceImpl(ChatClient.Builder chatClientBuilder, VectorStore vectorStore) {        this.chatClient = chatClientBuilder                .defaultAdvisors(                        QuestionAnswerAdvisor.builder(vectorStore)                                .searchRequest(SearchRequest.builder().similarityThreshold(0.5d).topK(4).build())                                .build())                .build();    }    @Override    public String qa(String question) {        return chatClient.prompt(question).call().content();    }}

实现一个测试Controller 作为入口:

@RestController@RequestMapping("/test")publicclassTestController {        private final QAService qaService;    public TestController(QAService qaService) {        this.qaService = qaService;    }    @GetMapping("/qa")    public String qa(@RequestParam(name = "question", required = true) String question){       return qaService.qa(question);    }}

到此,RAG 的过程就实现完成了。

启动服务。

四、效果测试

 

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Spring AI RAG Java OpenAI Milvus
相关文章