Spring AI 通关秘籍:从聊天到业务落地,Java 选手再也不用馋 Python 了!

作为天天跟代码打交道的 IT 人,你是不是也有过这种崩溃时刻:想给项目加个 AI 功能,结果对着 Python 的 LangChain、LLaMAIndex 一顿猛学,回头一看自己的 Spring 项目 ------"这俩咋凑一块儿啊?"

别慌!今天咱们聊的Spring AI,就是 Java 生态给咱们准备的 "AI 开发 Buff"。它把复杂的 AI 调用、流式交互、工具整合都封装成了熟悉的 Spring 风格,不用再当 "API 缝合怪",咱们用 Java 也能轻松玩明白 AI。

1. 先唠唠:Spring AI 到底是个啥?

说直白点,Spring AI 就是AI 领域的 "Spring 框架" 。它解决了 Java 开发者对接 AI 时的 3 个核心痛点:

  • 不用记各种 AI 模型(OpenAI、阿里云通义千问、讯飞星火)的不同 API 格式,统一用ChatClient调用;
  • 不用自己写流式输出、重试、降级逻辑,Spring 帮你封装好了;
  • 能无缝整合 Spring 生态的东西(Spring Boot、Spring Cloud),跟你现有的业务系统搭班子毫无违和感。

简单讲:以前你对接 AI 要写 100 行 "胶水代码",现在用 Spring AI,10 行搞定。

2. 入门实战:用 Spring AI 搞个 "普通对话"

先从最简单的开始 ------ 让 AI 跟你聊两句。步骤简单到离谱,跟搭 Spring Boot 项目没区别。

参考官方文档中的示例代码编写:👉 Chat Client API

2.1 先搭环境(3 步走)

  1. 新建 Spring Boot 项目,在pom.xml里加依赖(以对接 OpenAI 为例):
xml 复制代码
<!-- Spring AI核心依赖 -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
    <version>1.0.0-M1</version> <!-- 用最新版就行 -->
</dependency>
<!-- Web依赖(方便测接口) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
  1. application.properties里填 AI 密钥(去 OpenAI 官网申请,或者用国内模型的密钥):

properties

ini 复制代码
# OpenAI配置
spring.ai.openai.api-key=你的API密钥
spring.ai.openai.chat.model=gpt-3.5-turbo
  1. 写个 Controller 测试:
less 复制代码
@RestController
@RequestMapping("/ai")
public class AIChatController {

    // Spring AI自动注入ChatClient,不用自己new!
    private final ChatClient chatClient;

    public AIChatController(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    // 普通对话接口:传个问题,返回AI的回答
    @GetMapping("/chat")
    public String chat(@RequestParam String question) {
        // 调用AI,一句话搞定
        return chatClient.prompt().user(question).call().content();
    }
}

2.2 跑起来试试!

启动项目,访问http://localhost:8080/ai/chat?question=用Java写个HelloWorld,AI 直接给你返回代码 ------ 就这么简单,没有任何花里胡哨的操作。

3. 进阶:搞个 "流式对话",跟 ChatGPT 一样实时输出

普通对话是 "等 AI 想完一起返回",流式对话是 "AI 想一句输出一句",体验更丝滑(比如 ChatGPT 的打字效果)。Spring AI 搞这个也很简单,核心是用Flux(响应式编程)。

3.1 写个流式接口

less 复制代码
// 流式对话接口:返回Flux<String>,支持实时输出
@GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamChat(@RequestParam String question) {
    // 用stream()方法,返回Flux<ChatResponse>
    return chatClient.prompt()
            .user(question)
            .stream() // 关键:开启流式
            .map(chatResponse -> chatResponse.getResult().getOutput().getContent());
}

3.2 测效果

用 apifox 或者浏览器访问这个接口,你会看到 AI 的回答 "一行一行蹦出来",跟你平时用 ChatGPT 一模一样。前端要做的就是监听 SSE(Server-Sent Events),把内容实时渲染出来 ------Java 后端这边,咱们已经搞定了!

1

4. 给 AI 立规矩:System 角色设定

你有没有遇到过 AI "答非所问"?比如你让它当 Java 老师,它却跟你聊 Python。这时候就需要System 角色------ 给 AI 定个 "身份" 和 "规则",让它别跑偏。

Spring AI 里设定 System 角色超简单,就在prompt()里加个system()方法:

less 复制代码
@GetMapping("/chat/teacher")
public String javaTeacherChat(@RequestParam String question) {
    // System角色:告诉AI"你是Java导师,只聊Java,用简单的话讲"
    String systemPrompt = "你是一名资深Java导师,只回答与Java相关的问题," +
                          "避免涉及其他编程语言,解释时用大白话,别甩专业术语。";
    
    return chatClient.prompt()
            .system(systemPrompt) // 加System规则
            .user(question)       // 用户问题
            .call()
            .content();
}

测试一下:问 "Python 怎么写循环?",AI 会说 "我只聊 Java 哦,Java 的循环有 for 和 while 两种......"------ 规矩立住了!

5. 给 AI 加 "插件":Advisors 功能增强

下图展示了,在与大模型交互过程中,Advisors的执行流程:

Advisors 是 Spring AI 的 "增强器",能在 AI 调用的前、中、后插逻辑,比如日志记录、权限校验、参数修改。举个最实用的例子:记录每次 AI 调用的 "问题" 和 "回答"。

5.1 自定义一个日志 Advisor

java 复制代码
// 实现Advisor接口,重写before和after方法
@Component
public class AILogAdvisor implements Advisor {

    private static final Logger log = LoggerFactory.getLogger(AILogAdvisor.class);

    // AI调用前:记录用户的问题
    @Override
    public void before(Prompt prompt) {
        String userQuestion = prompt.getMessages().stream()
                .filter(msg -> msg.getRole() == Message.Role.USER)
                .findFirst()
                .map(Message::getContent)
                .orElse("无用户问题");
        
        log.info("AI调用开始,用户问题:{}", userQuestion);
    }

    // AI调用后:记录AI的回答
    @Override
    public void after(Response response) {
        String aiAnswer = response.getResult().getOutput().getContent();
        log.info("AI调用结束,AI回答:{}", aiAnswer);
    }
}

5.2 用 Advisor 增强 ChatClient

只需要在注入ChatClient时,用ChatClient.builder()把 Advisor 加进去:

kotlin 复制代码
@Configuration
public class AIClientConfig {

    @Value("${spring.ai.openai.api-key}")
    private String apiKey;

    @Bean
    public ChatClient chatClient(AILogAdvisor aiLogAdvisor) {
        // 构建ChatClient,加入日志Advisor
        return OpenAiChatClient.builder()
                .apiKey(apiKey)
                .model("gpt-3.5-turbo")
                .advisor(aiLogAdvisor) // 加增强器
                .build();
    }
}

这样一来,每次调用 AI,日志里都会自动记录 "用户问了啥""AI 答了啥"------ 排查问题、统计用量都方便!

6. 关键一步:Tool Calling 对接业务系统

AI 光会聊天没用,得能调用咱们业务系统的接口(比如查订单、查库存),这就是Tool Calling。Spring AI 把这个流程封装成了 3 步:定义工具、让 AI 选工具、执行工具并返回结果。

6.1 第一步:定义业务工具(比如 "查订单")

先写个 "订单查询服务",模拟业务系统:

typescript 复制代码
// 模拟业务系统:订单服务
@Service
public class OrderService {
    // 根据订单号查订单
    public String getOrderInfo(String orderId) {
        // 实际项目里这里会查数据库/调用微服务
        return "订单ID:" + orderId + ",状态:已付款,金额:99元,商品:Java编程思想";
    }
}

然后把这个服务包装成 AI 能调用的 "Tool":

typescript 复制代码
// 定义AI工具:订单查询工具
@Component
public class OrderQueryTool implements Tool {

    private final OrderService orderService;

    public OrderQueryTool(OrderService orderService) {
        this.orderService = orderService;
    }

    // 工具名称:AI会用这个名字调用
    @Override
    public String getName() {
        return "orderQueryTool";
    }

    // 工具描述:告诉AI"这个工具是干嘛的,怎么用"
    @Override
    public String getDescription() {
        return "用于查询用户的订单信息,需要传入订单号(orderId)作为参数," +
               "参数格式:{"orderId":"用户的订单号"}";
    }

    // 工具执行逻辑:AI调用时会触发这个方法
    @Override
    public Object call(Map<String, Object> parameters) {
        String orderId = (String) parameters.get("orderId");
        return orderService.getOrderInfo(orderId);
    }
}

6.2 第二步:让 AI 调用工具

Spring AI 提供了ToolCallingChatClient,能自动判断 "要不要调用工具":

less 复制代码
@RestController
@RequestMapping("/ai/tool")
public class AIToolController {

    private final ToolCallingChatClient toolChatClient;

    // 注入工具和ChatClient,构建ToolCallingChatClient
    public AIToolController(OrderQueryTool orderQueryTool, ChatClient chatClient) {
        this.toolChatClient = ToolCallingChatClient.builder(chatClient)
                .withTools(orderQueryTool) // 把订单工具加进去
                .build();
    }

    // 调用工具的接口
    @GetMapping("/queryOrder")
    public String queryOrder(@RequestParam String question) {
        // 比如用户问:"查一下我的订单号12345的信息"
        return toolChatClient.prompt().user(question).call().content();
    }
}

测试一下:用户问 "查一下订单号 12345 的信息",AI 会自动调用orderQueryTool,返回订单详情 ------ 这就把 AI 和你的业务系统打通了!

7. 终极优化:RAG 检索增强,让 AI "有记忆"

AI 有个毛病:"记不住" 你公司的私有数据(比如产品文档、内部规则)。这时候就需要RAG(检索增强生成) ------ 先从你的知识库(比如 MySQL、Elasticsearch)里查相关信息,再把信息传给 AI,让 AI 基于这些信息回答。

Spring AI 整合 RAG 很简单,核心是 "检索器(Retriever)+ Prompt"。

7.1 第一步:搞个简单的知识库(用 List 模拟)

typescript 复制代码
// 模拟知识库:比如公司的产品文档
@Component
public class ProductDocRetriever implements Retriever<String> {

    // 模拟知识库数据
    private final List<String> productDocs = Arrays.asList(
            "产品名称:Java云原生框架,版本:V2.0,支持Spring Boot 3.0+,不支持Spring Boot 2.x",
            "产品名称:Python数据分析工具,版本:V1.5,支持Python 3.9+,需要安装pandas库"
    );

    // 检索逻辑:根据用户问题,从知识库找相关内容
    @Override
    public List<String> retrieve(String query) {
        // 实际项目里这里会用Elasticsearch做全文检索
        return productDocs.stream()
                .filter(doc -> doc.contains(query.split(" ")[1])) // 简单匹配产品名
                .collect(Collectors.toList());
    }
}

7.2 第二步:整合 RAG 到 AI 调用

kotlin 复制代码
@RestController
@RequestMapping("/ai/rag")
public class AIRagController {

    private final ChatClient chatClient;
    private final ProductDocRetriever docRetriever;

    public AIRagController(ChatClient chatClient, ProductDocRetriever docRetriever) {
        this.chatClient = chatClient;
        this.docRetriever = docRetriever;
    }

    @GetMapping("/queryProduct")
    public String queryProduct(@RequestParam String question) {
        // 1. 从知识库检索相关信息(比如用户问"Java云原生框架支持哪些版本?")
        List<String> relatedDocs = docRetriever.retrieve(question);
        String context = String.join("\n", relatedDocs);

        // 2. 把检索到的信息传给AI,让AI基于这些信息回答
        String prompt = "根据以下产品文档内容,回答用户问题:\n" +
                       "文档内容:" + context + "\n" +
                       "用户问题:" + question;

        return chatClient.prompt().user(prompt).call().content();
    }
}

测试一下:用户问 "Java 云原生框架支持 Spring Boot 2.x 吗?",AI 会从知识库查到 "不支持 Spring Boot 2.x",然后准确回答 ------ 这就是 RAG 的魔力,让 AI 能 "读懂" 你的私有数据!

总结:Spring AI 让 Java 开发者玩 AI 更丝滑

从普通聊天到流式交互,从角色设定到工具整合,再到 RAG 检索增强 ------Spring AI 把 AI 开发变成了 "Java 开发者熟悉的样子",不用再羡慕 Python 生态的各种 AI 库。

接下来你可以试试:把 RAG 的知识库换成 Elasticsearch,让 Tool Calling 对接更多业务接口(比如查库存、生成报表),甚至用 Spring Cloud 把 AI 服务做成微服务 ------ 玩法还有很多!

最后留个问题:你在项目里想给 AI 加什么功能?评论区聊聊~

相关推荐
小羊失眠啦.3 分钟前
深入解析Rust的所有权系统:告别空指针和数据竞争
开发语言·后端·rust
q***718540 分钟前
Spring Boot 集成 MyBatis 全面讲解
spring boot·后端·mybatis
原来是好奇心40 分钟前
Spring Boot缓存实战:@Cacheable注解详解与性能优化
java·spring·mybatis·springboot
大象席地抽烟1 小时前
使用 Ollama 本地模型与 Spring AI Alibaba
后端
程序员小假1 小时前
SQL 语句左连接右连接内连接如何使用,区别是什么?
java·后端
小坏讲微服务1 小时前
Spring Cloud Alibaba Gateway 集成 Redis 限流的完整配置
数据库·redis·分布式·后端·spring cloud·架构·gateway
方圆想当图灵2 小时前
Nacos 源码深度畅游:Nacos 配置同步详解(下)
分布式·后端·github
方圆想当图灵2 小时前
Nacos 源码深度畅游:Nacos 配置同步详解(上)
分布式·后端·github
小羊失眠啦.2 小时前
用 Rust 实现高性能并发下载器:从原理到实战
开发语言·后端·rust
Filotimo_3 小时前
SpringBoot3入门
java·spring boot·后端