2. Spring AI 快速入门使用
@
- 2. Spring AI 快速入门使用
- 快速使用
- 接入deepseek
- 流式对话
- options配置选项
- temperature(温度)
- 建议
- maxTokens
- stop
- 模型推理
- temperature(温度)
- 原理:
- 接入阿里百炼
- 使用
- 文生图
- 文生语音text2audio
- 语音翻译audio2text
- 多模态
- 文生视频(更多功能)
- 接入deepseek
- 快速使用
- 最后:
快速使用
- 创建项目
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.4.5</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.xs</groupId><artifactId>spring-ai-GA</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-ai-GA</name><properties><java.version>17</java.version><spring-ai.version>1.0.0</spring-ai.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><!-- Spring AI 版本管理依赖,可以减少版本的冲突 --><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>${spring-ai.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
接入deepseek
- 依赖
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-deepseek</artifactId></dependency>
- 获取deepseek api-key
- API Key:需从 DeepSeek 创建并获取 API 密钥:https://platform.deepseek.com/api_keys
- 配置
spring:ai:deepseek:api-key: ${DEEP_SEEK_KEY}chat:options:model: deepseek-chat
- 测试
package com.xs.springaiga;import org.junit.jupiter.api.Test;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
public class DeepseelTest {@Testpublic void testChat(@AutowiredDeepSeekChatModel chatModel) {String call = chatModel.call("你是谁");System.out.println(call);}
}
上述是一种阻塞输出方式,就是要等服务器全部处理完了,才会被响应出来。
流式对话
@Testpublic void testChat2(@AutowiredDeepSeekChatModel chatModel) {Flux<String> stream = chatModel.stream("你是谁");// 流式输出stream.toIterable().forEach(System.out::print);}
流式输出,就是服务器接受到一点,就输出一点
options配置选项
temperature(温度)
0-2 浮点数值
数值越高 更有创造性 热情
数值越低 保守
@Test
public void testChatOptions(@AutowiredDeepSeekChatModel chatModel) {DeepSeekChatOptions options = DeepSeekChatOptions.builder().temperature(1.9d).build();ChatResponse res = chatModel.call(new Prompt("请写一句诗描述清晨。", options));System.out.println(res.getResult().getOutput().getText());
}
也可以通过配置文件配置
spring.ai.deepseek.chat.options.temperature=0.8
temperature:0.2 规规矩矩,像是被应试教育出来的老实学生没有创造力
temperature:1.9 可以看出来表现欲更强, 像是一个在领导面前想要表现的你.
也可以通过提示词降低他的主观臆想:
- 只引用可靠来源中的信息,不做任何假设或扩展描述。
- 请只基于已知事实回答,不要主观臆想或添加额外内容。
- 请简明、客观地给出答案,不要进行修饰或补充未经请求的信息。
建议
temperature 范围 | 建议业务场景 | 输出风格 | 说明/应用举例 |
---|---|---|---|
0.0 ~ 0.2 | 严谨问答、代码补全、数学答题 | 严格、确定、标准 | 法律/金融答题、接口返回模板、考试答卷等 |
0.3 ~ 0.6 | 聊天机器人、日常摘要、辅助写作 | 稍有变化、较稳妥 | 公众号摘要、普通对话、邮件生成等 |
0.7 ~ 1.0 | 创作内容、广告文案、标题生成 | 丰富、有创意、灵活 | 诗歌、短文案、趣味对话、产品描述等 |
1.1 ~ 1.5 | 脑洞风格、头脑风暴、灵感碰撞场景 | 大开脑洞、变化极强 | 故事创作、异想天开的推荐语、多样化内容 |
说明:
- 温度越低,输出越收敛和中规中矩;
- 温度越高,输出越多变、富有惊喜但有风险;
- 实战用法一般建议选 0.5~0.8 作为日常生产起点,需要根据业务不断测试调整。
maxTokens
默认低 token
maxTokens
: 限制AI模型生成的最大token数(近似理解为字数上限)。
- 需要简洁回复、打分、列表、短摘要等,建议小值(如10~50)。
- 防止用户跑长对话导致无关内容或花费过多token费用。
- 如果遇到生成内容经常被截断,可以适当配置更大maxTokens。
stop
截断你不想输出的内容 比如:
spring:ai:deepseek:api-key: ${DEEP_SEEK_KEY}chat:options:model: deepseek-chatmax-tokens: 20stop:- "\n" #只想一行- "。" #只想一句话- "政治" #敏感词- "最后最总结一下" #这种AI惯用的模板词, 减少AI词汇, 让文章更拟人
模型推理
设置深度思考, 思考的内容有个专业名词叫:Chain of Thought (CoT)
在deepseek中, deepseek-reasoner模型是深度思考模型:
@Testpublic void deepSeekReasonerExample(@Autowired DeepSeekChatModel deepSeekChatModel) {DeepSeekChatOptions options = DeepSeekChatOptions.builder().model("deepseek-reasoner").build();Prompt prompt = new Prompt("请写一句诗描述清晨。", options);ChatResponse res = deepSeekChatModel.call(prompt);DeepSeekAssistantMessage assistantMessage = (DeepSeekAssistantMessage)res.getResult().getOutput();String reasoningContent = assistantMessage.getReasoningContent();String content = assistantMessage.getText();System.out.println(reasoningContent);System.out.println("--------------------------------------------");System.out.println(content);}@Testpublic void deepSeekReasonerStreamExample(@Autowired DeepSeekChatModel deepSeekChatModel) {DeepSeekChatOptions options = DeepSeekChatOptions.builder().model("deepseek-reasoner").build();Prompt prompt = new Prompt("请写一句诗描述清晨。", options);Flux<ChatResponse> stream = deepSeekChatModel.stream(prompt);stream.toIterable().forEach(res -> {DeepSeekAssistantMessage assistantMessage = (DeepSeekAssistantMessage)res.getResult().getOutput();String reasoningContent = assistantMessage.getReasoningContent();System.out.print(reasoningContent);});System.out.println("--------------------------------------------");stream.toIterable().forEach(res -> {DeepSeekAssistantMessage assistantMessage = (DeepSeekAssistantMessage)res.getResult().getOutput();String content = assistantMessage.getText();System.out.print(content);});}
也可以在配置文件中配置
spring.ai.deepseek.chat.options.model= deepseek-reasoner
原理:
- 当调用chatModel.call
default String call(String message) {Prompt prompt = new Prompt(new UserMessage(message));Generation generation = call(prompt).getResult();return (generation != null) ? generation.getOutput().getText() : "";
}
1. 首先会将提示词解析到Prompt对象中 (用于远程请求的messages)
- 调用deepseekModel#call---> internalCall方法
public ChatResponse internalCall(Prompt prompt, ChatResponse previousChatResponse) {// aChatCompletionRequest request = createRequest(prompt, false);//..省略 ResponseEntity<ChatCompletion> completionEntity = this.retryTemplate// b.execute(ctx -> this.deepSeekApi.chatCompletionEntity(request));var chatCompletion = completionEntity.getBody();//..省略ChatResponse chatResponse = new ChatResponse(generations,from(completionEntity.getBody(), accumulatedUsage));observationContext.setResponse(chatResponse);return chatResponse;//.. 省略return response;
}
1. 通过createRequest封装为远程请求所需的json对象
2. 通过spring retry 重试机制去远程请求
deepseekthis.deepSeekApi.chatCompletionEntity(request)
// 通过restClient 进行远程请求
public ResponseEntity<ChatCompletion> chatCompletionEntity(ChatCompletionRequest chatRequest) {return this.restClient.post().uri(this.getEndpoint(chatRequest)).body(chatRequest).retrieve().toEntity(ChatCompletion.class);}
1. 封装响应数据
接入阿里百炼
https://bailian.console.aliyun.com/?tab=home#/home
阿里自己的团队维护spring-ai-alibaba. 但是也必须依赖spring-ai 。 好处是扩展度更高,坏处是必须是springai先出来, spring-ai-alibaba.延迟几天出来。
如果需要接入阿里的百炼平台, 就必须用该组件
使用
- 申请api-key
在调用前,您需要开通模型服务并获取API Key,再配置API Key到环境变量。
- 依赖
<dependencyManagement><dependencies><!-- 版本管理依赖 --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-bom</artifactId><version>1.0.0.2</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement><dependencies><!--阿里的百炼依赖 --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-dashscope</artifactId></dependency>
</dependencies>
- 配置
不配置指定通义千问的模型名的话,也是会自动配置一个默认模型名。
spring:ai:dashscope:api-key: ${AI_DASHSCOPE_API_KEY}
- 使用
@Testpublic void testQwen(@Autowired DashScopeChatModel dashScopeChatModel) {String content = dashScopeChatModel.call("你好你是谁");System.out.println(content);}
文生图
@Testpublic void text2Img(// 注意:这里是图片生成使用的是 DashScopeImageModel 也是被自动装配了。@Autowired DashScopeImageModel imageModel) {DashScopeImageOptions imageOptions = DashScopeImageOptions.builder().withModel("wanx2.1-t2i-turbo").build(); // 构建配置项// 返回一个图片想 Response 返回类ImageResponse imageResponse = imageModel.call(new ImagePrompt("小兔子", imageOptions));String imageUrl = imageResponse.getResult().getOutput().getUrl();// 图片urlSystem.out.println(imageUrl);// 图片base64// imageResponse.getResult().getOutput().getB64Json();/*按文件流相应InputStream in = url.openStream();response.setHeader("Content-Type", MediaType.IMAGE_PNG_VALUE);response.getOutputStream().write(in.readAllBytes());response.getOutputStream().flush();*/}
文生语音text2audio
// https://bailian.console.aliyun.com/?spm=5176.29619931.J__Z58Z6CX7MY__Ll8p1ZOR.1.74cd59fcXOTaDL&tab=doc#/doc/?type=model&url=https%3A%2F%2Fhelp.aliyun.com%2Fdocument_detail%2F2842586.html&renderType=iframe@Testpublic void testText2Audio(// DashScopeSpeechSynthesisModel 自动装配生成 语言类@Autowired DashScopeSpeechSynthesisModel speechSynthesisModel) throws IOException {// 语言配置项,.出来DashScopeSpeechSynthesisOptions options = DashScopeSpeechSynthesisOptions.builder()//.voice() // 人声 //.speed() // 语速//.model() // 模型//.responseFormat(DashScopeSpeechSynthesisApi.ResponseFormat.MP3).build();SpeechSynthesisResponse response = speechSynthesisModel.call(new SpeechSynthesisPrompt("大家好, 我是李华。",options));File file = new File( System.getProperty("user.dir") + "/output.mp3");try (FileOutputStream fos = new FileOutputStream(file)) {// 响应的语言的二进制流ByteBuffer byteBuffer = response.getResult().getOutput().getAudio();// 保存到我们,根路径下fos.write(byteBuffer.array());}catch (IOException e) {throw new IOException(e.getMessage());}}
语音翻译audio2text
// 这个设置的是一个远程的 url 文本内容
private static final String AUDIO_RESOURCES_URL = "https://dashscope.oss-cn-beijing.aliyuncs.com/samples/audio/paraformer/hello_world_female2.wav";@Testpublic void testAudio2Text(@AutowiredDashScopeAudioTranscriptionModel transcriptionModel) throws MalformedURLException {DashScopeAudioTranscriptionOptions transcriptionOptions = DashScopeAudioTranscriptionOptions.builder()//.withModel() 模型.build();AudioTranscriptionPrompt prompt = new AudioTranscriptionPrompt(new UrlResource(AUDIO_RESOURCES_URL),transcriptionOptions);AudioTranscriptionResponse response = transcriptionModel.call(prompt);System.out.println(response.getResult().getOutput());}
多模态
图片,语音,视频 传给大模型让大模型识别,理解其中的内容。
@Test
public void testMultimodal(@Autowired DashScopeChatModel dashScopeChatModel) throws MalformedURLException {// flac、mp3、mp4、mpeg、mpga、m4a、ogg、wav 或 webm。var audioFile = new ClassPathResource("/files/xushu.png");// MimeTypeUtils.IMAGE_JPEG 表示我们传递的文件类型Media media = new Media(MimeTypeUtils.IMAGE_JPEG, audioFile);DashScopeChatOptions options = DashScopeChatOptions.builder().withMultiModel(true) // 使用多模态要设置为 true .withModel("qwen-vl-max-latest").build();Prompt prompt= Prompt.builder().chatOptions(options).messages(UserMessage.builder().media(media)// 设置提示词 为“识别图片”.text("识别图片").build()).build();ChatResponse response = dashScopeChatModel.call(prompt);System.out.println(response.getResult().getOutput().getText());
}
文生视频(更多功能)
因为这里的 Spring AI 目前并没有提供文生视频的 Modles 内容,需要接入第三方的依赖,使用第三方 API。
<dependency><groupId>com.alibaba</groupId><artifactId>dashscope-sdk-java</artifactId><!-- 请将 'the-latest-version' 替换为最新版本号:https://mvnrepository.com/artifact/com.alibaba/dashscope-sdk-java --><version>the-latest-version</version><version>2.20.6</version>
</dependency>
@Testpublic void text2Video() throws ApiException, NoApiKeyException, InputRequiredException {VideoSynthesis vs = new VideoSynthesis();VideoSynthesisParam param =VideoSynthesisParam.builder().model("wanx2.1-t2v-turbo").prompt("一只小猫在月光下奔跑").size("1280*720")// 因为这里我们接入的是第三方API,对应的key并没有采用application.yaml的配置// 所以需要我们手动,System.getenv() 获取到环境变量当中的key值.apiKey(System.getenv("ALI_AI_KEY")).build();System.out.println("please wait...");VideoSynthesisResult result = vs.call(param);System.out.println(result.getOutput().getVideoUrl());}
更多的内容可以去参考阿里云百炼广场 https://bailian.console.aliyun.com/?tab=home#/home 当中的 SDK,以及提供的一些 Demo 进行配置操作。
最后:
“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”