2026 年,AI Agent 应用已经从实验阶段进入规模化落地期。但对于拥有数百万行 Java 代码的企业来说,一个核心矛盾始终存在:Python 生态垄断了 AI 工程,而 Java 生态垄断了企业后端。Spring AI 1.0 的正式发布彻底打破了这一僵局——它将 Spring 的依赖注入、声明式编程、AOP 切面等成熟工程范式注入 AI 开发,让 Java 开发者无需切换技术栈就能构建生产级 AI 应用。截至 2026 年 5 月,Spring AI 已支持 20+ 模型提供商、内置 RAG 向量检索和函数调用能力,成为 Java 生态中 AI 开发的事实标准。
📌 记住: Spring AI 不是简单的 API 封装层。它引入了统一的
ChatModel抽象、Advisor链式拦截器、DocumentReader管道等设计,本质上是用 Spring 的思维方式重新定义了 AI 应用的架构。
🚀 一、Spring AI 核心架构:一套代码切换所有大模型
1.1 为什么需要统一抽象?
在没有 Spring AI 之前,Java 项目接入大模型的典型做法是直接调用各家 HTTP API:
❌ 传统做法:每个模型写一套调用代码
// OpenAI 调用
var openaiReq = HttpRequest.newBuilder()
.uri(URI.create("https://api.openai.com/v1/chat/completions"))
.header("Authorization", "Bearer " + openaiKey)
.POST(HttpRequest.BodyPublishers.ofString("""
{"model":"gpt-4o","messages":[{"role":"user","content":"你好"}]}
"""))
.build();
var openaiRes = httpClient.send(openaiReq, HttpResponse.BodyHandlers.ofString());
// 解析 JSON... 超时处理... 错误重试... 每家写一遍
// DeepSeek 调用
var deepseekReq = HttpRequest.newBuilder()
.uri(URI.create("https://api.deepseek.com/v1/chat/completions"))
.header("Authorization", "Bearer " + deepseekKey)
// ... 又写一遍
这种方式的问题一目了然:代码重复率高、模型切换困难、错误处理分散。Spring AI 的核心价值在于提供了 ChatModel 统一接口——你只需改一行配置就能在 OpenAI、DeepSeek、Ollama 等模型之间无缝切换。
1.2 项目搭建与配置
第一步:添加依赖
<!-- pom.xml - Spring AI BOM 统一版本管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- OpenAI 兼容接口(也支持 DeepSeek、Moonshot 等兼容 API) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<!-- 向量存储:用于 RAG -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pgvector-store-spring-boot-starter</artifactId>
</dependency>
</dependencies>
第二步:配置多模型
# application.yml - 配置 OpenAI 兼容接口
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
base-url: https://api.deepseek.com # 切换到 DeepSeek 只需改这一行
chat:
options:
model: deepseek-chat
temperature: 0.7
max-tokens: 4096
⚠️ 警告:
spring-ai-openai-spring-boot-starter不仅支持 OpenAI,还兼容所有 OpenAI 格式的 API(DeepSeek、Moonshot、通义千问等)。不要被openai名字误导,这是一个通用的 OpenAI-compatible 启动器。
1.3 ChatModel 统一调用
@Service
public class ChatService {
private final ChatModel chatModel;
private final ChatClient chatClient;
public ChatService(ChatModel chatModel) {
this.chatModel = chatModel;
// ChatClient 是 Spring AI 提供的高级流式 API 入口
this.chatClient = ChatClient.builder(chatModel)
.defaultSystem("你是一个专业的技术助手,回答简洁准确。")
.build();
}
// 简单调用
public String chat(String userMessage) {
return chatClient.prompt()
.user(userMessage)
.call()
.content();
}
// 流式调用(适合前端 SSE 实时输出)
public Flux<String> chatStream(String userMessage) {
return chatClient.prompt()
.user(userMessage)
.stream()
.content();
}
// 结构化输出(直接映射到 Java 对象)
public MovieRecommendation recommend(String genre) {
return chatClient.prompt()
.user("推荐一部" + genre + "题材的电影,包含名称、导演、评分")
.call()
.entity(MovieRecommendation.class);
}
}
| 特性 | 手动调用 HTTP API | Spring AI ChatModel |
|---|---|---|
| 模型切换 | 修改代码 + 重新部署 | 改一行配置,热重载生效 |
| 错误处理 | 每处调用单独处理 | 全局 Advisor 统一拦截 |
| 流式输出 | 手动处理 SSE 解析 | Flux<String> 一行搞定 |
| 结构化输出 | 手动 JSON 解析 + 类型转换 | .entity(Class) 自动映射 |
| 代码量(平均) | ~80 行/调用点 | ~10 行/调用点 |
✅ 推荐: 优先使用 ChatClient 而不是直接使用 ChatModel。ChatClient 提供了链式 API、默认系统提示词、Advisor 集成等高级能力,是 Spring AI 推荐的首选入口。
🔧 二、Function Calling:让 AI 驱动你的 Java 业务逻辑
Function Calling(函数调用)是 AI Agent 的核心能力——它让大模型不仅能「说」,还能「做」。Spring AI 用 @Tool 注解将任意 Java 方法暴露给 AI 模型,配合 Spring 的依赖注入,模型可以直接调用你的业务服务。
2.1 声明工具方法
@Component
public class OrderTools {
@Autowired
private OrderRepository orderRepository;
@Autowired
private NotificationService notificationService;
@Tool(description = "根据订单号查询订单详情,包含状态、金额、商品列表")
public OrderDetail getOrderDetail(
@ToolParam(description = "订单号,格式如 ORD-20260531-001") String orderId
) {
return orderRepository.findById(orderId)
.map(order -> OrderDetail.builder()
.orderId(order.getId())
.status(order.getStatus().name())
.amount(order.getAmount())
.items(order.getItems())
.createdAt(order.getCreatedAt())
.build())
.orElse(null);
}
@Tool(description = "取消指定订单。只有 PENDING 和 CONFIRMED 状态的订单可以取消")
public String cancelOrder(
@ToolParam(description = "要取消的订单号") String orderId,
@ToolParam(description = "取消原因") String reason
) {
var order = orderRepository.findById(orderId).orElseThrow();
if (order.getStatus() == OrderStatus.SHIPPED) {
return "该订单已发货,无法取消。请联系客服处理退货。";
}
order.setStatus(OrderStatus.CANCELLED);
order.setCancelReason(reason);
orderRepository.save(order);
notificationService.notifyOrderCancelled(order);
return "订单 " + orderId + " 已成功取消,退款将在 3-5 个工作日内到账。";
}
}
2.2 注册工具并调用
@Service
public class OrderAgentService {
private final ChatClient chatClient;
public OrderAgentService(ChatModel chatModel, OrderTools orderTools) {
this.chatClient = ChatClient.builder(chatModel)
.defaultSystem("""
你是一个订单管理助手。用户可能会查询订单、取消订单。
调用工具前请确认用户意图,取消订单前请提醒用户确认。
""")
.defaultTools(orderTools) // 注册所有工具
.build();
}
public String handleOrderQuery(String userMessage) {
return chatClient.prompt()
.user(userMessage)
.call()
.content();
// 模型会自动决定调用哪个工具、是否需要多轮调用
}
}
用户输入:「帮我查一下 ORD-20260531-001 的状态」
模型执行流程:
- 理解意图 → 需要查询订单
- 自动调用
getOrderDetail("ORD-20260531-001") - 拿到返回结果 → 生成自然语言回复
💡 提示:
@Tool注解的description参数至关重要——模型完全依赖它来理解工具的用途。描述要精确、包含边界条件(如「只有 PENDING 和 CONFIRMED 状态」),这直接影响模型的调用准确率。
2.3 生产级注意事项
在生产环境中使用 Function Calling,有几个关键要点:
⚠️ 工具方法必须做输入校验——模型生成的参数不一定完全正确,不要信任任何来自模型的参数值。
⚠️ 敏感操作需要二次确认——对于扣款、删除数据等不可逆操作,在工具方法内部实现确认机制,或在 Advisor 中拦截。
⚠️ 设置超时——工具调用如果涉及外部服务(数据库、第三方 API),务必设置合理的超时时间。Spring AI 默认会将工具调用超时传递给模型的 requestTimeout。
📊 三、RAG 检索增强生成:让 AI 基于你的数据回答
RAG(Retrieval-Augmented Generation)是企业 AI 应用最常见的架构模式——先从你的知识库中检索相关文档,再将检索结果注入到模型的上下文中生成回答。Spring AI 提供了完整的 RAG 管道,从文档加载、向量化、存储到检索一应俱全。
3.1 文档加载与向量化
@Configuration
public class RagConfiguration {
@Bean
public VectorStore vectorStore(EmbeddingModel embeddingModel) {
// 使用 PostgreSQL pgvector 作为向量存储
return PgVectorStore.builder(embeddingModel)
.dimensions(1536) // OpenAI text-embedding-3-small 维度
.build();
}
@Bean
public CommandLineRunner loadDocuments(VectorStore vectorStore) {
return args -> {
// 从 classpath 加载 PDF 文档
var pdfReader = new PagePdfDocumentReader("classpath:docs/product-manual.pdf");
var documents = pdfReader.get();
// 文本分割:按 500 token 分块,50 token 重叠
var splitter = new TokenTextSplitter(500, 50, 5, 10000, true);
var chunks = splitter.apply(documents);
// 写入向量数据库
vectorStore.add(chunks);
log.info("已加载 {} 个文档片段到向量库", chunks.size());
};
}
}
3.2 检索增强 Advisor
Spring AI 的 Advisor 机制是其最精妙的设计之一——它类似于 Spring MVC 的 HandlerInterceptor,可以在请求发送给模型之前和之后插入自定义逻辑。RAG 的「检索 + 注入」正是通过 QuestionAnswerAdvisor 实现的:
@Service
public class KnowledgeBaseService {
private final ChatClient chatClient;
public KnowledgeBaseService(ChatModel chatModel, VectorStore vectorStore) {
this.chatClient = ChatClient.builder(chatModel)
.defaultSystem("你是一个产品知识库助手。仅基于提供的文档内容回答,不要编造信息。如果文档中没有相关信息,请明确告知用户。")
.defaultAdvisors(
// 检索 Top 5 相关文档片段,注入到用户提示词中
new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults().withTopK(5))
)
.build();
}
public String ask(String question) {
return chatClient.prompt()
.user(question)
.call()
.content();
// 内部流程:
// 1. QuestionAnswerAdvisor 拦截请求
// 2. 将用户问题向量化,在 pgvector 中搜索 Top 5
// 3. 将检索到的文档片段拼接到用户消息前面
// 4. 发送给大模型生成回答
}
}
| RAG 方案 | 适用场景 | 复杂度 | 延迟 |
|---|---|---|---|
| 本地 Embedding + pgvector | 中小规模知识库(<100 万条) | ⭐⭐ | ~200ms |
| OpenAI Embedding + pgvector | 大规模知识库、多语言 | ⭐⭐ | ~500ms |
| 向量数据库(Milvus/Qdrant) | 超大规模、高并发检索 | ⭐⭐⭐⭐ | ~100ms |
| 纯关键词检索(Elasticsearch) | 结构化数据、精确匹配 | ⭐⭐⭐ | ~150ms |
⚠️ 警告: 不要盲目设置很大的
topK值。检索结果越多,注入到上下文的 token 越多,会导致:(1)API 成本直线上升;(2)模型注意力分散,回答质量反而下降。一般来说,topK=3~7是最佳区间。
3.3 混合检索:向量 + 关键词的最优解
纯向量检索在精确匹配场景(如搜索产品编号、错误码)中表现不佳。生产环境推荐混合检索:
// 混合检索:向量相似度 + BM25 关键词匹配
var searchRequest = SearchRequest.defaults()
.withTopK(5)
.withSimilarityThreshold(0.7) // 相似度阈值过滤噪音
.withFilterExpression(
// 元数据过滤:只搜索特定文档类型
new FilterExpressionBuilder()
.eq("documentType", "product-manual")
.build()
);
⚡ 关键结论: RAG 的质量 80% 取决于文档分块策略和检索精度,而不是模型能力。投入时间优化
TokenTextSplitter的参数和SearchRequest的过滤条件,比升级模型版本的 ROI 高得多。
🎯 四、生产环境最佳实践与避坑指南
4.1 成本控制
大模型 API 的费用是按 token 计费的,不加控制的 AI 应用每月账单可能远超预期。
三个关键策略:
- ✅ 分层调用:简单问题用小模型(DeepSeek-V3),复杂推理用大模型(GPT-4o),用 Router Advisor 自动分流
- ✅ 缓存相似问题:Spring AI 内置
CacheAdvisor,对语义相似的问题返回缓存结果 - ✅ 控制输出长度:在
ChatOptions中设置maxTokens,避免模型「话痨」
// 成本优化:缓存 + 模型路由
ChatClient.builder(chatModel)
.defaultAdvisors(
new SimpleCacheAdvisor() // 相同问题直接返回缓存
)
.build();
4.2 可观测性
Spring AI 与 Micrometer 深度集成,每个 AI 调用都会自动产生指标:
# 开启 AI 调用的可观测性
management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
metrics:
tags:
application: ai-service
关键监控指标:
spring.ai.chat.client— 调用延迟分布(P50/P95/P99)spring.ai.chat.client.tokens.usage— Token 消耗量- 自定义指标:工具调用成功率、RAG 检索命中率
4.3 常见踩坑清单
- ❌ 不要在工具方法中做耗时操作不设超时——一次数据库慢查询会阻塞整个 Agent 流程,模型会等待超时后重试,Token 费用翻倍
- ❌ 不要将大量文档一次性加载到上下文——超过模型的上下文窗口会直接报错,即使用了 RAG 也要控制检索结果的总 token 数
- ❌ 不要忽略
@Tool的description质量——描述含糊会导致模型调用错误的工具,这是 Function Calling 最常见的失败原因 - ✅ 为每个工具方法添加日志——记录入参和返回值,方便排查模型调用了错误工具的问题
- ✅ 使用
@Retryable处理瞬时故障——模型 API 的可用性通常为 99.5%,比你的 SLA 低,必须有重试机制
@Tool(description = "查询商品库存")
@Retryable(retryFor = {RuntimeException.class}, maxAttempts = 2)
public StockInfo checkStock(@ToolParam(description = "商品SKU") String sku) {
log.info("AI 调用库存查询: sku={}", sku);
var result = inventoryService.query(sku);
log.info("库存查询结果: sku={}, stock={}", sku, result.getQuantity());
return result;
}
✅ 总结
Spring AI 1.0 让 Java 开发者第一次拥有了真正「Spring 风格」的 AI 开发体验。它的核心价值不在于提供了多少模型支持,而在于将 AI 调用融入了 Spring 已有的工程体系——依赖注入管理模型实例、AOP Advisor 处理横切关注点、Actuator 监控 AI 指标、Spring Security 保护 AI 端点。如果你的团队已经在用 Spring Boot,Spring AI 几乎是构建 AI 应用的唯一合理选择。
推荐技术栈组合:
- 🔧 快速原型:Spring AI + Ollama 本地模型(零成本开发调试)
- 🏢 企业生产:Spring AI + DeepSeek/GPT-4o + pgvector RAG + Micrometer 监控
- 💰 成本敏感:Spring AI + CacheAdvisor + DeepSeek-V3(国内模型性价比最高)
⚡ 关键结论: Spring AI 最大的优势不是技术先进性,而是降低 Java 团队的 AI 采用门槛。你的团队不需要学 Python、不需要理解 PyTorch,用已有的 Spring 知识就能构建完整的 AI Agent 应用。这才是企业 AI 落地的真正瓶颈——不是技术选型,而是团队技能迁移成本。