第五章:与 Spring Boot 集成与部署

16 阅读7分钟

第五章:与 Spring Boot 集成与部署

5.1 引言

在前四章中,我们已经完成了 RAG 系统的开发和封装:第一章介绍了 RAG 概念和开发环境,第二章实现了知识库构建和向量化,第三章整合了 RAG 核心逻辑,第四章使用 FastAPI 封装了 RESTful API。本章将完成整个教程的最后一步,展示如何在 Spring Boot 项目中调用 RAG API,实现前后端交互,并讨论如何部署整个系统。

本章的目标是帮助 Java 程序员实现以下内容:

  1. 创建一个 Spring Boot 项目,集成 RAG API。
  2. 实现前后端交互,展示 RAG 的查询和检索功能。
  3. 讨论 RAG 系统和 Spring Boot 项目的部署方案,包括本地部署和云端部署。
  4. 解决集成和部署中的常见问题。

我们将通过详细的代码示例和步骤,带你完成从 Spring Boot 项目配置到系统部署的完整流程。本章假设你已经按照第四章的说明运行了 FastAPI 服务(默认在 http://localhost:8000),并熟悉 Spring Boot 和 Java Web 开发。

5.2 Spring Boot 项目配置

5.2.1 创建 Spring Boot 项目

我们将使用 Spring Initializr 创建一个新的 Spring Boot 项目,包含必要的依赖。

  1. 访问 Spring Initializr

    • 打开 Spring Initializr

    • 配置项目:

      • Project:Maven

      • Language:Java

      • Spring Boot:3.2.x(最新稳定版)

      • Groupcom.example

      • Artifactrag-springboot

      • Java:17

      • Dependencies

        • Spring Web
        • Spring Boot DevTools
        • Thymeleaf(用于前端模板)
    • 下载项目并解压。

  2. 导入 IDE

    • 使用 IntelliJ IDEA 或 Eclipse 导入项目。
    • 确保 Maven 依赖已正确下载。
  3. 项目结构
    项目目录结构如下:

    rag-springboot/
    ├── src/
    │   ├── main/
    │   │   ├── java/
    │   │   │   └── com/example/ragspringboot/
    │   │   │       ├── RagSpringbootApplication.java
    │   │   │       ├── controller/
    │   │   │       ├── service/
    │   │   │       ├── model/
    │   │   │       ├── config/
    │   │   ├── resources/
    │   │   │   ├── templates/
    │   │   │   ├── static/
    │   │   │   ├── application.properties
    ├── pom.xml
    

5.2.2 配置 Maven 依赖

确保 pom.xml 包含以下核心依赖:

<?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-springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>rag springboot</name>
    <description>Spring Boot project integrating RAG API</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version>
        <relativePath/>
    </parent>

    <properties>
        <java.version>17</java.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-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

说明

  • spring-boot-starter-web:提供 REST 客户端和控制器支持。
  • spring-boot-starter-thymeleaf:用于渲染前端页面。
  • jackson-databind:处理 JSON 数据。

5.2.3 配置 application.properties

src/main/resources/application.properties 中配置应用的基本设置:

spring.application.name=rag springboot
server.port=8080

# RAG API 配置
rag.api.base-url=http://localhost:8000

说明

  • server.port=8080:Spring Boot 应用运行在 8080 端口,避免与 FastAPI(8000 端口)冲突。
  • rag.api.base-url:RAG API 的基础 URL,后续将在代码中使用。

5.3 实现 RAG API 调用

5.3.1 定义数据模型

我们需要定义 Java 类来映射 RAG API 的请求和响应,与第四章的 Pydantic 模型保持一致。

model/RagModels.java

package com.example.ragspringboot.model;

import java.util.List;

public class RagModels {

    public static class QueryRequest {
        private String query;
        private Integer topK;

        public QueryRequest() {
        }

        public QueryRequest(String query, Integer topK) {
            this.query = query;
            this.topK = topK;
        }

        public String getQuery() {
            return query;
        }

        public void setQuery(String query) {
            this.query = query;
        }

        public Integer getTopK() {
            return topK;
        }

        public void setTopK(Integer topK) {
            this.topK = topK;
        }
    }

    public static class DocumentResponse {
        private String file;
        private String chunkId;
        private String content;
        private Double distance;

        // Getters and setters
        public String getFile() {
            return file;
        }

        public void setFile(String file) {
            this.file = file;
        }

        public String getChunkId() {
            return chunkId;
        }

        public void setChunkId(String chunkId) {
            this.chunkId = chunkId;
        }

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }

        public Double getDistance() {
            return distance;
        }

        public void setDistance(Double distance) {
            this.distance = distance;
        }
    }

    public static class QueryResponse {
        private String question;
        private String answer;
        private List<DocumentResponse> retrievedDocs;

        // Getters and setters
        public String getQuestion() {
            return question;
        }

        public void setQuestion(String question) {
            this.question = question;
        }

        public String getAnswer() {
            return answer;
        }

        public void setAnswer(String answer) {
            this.answer = answer;
        }

        public List<DocumentResponse> getRetrievedDocs() {
            return retrievedDocs;
        }

        public void setRetrievedDocs(List<DocumentResponse> retrievedDocs) {
            this.retrievedDocs = retrievedDocs;
        }
    }

    public static class RetrieveResponse {
        private String query;
        private List<DocumentResponse> documents;

        // Getters and setters
        public String getQuery() {
            return query;
        }

        public void setQuery(String query) {
            this.query = query;
        }

        public List<DocumentResponse> getDocuments() {
            return documents;
        }

        public void setDocuments(List<DocumentResponse> documents) {
            this.documents = documents;
        }
    }

    public static class UploadResponse {
        private String status;
        private String message;
        private String fileName;

        // Getters and setters
        public String getStatus() {
            return status;
        }

        public void setStatus(String status) {
            this.status = status;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }

        public String getFileName() {
            return fileName;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }
    }
}

说明

  • QueryRequestQueryResponse 等类对应第四章的 Pydantic 模型。
  • 使用嵌套类组织代码,保持清晰。

5.3.2 实现服务层

服务层负责调用 RAG API,使用 Spring 的 RestTemplate 发送 HTTP 请求。

service/RagService.java

package com.example.ragspringboot.service;

import com.example.ragspringboot.model.RagModels.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.io.File;

@Service
public class RagService {

    private final RestTemplate restTemplate;
    private final String ragApiBaseUrl;

    public RagService(RestTemplate restTemplate, @Value("${rag.api.base-url}") String ragApiBaseUrl) {
        this.restTemplate = restTemplate;
        this.ragApiBaseUrl = ragApiBaseUrl;
    }

    public QueryResponse query(String query, Integer topK) {
        QueryRequest request = new QueryRequest(query, topK);
        HttpEntity<QueryRequest> entity = new HttpEntity<>(request, createHeaders());
        ResponseEntity<QueryResponse> response = restTemplate.exchange(
                ragApiBaseUrl + "/query",
                HttpMethod.POST,
                entity,
                QueryResponse.class
        );
        return response.getBody();
    }

    public RetrieveResponse retrieve(String query, Integer topK) {
        QueryRequest request = new QueryRequest(query, topK);
        HttpEntity<QueryRequest> entity = new HttpEntity<>(request, createHeaders());
        ResponseEntity<RetrieveResponse> response = restTemplate.exchange(
                ragApiBaseUrl + "/retrieve",
                HttpMethod.POST,
                entity,
                RetrieveResponse.class
        );
        return response.getBody();
    }

    public UploadResponse uploadFile(File file) {
        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("file", new FileSystemResource(file));
        
        HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, createHeaders());
        ResponseEntity<UploadResponse> response = restTemplate.exchange(
                ragApiBaseUrl + "/upload",
                HttpMethod.POST,
                entity,
                UploadResponse.class
        );
        return response.getBody();
    }

    public String healthCheck() {
        ResponseEntity<String> response = restTemplate.getForEntity(
                ragApiBaseUrl + "/health",
                String.class
        );
        return response.getBody();
    }

    private HttpHeaders createHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        return headers;
    }
}

说明

  • RestTemplate:Spring 提供的 HTTP 客户端,用于调用 RAG API。
  • queryretrieve 方法:发送 POST 请求,调用 /query/retrieve 端点。
  • uploadFile:发送 multipart/form-data 请求,调用 /upload 端点。
  • healthCheck:调用 /health 端点,检查 API 状态。

5.3.3 配置 RestTemplate

为了确保 RestTemplate 可用,我们在配置类中定义其 Bean。

config/AppConfig.java

package com.example.ragspringboot.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class AppConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

5.4 实现前端交互

我们使用 Thymeleaf 模板创建一个简单的 Web 界面,允许用户输入查询、查看结果和上传文档。

5.4.1 创建控制器

controller/RagController.java

package com.example.ragspringboot.controller;

import com.example.ragspringboot.model.RagModels.*;
import com.example.ragspringboot.service.RagService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;

@Controller
public class RagController {

    private final RagService ragService;

    public RagController(RagService ragService) {
        this.ragService = ragService;
    }

    @GetMapping("/")
    public String index(Model model) {
        model.addAttribute("queryRequest", new QueryRequest());
        return "index";
    }

    @PostMapping("/query")
    public String query(@ModelAttribute QueryRequest queryRequest, Model model) {
        QueryResponse response = ragService.query(queryRequest.getQuery(), queryRequest.getTopK());
        model.addAttribute("queryResponse", response);
        model.addAttribute("queryRequest", queryRequest);
        return "index";
    }

    @PostMapping("/retrieve")
    public String retrieve(@ModelAttribute QueryRequest queryRequest, Model model) {
        RetrieveResponse response = ragService.retrieve(queryRequest.getQuery(), queryRequest.getTopK());
        model.addAttribute("retrieveResponse", response);
        model.addAttribute("queryRequest", queryRequest);
        return "index";
    }

    @PostMapping("/upload")
    public String upload(@RequestParam("file") MultipartFile file, Model model) {
        try {
            File tempFile = File.createTempFile("upload-", file.getOriginalFilename());
            file.transferTo(tempFile);
            UploadResponse response = ragService.uploadFile(tempFile);
            model.addAttribute("uploadResponse", response);
            tempFile.delete();
        } catch (IOException e) {
            model.addAttribute("uploadResponse", new UploadResponse("error", "File upload failed: " + e.getMessage(), null));
        }
        model.addAttribute("queryRequest", new QueryRequest());
        return "index";
    }
}

说明

  • /:渲染主页面,显示查询表单。
  • /query:处理查询请求,显示 RAG 回答和检索文档。
  • /retrieve:处理检索请求,仅显示检索文档。
  • /upload:处理文件上传,显示上传结果。

5.4.2 创建 Thymeleaf 模板

resources/templates/index.html

<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>RAG 查询系统</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        .form-group { margin-bottom: 15px; }
        .result { margin-top: 20px; padding: 10px; border: 1px solid #ddd; }
        .error { color: red; }
    </style>
</head>
<body>
    <h1>RAG 查询系统</h1>

    <!-- 查询表单 -->
    <form th:action="@{/query}" th:object="${queryRequest}" method="post" class="form-group">
        <label for="query">查询内容:</label>
        <input type="text" id="query" th:field="*{query}" required style="width: 300px;">
        <label for="topK">Top K:</label>
        <input type="number" id="topK" th:field="*{topK}" value="3" min="1" max="10">
        <button type="submit">查询</button>
        <button type="button" onclick="document.forms[0].action='/retrieve'; document.forms[0].submit();">仅检索</button>
    </form>

    <!-- 文件上传表单 -->
    <form th:action="@{/upload}" method="post" enctype="multipart/form-data" class="form-group">
        <label for="file">上传文档:</label>
        <input type="file" id="file" name="file" accept=".txt,.pdf,.md">
        <button type="submit">上传</button>
    </form>

    <!-- 查询结果 -->
    <div th:if="${queryResponse}" class="result">
        <h3>查询结果</h3>
        <p><strong>问题:</strong> <span th:text="${queryResponse.question}"></span></p>
        <p><strong>回答:</strong> <span th:text="${queryResponse.answer}"></span></p>
        <h4>检索到的文档:</h4>
        <ul>
            <li th:each="doc : ${queryResponse.retrievedDocs}">
                <strong>文件:</strong> <span th:text="${doc.file}"></span><br>
                <strong>片段 ID:</strong> <span th:text="${doc.chunkId}"></span><br>
                <strong>内容:</strong> <span th:text="${doc.content}"></span><br>
                <strong>距离:</strong> <span th:text="${doc.distance}"></span>
            </li>
        </ul>
    </div>

    <!-- 检索结果 -->
    <div th:if="${retrieveResponse}" class="result">
        <h3>检索结果</h3>
        <p><strong>查询:</strong> <span th:text="${retrieveResponse.query}"></span></p>
        <h4>检索到的文档:</h4>
        <ul>
            <li th:each="doc : ${retrieveResponse.documents}">
                <strong>文件:</strong> <span th:text="${doc.file}"></span><br>
                <strong>片段 ID:</strong> <span th:text="${doc.chunkId}"></span><br>
                <strong>内容:</strong> <span th:text="${doc.content}"></span><br>
                <strong>距离:</strong> <span th:text="${doc.distance}"></span>
            </li>
        </ul>
    </div>

    <!-- 上传结果 -->
    <div th:if="${uploadResponse}" class="result">
        <h3>上传结果</h3>
        <p th:class="${uploadResponse.status == 'error'} ? 'error'"><strong>状态:</strong> <span th:text="${uploadResponse.status}"></span></p>
        <p><strong>消息:</strong> <span th:text="${uploadResponse.message}"></span></p>
        <p th:if="${uploadResponse.fileName}"><strong>文件名:</strong> <span th:text="${uploadResponse.fileName}"></span></p>
    </div>
</body>
</html>

说明

  • 提供查询、检索和文件上传表单。
  • 使用 Thymeleaf 动态渲染查询结果、检索结果和上传状态。
  • 包含简单的 CSS 样式,改善用户体验。

5.5 测试前后端交互

5.5.1 启动服务

  1. 启动 FastAPI 服务
    rag_api 目录下运行:

    uvicorn app.main:app --host 0.0.0.0 --port 8000
    
  2. 启动 Spring Boot 应用
    rag springboot 目录下运行:

    mvn spring-boot:run
    
  3. 访问 Web 界面
    打开浏览器,访问 http://localhost:8080

5.5.2 测试流程

  1. 查询测试

    • 输入查询:“Which operating systems are supported by the product?”
    • 设置 Top K 为 3。
    • 提交查询,页面显示回答和检索到的文档。
  2. 检索测试

    • 输入查询:“How to contact technical support?”
    • 点击“仅检索”,页面显示相关文档。
  3. 上传测试

    • 上传一个新的 .txt 文件(如包含“Test content”)。
    • 页面显示上传成功的消息。
    • 再次查询,确认新文档内容已生效。

示例结果

  • 查询结果:

    • 问题:Which operating systems are supported by the product?
    • 回答:Our product supports Windows 10/11, macOS 12+, and Ubuntu 20.04+.
    • 检索文档:包含 FAQ 文件的相关片段。
  • 上传结果:

    • 状态:success
    • 消息:Document added successfully.
    • 文件名:test_doc.txt

5.6 部署方案

5.6.1 本地部署

步骤

  1. 打包 FastAPI 应用

    • 确保 rag_api 目录包含所有依赖和知识库文件。

    • 使用 Gunicorn 替换 Uvicorn 提高生产环境性能:

      pip install gunicorn
      gunicorn -w 4 -k uvicorn.workers.UvicornWorker app.main:app --bind 0.0.0.0:8000
      
  2. 打包 Spring Boot 应用

    • rag springboot 目录下运行:

      mvn clean package
      
    • 运行生成的 JAR 文件:

      java -jar target/rag springboot-0.0.1-SNAPSHOT.jar
      
  3. 配置 Nginx 反向代理(可选):

    • 安装 Nginx:

      sudo apt-get install nginx
      
    • 配置 /etc/nginx/sites-available/rag

      server {
          listen 80;
          server_name your-domain.com;
      
          location / {
              proxy_pass http://localhost:8080;
              proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
          }
      
          location /api/ {
              proxy_pass http://localhost:8000/;
              proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
          }
      }
      
    • 启用配置:

      sudo ln -s /etc/nginx/sites-available/rag /etc/nginx/sites-enabled/
      sudo nginx -t
      sudo systemctl restart nginx
      

说明

  • FastAPI 运行在 8000 端口,Spring Boot 运行在 8080 端口。
  • Nginx 作为反向代理,统一入口,/api/ 路由到 FastAPI,其他请求路由到 Spring Boot。

5.6.2 云端部署

云平台选择

  • AWS:使用 EC2 实例部署 FastAPI 和 Spring Boot,Elastic Beanstalk 简化应用管理。
  • Google Cloud:使用 Compute Engine 或 Cloud Run。
  • Azure:使用 Azure App Service 或 Virtual Machines。

AWS EC2 部署示例

  1. 启动 EC2 实例

    • 选择 Ubuntu 22.04,推荐 t3.medium(2 vCPU,4GB 内存)。
    • 配置安全组,开放 80(HTTP)、8000(FastAPI)、8080(Spring Boot)端口。
  2. 安装依赖

    sudo apt-get update
    sudo apt-get install python3-pip nginx openjdk-17-jdk maven
    pip3 install gunicorn uvicorn fastapi
    
  3. 部署 FastAPI

    • 上传 rag_api 目录到 EC2。

    • 安装 Python 依赖:

      pip3 install -r requirements.txt
      
    • 使用 Gunicorn 运行:

      gunicorn -w 4 -k uvicorn.workers.UvicornWorker app.main:app --bind 0.0.0.0:8000 --daemon
      
  4. 部署 Spring Boot

    • 上传 rag springboot 目录。

    • 构建并运行:

      mvn clean package
      java -jar target/rag springboot-0.0.1-SNAPSHOT.jar &
      
  5. 配置 Nginx

    • 参考本地部署的 Nginx 配置。
    • 更新 application.properties 中的 rag.api.base-url 为 EC2 的公网 IP 或域名。
  6. 访问应用

    • 通过 EC2 公网 IP 或绑定的域名访问 http://<your-ec2-ip>

优化建议

  • 使用 Docker 容器化 FastAPI 和 Spring Boot,简化部署。
  • 配置 Auto Scaling 和 Load Balancer,支持高并发。
  • 使用 RDS 或 S3 存储知识库和 FAISS 索引。

5.6.3 Docker 部署

Dockerfile for FastAPIrag_api/Dockerfile):

FROM python:3.10-slim

WORKDIR /app
COPY . /app
RUN pip install --no-cache-dir -r requirements.txt

EXPOSE 8000
CMD ["gunicorn", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "app.main:app", "--bind", "0.0.0.0:8000"]

Dockerfile for Spring Bootrag springboot/Dockerfile):

FROM openjdk:17-jdk-slim

WORKDIR /app
COPY target/rag springboot-0.0.1-SNAPSHOT.jar /app/app.jar

EXPOSE 8080
CMD ["java", "-jar", "app.jar"]

docker-compose.yml(根目录):

version: '3.8'
services:
  rag-api:
    build: ./rag_api
    ports:
      - "8000:8000"
    volumes:
      - ./rag_api/rag_knowledge_base:/app/rag_knowledge_base
      - ./rag_api/rag_knowledge_base_index.faiss:/app/rag_knowledge_base_index.faiss
    environment:
      - PYTHONUNBUFFERED=1

  rag springboot:
    build: ./rag springboot
    ports:
      - "8080:8080"
    environment:
      - rag.api.base-url=http://rag-api:8000
    depends_on:
      - rag-api

运行

docker-compose up --build

说明

  • docker-compose 同时启动 FastAPI 和 Spring Boot 容器。
  • FastAPI 容器挂载知识库和索引文件,确保数据持久化。
  • Spring Boot 通过容器网络访问 FastAPI(http://rag-api:8000)。

5.7 常见问题与解决方案

  1. API 调用失败

    • 问题:Spring Boot 无法连接到 FastAPI。

    • 解决方案

      • 检查 application.properties 中的 rag.api.base-url
      • 确保 FastAPI 服务在运行(curl http://localhost:8000/health)。
      • 检查防火墙或安全组设置,开放 8000 端口。
  2. 文件上传失败

    • 问题:上传文档时返回 500 错误。

    • 解决方案

      • 检查 FastAPI 日志(rag_api.log)。
      • 确保上传文件格式正确(.txt.pdf.md)。
      • 增加 FastAPI 的超时时间(参考第四章)。
  3. 前端页面显示异常

    • 问题:Thymeleaf 模板未正确渲染。

    • 解决方案

      • 检查 index.html 中的 Thymeleaf 语法。
      • 确保控制器正确设置了 Model 属性。
  4. 部署性能问题

    • 问题:云端部署后响应缓慢。

    • 解决方案

      • 升级 EC2 实例类型(如 t3.large)。
      • 使用 Redis 缓存频繁查询(参考第四章)。
      • 优化 FAISS 索引(使用 IndexIVFFlat)。

5.8 本章总结

本章完成了 RAG 系统与 Spring Boot 的集成和部署,涵盖了以下内容:

  • 创建 Spring Boot 项目,配置 REST 客户端调用 RAG API。
  • 实现前后端交互,使用 Thymeleaf 渲染查询、检索和上传结果。
  • 提供本地和云端部署方案,包括 Nginx 反向代理和 Docker 容器化。
  • 解决集成和部署中的常见问题,如 API 连接、文件上传和性能优化。

通过本教程,你已经掌握了从零开始构建一个 RAG 系统并将其集成到 Spring Boot 项目的完整流程。你可以根据实际需求扩展功能,例如添加用户认证、支持多语言或优化知识库管理。