Spring AI 从最初的概念验证走到今天,2.0.0-M8 这个里程碑版本标志着它正在从"能跑"转向"能用在生产里"。如果你一直在观望 Java 生态的 AI 集成方案,这个版本值得认真看一眼——不是因为它突然冒出了什么惊天功能,而是因为它把之前散落的拼图逐渐拼成了完整画面。
统一 API 的承诺更进一步
Spring AI 的核心卖点始终是统一抽象:不管底层是 OpenAI、Anthropic、Ollama 还是 Azure,你的业务代码不应该因为换了一个模型供应商就大改。M8 在这个方向上继续打磨,ChatModel、EmbeddingModel、ImageModel、AudioModel 这些顶层接口更加稳定,同时各供应商适配器的实现细节也在收敛。
这意味着一件很实际的事——你可以先用 Ollama 在本地跑通整个链路,等上线时切换到 OpenAI 或 Azure,配置改几行就行,业务代码不动。
Function Calling 与结构化输出更可用
AI 应用最头疼的问题之一是让模型输出你真正能用的东西。M8 对 Function Calling(工具调用)的支持更加成熟,模型可以识别你注册的 Java 方法并主动调用;结构化输出(Structured Output)也做了增强,能把模型的自由文本回复映射到你定义的 Java POJO。
这两件事加在一起,让"让 AI 干实事"变得不那么玄学。
用 Spring AI 2.0.0-M8 搭一个最小可用的聊天+工具调用服务
下面是一个可以直接跑起来的示例项目。它用 Ollama 作为本地模型(零成本,不需要 API Key),注册一个自定义工具让模型调用,并用结构化输出把回复映射到 Java 对象。
1. 创建项目骨架
用 Spring Initializr 生成一个 Spring Boot 3.5+ 项目,或者手动建目录。核心依赖如下:
<!-- pom.xml 关键依赖 -->
<dependencies>
<!-- Spring AI 核心 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-core</artifactId>
<version>2.0.0-M8</version>
</dependency>
<!-- Ollama 适配器 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
<version>2.0.0-M8</version>
</dependency>
<!-- Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<!-- Spring AI milestone 仓库 -->
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots><enabled>false</enabled></snapshots>
</repository>
</repositories>
2. 配置 Ollama 连接
先确保本地 Ollama 已运行并拉了模型:
# 安装 Ollama 后拉取一个轻量模型
ollama pull qwen2.5:3b
# 确认服务在跑
curl http://localhost:11434/api/tags
然后在 application.yml 中配置:
spring:
ai:
ollama:
base-url: http://localhost:11434
chat:
model: qwen2.5:3b
options:
temperature: 0.7
3. 注册自定义工具 + 编写服务
package com.example.demo;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.tool.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Map;
// ---- 自定义工具:查时区当前时间 ----
public class TimeZoneTool {
@Tool(description = "根据时区ID返回当前时间,例如 Asia/Shanghai、America/New_York")
public String getCurrentTime(
@ToolParam(description = "IANA 时区ID") String zoneId
) {
try {
return LocalDateTime.now(ZoneId.of(zoneId)).toString();
} catch (Exception e) {
return "无效时区: " + zoneId;
}
}
}
// ---- REST 控制器 ----
@RestController
@RequestMapping("/api")
public class ChatController {
private final ChatClient chatClient;
public ChatController(ChatModel chatModel) {
this.chatClient = ChatClient.builder(chatModel)
.defaultTools(new TimeZoneTool())
.build();
}
@GetMapping("/chat")
public Map<String, String> chat(@RequestParam String message) {
String reply = chatClient.prompt()
.user(message)
.call()
.content();
return Map.of("reply", reply);
}
}
4. 启动并测试
# 启动 Spring Boot
mvn spring-boot:run
# 测试普通对话
curl "http://localhost:8080/api/chat?message=你好,介绍一下你自己"
# 测试工具调用——模型会自动调用 TimeZoneTool
curl "http://localhost:8080/api/chat?message=现在东京几点了?"
当你问"东京几点了",模型会识别出需要调用时区工具,Spring AI 自动执行 TimeZoneTool.getCurrentTime("Asia/Tokyo"),把结果喂回模型,最终生成包含真实时间的自然语言回复。整个过程你不需要写任何解析逻辑。
5. 切换到 OpenAI——只改配置
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
model: gpt-4o-mini
把 spring-ai-ollama-spring-boot-starter 替换为 spring-ai-openai-spring-boot-starter,业务代码零改动。这就是统一抽象的实际价值。
结构化输出:让模型返回 Java 对象
M8 的结构化输出支持让你直接把模型回复映射到 POJO,而不是手动解析字符串:
// 定义输出结构
public record TravelAdvice(
String destination,
String reason,
int estimatedCostCNY,
String bestSeason
) {}
// 在 ChatController 中新增方法
@GetMapping("/travel")
public TravelAdvice getTravelAdvice(@RequestParam String preference) {
return chatClient.prompt()
.user("根据偏好推荐一个旅行目的地:" + preference)
.call()
.entity(TravelAdvice.class); // 直接映射到 POJO
}
curl "http://localhost:8080/api/travel?preference=喜欢海和美食"
# 返回 JSON:{"destination":"青岛","reason":"海鲜丰富、海滨风光","estimatedCostCNY":3000,"bestSeason":"夏季"}
.entity(TravelAdvice.class) 这一行是关键——Spring AI 在底层通过提示词工程 + JSON Schema 约束模型输出格式,再自动反序列化。你拿到的是一个类型安全的 Java 对象。
观察与运维:不是黑箱了
M8 继续增强 Micrometer 集成,AI 调用的耗时、token 消耗、模型名称都会作为指标暴露。加上 Spring Boot Actuator,你可以在 Prometheus 里看到每次 AI 调用的详情:
management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
metrics:
tags:
ai:
model: ${spring.ai.ollama.chat.model}
这对生产环境至关重要——AI 调用不再是"调了等结果"的黑箱,你可以监控延迟、成本和失败率。
上手建议与风险提醒
- 先本地再云端:用 Ollama 跑通全链路,确认业务逻辑没问题,再切换到付费 API。省调试成本。
- M8 是里程碑,不是 GA:API 可能还会微调。如果项目有硬性稳定性要求,锁定版本号,不要自动升级 milestone。
- 工具调用不是万能的:模型有时会"幻觉调用"不存在的工具,或传错参数。生产环境务必做参数校验和兜底处理。
- 结构化输出的边界:小模型对 JSON Schema 的遵从率不如大模型。如果输出格式经常跑偏,考虑换更强的模型或在业务层加二次校验。
- 依赖仓库要配对:Spring AI milestone 不在 Maven Central,必须加
repo.spring.io/milestone仓库,否则依赖下载失败。
Spring AI 2.0 正在把"Java 开发者也能正经做 AI 应用"这件事从口号变成可落地的工程实践。M8 不是终点,但方向越来越清晰——统一抽象、工具调用、结构化输出、可观测性,这四根柱子已经立住了。