Spring AI 2.0.0-M8:Java 生态的 AI 工程化又往前迈了一步

2026-05-27 33 预计阅读时间:1 分钟
来源:spring.io AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:9 分钟

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 不是终点,但方向越来越清晰——统一抽象、工具调用、结构化输出、可观测性,这四根柱子已经立住了。


相关推荐