介绍:之前博客说过通过Spring AI搭建知识库,但复杂度较高,融合了企业需求,不少人半途而废,此次Demo版

需要具备初级Java能力,即可通过~

此篇需要用到milvus、minio,如果还不会的同学们,可以参考上篇博客

Spring AI实现知识库搭建(实战篇)

项目环境
jdk版本:17
spring-ai版本:1.0.0
spring-ai-alibaba版本:1.0.0.2
spring-boot版本:3.4.5

步骤一:引入依赖

依赖管理

<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.4.5</spring-boot.version>
  <spring-ai.version>1.0.0</spring-ai.version>
  <spring-ai-alibaba.version>1.0.0.2</spring-ai-alibaba.version>
</properties>

<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>

            <dependency>
                <groupId>com.alibaba.cloud.ai</groupId>
                <artifactId>spring-ai-alibaba-bom</artifactId>
                <version>${spring-ai-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
</dependencies>

具体依赖

		<dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-vector-store-milvus</artifactId>
        </dependency>


        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

注:不能使用依赖spring-ai-milvus-store,否则需要手动注入!

在这里插入图片描述

步骤二:配置信息

application.yml

server:
  port: 8093
spring:
  application:
    name: knowledge-demo
  ai:
    dashscope:
      api-key: 个人阿里云百炼账号
      chat:
        options:
          model: qwen-plus // 聊天模型
          temperature: 0.8
      embedding:
        options:
          model: text-embedding-v2 // 向量模型
        enabled: true
      rerank:
        options:
          model: gte-rerank-v2 // 检索模型
          top-n: 3
    vectorstore:
      milvus:
        client:
          host: localhost
          port: 19530
          username: 账号
          password: 密码
        initialize-schema: true

minio:
  endpoint: http://localhost:9000
  bucketName: test
  accessKey: 账号
  secretKey: 密码
  chunk-size: 1048576
  max-connections: 6

此次选择阿里云百炼模型,引入依赖、配置即可生效

排序模型

在这里插入图片描述
向量模型
在这里插入图片描述
聊天模型

在这里插入图片描述
需要配置Milvus、minio信息,如何安装,可参考以下博客

Spring AI实现知识库搭建(实战篇)

在这里插入图片描述

步骤三:核心代码

[1]ChatClientConfig

@Configuration
@Slf4j
public class ChatClientConfig {
    // 系统提示词
    private static final String SYSTEM_PROMPT = """
            你是一个专业的知识库智能助手,基于RAG(检索增强生成)技术构建.你的主要职责是:
                - 根据用户问题,从提供的知识库中检索最相关信息;
                - 基于检索到的内容,生成准确、专业、有帮助的回答;
                - 回答时保持专业、友好且易于理解的风格;

            请遵循以下原则:
                - 严格基于知识库内容回答,不编造不存在的信息;
                - 如果知识库中没有相关信息,明确告知用户"根据现有资料,我无法回答这个问题";
                - 回答要结构清晰,重要信息优先展示;
                - 对于复杂问题,可以分步骤或分点解答;
                - 保持中立客观,不表达个人观点或情感;
            """;

    /**
     * rag助手配置
     *
     * @param chatClientBuilder
     * @return
     */
    @Bean(value = "ragAssist")
    public ChatClient getChatClient(ChatClient.Builder chatClientBuilder) {
        log.info("getChatClient()...");
        MessageWindowChatMemory chatMemory = MessageWindowChatMemory.builder()
                .maxMessages(10)
                .build();

        ChatClient chatClient = chatClientBuilder
                .defaultSystem(SYSTEM_PROMPT)
                .defaultAdvisors(
                        PromptChatMemoryAdvisor.builder(chatMemory).build()
                )
                .build();
        log.info("chatClient success...");
        return chatClient;
    }
}

[2]RetrievalRerankAdvisorConfig

@Configuration
@RequiredArgsConstructor
@Slf4j
public class RetrievalRerankAdvisorConfig {
    private final MilvusVectorStore vectorStore;

    private final RerankModel rerankModel;

    // 用户提示词模板
    private final static String USER_PROMPT_RERANK = """
            以下是知识库检索信息:
            --------------------
            {question_answer_context}
            --------------------

            请基于上述信息,结合历史对话内容回答用户问题.回答应:
                - 内容完整且紧扣问题核心;
                - 避免直接摘抄原文,需语义转化;
                - 语言简洁专业,逻辑清晰连贯;
                - 若信息不足请礼貌告知用户;

            回答建议: 先直接回应问题关键,再展开必要解释,确保用户获得准确且易于理解的信息.
            """;

            
    @Bean
    public Advisor retrievalRerankAdvisor() {
        // 配置搜索参数
        SearchRequest searchRequest = SearchRequest.builder()
                .similarityThreshold(0.2)
                .topK(7)
                .build();

                
        PromptTemplate promptTemplate = new PromptTemplate(USER_PROMPT_RERANK);


        return new RetrievalRerankAdvisor(
                vectorStore,
                rerankModel,
                searchRequest,
                promptTemplate,
                0.6
        );
    }
}

[3]RagAdvisorFactory

public class RagAdvisorFactory {
    /**
     * 自定义的rag检索增强
     *
     * @param vectorStore
     * @param status
     * @return
     */
    public static Advisor createRagCustomAdvisor(VectorStore vectorStore, String status) {
        // 创建文档检索器
        DocumentRetriever documentRetriever = VectorStoreDocumentRetriever.builder()
                .vectorStore(vectorStore)
                // 相似度阈值
                .similarityThreshold(0.3)
                // 返回文档数量
                .topK(5)
                .build();

        return RetrievalAugmentationAdvisor.builder()
                .documentRetriever(documentRetriever)
                .queryAugmenter(ContextQueryAugumentFactory.createInstance())
                .build();
    }
}

步骤四:接口编写

[1]RagController

@RestController
@RequestMapping("/rag")
@RequiredArgsConstructor
@Slf4j
public class RagController {
    private final RagService ragService;

    private final TokenTextSplitter tokenTextSplitter;

    private final VectorStore vectorStore;

    /**
     * 基于知识库对话
     *
     * @param message
     * @param chatId
     * @return
     */
    @GetMapping(value = "/chatWithRag", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> chatWithRag(@RequestParam(value = "message") String message, @RequestParam(value = "chatId") String chatId) {
        return ragService.chatWithRag(message, chatId);
    }

    /**
     * 入向量库
     *
     * @return
     */
    @GetMapping(value = "/saveData")
    public String saveData() {
        // ELT三步走:提取(读取)、转换(分隔)和加载(写入)

        // 步骤一:读取
        DocumentReader reader = new TextReader("/static/personalInfo.txt");
        List<Document> documents = reader.read();

        // 步骤二:转换
        List<Document> splitCustomized = tokenTextSplitter.splitCustomized(documents);
        log.info("切片大小: {}", splitCustomized.size());
        // 步骤三:加载
        vectorStore.add(splitCustomized);
        return "success";
    }
}

[2]RagService

public interface RagService {
    /**
     * 基于知识库对话
     *
     * @param message
     * @param chatId
     * @return
     */
    public Flux<String> chatWithRag(String message, String chatId);
}

[3]RagServiceImpl

@Service
@Slf4j
public class RagServiceImpl implements RagService {
    @Resource(name = "ragAssist")
    private ChatClient chatClient;

    @Resource
    private VectorStore vectorStore;

    @Resource
    private Advisor retrievalRerankAdvisor;

    /**
     * 基于知识库对话
     *
     * @param message
     * @param chatId
     * @return
     */
    @Override
    public Flux<String> chatWithRag(String message, String chatId) {
        String currentTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        Flux<String> content = chatClient
                .prompt()
                .user(message)
                .system(s -> s.param("current_date", currentTime))
                .advisors(a -> a.param(CONVERSATION_ID, chatId))
                .advisors(
                        RagAdvisorFactory.createRagCustomAdvisor(
                                vectorStore, ""
                        )
                )
                .advisors(retrievalRerankAdvisor)
                .stream()
                .content();
        return content;
    }
}

步骤五:测试

在resources目录下,新建static目录并创建personalinfo.txt

1.小研身份介绍
性别:男
岗位:Java+AI领域工程师
职责:带领热爱学习的伙伴们,跟着小研学AI、Java,月薪过万不是梦

启动成功

在这里插入图片描述
接口测试
在这里插入图片描述
验证
在这里插入图片描述
对话测试
在这里插入图片描述
至此,基于知识库对话Demo版本结束啦,需要资料可以加入技术群获取!

本人正在打造技术交流群,欢迎志同道合的朋友一起探讨,一起努力,通过自己的努力,在技术岗位这条道路上走得更远。QQ群号:925317809 备注:技术交流 即可通过!

加入技术群可以获取资料,含AI资料、Spring AI中文文档等,等你加入~
在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐