Spring AI 2.0:Hello World
一、简介
Spring Boot 4 + Spring 7 + IDEA 2025 + JDK17 ,Spring AI 的定位是:大模型基础对话 + RAG + MCP + Tool + Memory等基础功能。
大模型和程序的关系:大模型适合做模糊的事情,而程序必须是要做非常确定的事。
LangChain4j vs SpringAl

Spring AI Alibaba
Spring AI 是更底层的基座能力,Spring AI Alibaba 在基础能力之上提供更多的企业功能,包括智能体编码Graph、支持多个Agent框架等。


大模型选择
- 自研
- 云端大模型:如阿里百云炼平,功能完善成熟
- 本地部署开源大模型:数据比较私密,不能对外暴漏,Ollama本地部署。
- 根据行业(如教育、医疗、金融、法律)选择大模型 大模型评测
- 根据模型成本选择
- 最后需要人工实际评估得出最终选择
- 或者直接选择通用能力比较好的综合模型
Spring AI 2.0 新特性
- 传输协议发生了变化:去掉了Spring AI 1.0中的SSE模式(Server Send Events 单向长连接),使用新的模式(
MCP Streamable HTTP)。 - 在上层ChatClient增加
日志拦截器。 - 增加了Agent的模式:
观察思考 - 执行工具 - 反思迭代 - 验证确认。

应用场景
- 智能客服:在项目中嵌入一个聊天窗,然后通过Tool调用系统内部的Java方法以及通过MCP调用系统外部的功能(如网络搜索、地图、天气等第三方发布的API),原来通过用户点点点来实现的,现在通过聊天完成。
- RAG知识库。
二、流式输出(打字机效果)
1. 添加依赖 pom.xml
SpringWeb + Spring AI + 第三方厂商(如 DeepSeek 、OpenAI、 Ollama):要考虑性能、成本、以及行业评分。

2. 配置application.properties
阿里云百炼支持多模态:如 文生图、文生语言、文生视频等。
获取API Key(创建API Key): https://bailian.console.aliyun.com/cn-beijing?tab=model#/api-key

获取API Host: https://bailian.console.aliyun.com/cn-beijing?tab=api#/api/?type=app&url=2782167

示例代码(获取模型名称、base_url) https://bailian.console.aliyun.com/cn-beijing?tab=model#/model-market/detail/qwen3.7-plus?serviceSite=asia-pacific-china&ref=suggest

API Key配置在环境变量中。

# 阿里百炼平台
spring.ai.deepseek.api-key=${DASHSCOPE_API_KEY}
spring.ai.deepseek.chat.model= qwen3.7-plus
spring.ai.deepseek.chat.base-url=https://llm-x2l5ucz6vk2xupzh.cn-beijing.maas.aliyuncs.com/compatible-mode/v1
# 可选参数(不是必须的)
spring.ai.deepseek.chat.options.temperature=1.0
spring.ai.deepseek.chat.options.maxTokens=2048
logging.level.org.springframework.ai=DEBUG
环境变量配置完成后需要重启一下IDEA,否则环境变量加载不到。
3. Bean Configuration
@Configuration
public class SpringAiConfig {
@Bean
public ChatClient chatClient(DeepSeekChatModel deepSeekChatModel) {
return ChatClient.builder(deepSeekChatModel)
.defaultSystem("""
# 角色
你是一个教育行业的只能小助手
# 要求
1. 永远讲中文
""")
.build();
}
}
4. Controller测试
- call():同步调用,模型全部返回后一次性返回结果。
- stream():流式返回,异步调用,模型输出一次chunk就返回一次。
@RestController
public class SpringAIController {
@Autowired
private ChatClient chatClient;
@GetMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> chat(@RequestParam("message") String message) {
Flux<String> content = chatClient.prompt()
.user(message)
.stream()
.content()
.withConcat(Flux.just("[complete]")); // 自定义一个结束标记,前端解析到就不会再请求,表示本轮会话全部结束
return content;
}
}

在Chrome浏览器中直接调用,可能会出现乱码,可以通过设置charset=UTF-8来解决。
@GetMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE + ";charset=UTF-8")
- content():返回String
- chatResponse():返回ChatResponse对象
Flux<ChatResponse> chatResponse = chatClient.prompt()
.user(message)
.stream()
.chatResponse();
// 消息id:好像只有STOP的时候才有值
var messageId = chatResponse.getMetadata().getId();
var finishReason = chatResponse.getResult().getMetadata().getFinishReason();
// 获取大模型的输出的内容
var text = chatResponse.getResult().getOutput().getText();
三、同步输出
@Bean
public ChatClient openAiChatClient(@Qualifier("openAiChatModel") ChatModel openAiChatModel,
Advisor loggerAdvisor // 日志记录器
) {
return ChatClient.builder(openAiChatModel)
.defaultAdvisors(loggerAdvisor)
.build();
}
// chatText 文本同步返回结果,不需要记忆也不需要工具,只需要设置提示词简单的调用大模型
public String chatText(String question) {
return this.openAiChatClient.prompt()
.system("系统提示词")
.user(question)
.call()
.content();
}
四、结构化输出 entity
直接将结果转为实体类。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Address {
/**
* 收件人姓名
*/
private String name;
/**
* 联系电话
*/
private String phone;
/**
* 省
*/
private String province;
/**
* 市
*/
private String city;
/**
* 区/县
*/
private String district;
/**
* 详细地址
*/
private String detail;
}
Address address = chatClient.prompt()
.system("""
请提取用户输入的收货地址信息,输出严格JSON,禁止输出任何解释、markdown标记。
字段说明:
name:收件人姓名
phone:联系电话
province:省份,例如浙江省
city:城市,例如杭州市
district:区/县,例如西湖区
detail:门牌号、街道等剩余详细地址;若无,则返回空字符串""
规则:
1. 严格拆分省、市、区,不要把省市区全部塞到detail字段;
2. 不允许编造不存在信息,原文没有的内容填空字符串,不要瞎编;
3. JSON只返回这6个字段,不要多出其他字段。
""")
.user("收货人:李四,电话13611112222,地址:广东省深圳市南山区科技园南路88号创新大厦A座1201")
.call()
.entity(Address.class);
System.out.println(address);
实际返回可能会统一包装成ChatEventVO
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ChatEventVO {
/**
* 文本内容
*/
private Object eventData;
/**
* 事件类型,1001-数据事件,1002-停止事件,1003-参数事件
*/
private int eventType;
}
五、多模型
<!--deepseek-->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-deepseek</artifactId>
</dependency>
<!--百炼-->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
@Configuration
public class SpringAiConfig {
@Bean("deepSeekChatClient")
public ChatClient chatClient(DeepSeekChatModel deepSeekChatModel) {
return ChatClient.builder(deepSeekChatModel)
.defaultSystem("You are a helpful assistant.")
.build();
}
@Bean("dashScopeChatClient")
public ChatClient chatClient(DashScopechatModel dashScopechatModel) {
return ChatClient.builder(dashScopechatModel)
.defaultSystem("You are a helpful assistant.")
.build();
}
@Bean
public ChatClient openAiChatClient(@Qualifier("openAiChatModel") ChatModel openAiChatModel,
Advisor loggerAdvisor // 日志记录器
) {
return ChatClient.builder(openAiChatModel)
.defaultAdvisors(loggerAdvisor)
.build();
}
}
@RestController
public class SpringAIController {
@Autowired
@Qualifier("dashScopeChatClient")
private ChatClient chatClient;
@GetMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> chat(@RequestParam("message") String message) {
Flux<String> content = chatClient.prompt()
.user(message)
.stream()
.content()
.withConcat(Flux.just("[complete]")); // 自定义一个结束标记,前端解析到就不会再请求,表示本轮会话全部结束
return content;
}
}
五、其它
Spring AI的本质还是以http的方式调用(restClient)大模型API,将请求参数封装成Prompt对象的JSON,接口返回值也是JSON。
HTTP请求。
curl --location "https://llm-x2l5ucz6vk2xupzh.cn-beijing.maas.aliyuncs.com/compatible-mode/v1" \
--header "Authorization: Bearer $DASHSCOPE_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "qwen3.8-max",
"input":{
"messages":[
{
"role": "system",
"content": [{"text": "You are a helpful assistant."}]
},
{
"role": "user",
"content": [{"text": "你是谁?"}]
}
]
},
"parameters": {
"result_format": "message"
}
}'
响应。
{
"status_code": 200,
"request_id": "902fee3b-f7f0-9a8c-96a1-6b4ea25af114",
"code": "",
"message": "",
"output": {
"text": null,
"finish_reason": null,
"choices": [
{
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": "我是阿里云开发的一款超大规模语言模型,我叫千问。"
}
}
]
},
"usage": {
"input_tokens": 22,
"output_tokens": 17,
"total_tokens": 39
}
}
更多推荐

所有评论(0)