Spring AI 1.0 生产实战:用 Java 构建 AI Agent 应用的完整指南

深度解析 Spring AI 1.0 核心能力,涵盖 ChatModel 统一抽象、Function Calling、RAG 检索增强生成、Advisor 链式调用等关键技术,附完整可运行代码与生产环境最佳实践。

Java 后端 2026-05-30 18 分钟

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 而不是直接使用 ChatModelChatClient 提供了链式 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 的状态」

模型执行流程:

  1. 理解意图 → 需要查询订单
  2. 自动调用 getOrderDetail("ORD-20260531-001")
  3. 拿到返回结果 → 生成自然语言回复

💡 提示: @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 数
  • 不要忽略 @Tooldescription 质量——描述含糊会导致模型调用错误的工具,这是 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 落地的真正瓶颈——不是技术选型,而是团队技能迁移成本。

📚 相关文章