feat: RAG

This commit is contained in:
zouzhiwen 2026-04-01 19:04:38 +08:00
parent f5b0e16c94
commit bf47df6ac6
5 changed files with 128 additions and 17 deletions

19
pom.xml
View File

@ -77,12 +77,25 @@
</dependency>
<!--mysql驱动-->
<!-- PostgreSQL聊天记忆 JDBC + pgvector 共用同一数据源 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
<version>1.1.2</version>
</dependency>
<!-- 向量数据库 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-advisors-vector-store</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
</project>

View File

@ -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;
}
}

View File

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

View File

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

View File

@ -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);
}
}