SpringAI Redis RAG 搜索

SpringAI Redis RAG 搜索

  • [1 依赖](#1 依赖)
  • [2 配置](#2 配置)
  • [3 代码](#3 代码)
    • [1 OllamaController .java](#1 OllamaController .java)
    • [2 RagController.java](#2 RagController.java)
    • [3 MemConf.java](#3 MemConf.java)
    • [4 TestController.java](#4 TestController.java)
    • [5 SpringaiRagApplication.java](#5 SpringaiRagApplication.java)
  • [4 结果](#4 结果)

1 依赖

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>

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

yml 复制代码
servlet:
  port: 8080
  context-path: /

spring:
  application:
    name: spring-onnx
  ai:
    vectorstore:
      redis:
        initialize-schema: true
        index-name: custom-index
        prefix: custom-prefix
    embedding:
      transformer:
        onnx:
          modelUri: classpath:/onnx/all-MiniLM-L6-v2/model.onnx
          modelOutputName: last_hidden_state
          gpuDeviceId: -1
        tokenizer:
          uri: classpath:/onnx/all-MiniLM-L6-v2/tokenizer.json
        cache:
          enabled: true
          directory: cache/onnx/all-MiniLM-L6-v2/
    ollama:
      base-url: http://localhost:11434
      chat:
        model: gemma3:latest
  data:
    redis:
      host: 127.0.0.1

3 代码

1 OllamaController .java

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

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

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 {

	@Bean
	public ChatMemory chatMemory() {
		return MessageWindowChatMemory.builder()
				.chatMemoryRepository(new InMemoryChatMemoryRepository())
				.maxMessages(20)
				.build();
	}

}

4 TestController.java

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

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

java 复制代码
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

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


相关推荐
深色風信子20 小时前
SpringAI 内嵌模型 ONNX
springai·springai onnx·embedding onnx·java springai·java onnx·java embedding
JAVA学习通6 天前
Spring AI 核心概念
java·人工智能·spring·springai
JAVA学习通8 天前
Spring AI 1.0 GA 深度解析:Java生态的AI革命已来
java·人工智能·spring·springai
深色風信子9 天前
SpringAI 本地调用 Ollama
rag·ollama·springai·springai ollama
深色風信子10 天前
SpringBoot 集成 LangChain4j RAG Redis 搜索
spring boot·langchain4j rag·rag redis 搜索·rag redis·springboot rag·rag 搜索
whltaoin10 天前
AI 超级智能体全栈项目阶段五:RAG 四大流程详解、最佳实践与调优(基于 Spring AI 实现)
java·人工智能·spring·rag·springai
mumu1307梦1 个月前
SpringAI 实战:解决 Netty 超时问题,优化 OpenAiApi 配置
java·spring boot·netty·超时·timeout·openapi·springai
孙半仙人1 个月前
SpringAI流式对话(带前端)
springai
孙半仙人1 个月前
SpringAI接入DeepSeek大模型实现流式对话
springai·deepseek