├── .gitignore ├── .idea ├── .gitignore ├── encodings.xml ├── misc.xml ├── uiDesigner.xml └── vcs.xml ├── LICENSE ├── README.md ├── pom.xml ├── spring-ai-audio-examples ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── ivy │ │ ├── AudioExamplesApplication.java │ │ └── controller │ │ ├── AudioController.java │ │ └── TranscriptionController.java │ └── resources │ ├── application.yml │ └── audio.mp3 ├── spring-ai-chat-examples ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── ivy │ │ │ ├── ChatExamplesApplication.java │ │ │ ├── controller │ │ │ ├── ChatController.java │ │ │ ├── ChatMemoryController.java │ │ │ ├── ChatRoleController.java │ │ │ ├── PromptTemplateController.java │ │ │ └── StructuredOutputController.java │ │ │ └── model │ │ │ └── Film.java │ └── resources │ │ ├── application.yml │ │ ├── code.st │ │ └── film.st │ └── test │ └── java │ └── com │ └── ivy │ ├── BeanOutputConverterTest.java │ ├── ChatClientResponseTest.java │ ├── JsonschemaTest.java │ └── ListStructuredListTest.java ├── spring-ai-deepseek-examples ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── ivy │ │ ├── DeepSeekExamplesApplication.java │ │ └── controller │ │ └── ChatController.java │ └── resources │ └── application.yml ├── spring-ai-functioncalling-examples ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── ivy │ │ ├── FunctionCallingExamplesApplication.java │ │ ├── config │ │ └── Config.java │ │ ├── controller │ │ └── FunctionCallingController.java │ │ └── func │ │ └── MockWeatherService.java │ └── resources │ ├── application.yml │ └── weather.st ├── spring-ai-image-examples ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── ivy │ │ ├── ImageExamplesApplication.java │ │ └── controller │ │ ├── AzureImageController.java │ │ ├── OpenAiImageController.java │ │ ├── StabilityImageController.java │ │ └── ZhiPuImageController.java │ └── resources │ └── application.yml ├── spring-ai-multimodality-examples ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── ivy │ │ ├── MultiModalityExamplesApplication.java │ │ └── controller │ │ └── MultiModalityController.java │ └── resources │ ├── application.yml │ └── img.png ├── spring-ai-rag-examples ├── pom.xml ├── redis.md └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── ivy │ │ │ ├── RagExamplesApplication.java │ │ │ ├── config │ │ │ └── Config.java │ │ │ ├── controller │ │ │ ├── OfflineController.java │ │ │ └── OnlineController.java │ │ │ └── service │ │ │ ├── OfflineService.java │ │ │ └── OnlineService.java │ └── resources │ │ ├── application.yml │ │ ├── rag.st │ │ └── rag.txt │ └── test │ ├── java │ └── org │ │ └── ivy │ │ └── rag │ │ ├── EnricherTest.java │ │ └── PgVectorServiceTest.java │ └── resources │ └── java.pdf └── spring-ai-toolcalling-examples ├── pom.xml └── src └── main ├── java └── org │ └── ivy │ ├── ToolCallingExamplesApplication.java │ ├── controller │ └── ToolsController.java │ └── tools │ └── DateTimeTools.java └── resources └── application.yml /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | !**/src/main/**/target/ 4 | !**/src/test/**/target/ 5 | 6 | ### IntelliJ IDEA ### 7 | .idea/modules.xml 8 | .idea/jarRepositories.xml 9 | .idea/compiler.xml 10 | .idea/libraries/ 11 | *.iws 12 | *.iml 13 | *.ipr 14 | 15 | ### Eclipse ### 16 | .apt_generated 17 | .classpath 18 | .factorypath 19 | .project 20 | .settings 21 | .springBeans 22 | .sts4-cache 23 | 24 | ### NetBeans ### 25 | /nbproject/private/ 26 | /nbbuild/ 27 | /dist/ 28 | /nbdist/ 29 | /.nb-gradle/ 30 | build/ 31 | !**/src/main/**/build/ 32 | !**/src/test/**/build/ 33 | 34 | ### VS Code ### 35 | .vscode/ 36 | 37 | ### Mac OS ### 38 | .DS_Store -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 ivy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # spring-ai-examples 2 | Spring AI 框架使用示例,主要实现如下功能 3 | - 接入OpenAI大模型, 4 | - 同步方式 5 | - 流式方式 6 | - 实现上下文记忆功能 7 | - 实现指定Chat角色 8 | - 实现返回内容格式化 9 | - 实现生成图片,语音转文字等,多模态实现方式 10 | - Spring AI 简单实现RAG问答系统 11 | 12 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 3.2.4 10 | 11 | 12 | 13 | org.ivy 14 | spring-ai-examples 15 | 1.0.0-SNAPSHOT 16 | pom 17 | 18 | 19 | spring-ai-chat-examples 20 | spring-ai-image-examples 21 | spring-ai-audio-examples 22 | spring-ai-functioncalling-examples 23 | spring-ai-multimodality-examples 24 | spring-ai-rag-examples 25 | spring-ai-deepseek-examples 26 | spring-ai-toolcalling-examples 27 | 28 | 29 | 30 | 17 31 | 17 32 | UTF-8 33 | 1.0.0-SNAPSHOT 34 | 35 | 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-test 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-web 44 | 45 | 46 | 47 | 48 | 49 | 50 | org.springframework.ai 51 | spring-ai-bom 52 | ${spring-ai.version} 53 | pom 54 | import 55 | 56 | 57 | 58 | 59 | 60 | 61 | spring-milestones 62 | Spring Milestones 63 | https://repo.spring.io/milestone 64 | 65 | false 66 | 67 | 68 | 69 | spring-snapshots 70 | Spring Snapshots 71 | https://repo.spring.io/snapshot 72 | 73 | false 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /spring-ai-audio-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.ivy 8 | spring-ai-examples 9 | 1.0.0-SNAPSHOT 10 | 11 | 12 | spring-ai-audio-examples 13 | 14 | 15 | 17 16 | 17 17 | UTF-8 18 | 19 | 20 | 21 | 22 | org.springframework.ai 23 | spring-ai-openai-spring-boot-starter 24 | 25 | 26 | commons-io 27 | commons-io 28 | 2.15.1 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /spring-ai-audio-examples/src/main/java/org/ivy/AudioExamplesApplication.java: -------------------------------------------------------------------------------- 1 | package org.ivy; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | 7 | @SpringBootApplication 8 | public class AudioExamplesApplication { 9 | public static void main(String[] args) { 10 | SpringApplication.run(AudioExamplesApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /spring-ai-audio-examples/src/main/java/org/ivy/controller/AudioController.java: -------------------------------------------------------------------------------- 1 | package org.ivy.controller; 2 | 3 | import org.springframework.ai.openai.OpenAiAudioSpeechModel; 4 | import org.springframework.ai.openai.OpenAiAudioSpeechOptions; 5 | import org.springframework.ai.openai.api.OpenAiAudioApi; 6 | import org.springframework.ai.openai.audio.speech.SpeechPrompt; 7 | import org.springframework.ai.openai.audio.speech.SpeechResponse; 8 | import org.springframework.http.MediaType; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.RequestParam; 11 | import org.springframework.web.bind.annotation.RestController; 12 | import reactor.core.publisher.Flux; 13 | 14 | 15 | @RestController 16 | public class AudioController { 17 | 18 | private final OpenAiAudioSpeechModel openAiAudioSpeechModel; 19 | public AudioController(OpenAiAudioSpeechModel openAiAudioSpeechModel) { 20 | this.openAiAudioSpeechModel = openAiAudioSpeechModel; 21 | } 22 | // 同步方式文本生成语音 23 | @GetMapping(value = "tts", produces = MediaType.TEXT_EVENT_STREAM_VALUE) 24 | public byte[] speech(@RequestParam(defaultValue = "Hello, this is a text-to-speech example.") String text) { 25 | OpenAiAudioSpeechOptions speechOptions = OpenAiAudioSpeechOptions.builder() 26 | .withModel("tts-1") // 指定模型, 目前Spring AI支持一种tts-1,可以不配置 27 | .withVoice(OpenAiAudioApi.SpeechRequest.Voice.ALLOY) // 指定生成的音色 28 | .withResponseFormat(OpenAiAudioApi.SpeechRequest.AudioResponseFormat.MP3) // 指定生成音频的格式 29 | .withSpeed(1.0f) // 指定生成速度 30 | .build(); 31 | SpeechPrompt speechPrompt = new SpeechPrompt(text, speechOptions); 32 | SpeechResponse response = openAiAudioSpeechModel.call(speechPrompt); 33 | return response.getResult().getOutput(); // 返回语音byte数组 34 | } 35 | 36 | // 流式方式文本生成语音 37 | @GetMapping(value = "stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) 38 | public Flux stream(@RequestParam(defaultValue = "Today is a wonderful day to build something people love!") String text) { 39 | OpenAiAudioSpeechOptions speechOptions = OpenAiAudioSpeechOptions.builder() 40 | .withResponseFormat(OpenAiAudioApi.SpeechRequest.AudioResponseFormat.MP3) 41 | .build(); 42 | SpeechPrompt speechPrompt = new SpeechPrompt(text, speechOptions); 43 | Flux stream = openAiAudioSpeechModel.stream(speechPrompt); 44 | return stream.map(speechResponse -> speechResponse.getResult().getOutput()).flatMapSequential(Flux::just); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /spring-ai-audio-examples/src/main/java/org/ivy/controller/TranscriptionController.java: -------------------------------------------------------------------------------- 1 | package org.ivy.controller; 2 | 3 | import org.springframework.ai.openai.OpenAiAudioTranscriptionModel; 4 | import org.springframework.ai.openai.OpenAiAudioTranscriptionOptions; 5 | import org.springframework.ai.openai.api.OpenAiAudioApi; 6 | import org.springframework.ai.openai.audio.transcription.AudioTranscriptionPrompt; 7 | import org.springframework.ai.openai.audio.transcription.AudioTranscriptionResponse; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | @RestController 13 | public class TranscriptionController { 14 | 15 | @Value("classpath:audio.mp3") 16 | private org.springframework.core.io.Resource audioResource; 17 | 18 | private final OpenAiAudioTranscriptionModel openAiTranscriptionModel; 19 | 20 | public TranscriptionController(OpenAiAudioTranscriptionModel openAiTranscriptionModel) { 21 | this.openAiTranscriptionModel = openAiTranscriptionModel; 22 | } 23 | 24 | @GetMapping("audio2Text") 25 | public String audio2Text() { 26 | var transcriptionOptions = OpenAiAudioTranscriptionOptions.builder() 27 | .withResponseFormat(OpenAiAudioApi.TranscriptResponseFormat.TEXT) 28 | .withTemperature(0f) 29 | .build(); 30 | AudioTranscriptionPrompt transcriptionRequest = new AudioTranscriptionPrompt(audioResource, transcriptionOptions); 31 | AudioTranscriptionResponse response = openAiTranscriptionModel.call(transcriptionRequest); 32 | return response.getResult().getOutput(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /spring-ai-audio-examples/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8803 3 | 4 | spring: 5 | ai: 6 | openai: 7 | api-key: xxx 8 | base-url: xxx 9 | 10 | -------------------------------------------------------------------------------- /spring-ai-audio-examples/src/main/resources/audio.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fj-ivy/spring-ai-examples/920f27a5326721e3393378078a5b68545858dd24/spring-ai-audio-examples/src/main/resources/audio.mp3 -------------------------------------------------------------------------------- /spring-ai-chat-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.ivy 8 | spring-ai-examples 9 | 1.0.0-SNAPSHOT 10 | 11 | 12 | spring-ai-chat-examples 13 | 14 | 15 | org.springframework.ai 16 | spring-ai-openai-spring-boot-starter 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /spring-ai-chat-examples/src/main/java/com/ivy/ChatExamplesApplication.java: -------------------------------------------------------------------------------- 1 | package com.ivy; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | 7 | @SpringBootApplication 8 | public class ChatExamplesApplication { 9 | public static void main(String[] args) { 10 | SpringApplication.run(ChatExamplesApplication.class,args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /spring-ai-chat-examples/src/main/java/com/ivy/controller/ChatController.java: -------------------------------------------------------------------------------- 1 | package com.ivy.controller; 2 | 3 | import org.springframework.ai.openai.OpenAiChatModel; 4 | import org.springframework.http.MediaType; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | import reactor.core.publisher.Flux; 8 | 9 | 10 | @RestController 11 | public class ChatController { 12 | 13 | private final OpenAiChatModel openAiChatModel; 14 | 15 | public ChatController(OpenAiChatModel openAiChatModel) { 16 | this.openAiChatModel = openAiChatModel; 17 | } 18 | 19 | @GetMapping("/chat") 20 | public String chat(String prompt) { 21 | return openAiChatModel.call(prompt); 22 | } 23 | 24 | @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) 25 | public Flux stream(String prompt) { 26 | return openAiChatModel.stream(prompt); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /spring-ai-chat-examples/src/main/java/com/ivy/controller/ChatMemoryController.java: -------------------------------------------------------------------------------- 1 | package com.ivy.controller; 2 | 3 | import jakarta.annotation.Resource; 4 | import org.springframework.ai.chat.client.ChatClient; 5 | import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor; 6 | import org.springframework.ai.chat.memory.ChatMemory; 7 | import org.springframework.ai.chat.memory.InMemoryChatMemory; 8 | import org.springframework.ai.chat.messages.AssistantMessage; 9 | import org.springframework.ai.chat.messages.Message; 10 | import org.springframework.ai.chat.messages.UserMessage; 11 | import org.springframework.ai.chat.model.Generation; 12 | import org.springframework.ai.chat.prompt.Prompt; 13 | import org.springframework.ai.openai.OpenAiChatModel; 14 | import org.springframework.web.bind.annotation.GetMapping; 15 | import org.springframework.web.bind.annotation.RestController; 16 | import reactor.core.publisher.Flux; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY; 22 | import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY; 23 | 24 | @RestController 25 | public class ChatMemoryController { 26 | private final List historyMessage = new ArrayList<>(); 27 | 28 | @Resource 29 | private OpenAiChatModel openAiChatModel; 30 | 31 | @GetMapping("/chatWithList") 32 | public String chatWithList(String prompt) { 33 | // 将用户消息添加到历史消息列表中 34 | historyMessage.add(new UserMessage(prompt)); 35 | Generation result = openAiChatModel.call(new Prompt(historyMessage)).getResult(); 36 | // 将AI消息添加到历史消息列表中 37 | AssistantMessage assistantMessage = result.getOutput(); 38 | historyMessage.add(assistantMessage); 39 | return assistantMessage.getContent(); 40 | } 41 | 42 | private final ChatMemory chatMemory = new InMemoryChatMemory(); 43 | @GetMapping("/chatWithChatMemory") 44 | public Flux chatWithChatMemory(String chatId, String prompt) { 45 | ChatClient chatClient = ChatClient.builder(openAiChatModel) 46 | .defaultAdvisors(new PromptChatMemoryAdvisor(chatMemory)) 47 | .build(); 48 | 49 | return chatClient.prompt() 50 | .user(prompt) 51 | .advisors(a -> a 52 | .param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId) 53 | .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100) 54 | ) 55 | .stream() 56 | .content(); 57 | } 58 | 59 | 60 | } 61 | -------------------------------------------------------------------------------- /spring-ai-chat-examples/src/main/java/com/ivy/controller/ChatRoleController.java: -------------------------------------------------------------------------------- 1 | package com.ivy.controller; 2 | 3 | import org.springframework.ai.chat.client.ChatClient; 4 | import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor; 5 | import org.springframework.ai.chat.memory.ChatMemory; 6 | import org.springframework.ai.chat.memory.InMemoryChatMemory; 7 | import org.springframework.ai.openai.OpenAiChatModel; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | import reactor.core.publisher.Flux; 11 | 12 | import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY; 13 | import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY; 14 | 15 | @RestController 16 | public class ChatRoleController { 17 | private final ChatMemory chatMemory = new InMemoryChatMemory(); 18 | private final OpenAiChatModel openAiChatModel; 19 | 20 | public ChatRoleController(OpenAiChatModel openAiChatModel) { 21 | this.openAiChatModel = openAiChatModel; 22 | } 23 | 24 | @GetMapping("/role") 25 | public Flux role(String chatId, String prompt) { 26 | ChatClient chatClient = ChatClient.builder(openAiChatModel) 27 | .defaultSystem("你现在是一个非常懒的生活助手,无论问什么,你都要巧妙的用礼貌用语回复。碰到无法回答的问题,就回复不知道。") 28 | .defaultAdvisors(new PromptChatMemoryAdvisor(chatMemory)) 29 | .build(); 30 | 31 | return chatClient.prompt() 32 | .user(prompt) 33 | .advisors(a -> a 34 | .param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId) 35 | .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100) 36 | ) 37 | .stream() 38 | .content(); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /spring-ai-chat-examples/src/main/java/com/ivy/controller/PromptTemplateController.java: -------------------------------------------------------------------------------- 1 | package com.ivy.controller; 2 | 3 | import jakarta.annotation.Resource; 4 | import org.springframework.ai.chat.client.ChatClient; 5 | import org.springframework.ai.chat.prompt.Prompt; 6 | import org.springframework.ai.chat.prompt.PromptTemplate; 7 | import org.springframework.ai.openai.OpenAiChatModel; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import java.util.Map; 13 | 14 | @RestController 15 | public class PromptTemplateController { 16 | 17 | @Resource 18 | private OpenAiChatModel openAiChatModel; 19 | 20 | 21 | @Value("classpath:film.st") 22 | private org.springframework.core.io.Resource template; 23 | 24 | @Value("classpath:code.st") 25 | private org.springframework.core.io.Resource codeTemplate; 26 | 27 | @GetMapping("/prompt") 28 | public String prompt(String director) { 29 | 30 | Map map = Map.of("director", director); 31 | PromptTemplate promptTemplate = new PromptTemplate(template, map); 32 | Prompt prompt = promptTemplate.create(); 33 | 34 | ChatClient chatClient = ChatClient.builder(openAiChatModel) 35 | .build(); 36 | return chatClient.prompt(prompt).call().content(); 37 | } 38 | 39 | @GetMapping("/code") 40 | public String code(String language, String methodName, String description) { 41 | PromptTemplate promptTemplate = new PromptTemplate(codeTemplate); 42 | Prompt prompt = promptTemplate.create( 43 | Map.of("language", language, "methodName", methodName, "description", description) 44 | ); 45 | ChatClient chatClient = ChatClient.builder(openAiChatModel) 46 | .build(); 47 | return chatClient.prompt(prompt).call().content(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /spring-ai-chat-examples/src/main/java/com/ivy/controller/StructuredOutputController.java: -------------------------------------------------------------------------------- 1 | package com.ivy.controller; 2 | 3 | import com.ivy.model.Film; 4 | import jakarta.annotation.Resource; 5 | import org.springframework.ai.chat.client.ChatClient; 6 | import org.springframework.ai.chat.prompt.Prompt; 7 | import org.springframework.ai.chat.prompt.PromptTemplate; 8 | import org.springframework.ai.converter.BeanOutputConverter; 9 | import org.springframework.ai.converter.ListOutputConverter; 10 | import org.springframework.ai.converter.StructuredOutputConverter; 11 | import org.springframework.ai.openai.OpenAiChatModel; 12 | import org.springframework.core.ParameterizedTypeReference; 13 | import org.springframework.core.convert.support.DefaultConversionService; 14 | import org.springframework.web.bind.annotation.GetMapping; 15 | import org.springframework.web.bind.annotation.RestController; 16 | 17 | import java.util.List; 18 | import java.util.Map; 19 | 20 | @RestController 21 | public class StructuredOutputController { 22 | @Resource 23 | private OpenAiChatModel openAiChatModel; 24 | 25 | @GetMapping("/bean") 26 | public Film structuredOutput(String director) { 27 | // 定义提示词模版 28 | // 其中 format指定输出的格式 29 | final String template = """ 30 | 请问{director}导演最受欢迎的电影是什么?哪年发行的,电影讲述的什么内容? 31 | {format} 32 | """; 33 | // 定义结构化输出转化器, 生成Bean 34 | StructuredOutputConverter structured = new BeanOutputConverter<>(Film.class); 35 | // 生成提示词对象 36 | PromptTemplate promptTemplate = new PromptTemplate(template); 37 | Prompt prompt = promptTemplate.create(Map.of("director", director, "format", structured.getFormat())); 38 | 39 | ChatClient chatClient = ChatClient.builder(openAiChatModel) 40 | .build(); 41 | String content = chatClient.prompt(prompt).call().content(); 42 | // 转换 43 | return structured.convert(content); 44 | } 45 | 46 | 47 | @GetMapping("/bean2") 48 | public Film structuredOutput2(String director) { 49 | return ChatClient.create(openAiChatModel) 50 | .prompt() 51 | .user(u -> u.text(""" 52 | 请问{director}导演最受欢迎的电影是什么?哪年发行的,电影讲述的什么内容 53 | """).params(Map.of("director", director)) 54 | ).call() 55 | .entity(Film.class); 56 | 57 | } 58 | 59 | /** 60 | * list output example, return a list of strings 61 | * Spring AI 也像BeanOutputConverter 一样也支持两种写法,这里只提供了一种写法示例,可以参考官方·文档 62 | * 63 | * @return 64 | */ 65 | @GetMapping("/list") 66 | public List structuredOutputList() { 67 | return ChatClient.create(openAiChatModel) 68 | .prompt() 69 | .user(u -> u.text(""" 70 | List five {subject} 71 | """).params(Map.of("subject", "ice cream flavors")) 72 | ).call() 73 | .entity(new ListOutputConverter(new DefaultConversionService())); 74 | 75 | } 76 | 77 | @GetMapping("/map") 78 | public Map structuredOutputMap() { 79 | return ChatClient.create(openAiChatModel).prompt() 80 | .user(u -> u.text("Provide me a List of {subject}") 81 | .param("subject", "an array of numbers from 1 to 9 under they key name 'numbers'")) 82 | .call() 83 | .entity(new ParameterizedTypeReference<>() { 84 | }); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /spring-ai-chat-examples/src/main/java/com/ivy/model/Film.java: -------------------------------------------------------------------------------- 1 | package com.ivy.model; 2 | 3 | /** 4 | * 电影返回对象 5 | * 6 | * @param director 7 | * @param filmName 8 | * @param publishedDate 9 | * @param description 10 | */ 11 | public record Film(String director, String filmName, String publishedDate, String description) { 12 | } 13 | -------------------------------------------------------------------------------- /spring-ai-chat-examples/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8801 3 | spring: 4 | ai: 5 | openai: 6 | api-key: sk-1wqTDyoDE2bBARsn63D8D45aEaB14d30B534C16b5514927d 7 | base-url: https://api.xty.app 8 | chat: 9 | options: 10 | model: gpt-3.5-turbo 11 | -------------------------------------------------------------------------------- /spring-ai-chat-examples/src/main/resources/code.st: -------------------------------------------------------------------------------- 1 | /** 2 | * @language {language} 3 | * @method {methodName} 4 | * @describe {description} 5 | */ -------------------------------------------------------------------------------- /spring-ai-chat-examples/src/main/resources/film.st: -------------------------------------------------------------------------------- 1 | 请问{director}导演最受欢迎的电影是什么?哪年发行的,电影讲述的什么内容? -------------------------------------------------------------------------------- /spring-ai-chat-examples/src/test/java/com/ivy/BeanOutputConverterTest.java: -------------------------------------------------------------------------------- 1 | package com.ivy; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.ai.converter.BeanOutputConverter; 5 | 6 | public class BeanOutputConverterTest { 7 | 8 | @Test 9 | public void testFormat() { 10 | BeanOutputConverter converter = new BeanOutputConverter<>(User.class); 11 | String format = converter.getFormat(); 12 | System.out.println(format); 13 | } 14 | 15 | 16 | public static class User { 17 | private String name; 18 | 19 | public String getName() { 20 | return name; 21 | } 22 | 23 | public void setName(String name) { 24 | this.name = name; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /spring-ai-chat-examples/src/test/java/com/ivy/ChatClientResponseTest.java: -------------------------------------------------------------------------------- 1 | package com.ivy; 2 | 3 | import jakarta.annotation.Resource; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.ai.chat.client.ChatClient; 6 | import org.springframework.ai.chat.model.ChatModel; 7 | import org.springframework.ai.chat.model.ChatResponse; 8 | import org.springframework.ai.chat.model.Generation; 9 | import org.springframework.ai.chat.prompt.Prompt; 10 | import org.springframework.ai.chat.prompt.PromptTemplate; 11 | import org.springframework.ai.converter.BeanOutputConverter; 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | @SpringBootTest 18 | public class ChatClientResponseTest { 19 | 20 | @Resource 21 | private ChatModel chatModel; 22 | @Resource 23 | private ChatClient.Builder builder; 24 | 25 | @Test 26 | public void testChatClientResponse() { 27 | String result = chatModel.call("Tell me a joke"); 28 | System.out.println(result); 29 | } 30 | 31 | @Test 32 | public void testChatClient() { 33 | ChatClient chatClient = builder.build(); 34 | ChatResponse chatResponse = chatClient.prompt() 35 | .user("Hello, how can I help you?") 36 | .call() 37 | .chatResponse(); 38 | 39 | System.out.println(chatResponse.getResult().getOutput().getContent()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /spring-ai-chat-examples/src/test/java/com/ivy/JsonschemaTest.java: -------------------------------------------------------------------------------- 1 | package com.ivy; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.core.util.DefaultIndenter; 5 | import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; 6 | import com.fasterxml.jackson.databind.JsonNode; 7 | import com.fasterxml.jackson.databind.ObjectMapper; 8 | import com.fasterxml.jackson.databind.ObjectWriter; 9 | import com.github.victools.jsonschema.generator.*; 10 | import com.github.victools.jsonschema.module.jackson.JacksonModule; 11 | import org.junit.jupiter.api.Test; 12 | 13 | public class JsonschemaTest { 14 | 15 | @Test 16 | public void testJsonSchema() throws JsonProcessingException { 17 | JacksonModule jacksonModule = new JacksonModule(); 18 | SchemaGeneratorConfigBuilder configBuilder = 19 | new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON) 20 | .with(jacksonModule); 21 | 22 | SchemaGeneratorConfig config = configBuilder.build(); 23 | SchemaGenerator generator = new SchemaGenerator(config); 24 | JsonNode jsonNode = generator.generateSchema(BeanOutputConverterTest.User.class); 25 | 26 | ObjectWriter objectWriter = new ObjectMapper().writer( 27 | new DefaultPrettyPrinter() 28 | .withObjectIndenter((new DefaultIndenter()) 29 | .withLinefeed(System.lineSeparator()))); 30 | 31 | String jsonSchema = objectWriter.writeValueAsString(jsonNode); 32 | 33 | System.out.println(jsonSchema); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /spring-ai-chat-examples/src/test/java/com/ivy/ListStructuredListTest.java: -------------------------------------------------------------------------------- 1 | package com.ivy; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.ai.converter.ListOutputConverter; 5 | import org.springframework.core.convert.support.DefaultConversionService; 6 | 7 | import java.util.List; 8 | 9 | public class ListStructuredListTest { 10 | 11 | @Test 12 | public void testListStructuredList() { 13 | 14 | ListOutputConverter converter = new ListOutputConverter(new DefaultConversionService()); 15 | List strings = converter.convert("one,two,three"); 16 | 17 | System.out.println(strings); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /spring-ai-deepseek-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | org.ivy 9 | spring-ai-examples 10 | 1.0.0-SNAPSHOT 11 | 12 | 13 | spring-ai-deepseek-examples 14 | 15 | 16 | 17 | org.springframework.ai 18 | spring-ai-openai-spring-boot-starter 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /spring-ai-deepseek-examples/src/main/java/com/ivy/DeepSeekExamplesApplication.java: -------------------------------------------------------------------------------- 1 | package com.ivy; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | 7 | @SpringBootApplication 8 | public class DeepSeekExamplesApplication { 9 | public static void main(String[] args) { 10 | SpringApplication.run(DeepSeekExamplesApplication.class,args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /spring-ai-deepseek-examples/src/main/java/com/ivy/controller/ChatController.java: -------------------------------------------------------------------------------- 1 | package com.ivy.controller; 2 | 3 | import org.springframework.ai.chat.messages.UserMessage; 4 | import org.springframework.ai.chat.model.ChatResponse; 5 | import org.springframework.ai.chat.prompt.Prompt; 6 | import org.springframework.ai.openai.OpenAiChatModel; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RequestParam; 9 | import org.springframework.web.bind.annotation.RestController; 10 | import reactor.core.publisher.Flux; 11 | 12 | import java.util.Map; 13 | 14 | 15 | @RestController 16 | public class ChatController { 17 | 18 | private final OpenAiChatModel chatModel; 19 | 20 | public ChatController(OpenAiChatModel chatModel) { 21 | this.chatModel = chatModel; 22 | } 23 | 24 | @GetMapping("/ai/generate") 25 | public Map generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) { 26 | return Map.of("generation", this.chatModel.call(message)); 27 | } 28 | 29 | @GetMapping("/ai/generateStream") 30 | public Flux generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) { 31 | Prompt prompt = new Prompt(new UserMessage(message)); 32 | return this.chatModel.stream(prompt); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /spring-ai-deepseek-examples/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8801 3 | spring: 4 | ai: 5 | openai: 6 | api-key: sk-xxx 7 | base-url: https://api.deepseek.com 8 | chat: 9 | options: 10 | model: deepseek-chat 11 | -------------------------------------------------------------------------------- /spring-ai-functioncalling-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.ivy 8 | spring-ai-examples 9 | 1.0.0-SNAPSHOT 10 | 11 | 12 | spring-ai-functioncalling-examples 13 | 14 | 15 | 17 16 | 17 17 | UTF-8 18 | 19 | 20 | 21 | 22 | org.springframework.ai 23 | spring-ai-openai-spring-boot-starter 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /spring-ai-functioncalling-examples/src/main/java/org/ivy/FunctionCallingExamplesApplication.java: -------------------------------------------------------------------------------- 1 | package org.ivy; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class FunctionCallingExamplesApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(FunctionCallingExamplesApplication.class,args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /spring-ai-functioncalling-examples/src/main/java/org/ivy/config/Config.java: -------------------------------------------------------------------------------- 1 | package org.ivy.config; 2 | 3 | import org.ivy.func.MockWeatherService; 4 | import org.springframework.ai.model.function.FunctionCallback; 5 | import org.springframework.ai.model.function.FunctionCallbackWrapper; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | public class Config { 11 | 12 | @Bean 13 | public FunctionCallback weatherFunctionInfo() { 14 | 15 | return FunctionCallbackWrapper.builder(new MockWeatherService()) 16 | .withName("WeatherInfo") 17 | .withDescription("Get the weather in location") 18 | .withResponseConverter((response) -> "" + response.temp() + response.unit()) 19 | .build(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /spring-ai-functioncalling-examples/src/main/java/org/ivy/controller/FunctionCallingController.java: -------------------------------------------------------------------------------- 1 | package org.ivy.controller; 2 | 3 | import org.springframework.ai.chat.client.ChatClient; 4 | import org.springframework.ai.chat.messages.UserMessage; 5 | import org.springframework.ai.chat.prompt.Prompt; 6 | import org.springframework.ai.chat.prompt.PromptTemplate; 7 | import org.springframework.ai.openai.OpenAiChatModel; 8 | import org.springframework.ai.openai.OpenAiChatOptions; 9 | import org.springframework.beans.factory.annotation.Value; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | import reactor.core.publisher.Flux; 13 | 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | @RestController 18 | public class FunctionCallingController { 19 | private final OpenAiChatModel openAiChatModel; 20 | 21 | @Value("classpath:weather.st") 22 | private org.springframework.core.io.Resource weather; 23 | 24 | public FunctionCallingController(OpenAiChatModel openAiChatModel) { 25 | this.openAiChatModel = openAiChatModel; 26 | } 27 | 28 | /** 29 | * 没有函数调用,看看返回结果 30 | * 31 | * @return 返回天气情况 32 | */ 33 | @GetMapping("/noFunc") 34 | public Flux noFunc(String prompt) { 35 | ChatClient chatClient = ChatClient.builder(openAiChatModel).build(); 36 | return chatClient.prompt(new PromptTemplate(weather, Map.of("prompt", prompt)).create()) 37 | .stream() 38 | .content(); 39 | } 40 | 41 | /** 42 | * 调用函数,看看返回结果 43 | * 44 | * @return 天气状况 45 | */ 46 | @GetMapping("/func") 47 | public Flux func(String prompt) { 48 | UserMessage userMessage = new UserMessage(prompt + " 你可以调用函数:'WeatherInfo'"); 49 | ChatClient chatClient = ChatClient.builder(openAiChatModel).build(); 50 | return chatClient.prompt(new Prompt( 51 | List.of(userMessage), 52 | OpenAiChatOptions.builder() 53 | .withFunction("WeatherInfo") 54 | .build() 55 | ) 56 | ).stream() 57 | .content(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /spring-ai-functioncalling-examples/src/main/java/org/ivy/func/MockWeatherService.java: -------------------------------------------------------------------------------- 1 | package org.ivy.func; 2 | 3 | import com.fasterxml.jackson.annotation.JsonClassDescription; 4 | import com.fasterxml.jackson.annotation.JsonInclude; 5 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 6 | import com.fasterxml.jackson.annotation.JsonProperty; 7 | import com.fasterxml.jackson.annotation.JsonPropertyDescription; 8 | 9 | import java.util.function.Function; 10 | 11 | public class MockWeatherService implements Function { 12 | 13 | /** 14 | * Weather Function request. 15 | */ 16 | @JsonInclude(Include.NON_NULL) 17 | @JsonClassDescription("Weather API request") 18 | public record Request(@JsonProperty(required = true, value = "location") @JsonPropertyDescription("The city and state e.g. 北京") String location, 19 | @JsonProperty(required = true, value = "unit") @JsonPropertyDescription("Temperature unit") Unit unit) { 20 | } 21 | 22 | /** 23 | * Temperature units. 24 | */ 25 | public enum Unit { 26 | C, F 27 | } 28 | 29 | /** 30 | * Weather Function response. 31 | */ 32 | public record Response(double temp, Unit unit) { 33 | } 34 | 35 | @Override 36 | public Response apply(Request request) { 37 | System.out.println("function called :" + request); 38 | double temperature = 0; 39 | if (request.location().contains("北京")) { 40 | temperature = 15; 41 | } else if (request.location().contains("天津")) { 42 | temperature = 10; 43 | } else if (request.location().contains("南京")) { 44 | temperature = 30; 45 | } 46 | return new Response(temperature, Unit.C); 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /spring-ai-functioncalling-examples/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8804 3 | 4 | spring: 5 | ai: 6 | openai: 7 | api-key: xxx 8 | base-url: xxx 9 | chat: 10 | options: 11 | model: gpt-3.5-turbo 12 | -------------------------------------------------------------------------------- /spring-ai-functioncalling-examples/src/main/resources/weather.st: -------------------------------------------------------------------------------- 1 | 问题: {prompt}, 如果你无法获取到最新的真实有效的数据,请回答:抱歉 -------------------------------------------------------------------------------- /spring-ai-image-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.ivy 8 | spring-ai-examples 9 | 1.0.0-SNAPSHOT 10 | 11 | 12 | spring-ai-image-examples 13 | 14 | 15 | 17 16 | 17 17 | UTF-8 18 | 19 | 20 | 21 | 22 | 23 | org.springframework.ai 24 | spring-ai-openai-spring-boot-starter 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /spring-ai-image-examples/src/main/java/org/ivy/ImageExamplesApplication.java: -------------------------------------------------------------------------------- 1 | package org.ivy; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ImageExamplesApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(ImageExamplesApplication.class,args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /spring-ai-image-examples/src/main/java/org/ivy/controller/AzureImageController.java: -------------------------------------------------------------------------------- 1 | //package org.ivy.controller; 2 | // 3 | //import jakarta.annotation.Resource; 4 | //import org.springframework.ai.azure.openai.AzureOpenAiImageModel; 5 | //import org.springframework.ai.azure.openai.AzureOpenAiImageOptions; 6 | //import org.springframework.ai.image.Image; 7 | //import org.springframework.ai.image.ImagePrompt; 8 | //import org.springframework.ai.image.ImageResponse; 9 | //import org.springframework.ai.openai.api.OpenAiImageApi; 10 | //import org.springframework.web.bind.annotation.GetMapping; 11 | //import org.springframework.web.bind.annotation.RestController; 12 | // 13 | ////@RestController 14 | //public class AzureImageController { 15 | // 16 | // @Resource 17 | // private AzureOpenAiImageModel azureOpenAiImageModel; 18 | // 19 | // @GetMapping("/azure") 20 | // public String image(String prompt) { 21 | // // AzureOpenAiImageOptions 配置要求与OpenAiImageOptions一样,没有任何区别 22 | // AzureOpenAiImageOptions azureOpenAiImageOptions = AzureOpenAiImageOptions.builder() 23 | // .withModel(OpenAiImageApi.ImageModel.DALL_E_3.getValue()) 24 | // .withResponseFormat("url") // url or base 25 | // .build(); 26 | // ImageResponse imageResponse = azureOpenAiImageModel.call(new ImagePrompt(prompt, azureOpenAiImageOptions)); 27 | // Image image = imageResponse.getResult().getOutput(); 28 | // return String.format("%s", image.getUrl(), prompt); 29 | // } 30 | //} 31 | -------------------------------------------------------------------------------- /spring-ai-image-examples/src/main/java/org/ivy/controller/OpenAiImageController.java: -------------------------------------------------------------------------------- 1 | package org.ivy.controller; 2 | 3 | import jakarta.annotation.Resource; 4 | import org.springframework.ai.image.Image; 5 | import org.springframework.ai.image.ImagePrompt; 6 | import org.springframework.ai.image.ImageResponse; 7 | import org.springframework.ai.openai.OpenAiImageModel; 8 | import org.springframework.ai.openai.OpenAiImageOptions; 9 | import org.springframework.ai.openai.api.OpenAiImageApi; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | @RestController 14 | public class OpenAiImageController { 15 | 16 | @Resource 17 | private OpenAiImageModel openAiImageModel; 18 | 19 | /** 20 | * 根据提示词生成图片,并返回图片的URL 21 | * 22 | * @param prompt 提示词 23 | * @return 图片的URL 24 | */ 25 | @GetMapping("/image") 26 | public String image(String prompt) { 27 | ImageResponse imageResponse = openAiImageModel.call( 28 | new ImagePrompt(prompt, OpenAiImageOptions.builder() // 默认model为 dall-e-3 29 | .withModel(OpenAiImageApi.ImageModel.DALL_E_2.getValue()) 30 | .withResponseFormat("url") // url or base 31 | .build() 32 | ) 33 | ); 34 | Image image = imageResponse.getResult().getOutput(); 35 | return String.format("%s", image.getUrl(), prompt); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /spring-ai-image-examples/src/main/java/org/ivy/controller/StabilityImageController.java: -------------------------------------------------------------------------------- 1 | //package org.ivy.controller; 2 | // 3 | //import jakarta.annotation.Resource; 4 | //import org.springframework.ai.image.Image; 5 | //import org.springframework.ai.image.ImagePrompt; 6 | //import org.springframework.ai.image.ImageResponse; 7 | //import org.springframework.ai.stabilityai.StabilityAiImageModel; 8 | //import org.springframework.ai.stabilityai.api.StabilityAiImageOptions; 9 | //import org.springframework.web.bind.annotation.GetMapping; 10 | //import org.springframework.web.bind.annotation.RestController; 11 | // 12 | ////@RestController 13 | //public class StabilityImageController { 14 | // 15 | // @Resource 16 | // private StabilityAiImageModel stabilityAiImageModel; 17 | // 18 | // @GetMapping("/stability") 19 | // public String image(String prompt) { 20 | // // 大家可以自行研究 21 | // StabilityAiImageOptions stabilityAiImageOptions = StabilityAiImageOptions.builder() 22 | //// .withModel() // 指定模型 23 | //// .withHeight() // 指定生成图片的高 24 | //// .withWidth() // 指定生成图片的宽 25 | // .withResponseFormat("image/png") // Must be "application/json" or "image/png" 26 | // .build(); 27 | // ImageResponse imageResponse = stabilityAiImageModel.call(new ImagePrompt(prompt, stabilityAiImageOptions)); 28 | // Image image = imageResponse.getResult().getOutput(); 29 | // return String.format("%s", image.getUrl(), prompt); 30 | // } 31 | //} 32 | -------------------------------------------------------------------------------- /spring-ai-image-examples/src/main/java/org/ivy/controller/ZhiPuImageController.java: -------------------------------------------------------------------------------- 1 | //package org.ivy.controller; 2 | // 3 | //import jakarta.annotation.Resource; 4 | //import org.springframework.ai.image.Image; 5 | //import org.springframework.ai.image.ImagePrompt; 6 | //import org.springframework.ai.image.ImageResponse; 7 | //import org.springframework.ai.zhipuai.ZhiPuAiImageModel; 8 | //import org.springframework.ai.zhipuai.ZhiPuAiImageOptions; 9 | //import org.springframework.web.bind.annotation.GetMapping; 10 | //import org.springframework.web.bind.annotation.RestController; 11 | // 12 | //@RestController 13 | //public class ZhiPuImageController { 14 | // 15 | // @Resource 16 | // private ZhiPuAiImageModel zhiPuAiImageModel; 17 | // 18 | // 19 | // @GetMapping("/zhipu") 20 | // public String image(String prompt) { 21 | // ZhiPuAiImageOptions zhiPuAiImageOptions = ZhiPuAiImageOptions.builder() 22 | // .withModel("cogview-3") // 默认 cogview-3,目前仅支持这一个 23 | // .withUser("xxx") // 帮助 ZhiPuAI 监控和检测滥用行为,传用户user_id 24 | // .build(); 25 | // ImageResponse imageResponse = zhiPuAiImageModel.call(new ImagePrompt(prompt, zhiPuAiImageOptions)); 26 | // Image image = imageResponse.getResult().getOutput(); 27 | // return String.format("%s", image.getUrl(), prompt); 28 | // } 29 | //} 30 | -------------------------------------------------------------------------------- /spring-ai-image-examples/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8802 3 | 4 | spring: 5 | ai: 6 | # openai 模型配置 7 | openai: 8 | api-key: xxx 9 | base-url: xxx 10 | # zhipuai 模型配置 11 | zhipuai: 12 | base-url: xxx 13 | api-key: xxx 14 | chat: 15 | enabled: false 16 | # azure 模型配置 17 | azure: 18 | openai: 19 | chat: 20 | enabled: off 21 | endpoint: xxx 22 | image: 23 | enabled: off 24 | # stabilityai 模型配置 25 | stabilityai: 26 | image: 27 | enabled: off 28 | base-url: xxx 29 | api-key: xxx 30 | 31 | -------------------------------------------------------------------------------- /spring-ai-multimodality-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.ivy 8 | spring-ai-examples 9 | 1.0.0-SNAPSHOT 10 | 11 | 12 | spring-ai-multimodality-examples 13 | 14 | 15 | 17 16 | 17 17 | UTF-8 18 | 19 | 20 | 21 | 22 | org.springframework.ai 23 | spring-ai-ollama-spring-boot-starter 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /spring-ai-multimodality-examples/src/main/java/org/ivy/MultiModalityExamplesApplication.java: -------------------------------------------------------------------------------- 1 | package org.ivy; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | 7 | @SpringBootApplication 8 | public class MultiModalityExamplesApplication { 9 | public static void main(String[] args) { 10 | SpringApplication.run(MultiModalityExamplesApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /spring-ai-multimodality-examples/src/main/java/org/ivy/controller/MultiModalityController.java: -------------------------------------------------------------------------------- 1 | package org.ivy.controller; 2 | 3 | import org.springframework.ai.chat.client.ChatClient; 4 | import org.springframework.ai.chat.messages.Media; 5 | import org.springframework.ai.chat.messages.UserMessage; 6 | import org.springframework.ai.chat.prompt.Prompt; 7 | import org.springframework.ai.ollama.OllamaChatModel; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.util.MimeTypeUtils; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import org.springframework.web.bind.annotation.RequestParam; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import java.util.List; 15 | 16 | @RestController 17 | public class MultiModalityController { 18 | 19 | @Value("classpath:img.png") 20 | private org.springframework.core.io.Resource imageResource; 21 | 22 | private final OllamaChatModel ollamaChatModel; 23 | 24 | public MultiModalityController(OllamaChatModel ollamaChatModel) { 25 | this.ollamaChatModel = ollamaChatModel; 26 | } 27 | 28 | @GetMapping("multi") 29 | public String multiModality(@RequestParam(defaultValue = "Explain what do you see on this picture?") String text) { 30 | ChatClient chatClient = ChatClient.builder(ollamaChatModel).build(); 31 | var userMessage = new UserMessage(text, List.of(new Media(MimeTypeUtils.IMAGE_PNG, imageResource))); 32 | return chatClient.prompt(new Prompt(List.of(userMessage))) 33 | .call() 34 | .content(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /spring-ai-multimodality-examples/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8804 3 | 4 | spring: 5 | ai: 6 | ollama: 7 | base-url: http://localhost:11434 8 | chat: 9 | model: llava:7b 10 | -------------------------------------------------------------------------------- /spring-ai-multimodality-examples/src/main/resources/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fj-ivy/spring-ai-examples/920f27a5326721e3393378078a5b68545858dd24/spring-ai-multimodality-examples/src/main/resources/img.png -------------------------------------------------------------------------------- /spring-ai-rag-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.ivy 8 | spring-ai-examples 9 | 1.0.0-SNAPSHOT 10 | 11 | 12 | spring-ai-rag-examples 13 | 14 | 15 | 17 16 | 17 17 | UTF-8 18 | 19 | 20 | 21 | 22 | org.springframework.ai 23 | spring-ai-ollama-spring-boot-starter 24 | 25 | 26 | org.springframework.ai 27 | spring-ai-pgvector-store-spring-boot-starter 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.projectlombok 36 | lombok 37 | 38 | 39 | org.springframework.ai 40 | spring-ai-tika-document-reader 41 | 42 | 43 | org.springframework.ai 44 | spring-ai-pdf-document-reader 45 | 46 | 47 | -------------------------------------------------------------------------------- /spring-ai-rag-examples/redis.md: -------------------------------------------------------------------------------- 1 | # redis作为vector使用 2 | https://redis.io/docs/latest/operate/oss_and_stack/install/install-stack/docker/ -------------------------------------------------------------------------------- /spring-ai-rag-examples/src/main/java/org/ivy/RagExamplesApplication.java: -------------------------------------------------------------------------------- 1 | package org.ivy; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RagExamplesApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(RagExamplesApplication.class,args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /spring-ai-rag-examples/src/main/java/org/ivy/config/Config.java: -------------------------------------------------------------------------------- 1 | package org.ivy.config; 2 | 3 | import org.springframework.ai.document.DocumentTransformer; 4 | import org.springframework.ai.transformer.splitter.TokenTextSplitter; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | public class Config { 10 | 11 | @Bean 12 | public DocumentTransformer transformer() { 13 | return new TokenTextSplitter(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /spring-ai-rag-examples/src/main/java/org/ivy/controller/OfflineController.java: -------------------------------------------------------------------------------- 1 | package org.ivy.controller; 2 | 3 | import org.ivy.service.OfflineService; 4 | import org.springframework.http.ResponseEntity; 5 | import org.springframework.web.bind.annotation.PostMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | import org.springframework.web.multipart.MultipartFile; 8 | 9 | /** 10 | * RAG 系统的离线部分实现 11 | */ 12 | @RestController 13 | public class OfflineController { 14 | 15 | private final OfflineService offlineService; 16 | 17 | public OfflineController(OfflineService offlineService) { 18 | this.offlineService = offlineService; 19 | } 20 | @PostMapping("/upload") 21 | public ResponseEntity upload(MultipartFile file) { 22 | return ResponseEntity.ok(offlineService.upload(file)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /spring-ai-rag-examples/src/main/java/org/ivy/controller/OnlineController.java: -------------------------------------------------------------------------------- 1 | package org.ivy.controller; 2 | 3 | import jakarta.annotation.Resource; 4 | import org.ivy.service.OnlineService; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | import reactor.core.publisher.Flux; 8 | 9 | @RestController 10 | public class OnlineController { 11 | 12 | @Resource 13 | private OnlineService onlineService; 14 | 15 | /** 16 | * Simple response generation. 17 | * 18 | * @param prompt 提示词 19 | * @return 返回内容 20 | */ 21 | @GetMapping("/simple") 22 | public Flux simple(String prompt) { 23 | return onlineService.simple(prompt); 24 | } 25 | 26 | /** 27 | * RAG-based response generation. 28 | * 29 | * @param prompt 提示词 30 | * @return 返回内容 31 | */ 32 | @GetMapping("/rag") 33 | public Flux rag(String prompt) { 34 | return onlineService.rag(prompt); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /spring-ai-rag-examples/src/main/java/org/ivy/service/OfflineService.java: -------------------------------------------------------------------------------- 1 | package org.ivy.service; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import org.springframework.ai.document.Document; 5 | import org.springframework.ai.document.DocumentTransformer; 6 | import org.springframework.ai.reader.tika.TikaDocumentReader; 7 | import org.springframework.ai.vectorstore.VectorStore; 8 | import org.springframework.core.io.Resource; 9 | import org.springframework.stereotype.Service; 10 | import org.springframework.web.multipart.MultipartFile; 11 | 12 | import java.util.List; 13 | 14 | @Service 15 | @RequiredArgsConstructor 16 | public class OfflineService { 17 | 18 | private final VectorStore vectorStore; 19 | private final DocumentTransformer transformer; 20 | 21 | /** 22 | * 上传文件,并拆分文档,向量化到数据库 23 | * 24 | * @param file 文件 25 | * @return 上传结果 26 | */ 27 | public String upload(MultipartFile file) { 28 | Resource resource = file.getResource(); 29 | TikaDocumentReader reader = new TikaDocumentReader(resource); 30 | // 读取文档 31 | List documents = reader.get(); 32 | // 拆分文档 33 | List transform = transformer.transform(documents); 34 | // 向量化到数据库 35 | vectorStore.accept(transform); 36 | return "ok"; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /spring-ai-rag-examples/src/main/java/org/ivy/service/OnlineService.java: -------------------------------------------------------------------------------- 1 | package org.ivy.service; 2 | 3 | import jakarta.annotation.Resource; 4 | import org.apache.commons.collections4.CollectionUtils; 5 | import org.springframework.ai.chat.client.ChatClient; 6 | import org.springframework.ai.chat.prompt.Prompt; 7 | import org.springframework.ai.chat.prompt.SystemPromptTemplate; 8 | import org.springframework.ai.document.Document; 9 | import org.springframework.ai.ollama.OllamaChatModel; 10 | import org.springframework.ai.vectorstore.SearchRequest; 11 | import org.springframework.ai.vectorstore.VectorStore; 12 | import org.springframework.beans.factory.annotation.Value; 13 | import org.springframework.stereotype.Service; 14 | import reactor.core.publisher.Flux; 15 | 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | @Service 20 | public class OnlineService { 21 | @Value("classpath:rag.st") 22 | private org.springframework.core.io.Resource ragTemplate; 23 | @Resource 24 | private OllamaChatModel chatModel; 25 | @Resource 26 | private VectorStore vectorStore; 27 | 28 | public Flux simple(String prompt) { 29 | ChatClient client = ChatClient.builder(chatModel).build(); 30 | return client.prompt() 31 | .user(prompt) 32 | .stream() 33 | .content(); 34 | 35 | } 36 | 37 | public Flux rag(String prompt) { 38 | // 检索 39 | SearchRequest searchRequest = SearchRequest.builder().query(prompt).similarityThreshold(0.8).build(); 40 | List documents = vectorStore.similaritySearch(searchRequest); 41 | if (CollectionUtils.isEmpty(documents)) { 42 | return Flux.empty(); 43 | } 44 | // 提示词生成 45 | List context = documents.stream().map(Document::getFormattedContent).toList(); 46 | SystemPromptTemplate promptTemplate = new SystemPromptTemplate(ragTemplate); 47 | Prompt p = promptTemplate.create(Map.of("context", context, "question", prompt)); 48 | ChatClient chatClient = ChatClient.builder(chatModel).build(); 49 | // 大模型生成内容 50 | return chatClient.prompt(p).stream().content(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /spring-ai-rag-examples/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8806 3 | 4 | spring: 5 | datasource: 6 | url: jdbc:postgresql://localhost:5432/postgres 7 | username: pgvector 8 | password: pgvector 9 | driver-class-name: org.postgresql.Driver 10 | ai: 11 | ollama: 12 | base-url: http://localhost:11434 13 | embedding: 14 | options: 15 | model: qwen:7b 16 | chat: 17 | model: qwen:7b 18 | vectorstore: 19 | pgvector: 20 | index-type: NONE # 索引类型 21 | distance-type: cosine_distance # 指定相似度计算方式 22 | dimensions: 2048 # 向量维度 23 | redis: 24 | uri: redis://localhost:6379 -------------------------------------------------------------------------------- /spring-ai-rag-examples/src/main/resources/rag.st: -------------------------------------------------------------------------------- 1 | Context information is below. 2 | --------------------- 3 | {context} 4 | --------------------- 5 | Given the context information and not prior knowledge, answer the question in Chinese. 6 | You need to respond with content in context first, and then respond with your own database. When the given context doesn't help you answer the question, just say "I don't know." 7 | 8 | Question: {question} 9 | Answer: 10 | -------------------------------------------------------------------------------- /spring-ai-rag-examples/src/main/resources/rag.txt: -------------------------------------------------------------------------------- 1 | 一、基本介绍 2 | ivy,毕业于哈尔滨工业大学。他的工作主要是开发基于机器学习的智能问答系统。 3 | 4 | 二、教育背景 5 | 2015.09-2019.06 哈尔滨工业大学 软件工程专业 6 | 7 | 三、工作经历 8 | 2019.06-至今 xxx公司 软件工程专业 9 | 10 | 四、项目经历 11 | 1. 基于深度学习的智能问答系统(2019.06-至今) 12 | 项目名称:基于深度学习的智能问答系统 13 | 项目描述: 14 | 基于深度学习的智能问答系统,主要基于BERT等预训练模型,通过对问题和答案的文本进行编码,并训练模型,使得系统能够自动回答用户的问题。 15 | 项目职责: 16 | - 负责模型的搭建、训练、评估、调优 17 | - 负责模型的部署与维护 18 | - 负责模型的性能优化 19 | - 负责模型的文档编写、报告撰写 20 | 21 | 22 | 五、个人技能 23 | - 熟悉Python、Java、C++等编程语言 24 | - 了解机器学习、深度学习、NLP等领域的基本理论和技术 25 | - 了解Linux、Docker、Kubernetes等云计算技术 26 | 27 | 六、个人评价 28 | - 具有良好的沟通能力、团队协作能力、学习能力、创新能力 29 | - 具有较强的分析问题、解决问题的能力、解决问题的能力 30 | 31 | Github地址:https://github.com/ivy 32 | -------------------------------------------------------------------------------- /spring-ai-rag-examples/src/test/java/org/ivy/rag/EnricherTest.java: -------------------------------------------------------------------------------- 1 | package org.ivy.rag; 2 | 3 | import jakarta.annotation.Resource; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.ai.document.Document; 6 | import org.springframework.ai.ollama.OllamaChatModel; 7 | import org.springframework.ai.reader.pdf.PagePdfDocumentReader; 8 | import org.springframework.ai.reader.tika.TikaDocumentReader; 9 | import org.springframework.ai.transformer.KeywordMetadataEnricher; 10 | import org.springframework.ai.transformer.SummaryMetadataEnricher; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | 14 | import java.util.List; 15 | 16 | @SpringBootTest 17 | public class EnricherTest { 18 | @Resource 19 | private OllamaChatModel ollamaChatModel; 20 | 21 | @Value("classpath:java.pdf") 22 | private org.springframework.core.io.Resource testFileResource; 23 | 24 | /** 25 | * 关键词提取 26 | */ 27 | @Test 28 | public void testEnrichKeywordMetadata() { 29 | PagePdfDocumentReader reader = new PagePdfDocumentReader(testFileResource); 30 | List documents = reader.get(); 31 | KeywordMetadataEnricher keywordMetadataEnricher = new KeywordMetadataEnricher(ollamaChatModel, 1000); 32 | List enrichers = keywordMetadataEnricher.apply(documents); 33 | System.out.println(enrichers); 34 | } 35 | 36 | /** 37 | * 文档摘要 38 | */ 39 | @Test 40 | public void testSummaryMetadataEnricher() { 41 | PagePdfDocumentReader reader = new PagePdfDocumentReader(testFileResource); 42 | List documents = reader.get(); 43 | SummaryMetadataEnricher keywordMetadataEnricher = new SummaryMetadataEnricher(ollamaChatModel,List.of(SummaryMetadataEnricher.SummaryType.CURRENT)); 44 | List enrichers = keywordMetadataEnricher.apply(documents); 45 | System.out.println(enrichers); 46 | 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /spring-ai-rag-examples/src/test/java/org/ivy/rag/PgVectorServiceTest.java: -------------------------------------------------------------------------------- 1 | package org.ivy.rag; 2 | 3 | import jakarta.annotation.Resource; 4 | import org.junit.jupiter.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | import org.springframework.ai.document.Document; 7 | import org.springframework.ai.vectorstore.SearchRequest; 8 | import org.springframework.ai.vectorstore.VectorStore; 9 | import org.springframework.ai.vectorstore.filter.FilterExpressionBuilder; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | @SpringBootTest 16 | public class PgVectorServiceTest { 17 | @Resource 18 | private VectorStore vectorStore; 19 | 20 | @Test 21 | public void testAdd() { 22 | List documents = List.of( 23 | new Document("Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!!", Map.of("year", "2021", "user", "zhang")), 24 | new Document("The World is Big and Salvation Lurks Around the Corner", Map.of("year", "2019", "user", "li")), 25 | new Document("You walk forward facing the past and you turn back toward the future.", Map.of("year", "2024", "user", "wang"))); 26 | 27 | vectorStore.accept(documents); 28 | } 29 | 30 | 31 | /** 32 | * 测试相似查询,仅设置query参数 33 | */ 34 | @Test 35 | public void testSimilaritySearch() { 36 | List documents = vectorStore.similaritySearch("Spring AI rocks!!"); 37 | Assertions.assertEquals(documents.size(), 3); 38 | } 39 | 40 | /** 41 | * 相似度查询,设置相似度阈值和返回结果数 42 | */ 43 | @Test 44 | public void testSimilaritySearchWithRequest() { 45 | List documents = vectorStore.similaritySearch( 46 | SearchRequest 47 | .query("Spring AI rocks!!") 48 | .withTopK(2) 49 | .withSimilarityThreshold(0.8)); 50 | 51 | Assertions.assertEquals(documents.size(), 1); 52 | } 53 | 54 | 55 | /** 56 | * 查询相似度,并且是zhang的数据 57 | */ 58 | @Test 59 | public void testSimilaritySearchWithRequestAndFilter() { 60 | FilterExpressionBuilder b = new FilterExpressionBuilder(); 61 | 62 | List documents = vectorStore.similaritySearch( 63 | SearchRequest 64 | .query("Spring AI rocks!!") 65 | .withFilterExpression(b.eq("user", "zhang").build()) 66 | ); 67 | 68 | Assertions.assertEquals(documents.size(), 1); 69 | 70 | // 另外一种写法 71 | List docs = vectorStore.similaritySearch( 72 | SearchRequest 73 | .query("Spring AI rocks!!") 74 | .withFilterExpression("user == 'zhang'") 75 | ); 76 | 77 | Assertions.assertEquals(docs.size(), 1); 78 | 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /spring-ai-rag-examples/src/test/resources/java.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fj-ivy/spring-ai-examples/920f27a5326721e3393378078a5b68545858dd24/spring-ai-rag-examples/src/test/resources/java.pdf -------------------------------------------------------------------------------- /spring-ai-toolcalling-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.ivy 8 | spring-ai-examples 9 | 1.0.0-SNAPSHOT 10 | 11 | 12 | spring-ai-toolcalling-examples 13 | 14 | 15 | 17 16 | 17 17 | UTF-8 18 | 19 | 20 | 21 | 22 | org.springframework.ai 23 | spring-ai-ollama-spring-boot-starter 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /spring-ai-toolcalling-examples/src/main/java/org/ivy/ToolCallingExamplesApplication.java: -------------------------------------------------------------------------------- 1 | package org.ivy; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ToolCallingExamplesApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(ToolCallingExamplesApplication.class,args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /spring-ai-toolcalling-examples/src/main/java/org/ivy/controller/ToolsController.java: -------------------------------------------------------------------------------- 1 | package org.ivy.controller; 2 | 3 | import org.ivy.tools.DateTimeTools; 4 | import org.springframework.ai.chat.client.ChatClient; 5 | import org.springframework.ai.ollama.OllamaChatModel; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestParam; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | @RestController 11 | public class ToolsController { 12 | private final OllamaChatModel ollamaChatModel; 13 | 14 | public ToolsController(OllamaChatModel ollamaChatModel) { 15 | this.ollamaChatModel = ollamaChatModel; 16 | } 17 | 18 | @GetMapping("/search-tool") 19 | public String get(@RequestParam(value = "prompt", required = false) String prompt) { 20 | return ChatClient.create(ollamaChatModel) 21 | .prompt(prompt) 22 | .tools(new DateTimeTools()) 23 | .call() 24 | .content(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /spring-ai-toolcalling-examples/src/main/java/org/ivy/tools/DateTimeTools.java: -------------------------------------------------------------------------------- 1 | package org.ivy.tools; 2 | 3 | import org.springframework.ai.tool.annotation.Tool; 4 | import org.springframework.context.i18n.LocaleContextHolder; 5 | 6 | import java.time.LocalDateTime; 7 | import java.time.format.DateTimeFormatter; 8 | 9 | public class DateTimeTools { 10 | 11 | @Tool(description = "Get the current date and time in the user's timezone") 12 | String getCurrentDateTime() { 13 | return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString(); 14 | } 15 | 16 | @Tool(description = "Set a user alarm for the given time, provided in ISO-8601 format") 17 | LocalDateTime setAlarm(String time) { 18 | LocalDateTime alarmTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME); 19 | System.out.println("Alarm set for " + alarmTime); 20 | return alarmTime; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /spring-ai-toolcalling-examples/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8808 3 | 4 | spring: 5 | ai: 6 | ollama: 7 | chat: 8 | model: qwen2.5 --------------------------------------------------------------------------------