SpringAI Redis RAG 搜索
SpringAI Redis RAG 搜索
- 1 依赖
- 2 配置
- 3 代码
- 1 OllamaController .java
- 2 RagController.java
- 3 MemConf.java
- 4 TestController.java
- 5 SpringaiRagApplication.java
- 4 结果
1 依赖
<?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><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.5.6</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.xu</groupId><artifactId>springai-rag</artifactId><version>0.0.1-SNAPSHOT</version><name>springai-rag</name><description>Demo project for Spring Boot</description><properties><java.version>25</java.version><spring-ai.version>1.0.3</spring-ai.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-transformers</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-vector-store-redis</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-pdf-document-reader</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-ollama</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><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><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><annotationProcessorPaths><path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></path></annotationProcessorPaths></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>
2 配置
servlet:port: 8080context-path: /spring:application:name: spring-onnxai:vectorstore:redis:initialize-schema: trueindex-name: custom-indexprefix: custom-prefixembedding:transformer:onnx:modelUri: classpath:/onnx/all-MiniLM-L6-v2/model.onnxmodelOutputName: last_hidden_stategpuDeviceId: -1tokenizer:uri: classpath:/onnx/all-MiniLM-L6-v2/tokenizer.jsoncache:enabled: truedirectory: cache/onnx/all-MiniLM-L6-v2/ollama:base-url: http://localhost:11434chat:model: gemma3:latestdata:redis:host: 127.0.0.1
3 代码
1 OllamaController .java
package com.xu.controller;import lombok.AllArgsConstructor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.content.Media;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.http.MediaType;
import org.springframework.util.MimeType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;@RestController
@AllArgsConstructor
@RequestMapping("/ollama")
public class OllamaController {private final ChatMemory chatMemory;private final OllamaChatModel model;/*** 聊天** @param content 聊天内容* @return 聊天结果*/@RequestMapping("/common/chat")public Object chat(String content) {return model.call(content);}/*** 聊天记忆** @param content 聊天内容* @return 聊天结果*/@RequestMapping("/common/memory")public Object memory(String content, String msgId) {UserMessage message = UserMessage.builder().text(content).build();chatMemory.add(msgId, message);ChatResponse response = model.call(new Prompt(message));chatMemory.add(msgId, response.getResult().getOutput());return response.getResult().getOutput().getText();}/*** 聊天图片** @param content 聊天内容* @return 聊天结果*/@RequestMapping("/common/image")public Object image(@RequestParam("content") String content, @RequestParam("file") MultipartFile file) {if (file.isEmpty()) {return model.call(content);}var media = new Media(new MimeType("image", "png"), file.getResource());return model.call(new Prompt(UserMessage.builder().media(media).text(content).build()));}/*** 聊天流式** @param content 聊天内容* @return 聊天结果*/@RequestMapping(value = "/stream/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<String> stream(String content) {return model.stream(content);}}
2 RagController.java
package com.xu.controller;import lombok.AllArgsConstructor;
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.ExtractedTextFormatter;
import org.springframework.ai.reader.pdf.PagePdfDocumentReader;
import org.springframework.ai.reader.pdf.config.PdfDocumentReaderConfig;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;
import java.util.List;
import java.util.Map;@RestController
@AllArgsConstructor
@RequestMapping("/rag")
public class RagController {private final VectorStore vectorStore;/*** 聊天** @param content 聊天内容* @return 聊天结果*/@RequestMapping("/save")public Object save(String content) {Resource resource = new FileSystemResource("E:\\我的照片\\我的简历");PagePdfDocumentReader reader = new PagePdfDocumentReader(resource,PdfDocumentReaderConfig.builder().withPageExtractedTextFormatter(ExtractedTextFormatter.defaults()).withPagesPerDocument(1).build());List<Document> documents = reader.read();vectorStore.add(documents);return documents.size();}/*** rag 搜索** @param content 聊天内容* @return 搜索结果*/@RequestMapping("/search1")public Object search1(String content) {SearchRequest request = SearchRequest.builder().query(content) // 查询.topK(5) // 返回的相似文档数量.similarityThreshold(0.9) // 相似度阈值//.filterExpression("file_name == '中二知识笔记.pdf'") // 过滤条件.build();List<Document> docs = vectorStore.similaritySearch(request);return docs.stream().map(doc -> {Map<String, Object> map = new HashMap<>();map.put("id", doc.getId());map.put("score", doc.getScore());map.put("text", doc.getText());return map;}).toList();}/*** rag 搜索** @param content 聊天内容* @return 搜索结果*/@RequestMapping("/search2")public Object search2(String content) {List<Document> docs = vectorStore.similaritySearch("content");return docs.stream().map(doc -> {Map<String, Object> map = new HashMap<>();map.put("id", doc.getId());map.put("score", doc.getScore());map.put("text", doc.getText());return map;}).toList();}}
3 MemConf.java
package com.xu.conf;import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemoryRepository;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MemConf {@Beanpublic ChatMemory chatMemory() {return MessageWindowChatMemory.builder().chatMemoryRepository(new InMemoryChatMemoryRepository()).maxMessages(20).build();}}
4 TestController.java
package com.xu.controller;import lombok.AllArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@AllArgsConstructor
@RequestMapping("/test")
public class TestController {private final OllamaChatModel chatModel;private final VectorStore vectorStore;/*** 聊天** @param content 聊天内容* @return 聊天结果*/@RequestMapping("/common/rag1")public Object rag1(String content) {ChatClient chatClient = ChatClient.builder(chatModel).defaultAdvisors(QuestionAnswerAdvisor.builder(vectorStore).searchRequest(SearchRequest.builder().build()).build()).build();return chatClient.prompt().user(content).call().chatResponse();}/*** 聊天** @param content 聊天内容* @return 聊天结果*/@RequestMapping("/common/rag2")public Object rag2(String content) {return ChatClient.builder(chatModel).build().prompt().advisors(QuestionAnswerAdvisor.builder(vectorStore).searchRequest(SearchRequest.builder().similarityThreshold(0.8d).topK(6).build()).build()).user(content).call().chatResponse();}}
5 SpringaiRagApplication.java
package com.xu;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SpringaiRagApplication {static void main(String[] args) {SpringApplication.run(SpringaiRagApplication.class, args);}}
4 结果
. ____ _ __ _ _/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \\\/ ___)| |_)| | | | | || (_| | ) ) ) )' |____| .__|_| |_|_| |_\__, | / / / /=========|_|==============|___/=/_/_/_/:: Spring Boot :: (v3.5.6)2025-10-23T22:33:18.966+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] com.xu.SpringaiRagApplication : Starting SpringaiRagApplication using Java 25 with PID 29416 (D:\SourceCode\JavaLearn\springai-rag\target\classes started by xuhya in D:\SourceCode\JavaLearn\springai-rag)
2025-10-23T22:33:18.971+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] com.xu.SpringaiRagApplication : No active profile set, falling back to 1 default profile: "default"
2025-10-23T22:33:19.039+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2025-10-23T22:33:19.039+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2025-10-23T22:33:19.951+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode
2025-10-23T22:33:19.954+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Redis repositories in DEFAULT mode.
2025-10-23T22:33:19.986+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 15 ms. Found 0 Redis repository interfaces.
2025-10-23T22:33:20.553+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
2025-10-23T22:33:20.573+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2025-10-23T22:33:20.573+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.46]
2025-10-23T22:33:20.643+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2025-10-23T22:33:20.644+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1604 ms
2025-10-23T22:33:21.204+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] o.s.a.transformers.ResourceCacheService : The class path resource [onnx/all-MiniLM-L6-v2/tokenizer.json] resource with URI schema [file] is excluded from caching
2025-10-23T22:33:21.415+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] ai.djl.util.Platform : Found matching platform from: jar:file:/E:/Maven/ai/djl/huggingface/tokenizers/0.32.0/tokenizers-0.32.0.jar!/native/lib/tokenizers.properties
2025-10-23T22:33:21.757+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] o.s.a.transformers.ResourceCacheService : The class path resource [onnx/all-MiniLM-L6-v2/model.onnx] resource with URI schema [file] is excluded from caching
2025-10-23T22:33:22.167+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] o.s.a.t.TransformersEmbeddingModel : Model input names: input_ids, attention_mask, token_type_ids
2025-10-23T22:33:22.168+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] o.s.a.t.TransformersEmbeddingModel : Model output names: last_hidden_state
2025-10-23T22:33:23.227+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2025-10-23T22:33:23.271+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
2025-10-23T22:33:23.289+08:00 INFO 29416 --- [spring-onnx] [ restartedMain] com.xu.SpringaiRagApplication : Started SpringaiRagApplication in 4.907 seconds (process running for 5.543)


