一文掌握 Spring AI:集成主流大模型的完整方案与思考

前言

随着 AI 大模型技术的日益成熟,Spring 官方推出了 Spring AI 框架,为开发者提供了统一的大模型集成方案。开发者无需再通过繁琐的 HTTP 请求调用不同的模型 API,只需引入相应依赖,即可快速实现与各类大模型的对接。

准备

spring ai 集成最低版本要求

  • spring boot 版本 3.x
  • jdk 版本 17+

本文使用 spring ai 依赖版本为 1.1.0(该版本更新时间为 2025 年 11 月 22 号)

模型选择

全球大模型市场呈现三足鼎立的局面,分别由 OpenAI 的 ChatGPT、Anthropic 的 Claude 以及 Google 的 Gemini 占据前三。与此同时,国内也涌现出了优秀的大模型产品,如 DeepSeek 和智谱的 GLM,在技术能力上毫不逊色。然而,Google 的 Gemini 目前限制了中国地区的服务无法调用(pass)。

本文主要集成 4 种大模型

  • openai 公司 ChatGPT 大模型 (新账号送 5 美元免费额度)
  • anthropic 公司 Claude 大模型 (无免费额度)
  • deepseek 公司 DeepSeek 大模型 (无免费额度)
  • zhipu 公司 GLM 大模型 (新账号送 千万 token 相当友好,邀请新人注册还送,对于大家测试调试妥妥够用了)

实践

完整源码获取:GitHub - RemainderTime/spring-ai-lab: LLM 相关对接实现 ai-models-chat 模块

注:本文只实现大模型文本对话功能,多模块不在本文实现。

本项目在多模块项目中管理,方便版本统一。

本文仅说明核心功能源码实现,细节请参考上面源码。

依赖引入

1: 父 pom.xml 依赖

xml 复制代码
<dependencyManagement>
  <dependencies>
    <!-- 引入 Spring AI bom 统一版本 -->
    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-bom</artifactId>
      <version>1.1.0</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

2: ai-models-chat 模型 pom.xml 依赖引入

直接引入 4 个大模型依赖

xml 复制代码
<dependencies>
  <!-- 集成anthropic公司依赖 用于claude 模型-->
  <dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-anthropic</artifactId>
  </dependency>
  <!-- 集成openai公司依赖 用于gpt 模型-->
  <dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
  </dependency>
  <!-- 集成zhipu ai公司依赖 用于GLM 模型-->
  <dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-zhipuai</artifactId>
  </dependency>
  <!-- 集成deepseek公司依赖 用于DeepSeek 模型-->
  <dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-deepseek</artifactId>
  </dependency>
</dependencies>

配置 yml 文件

spring 对支持的大模型做了统一的规范

yml 复制代码
spring:
  ai:
    anthropic:
      api-key: xxx
        options:
          model: claude-3-5-sonnet-20241022
          temperature: 0.7
    openai:
      api-key: xxx
      chat:
        options:
          model: gpt-4o-mini
          temperature: 0.7
    zhipuai:
      api-key: xxx
      chat:
        options:
          model: glm-4.6
          temperature: 0.7
    deepseek:
      api-key: xxx
      chat:
        options:
          model: deepseek-chat
          temperature: 0.7
  • api-key: 调用大模型的密钥(去对应大模型网站创建申请)
  • model: 模型大模型版本(也可在代码中动态设置)
  • temperature:用于控制模型的创意程度(0-2 之间),越小返回的内容越固定,越大创意程度越高可能偏离想要的答案,根据业务情况设置,一般设置 0.7 适中

API 接口实现

每种模型显示两种接口:

  • 直接应答模式
  • 流式应答模式(SSE 模式)

1: chatGPT 接口

java 复制代码
@RestController
@RequestMapping("/ai/chatgpt")
public class ChatGPTModelController {

    @Autowired
    private OpenAiChatModel chatModel;

    /**
     * chatgpt 模型直接调用
     *
     * @return
     */
    @GetMapping("/call/chat")
    public String callChat(@RequestParam String message, @RequestParam(defaultValue = "gpt-4o-mini") String model) {
        ChatResponse response = chatModel.call(
            new Prompt(
                message,
                OpenAiChatOptions.builder()
                .model(model)
                .temperature(0.7)
                .build()
            ));
        return response.getResult().getOutput().getText();
    }

    /**
     * chatgpt 模型流式调用
     *
     * @return
     */
    @GetMapping(value = "/stream/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<String>> streamChat(@RequestParam String message, @RequestParam(defaultValue = "gpt-4o-mini") String model) {
        return chatModel.stream(
            new Prompt(message, OpenAiChatOptions.builder().model(model).build())
        )
        .map(chatResponse -> {
            String text = chatResponse.getResults()
            .stream()
            .filter(r -> r.getOutput().getText() != null)
            .map(r -> r.getOutput().getText())
            .findFirst()
            .orElse("");

            return ServerSentEvent.<String>builder()
            .data(text)
            .build();
        })
        .concatWith(Flux.just(
            ServerSentEvent.<String>builder()
            .data("[DONE]")
            .build()
        ))
        .doOnError(Throwable::printStackTrace);
    }

    /**
     * chatgpt 模型直接调用(图片内容)
     * 只支持 GPT_4_O 或 GPT_4_TURBO 模型
     *
     * @return
     */
    @PostMapping("/call/chatImg")
    public String callChatImg(@RequestParam String message,
                              @RequestParam(defaultValue = "gpt-4o") String model,
                              @RequestParam MultipartFile imageFile) {
        // 读取图片
        byte[] imageBytes = null;
        try {
            imageBytes = imageFile.getBytes();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        Resource imageResource = new ByteArrayResource(imageBytes);
        // 创建消息列表
        List<org.springframework.ai.chat.messages.Message> messages = new ArrayList<>();
        // 添加文本消息
        messages.add(new UserMessage(message));
        // 添加图片消息
        messages.add(new UserMessage(imageResource));
        // 调用模型
        ChatResponse response = chatModel.call(
            new Prompt(
                messages,
                OpenAiChatOptions.builder()
                .model(model)
                                .build()
                )
        );
        return response.getResult().getOutput().getText();
    }

2: Claude 模型调用

java 复制代码
@RestController
@RequestMapping("/ai/claude")
public class ClaudeModelController {

    @Resource
    private AnthropicChatModel chatModel;

    /**
     * claude 模型直接调用
     * @return
     */
    @GetMapping("/call/chat")
    public ChatResponse callChat(@RequestParam String message, @RequestParam(defaultValue = "claude-3-7-sonnet-latest")String model) {
        return chatModel.call(
            new Prompt(
                message,
                AnthropicChatOptions.builder()
                .model(model)
                .temperature(0.7)
                .build()
            ));
    }

    /**
     * claude 模型流式调用
     * @return
     */
    @GetMapping(value = "/stream/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ChatResponse> streamChat(@RequestParam String message, @RequestParam(defaultValue = "claude-3-7-sonnet-latest")String model) {
        return chatModel.stream(
            new Prompt(
                message,
                AnthropicChatOptions.builder()
                .model(model)
                .temperature(0.7)
                .build()
            ));
    }

}

3: DeepSeek 模型调用

java 复制代码
@RestController
@RequestMapping("/ai/deepseek")
public class DeepSeekModelController {

    @Resource
    private DeepSeekChatModel chatModel;

    /**
     * deepseek 模型直接调用
     *
     * @return
     */
    @GetMapping("/call/chat")
    public String callChat(@RequestParam String message, @RequestParam(defaultValue = "deepseek-chat") String model) {
        ChatResponse response = chatModel.call(
            new Prompt(
                message,
                DeepSeekChatOptions.builder()
                .model(model)
                .temperature(0.7)
                .build()
            ));
        return response.getResult().getOutput().getText();
    }

    /**
     * deepseek 模型流式调用
     *
     * @return
     */
    @GetMapping(value = "/stream/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<String>> streamChat(@RequestParam String message, @RequestParam(defaultValue = "deepseek-chat") String model) {
        return chatModel.stream(
            new Prompt(message, DeepSeekChatOptions.builder().model(model).build())
        )
        .map(chatResponse -> {
            String text = chatResponse.getResults()
            .stream()
            .filter(r -> r.getOutput().getText() != null)
            .map(r -> r.getOutput().getText())
            .findFirst()
            .orElse("");

            return ServerSentEvent.<String>builder()
            .data(text)
            .build();
        })
        .concatWith(Flux.just(
            ServerSentEvent.<String>builder()
            .data("[DONE]")
            .build()
        ))
        .doOnError(Throwable::printStackTrace);
    }
}

4:GLM 模型调用

java 复制代码
@RestController
@RequestMapping("/ai/glm")
public class GLMModelController {

    @Resource
    private ZhiPuAiChatModel chatModel;

    /**
     * glm 模型直接调用
     *
     * @return
     */
    @GetMapping("/call/chat")
    public String callChat(@RequestParam String message, @RequestParam(defaultValue = "glm-4.6") String model) {
        ChatResponse response = chatModel.call(
            new Prompt(
                message,
                ZhiPuAiChatOptions.builder()
                .model(model)
                .temperature(0.7)
                .build()
            ));
        return response.getResult().getOutput().getText();
    }

    /**
     * glm 模型流式调用
     *
     * @return
     */
    @GetMapping(value = "/stream/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<String>> streamChat(@RequestParam String message, @RequestParam(defaultValue = "glm-4.6") String model) {
        return chatModel.stream(
            new Prompt(message, ZhiPuAiChatOptions.builder().model(model).build())
        )
        .map(chatResponse -> {
            String text = chatResponse.getResults()
            .stream()
            .filter(r -> r.getOutput().getText() != null)
            .map(r -> r.getOutput().getText())
            .findFirst()
            .orElse("");

            return ServerSentEvent.<String>builder()
            .data(text)
            .build();
        })
        .concatWith(Flux.just(
            ServerSentEvent.<String>builder()
            .data("[DONE]")
            .build()
        ))
        .doOnError(Throwable::printStackTrace);
    }
}

一些思考⁉️

我们应该理性对待 AI 工具。不能将整个项目的功能业务全权交由 AI 处理,因为 AI 并不真正理解项目的全局设计、架构约束和业务复杂性。盲目依赖 AI 生成的代码,会增加代码审查、修改和测试的成本,其合理性也难以保证。

AI 作为特定功能模块或业务逻辑的 辅助工具,用来快速提供解决思路或代码框架,但核心的架构设计、设计模式的选用、并发控制、系统整体优化等,仍需由经验丰富的开发者主导。过度依赖工具只会适得其反,削弱开发者的思考能力和解决问题的能力。

AI 工具只是辅助手段,用于加速特定模块的开发,但不能替代人的 ****架构思维和全局考量。理性、有节制地使用 AI,充分发挥其优势同时规避风险,才是正确的态度。

总结

与其追捧各类 AI 开发工具,不如主动掌握和应用 AI 大模型技术。作为开发者,我们应该利用大模型的强大能力来解决实际问题、优化日常工作流程,从而在竞争中脱颖而出。实际上,无论选用哪款大模型,对于大多数日常任务的处理效果差异不大------关键在于如何创意性地应用,而非被特定工具绑定。

相关推荐
踏浪无痕1 天前
缓存一致性的工业级解法:用Java实现Facebook租约机制
后端·面试·架构
Lear1 天前
【JavaSE】多态深度解析:从核心概念到最佳实践
后端
血小溅1 天前
SpringBoot 整合 QLExpress 教程:患者随访画像多条件适配案例
后端
HelloReader1 天前
从 Rocket 0.4 升级到 0.5一份实战迁移指南
后端·rust
ChrisitineTX1 天前
Spring Boot 3 + GraalVM Native Image 原理:从启动 10秒 到 0.05秒,AOT 编译到底干了什么?
java·spring boot·后端
CodeSheep1 天前
华为又招天才少年了。。
前端·后端·程序员
武子康1 天前
大数据-179 Elasticsearch 倒排索引与读写流程全解析:从 Lucene 原理到 Query/Fetch 实战
大数据·后端·elasticsearch
回家路上绕了弯1 天前
微信抢红包深度解析:从算法原理到高并发工程实现
分布式·后端
编程修仙1 天前
第五篇 SpringMVC
java·spring boot·spring