Spring AI:让大模型住进 Spring 生态(六)



个人主页:手握风云
目录
一、Qianfan
1.1. 平台概述
百度千帆是百度智能云推出的AI 原生应用开发平台,基于文心大模型打造,提供从模型开发到应用部署的全栈 AI 能力支持。千帆 V2 版本完全兼容 OpenAI 标准(身份认证、接口协议);V1 为早期独立接口,自2025 年 4 月 30 日起关闭推理服务创建入口,新服务默认基于 V2 接口开发。依托兼容特性,项目搭建、代码开发可复用 OpenAI 相关依赖与编码逻辑,仅需小幅修改配置即可完成适配。
使用千帆服务的前置条件需完成账号登录、申请密钥、实名认证、开通模型服务四步操作,新用户可领取免费调用额度。
1.2. 项目搭建
- Maven 依赖
<dependencies>
<!-- Web依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 复用OpenAI启动器,兼容千帆V2接口 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
- 启动类
package com.yang.qianfan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class QianfanApplication {
public static void main(String[] args) {
SpringApplication.run(QianfanApplication.class, args);
}
}
1.3. 聊天模型
千帆 V2 对话接口路径与 OpenAI 默认路径不同,需手动指定接口地址、基础域名、模型等参数。参考文档:文本生成 - 千帆AI应用开发者中心-API参考qianfan-api | 百度智能云文档

配置文件代码:
spring:
ai:
openai:
api-key: ${qian-fan-api-key}$
# 千帆V2基础域名
base-url: https://qianfan.baidubce.com
chat:
options:
model: "ernie-lite-pro-128k" # 指定文心系列聊天模型
completions-path: /v2/chat/completions # 千帆V2聊天接口路径
接口代码:
package com.yang.qianfan.controller;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/qianfan")
public class QianfanController {
@Autowired
private OpenAiChatModel openAiChatModel;
@RequestMapping("/chat")
public String chat(String message) {
return openAiChatModel.call(message);
}
}
1.4. 图像模型
配置代码:
spring:
ai:
openai:
api-key: ${QIANFAN_API_KEY}
# 千帆V2基础域名
base-url: https://qianfan.baidubce.com
image:
options:
model: flux.1-schnell # 指定千帆图像模型
images-path: /v2/images/generations # 千帆V2图像生成接口路径
接口代码:
package com.yang.qianfan.controller;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.ai.openai.OpenAiImageModel;
import org.springframework.ai.openai.OpenAiImageOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/qianfan")
public class QianfanController {
@Autowired
private OpenAiImageModel openAiImageModel;
@RequestMapping("/image")
public void image() {
ImageResponse response = openAiImageModel.call(
new ImagePrompt("一个穿着宇航服的猫咪在月球上弹吉他", OpenAiImageOptions.builder()
.quality("medium")
.N(1)
.height(1024)
.width(1024)
.build())
);
String imageUrl = response.getResult().getOutput().getUrl();
System.out.println(imageUrl);
}
}
二、Spring AI Alibaba
Spring AI Alibaba 是基于 Spring AI 开源构建的 Java AI 开发框架,深度对接阿里云百炼(DashScope)平台的通义、万相等大模型与多模态服务,提供云原生统一 AI API 抽象层,屏蔽不同模型的接口差异,帮助 Spring 生态开发者快速落地对话、图像、语音、视频等多模态 AI 应用。框架提供 Spring Boot Starter(框架集成)和原生 DashScope SDK(通用 Java 项目)两种使用形态,新用户可领取阿里云百炼免费调用额度。
2.1. 环境与密钥配置
获取 API-KEY:百炼平台
我们首先需要登录阿里云百炼平台,开通大模型推理、训练等服务,领取新人免费 Token 额度,并且需要完成实名认证。进入 API-Key 管理页面创建密钥:

2.2. 项目搭建
Maven 依赖配置:
<dependencies>
<!-- Spring Boot Web 基础(接口开发必备) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- WebFlux 响应式组件(流式对话/流式语音推荐引入) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
</dependency>
<!-- Spring Boot 单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring AI Alibaba 核心启动器(整合百炼全能力:对话/图像/语音/视频) -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!-- Spring AI Alibaba 版本统一管理BOM -->
<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>
配置文件:
spring:
ai:
dashscope:
api-key: ${DASHSCOPE_API_KEY}
启动类:
package com.yang.alibaba;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AlibabaApplication {
public static void main(String[] args) {
SpringApplication.run(AlibabaApplication.class, args);
}
}
基础对话测试:自动注入 DashScopeChatModel,调用 call() 方法即可完成基础大模型对话。
package com.yang.alibaba;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class ChatModelTest {
@Autowired
private DashScopeChatModel chatModel;
@Test
public void chat() {
String message = chatModel.call("你是谁?");
System.out.println(message);
}
}

2.3. 图像生成
阿里云百炼 DashScope 的 Spring AI Alibaba 框架实现 AI 图像生成能力,依托 Spring AI 统一 ImageModel 标准接口,对接通义万相、通义文生图系列模型。
核心 API 统一使用 DashScopeImageModel,该类实现 Spring AI 通用 ImageModel 顶层接口,屏蔽不同图像模型的底层接口差异,一套代码可切换通义全系绘图模型。
图像生成功能的最简调用分为四步:首先注入 DashScopeImageModel 模型实例,接着构建携带文字描述提示词的 ImagePrompt 对象,随后执行 call() 方法发起绘图请求,该方法会返回ImageResponse 响应对象,最后从响应结果中解析提取出生成图片对应的在线 URL。配套基础示例以提示词 “孩子在海边玩耍” 作为输入,完整走完上述调用流程后,程序会输出打印本次生成图片的访问链接。
package com.yang.alibaba;
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageModel;
import org.junit.jupiter.api.Test;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class ImageModelTest {
@Autowired
private DashScopeImageModel imageModel;
@Test
public void textToImage() {
// 默认为通义万相模型
ImageResponse imageResponse = imageModel.call(new ImagePrompt("孩子们在海边玩耍"));
String imgUrl = imageResponse.getResult().getOutput().getUrl();
System.out.println(imgUrl);
}
}

自动配置类 DashScopeImageAutoConfiguration:框架自动装配图像模型 Bean,装配依赖:阿里云连接配置、图像专属属性、RestClient/WebClient、重试模板、异常处理器、链路观测组件;仅当未自定义 DashScopeImageModel 时自动创建。

DashScopeImageProperties 是图像生成功能的配置属性载体,其配置前缀统一为 spring.ai.dashscope.image ;该配置类默认开启图像生成相关能力,内部内置了 DashScopeImageOptions 的全套默认参数,且框架默认使用 wanx-v1 也就是通义万相初代绘图模型作为图像生成基础模型。

DashScopeImageOptions 是核心参数配置,支持 yml 全局配置、代码链式构建两种配置方式,参数适配通义万相(wan 系列)、通义文生图(qwen-image)两类模型,两类模型参数支持范围存在明显差异。
| 参数 | 作用 | 模型差异化规则 |
|---|---|---|
| model | 指定绘图模型 | 1. qwen-image:擅长海报、对联等复杂文字渲染,仅支持 5 种固定比例尺寸2. wan2.2 系列(plus/flash):通用写实摄影;flash 极速出图、plus 高清专业;支持 512~1440 任意自定义宽高3. wanx-v1:初代模型,支持风格转换、图生图垫图;wanx2.0-t2i-turbo 低成本基础画质 |
| n | 生成图片数量 | qwen-image 仅支持 1 张;万相系列支持 1~4 张 |
| width/height/size | 画布分辨率 | size 参数已废弃;wan2.2 可自定义宽高;qwen-image 仅固定 5 种比例尺寸;尺寸超出范围直接报错 |
| style | 绘画风格 | 仅 wanx-v1 支持,可选摄影、人像、3D 卡通、动漫、油画、水彩、素描、中国画、扁平插画、auto 自动 |
| seed | 随机种子 | 固定相同 seed,可复现完全一致的生成图片;不传则自动随机 |
| watermark | AI 水印 | true:图片右下角添加「AI 生成」水印;默认 false 无水印 |
package com.yang.alibaba;
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageModel;
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageOptions;
import org.junit.jupiter.api.Test;
import org.springframework.ai.image.ImageGeneration;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.List;
@SpringBootTest
public class ImageModelTest {
@Autowired
private DashScopeImageModel imageModel;
@Test
public void textToImage1() {
// 默认为通义万相模型
// 风格为水彩
DashScopeImageOptions options = DashScopeImageOptions.builder()
.withStyle("<watercolor>")
.build();
ImageResponse imageResponse = imageModel.call(new ImagePrompt("孩子们在海边玩耍", options));
String imgUrl = imageResponse.getResult().getOutput().getUrl();
System.out.println(imgUrl);
}
@Test
public void textToImage2() {
String prompt = "中国女孩, 圆脸, 看着镜头, 优雅的民族服装, 商业摄影, 室外, 电影级光照, 半身特写, 精致的淡妆, 锐利的边缘。";
// 模型为通义千问
DashScopeImageOptions options = DashScopeImageOptions.builder()
.withModel("qwen-image-2.0")
.build();
ImageResponse imageResponse = imageModel.call(new ImagePrompt(prompt, options));
String imgUrl = imageResponse.getResult().getOutput().getUrl();
System.out.println(imgUrl);
}
@Test
public void textToImage3() {
String prompt = "中国女孩, 圆脸, 看着镜头, 优雅的民族服装, 商业摄影, 室外, 电影级光照, 半身特写, 精致的淡妆, 锐利的边缘。";
// 模型为通义千问
DashScopeImageOptions options = DashScopeImageOptions.builder()
.withModel("wan2.2-t2i-flash")
.withWatermark(true)
.withWidth(1024)
.withWidth(1024)
.build();
ImageResponse imageResponse = imageModel.call(new ImagePrompt(prompt, options));
String imgUrl = imageResponse.getResult().getOutput().getUrl();
System.out.println(imgUrl);
}
@Test
public void textToImage4() {
String prompt = "特斯拉 Model3";
DashScopeImageOptions options = DashScopeImageOptions.builder()
.withModel("wan2.2-t2i-flash")
.withN(3)
.build();
ImageResponse imageResponse = imageModel.call(new ImagePrompt(prompt, options));
List<ImageGeneration> results = imageResponse.getResults();
List<String> urls = new ArrayList<>();
for (ImageGeneration generation : results) {
urls.add(generation.getOutput().getUrl());
}
System.out.println(urls);
}
}
不同绘图模型具备差异化能力与适用场景,其中 wanx-v1 模型擅长图生图、风格转换类需求,但无法自定义图片分辨率;wan2.2-t2i-flash 与 wan2.2-t2i-plus 两款模型侧重根据纯文字生成高清写实图像,支持自定义任意分辨率尺寸,缺点是不支持 style 美术风格参数;qwen-image 模型的文字渲染效果最优,适合制作海报、对联等带有文字元素的创意画面,该模型分辨率固定,无法自行调整。
图像生成接口存在多项调用约束与异常触发规则,首先作为输入的参考图 URL 内不允许出现中文,同时图片文件大小、像素尺寸都有硬性区间要求;若设置的分辨率超出对应模型支持范围,程序会直接抛出请求异常;各模型参数体系相互独立无法通用,例如 wan2.2 系列模型不识别 style 美术风格参数,即便进行配置也不会生效;另外通义 qwen-image 模型单次调用仅能生成一张图片,用于设置生成数量的 n 参数对其不起作用。
2.4. 语音合成
框架会自动装配 DashScopeSpeechSynthesisModel 对象,开发时只需使用 @Autowired 注解完成依赖注入,就能直接调用该语音合成模型。
语音合成的标准调用分为四步:首先借助 DashScopeSpeechSynthesisOptions.builder() 构造语音合成所需的各类参数;接着把待转语音的文本和前面配置好的参数,一起封装成 SpeechSynthesisPrompt 请求实体;随后调用模型实例的call()方法发起合成请求,接口会返回 SpeechSynthesisResponse 响应结果;最后从响应对象中提取音频二进制数据 ByteBuffer,将数据流写入本地 MP3 文件,即可完成音频文件的保存。
package com.yang.alibaba;
import com.alibaba.cloud.ai.dashscope.audio.DashScopeSpeechSynthesisModel;
import com.alibaba.cloud.ai.dashscope.audio.synthesis.SpeechSynthesisPrompt;
import com.alibaba.cloud.ai.dashscope.audio.synthesis.SpeechSynthesisResponse;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
@SpringBootTest
public class AudioModelTest {
@Autowired
private DashScopeSpeechSynthesisModel speechSynthesisModel;
private static final String TEXT = "IntelliJ IDEA 树立智能开发工具行业标杆,同时始终坚守创立初心。";
@Test
public void tts1() {
SpeechSynthesisPrompt prompt = new SpeechSynthesisPrompt(TEXT);
SpeechSynthesisResponse response = speechSynthesisModel.call(prompt);
File file = new File(System.getProperty("user.dir") + "/out.mp3");
try (FileOutputStream fos = new FileOutputStream(file)) {
ByteBuffer audio = response.getResult().getOutput().getAudio();
fos.write(audio.array());
} catch (IOException e) {
System.out.println("写入文件失败!");
}
}
}
系统提供统一顶层抽象接口 SpeechSynthesisModel ,该接口定义了语音合成两大核心能力:同步一次性生成完整音频的 call(SpeechSynthesisPrompt) 方法、适配实时播报场景的流式音频输出stream(SpeechSynthesisPrompt) 方法,而 DashScopeSpeechSynthesisModel 是这套标准接口面向阿里云 DashScope 平台的专属实现类。

DashScopeAudioSpeechAutoConfiguration 是 Spring Boot 实现自动装配的核心配置类,它会自动注入平台连接配置、语音合成专属配置、重试模板与监控观测相关组件,在无开发者自定义实现的条件下,自动创建并注册 DashScopeSpeechSynthesisModel Bean,简化项目初始化开发流程。

DashScopeAudioSpeechSynthesisProperties 为全局语音合成配置承载类,配置前缀为 spring.ai.dashscope.audio.synthesis,内部预设默认语音模型、音色、语速、MP3 音频格式等基础参数,同时内置 DashScopeSpeechSynthesisOptions 对象,用于承载业务中动态自定义的各项合成参数。

配置前缀:spring.ai.dashscope.audio.synthesis.options,所有参数支持 yml 全局配置、代码动态构建两种方式。
| 参数 | 说明 | 取值范围 / 规则 |
|---|---|---|
| model | 语音模型 | 支持 CosyVoice、Sambert 系列;模型与音色必须匹配,部分模型需单独开通权限 |
| voice | 音色 | 各模型专属音色(男声 / 女声),部分音色需申请权限 |
| text | 待合成文本 | 业务输入文本,一般通过 Prompt 传入 |
| request_text_type | 文本类型 | 默认PLAIN_TEXT纯文本 |
| sample_rate | 音频采样率 | 默认 48000 |
| volume | 音量 | 0~100,数值越大音量越高 |
| speed | 语速 | 0.5~2.0,1.0 为正常语速;小于 1 慢速,大于 1 快速 |
| pitch | 语调 | 0.5~2.0,调整声音高低 |
| enable_word_timestamp | 字级时间戳 | true/false,开启后返回每个字的时间节点 |
| enable_phoneme_timestamp | 音素时间戳 | true/false,精细化语音时间标记 |
| response_format | 音频输出格式 | 支持 mp3、wav、pcm,默认 mp3 |
@Test
public void tts2() {
DashScopeSpeechSynthesisOptions options = DashScopeSpeechSynthesisOptions.builder()
.model("cosyvoice-v3-flash")
.voice("longanhuan")
.speed(0.5f)
.volume(10)
.build();
SpeechSynthesisPrompt prompt = new SpeechSynthesisPrompt(TEXT, options);
SpeechSynthesisResponse response = speechSynthesisModel.call(prompt);
File file = new File(System.getProperty("user.dir") + "/out.mp3");
try (FileOutputStream fos = new FileOutputStream(file)) {
ByteBuffer audio = response.getResult().getOutput().getAudio();
fos.write(audio.array());
} catch (IOException e) {
System.out.println("写入文件失败!");
}
}
dashscope-sdk-java 是阿里云底层原生 Java SDK,不绑定任何开发框架,是语音合成能力的底层基础实现。原生 SDK 的引入方式十分简单,仅需要在 Maven 中单独引入 dashscope-sdk-java 依赖即可,不需要额外导入任何 Spring AI 相关 starter 包。
原生 SDK 拥有一套完整独立的调用流程:首先构造 SpeechSynthesisParam 参数对象,完成 API Key、语音模型、音色等核心配置;接着实例化 SpeechSynthesizer 合成器;然后传入文本调用 call 方法,获取音频二进制 ByteBuffer 数据;再将二进制数据流写入本地磁盘,生成完整音频文件;同时该 SDK 支持两种 API Key 配置方式,既可以硬编码写入,也能读取系统环境变量,配置方式灵活度更高。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dashscope-sdk-java</artifactId>
<version>the-latest-version</version>
</dependency>
@Test
public void textToAudio() {
SpeechSynthesisParam param = SpeechSynthesisParam.builder()
.apiKey("sk-22c4373f299c4618ac31a64e299afafb")
.model("cosyvoice-v3-flash")
.text("今天天气怎么样?")
.build();
// 同步模式:直接调用 call 获取音频
SpeechSynthesizer synthesizer = new SpeechSynthesizer();
ByteBuffer audio = synthesizer.call(param);
System.out.println("[Metric] requestId为:" + synthesizer.getLastRequestId());
File file = new File("output.mp3");
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(audio.array());
} catch (IOException e) {
throw new RuntimeException(e);
}
}更多推荐
所有评论(0)