├── .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 |
12 |
13 |
14 |
15 |
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("
", 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("
", 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("
", 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("
", 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
--------------------------------------------------------------------------------