【Spring Boot 3 + Spring AI】 实战:十分钟集成 OpenAI API 构建智能应用

Spring Boot 3 + Spring AI 实战:十分钟集成 OpenAI API 构建智能应用

    • [🚀 前言:为什么选择 Spring AI?](#🚀 前言:为什么选择 Spring AI?)
    • [🧠 一、Spring AI 核心架构与原理](#🧠 一、Spring AI 核心架构与原理)
      • [1.1 整体架构原理图](#1.1 整体架构原理图)
      • [1.2 AI 交互流程图](#1.2 AI 交互流程图)
    • [⚙️ 二、环境准备与项目初始化](#⚙️ 二、环境准备与项目初始化)
      • [2.1 技术栈要求](#2.1 技术栈要求)
      • [2.2 Maven 依赖配置](#2.2 Maven 依赖配置)
      • [2.3 配置文件设置](#2.3 配置文件设置)
    • [💬 三、快速入门:你的第一个 AI 对话机器人](#💬 三、快速入门:你的第一个 AI 对话机器人)
      • [3.1 创建 Service 层](#3.1 创建 Service 层)
      • [3.2 创建 Controller 层](#3.2 创建 Controller 层)
    • [🚀 四、进阶实战:提示词工程与流式响应](#🚀 四、进阶实战:提示词工程与流式响应)
      • [4.1 提示词模板](#4.1 提示词模板)
      • [4.2 流式响应](#4.2 流式响应)
    • [🔍 五、核心应用:RAG(检索增强生成)实战](#🔍 五、核心应用:RAG(检索增强生成)实战)
      • [5.2 Spring AI 实现 RAG](#5.2 Spring AI 实现 RAG)
    • [🛠️ 六、Function Calling:赋予 AI 调用 Java 方法的能力](#🛠️ 六、Function Calling:赋予 AI 调用 Java 方法的能力)
      • [6.1 Function Calling 流程图](#6.1 Function Calling 流程图)
      • [6.2 实战:查询天气机器人](#6.2 实战:查询天气机器人)
    • [🛡️ 七、生产环境最佳实践](#🛡️ 七、生产环境最佳实践)
      • [7.1 安全性](#7.1 安全性)
      • [7.2 Token 计费控制](#7.2 Token 计费控制)
      • [7.3 异常处理](#7.3 异常处理)
      • [7.4 性能优化](#7.4 性能优化)
    • [🎯 八、总结](#🎯 八、总结)

摘要:随着生成式 AI 的爆发,Java 开发者不再需要羡慕 Python 的丰富生态。Spring AI 作为 Spring 家族的新成员,为 Java 生态带来了类似 LangChain 的标准化抽象。本文将基于 Spring Boot 3,深入剖析 Spring AI 的核心架构,通过实战案例带你十分钟集成 OpenAI API,构建具备流式输出、提示词模板甚至 RAG(检索增强生成)能力的智能应用。


🚀 前言:为什么选择 Spring AI?

在过去的一年里,如果你想用 Java 开发 AI 应用,可能需要直接调用 OpenAI 的 HTTP 接口,或者移植 Python 的 LangChain 库。这不仅繁琐,而且缺乏 Java 生态的"味道"。
Spring AI 的诞生改变了这一切。它并非 LangChain 的简单移植,而是遵循 Spring 设计哲学(可移植性、模块化、面向接口)构建的 AI 应用开发框架。它提供了以下核心价值:

  1. API 抽象:一套代码支持 OpenAI、Azure OpenAI、HuggingFace 等多种模型提供商。
  2. 同步与流式:原生支持流式响应,不再需要手动处理 Server-Sent Events (SSE)。
  3. Spring Boot 集成:自动配置、外部化配置,开箱即用。

🧠 一、Spring AI 核心架构与原理

在写代码之前,理解 Spring AI 的架构设计至关重要,这有助于我们理解它的扩展性。

1.1 整体架构原理图

Spring AI 将 AI 模型交互抽象为多个层次,从底层的 HTTP 通信到上层的 POJO 转换。
基础设施与外部服务
模型提供商适配层
Spring AI 抽象层
应用层
Spring Boot Application
Chat Client / Image Client
Prompt Templates
Output Parser
Embedding Model
OpenAI Adapter
Azure Adapter
HuggingFace Adapter
OpenAI API
Vector Database

e.g. Redis/PGVector

核心组件解析:

  • Client 层 :最顶层的入口,如 ChatClient,开发者通过它与 AI 交互。
  • Prompt 层:负责将用户输入、系统指令和变量组装成 AI 能理解的格式。
  • Model 层:具体的模型实现,负责将 Prompt 发送给 API 并解析响应。

1.2 AI 交互流程图

当我们调用 chatClient.call() 时,Spring AI 内部发生了什么?
Converter OpenAI HTTP API Converter Jackson/JSON Prompt Template ChatClient Spring Boot App Converter OpenAI HTTP API Converter Jackson/JSON Prompt Template ChatClient Spring Boot App .prompt().user("...").call() 组装 Prompt (System/User) String / ChatRequest 序列化为 JSON JSON Body HTTP POST (/v1/chat/completions) JSON Response 反序列化为 ChatResponse ChatResponse 对象 返回 Entity / String


⚙️ 二、环境准备与项目初始化

2.1 技术栈要求

硬性要求:

  • JDK 17+:Spring Boot 3 强制要求。
  • Spring Boot 3.2.x+:确保兼容性。
  • OpenAI API Key:你需要一个密钥。

2.2 Maven 依赖配置

Spring AI 的版本更新较快,建议使用 BOM(Bill of Materials)管理版本。

xml 复制代码
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>1.0.0-M2</version> <!-- 请检查最新版本 -->
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <!-- Spring AI OpenAI Starter -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
    </dependency>
    
    <!-- Web Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

注意:由于 Spring AI 尚未放入 Maven 中央仓库的 release 版本,你需要确保添加了 Spring Milestone 或 Snapshot 仓库。

xml 复制代码
<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.3 配置文件设置

在 application.yml 中配置 API Key 和基础选项:

yaml 复制代码
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY} # 建议使用环境变量
      chat:
        options:
          model: gpt-4-turbo # 或 gpt-3.5-turbo
          temperature: 0.7 # 控制随机性,0.0-2.0

💬 三、快速入门:你的第一个 AI 对话机器人

我们将构建一个简单的 REST API,接收用户问题并返回 AI 回答。

3.1 创建 Service 层

java 复制代码
@Service
public class ChatService {
    private final ChatClient chatClient;
    public ChatService(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }
    public String chat(String message) {
        // 简单调用
        return chatClient.prompt()
                .user(message)
                .call()
                .content();
    }
}

代码解析:

  • ChatClient.Builder:Spring Boot 自动配置注入的构建器。
  • .prompt():开始构建对话请求。
  • .user():添加用户消息。
  • .call():同步阻塞调用(等待完整响应)。
  • .content():提取返回文本内容。

3.2 创建 Controller 层

java 复制代码
@RestController
@RequestMapping("/api/ai")
public class ChatController {
    private final ChatService chatService;
    public ChatController(ChatService chatService) {
        this.chatService = chatService;
    }
    @GetMapping("/chat")
    public Map<String, String> chat(@RequestParam String message) {
        String response = chatService.chat(message);
        return Map.of("answer", response);
    }
}

运行项目,访问 http://localhost:8080/api/ai/chat?message=Hello%20Spring%20AI,你将看到 AI 的回复。

🚀 四、进阶实战:提示词工程与流式响应

简单的字符串拼接无法胜任复杂业务。我们需要提示词模板 来管理上下文,并使用流式传输来提升用户体验。

4.1 提示词模板

假设我们要做一个"写诗助手",需要固定的角色设定。
创建 prompts/poet-template.st 文件(放在 src/main/resources 下):

text 复制代码
你是一位古代诗人,擅长唐诗宋词。
请根据以下主题:{topic},创作一首七言绝句。
要求:
1. 韵律工整
2. 意境优美
3. 字数严格

Service 代码升级:

java 复制代码
@Service
public class PoetService {
    private final ChatClient chatClient;
    // Spring AI 自动加载 resources 目录下的 .st 文件
    public PoetService(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder
                .defaultSystem("你是一位专业的文学创作助手") // 默认系统提示
                .build();
    }
    public String writePoem(String topic) {
        return chatClient.prompt()
                .user(userSpec -> userSpec
                        .text("请根据主题:{topic} 写一首诗") // 内联模板
                        .param("topic", topic)
                )
                .call()
                .content();
    }
}

4.2 流式响应

流式响应让用户感觉像是在实时打字,而不是等待几秒钟后一次性蹦出一段文字。这在 Web 界面中尤为重要。
流式接口原理图:
SSE Request
Flux
Async HTTP
Chunks
Chunks
SSE Events
Client
Spring Controller
ChatClient
OpenAI API

代码实现:

Spring AI 的 stream() 方法返回的是 Reactor 的 Flux<String>,这可以完美适配 Spring WebFlux 或者 Spring MVC 的流式响应。

java 复制代码
@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamChat(@RequestParam String message) {
    return chatClient.prompt()
            .user(message)
            .stream() // 关键:开启流式
            .content(); // 返回 Flux<String>
}

前端测试体验:

使用 curl 测试可以看到数据一行行吐出:

bash 复制代码
curl -N http://localhost:8080/api/ai/stream?message=讲个笑话

🔍 五、核心应用:RAG(检索增强生成)实战

大模型有两个致命弱点:知识幻觉 (瞎编乱造)和知识截止日期 (不知道今天发生的事)。
RAG (Retrieval-Augmented Generation) 是解决这些问题的银弹:先去外部知识库检索相关信息,然后扔给 LLM 让它基于这些信息回答。

5.2 Spring AI 实现 RAG

我们需要 EmbeddingModel(将文本转向量)和 VectorStore(存向量)。为了简化演示,我们使用基于内存的向量存储(生产环境建议用 PgVector 或 Milvus)。
添加依赖:

xml 复制代码
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-transformers-spring-boot-starter</artifactId>
</dependency>
<!-- 注意:Transformers 比较重,适合本地演示。生产环境建议用 OpenAI 的 Embedding API -->

RAG Service 代码:

java 复制代码
@Service
public class RagService {
    private final ChatClient chatClient;
    private final VectorStore vectorStore;
    public RagService(ChatClient.Builder chatClientBuilder, VectorStore vectorStore) {
        this.chatClient = chatClientBuilder.build();
        this.vectorStore = vectorStore;
        
        // 初始化时加载一些文档
        loadKnowledgeBase();
    }
    private void loadKnowledgeBase() {
        List<Document> documents = List.of(
            new Document("Spring Boot 3 最低要求 JDK 17。"),
            new Document("Spring AI 支持函数调用,可以连接外部 API。"),
            new Document("GraalVM 可以将 Java 应用编译为本地镜像,实现毫秒级启动。")
        );
        vectorStore.add(documents);
    }
    public String ask(String question) {
        // 1. 检索相关文档
        List<Document> similarDocs = vectorStore.similaritySearch(SearchRequest.query(question).withTopK(2));
        
        // 2. 构建包含上下文的 Prompt
        String context = similarDocs.stream()
                .map(Document::getContent)
                .collect(Collectors.joining("\n"));
        
        String systemPrompt = """
            你是一个助手。请仅使用以下提供的上下文信息来回答用户的问题。
            如果上下文中不包含答案,请说"我不知道"。
            
            上下文:
            {context}
            """;
        // 3. 发送给 LLM
        return chatClient.prompt()
                .system(systemPrompt)
                .user(question)
                .call()
                .content();
    }
}

关键点解析:

  1. VectorStore :Spring AI 抽象了向量数据库接口。我们调用 similaritySearch 即可找到语义最相近的文本片段。
  2. Prompt 注入:我们将检索到的文档塞进 System Prompt,这是 RAG 成功的关键。

🛠️ 六、Function Calling:赋予 AI 调用 Java 方法的能力

这是 AI 应用最强大的功能之一。AI 不再只是"聊天机器人",它可以理解意图并调用后端业务逻辑,比如"查询天气"、"下单"。

6.1 Function Calling 流程图

Java Function Spring AI LLM 用户 Java Function Spring AI LLM 用户 帮我查询北京现在的天气 识别意图 ->> 需要调用 getWeather(city) 返回 Function Call 指令 执行 getWeather("Beijing") 返回 "晴, 25度" 将结果作为上下文再次请求 北京现在天气晴朗,气温25度

6.2 实战:查询天气机器人

步骤 1:定义 Java Function

java 复制代码
public record WeatherRequest(String city) {}
public record WeatherResponse(String city, double temperature, String condition) {}
@Component
public class WeatherService {
    @Bean
    public Function<WeatherRequest, WeatherResponse> weatherFunction() {
        return request -> {
            // 模拟调用第三方天气 API
            if ("Beijing".equalsIgnoreCase(request.city())) {
                return new WeatherResponse("Beijing", 25.5, "Sunny");
            }
            return new WeatherResponse(request.city(), 0, "Unknown");
        };
    }
}

步骤 2:启用 Function Calling

java 复制代码
String response = chatClient.prompt()
        .user("北京现在天气怎么样?")
        .functions("weatherFunction") // 指定 Bean 名称
        .call()
        .content();

原理: Spring AI 会自动扫描容器中注册的 Function Bean,并在调用 OpenAI 时将函数的 JSON Schema 发送给模型。如果模型判断需要调用该函数,它会暂停生成,返回一个工具调用指令,Spring AI 拦截该指令,执行 Java 方法,将结果再次喂给模型,模型最后组织语言回复用户。

🛡️ 七、生产环境最佳实践

将 Demo 级应用投入生产,需要注意以下几点:

7.1 安全性

绝对不要将 API Key 提交到 Git。

  • 方案 A :使用环境变量(推荐)。

    bash 复制代码
    export OPENAI_API_KEY=sk-xxxx...
  • 方案 B:使用 Spring Cloud Config 或 Vault。

7.2 Token 计费控制

LLM 按输入和输出的 Token 计费。为了防止用户滥用导致账单爆炸:

  1. 限制 Max Tokens :

    java 复制代码
    chatClient.prompt()
            .options(OpenAiChatOptions.builder().withMaxTokens(500).build())
            ...
  2. 输入长度截断:在发送给 AI 前,截断过长的 Prompt。

7.3 异常处理

网络波动或 OpenAI 服务不可用是常态。

java 复制代码
try {
    return chatClient.prompt().user(msg).call().content();
} catch (OpenAiApiException e) {
    if (e.getStatusCode().is5xxServerError()) {
        // 服务端错误,重试
        return retryLogic(msg);
    }
    // 其他错误
    return "抱歉,AI 服务暂时不可用。";
}

7.4 性能优化

  • 连接池配置:Spring AI 底层使用 WebClient 或 RestTemplate,确保配置了适当的连接池大小。
  • 缓存:对于常见问题(如 FAQ),可以使用 Redis 缓存 AI 的回答,直接返回,避免重复计费。

🎯 八、总结

通过 Spring Boot 3 和 Spring AI,Java 开发者现在拥有了构建企业级 AI 应用的强力武器。本文涵盖了从基础架构、简单对话、流式交互到复杂的 RAG 和 Function Calling 的完整链路。
技术演进路径:
手工 HTTP 调用 ➡️ Spring AI 标准化 Client ➡️ RAG + Function Calling 的智能 Agent

Spring AI 的优势在于它完美融合了 Spring 生态的非侵入式设计理念,让 Java 开发者能专注于业务逻辑,而不是繁琐的 HTTP 编解码。未来的 AI 应用开发,将不仅仅是算法模型的比拼,更是工程化落地能力的较量。

现在,打开你的 IDE,开始构建你的第一个 Spring AI 应用吧!

相关推荐
Pniubi1 分钟前
区分Java创建线程池、多线程
java·线程·线程池·多线程·并发
程序员梅雨7 分钟前
ZooKeeper面经总结
java·大数据·linux·分布式·后端·zookeeper·中间件
llgdwuhan12 分钟前
光制造突围 | 国产耦合设备的替代与迭代
人工智能·光模块·耦合测试设备·光模块耦合设备·芯片测试设备·双透镜自动耦合设备
秦先生在广东18 分钟前
Microsoft BitNet b1.58: 重新定义本地化 AI 推理的性能与能效极限
人工智能
秦先生在广东24 分钟前
去中心化与全能化:深入剖析 Open WebUI 的自托管架构与工程实践
人工智能
IvorySQL25 分钟前
PostgreSQL 日报|堆表选择性索引更新(10 月 13 日)
数据库·人工智能·postgresql·开源·区块链
Yyyyyy~27 分钟前
【Java】多线程初阶
java
蜗牛互联网28 分钟前
Java 17 调用视觉 Responses API:JSON 约束与人工复核路由
java·人工智能·后端
秦先生在广东28 分钟前
Agent 驱动的逆向工程工作流:REA 全栈二进制与多格式分析工具深度解析
人工智能
2603_9688173432 分钟前
AI视频怎么超清增强
人工智能