@
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.4.5
com.xs
spring-ai-GA
0.0.1-SNAPSHOT
spring-ai-GA
17
1.0.0
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.ai
spring-ai-bom
${spring-ai.version}
pom
import
org.springframework.boot
spring-boot-maven-plugin
org.springframework.ai
spring-ai-starter-model-deepseek
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 {
@Test
public void testChat(@Autowired
DeepSeekChatModel chatModel) {
String call = chatModel.call("你是谁");
System.out.println(call);
}
}
上述是一种阻塞输出方式,就是要等服务器全部处理完了,才会被响应出来。
@Test
public void testChat2(@Autowired
DeepSeekChatModel chatModel) {
Flux stream = chatModel.stream("你是谁");
// 流式输出
stream.toIterable().forEach(System.out::print);
}
流式输出,就是服务器接受到一点,就输出一点
0-2 浮点数值
数值越高 更有创造性 热情
数值越低 保守
@Test
public void testChatOptions(@Autowired
DeepSeekChatModel 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 | 脑洞风格、头脑风暴、灵感碰撞场景 | 大开脑洞、变化极强 | 故事创作、异想天开的推荐语、多样化内容 |
说明:
默认低 token
maxTokens
: 限制AI模型生成的最大token数(近似理解为字数上限)。
截断你不想输出的内容 比如:
spring:
ai:
deepseek:
api-key: ${DEEP_SEEK_KEY}
chat:
options:
model: deepseek-chat
max-tokens: 20
stop:
- "n" #只想一行
- "。" #只想一句话
- "政治" #敏感词
- "最后最总结一下" #这种AI惯用的模板词, 减少AI词汇, 让文章更拟人
设置深度思考, 思考的内容有个专业名词叫:Chain of Thought (CoT)
在deepseek中, deepseek-reasoner模型是深度思考模型:
@Test
public 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);
}
@Test
public void deepSeekReasonerStreamExample(@Autowired DeepSeekChatModel deepSeekChatModel) {
DeepSeekChatOptions options = DeepSeekChatOptions.builder()
.model("deepseek-reasoner").build();
Prompt prompt = new Prompt("请写一句诗描述清晨。", options);
Flux 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
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)
public ChatResponse internalCall(Prompt prompt, ChatResponse previousChatResponse) {
// a
ChatCompletionRequest request = createRequest(prompt, false);
//..省略
ResponseEntity 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 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到环境变量。
com.alibaba.cloud.ai
spring-ai-alibaba-bom
1.0.0.2
pom
import
com.alibaba.cloud.ai
spring-ai-alibaba-starter-dashscope
不配置指定通义千问的模型名的话,也是会自动配置一个默认模型名。
spring:
ai:
dashscope:
api-key: ${AI_DASHSCOPE_API_KEY}
@Test
public void testQwen(@Autowired DashScopeChatModel dashScopeChatModel) {
String content = dashScopeChatModel.call("你好你是谁");
System.out.println(content);
}
@Test
public 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();
// 图片url
System.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();*/
}
// 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
@Test
public 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());
}
}
// 这个设置的是一个远程的 url 文本内容
private static final String AUDIO_RESOURCES_URL = "https://dashscope.oss-cn-beijing.aliyunccnblogs.com/samples/audio/paraformer/hello_world_female2.wav";
@Test
public void testAudio2Text(
@Autowired
DashScopeAudioTranscriptionModel 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。
com.alibaba
dashscope-sdk-java
the-latest-version
2.20.6
@Test
public 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 进行配置操作。
“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”
参与评论
手机查看
返回顶部