这期 A Bootiful Podcast 把焦点放在 Sébastien Deleuze 对 Spring AI 和 Spring Framework 近况的讨论上。虽然播客本身是访谈形式,但它指向了一个很实际的变化:Spring 生态正在把 AI 应用开发拉回 Java 开发者熟悉的工程模型里,配置、Bean、自动装配、测试和部署仍然是主战场。
Spring AI 的价值不只是“调模型”
对后端工程师来说,AI 接入最容易被低估的部分不是 HTTP 请求本身,而是模型客户端、提示词、上下文、向量检索、重试、限流、观测性这些工程细节如何进入现有应用。
Spring AI 的意义在于,它尝试把这些能力包装成 Spring 风格的抽象:你可以把大模型调用当作服务依赖注入,把提示词模板当作应用资源,把模型配置放进 application.yml,再用熟悉的测试和配置隔离方式管理不同环境。
这并不意味着 AI 应用会自动变简单。它只是把问题放到了更容易被团队治理的位置:
- 模型供应商可以通过配置切换,而不是散落在业务代码里。
- Prompt 可以像模板一样版本化,而不是藏在字符串拼接中。
- AI 调用可以进入已有的日志、指标、追踪和异常处理体系。
- Java 团队不需要为了第一个 AI 功能立刻重写技术栈。
Spring Framework 仍然是底座
Spring AI 听起来是新东西,但它真正能落地,靠的还是 Spring Framework 的基本功:依赖注入、配置绑定、资源加载、Web 编程模型、测试支持,以及和 Spring Boot 的自动配置配合。
这也是为什么关注 Spring Framework 本身仍然重要。AI 功能通常不会独立存在,它会进入现有订单系统、知识库、客服后台、研发平台或内部工具。你需要的是一个能被纳入生产系统的 AI 能力,而不是一个孤立 demo。
可以把它理解为三层:
- Spring Framework 提供应用结构和运行时基础。
- Spring Boot 降低配置和集成成本。
- Spring AI 把模型调用、Prompt 和相关 AI 能力接入这个结构。
可以这样实践:写一个最小 Spring AI 聊天接口
下面是一个可改造的最小示例,用 Spring Boot 暴露一个 /chat 接口,并通过 Spring AI 的 ChatClient 调用模型。你需要替换自己的模型供应商配置和 API Key。
pom.xml 示例:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-ai-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
<relativePath/>
</parent>
<properties>
<java.version>21</java.version>
<spring-ai.version>1.0.0-M3</spring-ai.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
src/main/resources/application.yml:
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-4o-mini
src/main/java/com/example/demo/DemoApplication.java:
package com.example.demo;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@RestController
class ChatController {
private final ChatClient chatClient;
ChatController(ChatClient.Builder builder) {
this.chatClient = builder
.defaultSystem("You are a concise assistant for Java backend developers.")
.build();
}
@GetMapping("/chat")
String chat(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
}
运行方式:
export OPENAI_API_KEY="替换成你的 API Key"
mvn spring-boot:run
调用接口:
curl "http://localhost:8080/chat?message=Explain%20Spring%20AI%20in%203%20sentences"
需要注意:上面的依赖版本只是一个可实践起点。Spring AI 仍在快速演进,真实项目应以当前官方 BOM 和 starter 名称为准,并锁定版本,避免构建在升级时突然漂移。
不要把 Prompt 写成散装字符串
AI 功能进入业务系统后,最常见的维护问题是 Prompt 越写越散。一个接口里拼接系统指令,另一个 service 里拼接用户上下文,再加几段条件判断,几周后很难回答“线上模型到底收到了什么”。
可以这样实践:把 Prompt 模板放到资源文件里,用明确变量填充。即使暂时不用复杂模板引擎,也要先让 Prompt 可读、可审查、可版本化。
src/main/resources/prompts/review-system.txt:
You are a senior Java reviewer.
Focus on correctness, maintainability, and production risk.
Return concise findings with severity and evidence.
控制器中加载资源的思路如下:
package com.example.demo;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@RestController
class ReviewController {
private final ChatClient.Builder builder;
private final Resource systemPrompt;
ReviewController(ChatClient.Builder builder,
@Value("classpath:prompts/review-system.txt") Resource systemPrompt) {
this.builder = builder;
this.systemPrompt = systemPrompt;
}
@PostMapping("/review")
String review(@RequestBody String diff) throws IOException {
String system = StreamUtils.copyToString(systemPrompt.getInputStream(), StandardCharsets.UTF_8);
return builder.defaultSystem(system)
.build()
.prompt()
.user("Review this diff:\n" + diff)
.call()
.content();
}
}
这段代码的重点不是“代码审查机器人”,而是 Prompt 的工程化方式:系统提示词作为资源文件管理,业务输入作为用户消息传入,二者边界清楚,后续做审计和测试更容易。
落地时该保守的地方
Spring AI 很适合 Java/Spring 团队做增量试点,但生产接入要把边界先画清楚。
建议从低风险场景开始:内部知识问答、摘要、草稿生成、运营辅助、研发工具,而不是一上来接管核心交易流程。模型输出要默认不可信,尤其涉及权限、金额、合规、医疗、法律或安全动作时,必须有明确校验和人工确认。
上线前可以用这份简短清单检查:
- API Key 是否只来自环境变量或密钥系统。
- 模型请求和响应是否有必要的日志脱敏。
- 超时、重试、限流和降级策略是否明确。
- Prompt 是否版本化,而不是散落在业务字符串里。
- 是否记录模型名称、参数和调用链,方便排查线上问题。
- 是否为高成本调用设置预算或速率保护。
这期播客值得关注的地方,不在于某个单点 API,而在于 Spring 生态正在把 AI 应用开发纳入成熟的 Java 工程节奏。对团队来说,最好的切入点不是追逐每个新模型能力,而是选一个具体业务流程,把配置、Prompt、测试、观测和安全边界一起做扎实。