From bf47df6ac6e5e7a18388c285a390c50ced499d52 Mon Sep 17 00:00:00 2001 From: zouzhiwen <409053122@qq.com> Date: Wed, 1 Apr 2026 19:04:38 +0800 Subject: [PATCH] feat: RAG --- pom.xml | 19 ++++- src/main/java/com/baoshi/conf/AiConfig.java | 13 +++- src/main/resources/application.yml | 17 ++++- src/test/java/com/baoshi/JDBCMemoryTest.java | 20 ++--- .../com/baoshi/SimpleVectorStoreTest.java | 76 +++++++++++++++++++ 5 files changed, 128 insertions(+), 17 deletions(-) create mode 100644 src/test/java/com/baoshi/SimpleVectorStoreTest.java diff --git a/pom.xml b/pom.xml index 680bc9f..2ae0931 100644 --- a/pom.xml +++ b/pom.xml @@ -77,12 +77,25 @@ - + - com.mysql - mysql-connector-j + org.postgresql + postgresql runtime + + + org.springframework.ai + spring-ai-starter-vector-store-pgvector + 1.1.2 + + + + + org.springframework.ai + spring-ai-advisors-vector-store + 1.1.2 + \ No newline at end of file diff --git a/src/main/java/com/baoshi/conf/AiConfig.java b/src/main/java/com/baoshi/conf/AiConfig.java index 3238b91..ca21dab 100644 --- a/src/main/java/com/baoshi/conf/AiConfig.java +++ b/src/main/java/com/baoshi/conf/AiConfig.java @@ -1,14 +1,19 @@ package com.baoshi.conf; import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel; +import com.alibaba.cloud.ai.dashscope.spec.DashScopeModel; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor; import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.ai.chat.memory.MessageWindowChatMemory; import org.springframework.ai.chat.memory.repository.jdbc.JdbcChatMemoryRepository; +import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.model.ollama.autoconfigure.OllamaChatProperties; import org.springframework.ai.ollama.OllamaChatModel; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; @Configuration public class AiConfig { @@ -16,7 +21,7 @@ public class AiConfig { @Bean public ChatMemory chatMemory(JdbcChatMemoryRepository chatMemoryRepository) { return MessageWindowChatMemory.builder() - .maxMessages(1) + .maxMessages(3) .chatMemoryRepository(chatMemoryRepository) .build(); } @@ -37,4 +42,10 @@ public class AiConfig { .defaultAdvisors(PromptChatMemoryAdvisor.builder(chatMemory).build()) .build(); } + + @Primary + @Bean + public EmbeddingModel embeddingModel(@Autowired @Qualifier("ollamaEmbeddingModel") EmbeddingModel embeddingModel) { + return embeddingModel; + } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e4814f5..0fca9e6 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -5,6 +5,8 @@ spring: base-url: http://100.121.13.117:11434 chat: model: qwen2.5:7b + embedding: + model: bge-m3 dashscope: api-key: sk-36a57382b9ae4db696ecd07eb7150a88 chat: @@ -14,11 +16,18 @@ spring: repository: jdbc: initialize-schema: always + vectorstore: + pgvector: + initialize-schema: true + index-type: HNSW + distance-type: COSINE_DISTANCE datasource: - username: root - password: 123456 - url: jdbc:mysql://localhost:3306/springai?characterEncoding=utf8&useSSL=false&serverTimezone=UTC& - driver-class-name: com.mysql.cj.jdbc.Driver + username: postgres + password: postgres + url: jdbc:postgresql://localhost:5432/springai + driver-class-name: org.postgresql.Driver + + server: port: 8080 diff --git a/src/test/java/com/baoshi/JDBCMemoryTest.java b/src/test/java/com/baoshi/JDBCMemoryTest.java index c7f05fb..62e5c68 100644 --- a/src/test/java/com/baoshi/JDBCMemoryTest.java +++ b/src/test/java/com/baoshi/JDBCMemoryTest.java @@ -6,6 +6,7 @@ import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.ai.chat.memory.repository.jdbc.JdbcChatMemoryRepository; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.jdbc.core.JdbcTemplate; @@ -23,14 +24,12 @@ class JDBCMemoryTest { private static final String CONVERSATION_ID = "1"; @Autowired - private ChatClient ollama; + @Qualifier("ollama") + private ChatClient chatClient; @Autowired private ChatMemory chatMemory; - @Autowired - private JdbcChatMemoryRepository chatMemoryRepository; - @Autowired private JdbcTemplate jdbcTemplate; @@ -41,20 +40,23 @@ class JDBCMemoryTest { @Test void shouldPersistMessagesIntoJdbcRepositoryByChatModelConversation() { - ollama.prompt() + chatClient.prompt() .advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, CONVERSATION_ID)) .user("我叫邹志文") .call() .content(); - - String secondResponse = ollama.prompt() + chatClient.prompt() + .advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, CONVERSATION_ID)) + .user("她叫冬马和纱") + .call() + .content(); + String secondResponse = chatClient.prompt() .advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, CONVERSATION_ID)) .user("我叫什么") .call() .content(); - assertThat(secondResponse).isNotBlank(); - assertThat(chatMemoryRepository.findByConversationId(CONVERSATION_ID)).isNotEmpty(); + System.out.println(secondResponse); Integer rowCount = jdbcTemplate.queryForObject( "SELECT COUNT(*) FROM SPRING_AI_CHAT_MEMORY WHERE conversation_id = ?", Integer.class, diff --git a/src/test/java/com/baoshi/SimpleVectorStoreTest.java b/src/test/java/com/baoshi/SimpleVectorStoreTest.java new file mode 100644 index 0000000..05c3ebf --- /dev/null +++ b/src/test/java/com/baoshi/SimpleVectorStoreTest.java @@ -0,0 +1,76 @@ +package com.baoshi; + +import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor; +import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor; +import org.springframework.ai.document.Document; +import org.springframework.ai.vectorstore.SearchRequest; +import org.springframework.ai.vectorstore.VectorStore; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.Arrays; + +@SpringBootTest +public class SimpleVectorStoreTest { + + @BeforeEach + public void init( @Autowired + VectorStore vectorStore) { + // 1. 声明内容文档 + Document doc = Document.builder() + .text(""" + 预订航班: + - 通过我们的网站或移动应用程序预订。 + - 预订时需要全额付款。 + - 确保个人信息(姓名、ID 等)的准确性,因为更正可能会产生 25 的费用。 + """) + .build(); + Document doc2 = Document.builder() + .text(""" + 取消预订: + - 最晚在航班起飞前 48 小时取消。 + - 取消费用:经济舱 75 美元,豪华经济舱 50 美元,商务舱 25 美元。 + - 退款将在 7 个工作日内处理。 + """) + .build(); + + + // 2. 将文本进行向量化,并且存入向量数据库(无需再手动向量化) + vectorStore.add(Arrays.asList(doc,doc2)); + } + + + @Test + void chatRagTest( + @Autowired + VectorStore vectorStore, + @Autowired + @Qualifier("ollama") + ChatClient chatClient + ) { + + + String message="退费需要多少费用?"; + String content = chatClient.prompt().user(message) + .advisors( + new SimpleLoggerAdvisor(), + QuestionAnswerAdvisor.builder(vectorStore) + .searchRequest( + SearchRequest + .builder().query(message) + .topK(5) + .similarityThreshold(0.3) + .build()) + .build() + ).call().content(); + + System.out.println(content); + + } + +} \ No newline at end of file