Spring AI 入门教程:Java开发者的AI应用捷径

前言

当LLM浪潮席卷全球,Python似乎成了AI的"官方语言"时,我们Java开发者该如何快速拥抱这个新时代?Spring AI给出了官方答案:像整合数据库一样整合AI,像写Controller一样调用大模型。

本文将从零开始,带你一步步掌握Spring AI的核心用法。学完本文,你将能够:

  • ✅ 10分钟搭建一个AI聊天应用

  • ✅ 掌握提示词工程的最佳实践

  • ✅ 构建一个带知识库的RAG问答系统


一、Spring AI是什么?

一句话定义:Spring AI是Spring官方推出的AI应用开发框架,为Java开发者提供统一的AI模型调用接口。

1.1 为什么需要Spring AI?

在没有Spring AI之前,Java调用大模型是这样的:

java

复制代码
// 原生HTTP调用
OkHttpClient client = new OkHttpClient();
String json = "{ \"model\": \"gpt-3.5-turbo\", \"messages\": [...] }";
Request request = new Request.Builder()
    .url("https://api.openai.com/v1/chat/completions")
    .header("Authorization", "Bearer sk-xxx")
    .post(RequestBody.create(json, MediaType.parse("application/json")))
    .build();
Response response = client.newCall(request).execute();
// 手动解析JSON...

有了Spring AI之后:

java

复制代码
@RestController
public class ChatController {
    @Autowired
    private ChatClient chatClient;
    
    @GetMapping("/chat")
    public String chat(@RequestParam String msg) {
        return chatClient.prompt().user(msg).call().content();
    }
}

简洁、优雅、符合Spring风格------这就是Spring AI的魅力。

1.2 核心能力一览

能力模块 说明 支持的提供商
Chat(对话) 大语言模型对话 OpenAI、DeepSeek、通义千问、智谱AI等
Embedding(向量化) 文本转向量 OpenAI、Ollama、阿里云等
Image Generation(图像生成) 文生图 OpenAI DALL-E、Stability AI
Vector Store(向量数据库) 向量存储与检索 PGVector、Chroma、Qdrant、Redis等
Function Calling(函数调用) 模型调用业务API 各模型均已支持

Spring AI支持超过15种AI提供商,通过统一的API抽象,你可以轻松切换底层模型而无需修改业务代码。


二、环境准备

2.1 前置要求

工具 版本要求 说明
JDK 17+ Spring AI基于Spring Boot 3.x
Maven 3.6+ 或Gradle 7.x
IDE IntelliJ IDEA / VS Code 推荐IDEA

2.2 获取API Key(二选一)

方案一:DeepSeek(推荐国内开发者)

DeepSeek与OpenAI API完全兼容,价格便宜且无需科学上网。

bash

复制代码
# 访问 https://platform.deepseek.com/ 注册并获取API Key
# 新用户通常赠送免费额度

方案二:OpenAI(国际用户)

bash

复制代码
# 访问 https://platform.openai.com/api-keys 创建API Key
# 需要科学上网和海外信用卡

2.3 创建Spring Boot项目

使用 Spring Initializr 创建项目,选择以下依赖:

依赖 用途
Spring Web 提供REST API能力
Spring AI OpenAI 集成大模型

Maven依赖配置

xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<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 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.5.0</version>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>spring-ai-demo</artifactId>
    <version>1.0.0</version>

    <properties>
        <java.version>17</java.version>
    </properties>

    <!-- 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>
        <!-- Spring Boot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Spring AI OpenAI Starter -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-openai</artifactId>
        </dependency>
    </dependencies>

</project>

三、快速开始:第一个AI应用

3.1 配置文件

src/main/resources/application.yml 中添加配置:

yaml

复制代码
spring:
  ai:
    openai:
      # DeepSeek / OpenAI API Key
      api-key: ${AI_API_KEY:your-api-key-here}
      # DeepSeek的base-url
      base-url: https://api.deepseek.com
      chat:
        options:
          model: deepseek-chat
          temperature: 0.7  # 0-2之间,越高越有创造性

⚠️ 安全提示 :不要将API Key硬编码在配置文件中!推荐使用环境变量 AI_API_KEY

3.2 创建Controller

java

复制代码
package com.example.ai.controller;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/ai")
public class AIController {

    private final ChatClient chatClient;

    // 构造器注入
    public AIController(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }

    /**
     * 基础对话接口
     * GET /api/ai/chat?msg=你好
     */
    @GetMapping("/chat")
    public String chat(@RequestParam String msg) {
        return chatClient.prompt()
                .user(msg)
                .call()
                .content();
    }
}

3.3 运行测试

bash

复制代码
# 启动应用
mvn spring-boot:run

# 测试接口
curl "http://localhost:8080/api/ai/chat?msg=用Java写一个Hello World"

预期输出

java

复制代码
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

恭喜!你已经成功搭建了第一个AI应用 🎉


四、进阶用法:提示词模板

在实际业务中,我们通常需要更结构化的提示词。Spring AI提供了 PromptTemplate 来支持动态模板。

4.1 翻译接口示例

java

复制代码
package com.example.ai.controller;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/ai")
public class AIController {

    private final ChatClient chatClient;

    public AIController(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }

    /**
     * 翻译接口
     * POST /api/ai/translate
     * Body: {"sourceLang": "中文", "targetLang": "英文", "text": "今天天气真好"}
     */
    @PostMapping("/translate")
    public String translate(@RequestBody TranslateRequest request) {
        // 定义提示词模板
        PromptTemplate promptTemplate = new PromptTemplate("""
            请将以下{sourceLang}文本翻译成{targetLang}:
            
            {text}
            
            只返回翻译结果,不要添加任何解释。
            """);
        
        // 填充模板变量
        promptTemplate.add("sourceLang", request.sourceLang());
        promptTemplate.add("targetLang", request.targetLang());
        promptTemplate.add("text", request.text());
        
        // 调用并返回
        return chatClient.prompt(promptTemplate.render()).call().content();
    }

    // 请求DTO
    public record TranslateRequest(String sourceLang, String targetLang, String text) {}
}

4.2 结构化输出:让AI返回JSON

java

复制代码
import com.fasterxml.jackson.databind.ObjectMapper;

@PostMapping("/analyze")
public Map<String, Object> analyze(@RequestBody String text) {
    String prompt = """
        分析以下文本的情感倾向和关键词,以JSON格式返回:
        格式:{"sentiment": "positive/negative/neutral", "keywords": ["关键词1", "关键词2"]}
        
        文本:%s
        """.formatted(text);
    
    String response = chatClient.prompt(prompt).call().content();
    
    // 解析JSON返回
    ObjectMapper mapper = new ObjectMapper();
    try {
        return mapper.readValue(response, Map.class);
    } catch (Exception e) {
        return Map.of("error", "解析失败");
    }
}

五、RAG知识库集成

RAG(检索增强生成)是让AI回答私有数据问题的核心技术。Spring AI提供了完整的RAG支持,包括向量存储和检索增强。

5.1 添加依赖

xml

复制代码
<!-- PGVector 支持 -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-pgvector-store-spring-boot-starter</artifactId>
</dependency>

<!-- PDF 文档解析 -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-tika-document-reader</artifactId>
</dependency>

5.2 配置PGVector

首先启动PostgreSQL并安装PGVector扩展:

sql

复制代码
-- 安装扩展
CREATE EXTENSION IF NOT EXISTS vector;

配置文件:

yaml

复制代码
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/rag_db
    username: postgres
    password: password
  ai:
    vectorstore:
      pgvector:
        index-type: HNSW
        distance-type: COSINE_DISTANCE
        dimensions: 1536  # 向量维度,需与embeddings模型一致

5.3 实现RAG服务

java

复制代码
package com.example.ai.service;

import org.springframework.ai.document.Document;
import org.springframework.ai.reader.tika.TikaDocumentReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.ai.chat.client.ChatClient;

import java.util.List;

@Service
public class RagService {

    private final VectorStore vectorStore;
    private final ChatClient chatClient;
    private final TokenTextSplitter textSplitter;

    public RagService(VectorStore vectorStore, 
                      ChatClient.Builder chatClientBuilder) {
        this.vectorStore = vectorStore;
        this.chatClient = chatClientBuilder.build();
        // 文本分块:每块800字符,重叠200
        this.textSplitter = new TokenTextSplitter(800, 200, 10, 10000);
    }

    /**
     * 将文档加载到知识库
     */
    public void loadDocument(Resource pdfResource) {
        // 1. 读取PDF文档
        TikaDocumentReader reader = new TikaDocumentReader(pdfResource);
        List<Document> documents = reader.read();
        
        // 2. 文本分块(RAG的关键步骤)
        List<Document> chunks = textSplitter.apply(documents);
        
        // 3. 向量化并存入数据库
        vectorStore.add(chunks);
        
        System.out.println("已加载 " + chunks.size() + " 个文档片段");
    }

    /**
     * 基于知识库问答
     */
    public String ask(String question) {
        // 1. 检索相关文档片段(RAG召回)
        List<Document> relevantDocs = vectorStore.similaritySearch(question, 3);
        
        // 2. 构建上下文
        StringBuilder context = new StringBuilder();
        for (int i = 0; i < relevantDocs.size(); i++) {
            context.append("【文档").append(i + 1).append("】\n");
            context.append(relevantDocs.get(i).getContent()).append("\n\n");
        }
        
        // 3. 构建提示词
        String prompt = """
            请基于以下参考内容回答问题。
            
            参考内容:
            %s
            
            问题:%s
            
            要求:
            - 如果参考内容包含答案,基于内容回答
            - 如果不包含,请说"根据现有资料无法回答"
            - 回答时请引用来源
            """.formatted(context.toString(), question);
        
        // 4. 调用大模型生成回答
        return chatClient.prompt(prompt).call().content();
    }
}

5.4 创建REST接口

java

复制代码
package com.example.ai.controller;

import com.example.ai.service.RagService;
import org.springframework.core.io.FileSystemResource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

@RestController
@RequestMapping("/api/rag")
public class RagController {

    private final RagService ragService;

    public RagController(RagService ragService) {
        this.ragService = ragService;
    }

    /**
     * 上传文档到知识库
     */
    @PostMapping("/upload")
    public String upload(@RequestParam MultipartFile file) throws IOException {
        // 保存临时文件并加载
        String tempPath = "/tmp/" + file.getOriginalFilename();
        file.transferTo(new java.io.File(tempPath));
        
        ragService.loadDocument(new FileSystemResource(tempPath));
        return "文档加载成功: " + file.getOriginalFilename();
    }

    /**
     * 基于知识库问答
     */
    @GetMapping("/ask")
    public String ask(@RequestParam String question) {
        return ragService.ask(question);
    }
}

六、高级配置

6.1 模型参数调优

yaml

复制代码
spring:
  ai:
    openai:
      chat:
        options:
          model: gpt-4o-mini      # 模型名称
          temperature: 0.7         # 创造性 (0-2)
          max-tokens: 2000         # 最大输出长度
          top-p: 1.0              # 核采样
          frequency-penalty: 0    # 重复惩罚
          presence-penalty: 0     # 话题惩罚

6.2 流式响应(打字机效果)

java

复制代码
import org.springframework.ai.chat.client.StreamingChatClient;
import reactor.core.publisher.Flux;

@RestController
@RequestMapping("/api/stream")
public class StreamController {

    private final StreamingChatClient streamingChatClient;

    public StreamController(StreamingChatClient streamingChatClient) {
        this.streamingChatClient = streamingChatClient;
    }

    /**
     * 流式输出,实现"打字机"效果
     */
    @GetMapping(value = "/chat", produces = "text/plain; charset=UTF-8")
    public Flux<String> streamChat(@RequestParam String msg) {
        return streamingChatClient.stream(msg);
    }
}

6.3 函数调用(Function Calling)

让AI能够调用你的业务代码:

java

复制代码
import org.springframework.ai.model.function.FunctionCallback;

@Configuration
public class FunctionCallConfig {

    @Bean
    public FunctionCallback weatherFunction() {
        return FunctionCallback.builder()
            .function("getWeather", (String city) -> {
                // 调用天气API
                return "北京:晴,25°C";
            })
            .description("获取指定城市的天气信息")
            .inputType(String.class)
            .build();
    }
}

// 使用时,AI会自动判断是否需要调用天气函数

七、常见问题与最佳实践

7.1 常见错误及解决

错误 原因 解决方案
401 Unauthorized API Key无效 检查配置是否正确
Connection timed out 网络不通 检查base-url,DeepSeek用户注意配置正确
Context window exceeded 输入太长 减少max-tokens或使用RAG分段处理
JSON parse error 模型输出不是有效JSON 在prompt中明确要求JSON格式

7.2 最佳实践清单

生产环境配置

  • 使用环境变量管理API Key

  • 配置超时和重试机制

  • 添加限流保护

提示词工程

  • System Prompt明确定义AI角色

  • Few-shot示例提升准确率

  • 输出格式要明确(JSON、Markdown等)

RAG优化

  • 文档分块大小:500-1000字符

  • 块之间有重叠(overlap)

  • Top-K检索3-5个片段即可


八、总结

本文涵盖了Spring AI的核心使用场景:

  1. 基础对话:3步集成,一行代码调用大模型

  2. 提示词模板:结构化的AI交互

  3. RAG知识库:让AI回答私有数据问题

  4. 流式响应:打字机般的交互体验

Spring AI的最大价值在于:用Spring的方式做AI应用,让Java开发者无需学习Python就能快速构建AI能力。

后续学习建议

  • 探索更多模型提供商(Ollama本地部署、通义千问等)

  • 深入理解向量数据库和RAG原理

  • 学习AI Agent多智能体编排


参考资源

如果觉得本文对你有帮助,欢迎点赞收藏,有问题评论区交流~

相关推荐
极客老王说Agent1 小时前
2026智造前瞻:实在Agent生产排期智能助理核心功能与使用方法详解
大数据·人工智能·ai·chatgpt
巫山老妖1 小时前
鹅厂十年:三段式技术成长复盘
android·人工智能·程序员
aircrushin1 小时前
英伟达份额从95%跌到0,DeepSeek V4选择国产芯片
人工智能
aircrushin1 小时前
GPT-5.5免费了,但这个数字让你还敢用它吗?
人工智能
Zephyr_02 小时前
Leedcode算法题
java·算法
苍煜2 小时前
Java开发IO零基础吃透:BIO、NIO、同步异步、阻塞非阻塞
java·python·nio
后端小肥肠2 小时前
公众号漫画卷疯了?我用漫画工厂Skill,3天带群友入池,小白也能抄作业
人工智能·aigc·agent
扑兔AI2 小时前
扑兔AI基于公开数据的B2B客源筛选与意向评分系统设计
人工智能·生活
数智化精益手记局2 小时前
什么是设备维护管理?设备维护管理包含哪些内容?
大数据·网络·人工智能·安全·信息可视化