(第二篇)Spring AI 基础入门:从环境搭建到模型接入全攻略(覆盖国内外模型 + 本地部署)

(第二篇)Spring AI 基础入门:从环境搭建到模型接入全攻略(覆盖国内外模型 + 本地部署)

 

前言:为什么要学 Spring AI?

        最近在做 AI 应用开发时,发现很多朋友卡在了工具链整合这一步:用原生 SDK 调用 OpenAI 要处理一堆 HTTP 请求,切换到通义千问又得改大量代码,本地部署 Llama3 更是不知道怎么和 Spring 项目结合…

        直到接触了 Spring AI 才发现,这个框架简直是为 Java 开发者量身定做的 AI 开发工具 —— 它把不同模型的调用逻辑标准化了,不管是 OpenAI、通义千问还是本地 Llama3,都能用几乎一样的 API 调用。

        这篇教程从基础环境讲到实战接口,全程手把手操作,哪怕是 AI 开发新手,跟着走也能跑通第一个 Spring AI 应用。

目录

基础环境搭建:JDK17+Maven3.8+Spring Boot3.x 核心配置商业模型接入:OpenAI/Azure OpenAI / 通义千问 密钥配置与调用本地私有化部署:Ollama+Llama3 搭建专属 AI 服务代理配置与排坑指南:从网络异常到日志解读实战:同步响应 vs 流式响应 对话接口开发总结与进阶方向

1. 基础环境搭建:JDK17+Maven3.8+Spring Boot3.x 核心配置

        Spring AI 依赖 Spring Boot3.x,而 Spring Boot3.x 强制要求 JDK17 及以上 —— 这一步要是版本错了,后面全白搭。

1.1 JDK17:必须选对的底层引擎

为什么是 JDK17?
Spring Boot3.x 基于 Java 17 的模块化系统,用 JDK8 会直接报java.lang.UnsupportedClassVersionErrorSpring AI 的很多特性(比如 Record 类型接收模型响应)依赖 JDK17 语法主流 AI 厂商的 Java SDK(如通义千问)默认支持 JDK17
安装步骤(以 Windows 为例):
  1. 下载地址:推荐Eclipse Temurin 17(OpenJDK 的稳定发行版,免费无限制)
  2. 安装注意:路径绝对不能有空格或中文(比如D:\jdk17,别放Program Files
  3. 配置环境变量:
    • 新建JAVA_HOME:值为安装路径(如D:\jdk17
    • 编辑Path:添加%JAVA_HOME%\bin(建议移到最上面,避免和其他 JDK 冲突)

验证:cmd 输入java -version,出现以下信息说明成功:

openjdk version "17.0.10" 2024-01-16 OpenJDK Runtime Environment Temurin-17.0.10+7 (build 17.0.10+7) OpenJDK 64-Bit Server VM Temurin-17.0.10+7 (build 17.0.10+7, mixed mode, sharing) 

1.2 Maven3.8:依赖管理的加速器

为什么选 3.8?
对 JDK17 兼容性更好,老版本(如 3.6)可能出现依赖下载失败支持 HTTPS 仓库(Spring AI 的仓库是 HTTPS,老版本可能报协议错误)
安装与配置:
  1. 下载:Apache Maven 3.8.8(3.8.x 最新稳定版)
  2. 解压到无空格路径(如D:\maven3.8
  3. 环境变量:
    • 新建MAVEN_HOMED:\maven3.8
    • Path添加%MAVEN_HOME%\bin
  4. 验证:mvn -v能看到版本信息即可
  5. 关键配置(conf/settings.xml):

阿里云镜像(国内下载 Spring AI 依赖提速 10 倍):

<mirrors> <mirror> <id>aliyun</id> <name>阿里云公共仓库</name> <url>https://maven.aliyun.com/repository/public</url> <mirrorOf>central</mirrorOf> </mirror> </mirrors> 

本地仓库(避免占 C 盘):

<localRepository>D:\maven-repo</localRepository> 

1.3 Spring Boot3.x + Spring AI:项目初始化

Spring AI 目前还没进入 Spring 官方仓库,需要手动添加仓库地址。

步骤:
  1. Spring Initializr生成项目:
    • 版本选3.2.4(最新稳定版)
    • 依赖勾选:Spring WebLombokSpring Reactive Web(流式响应需要)
  2. 等待 Maven 下载依赖(第一次可能需要 5-10 分钟,耐心等,别断网)

解压后打开pom.xml,添加 Spring AI 仓库和核心依赖:

<!-- Spring AI仓库 --> <repositories> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> <!-- Spring AI核心依赖 --> <dependencies> <!-- 模型调用核心 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-core</artifactId> <version>0.8.1-SNAPSHOT</version> </dependency> <!-- OpenAI支持 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai</artifactId> <version>0.8.1-SNAPSHOT</version> </dependency> <!-- 通义千问支持 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-tongyi</artifactId> <version>0.8.1-SNAPSHOT</version> </dependency> <!-- Ollama本地模型支持 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-ollama</artifactId> <version>0.8.1-SNAPSHOT</version> </dependency> </dependencies> 

1.4 环境依赖关系图

2. 商业模型接入:从密钥到调用全流程

Spring AI 的核心优势就是标准化接口—— 不管是哪个厂商的模型,调用方式几乎一样。

2.1 OpenAI:最主流的商业模型

准备工作:
  1. 注册 OpenAI 账号:OpenAI 平台(需要国外手机号验证)
  2. 创建 API 密钥:右上角头像 → View API keys → Create new secret key密钥只显示一次,赶紧存起来
  3. 充值:新账号有免费额度,用完后需要绑定信用卡充值(支持 Visa/MasterCard)
配置步骤:

application.yml中添加:

spring: ai: openai: api-key: 你的sk-xxx密钥 chat: model: gpt-3.5-turbo # 模型名称,也可以用gpt-4 
测试代码:
import lombok.RequiredArgsConstructor; import org.springframework.ai.chat.ChatClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @RequiredArgsConstructor // Lombok自动注入 public class OpenAIController { private final ChatClient chatClient; // Spring AI自动配置的客户端 @GetMapping("/openai/chat") public String chat(@RequestParam String message) { // 调用模型并返回结果 return chatClient.call(message); } } 

2.2 Azure OpenAI:国内可用的OpenAI 平替

如果访问 OpenAI 官网困难,Azure OpenAI 是个好选择(需要企业资质申请)。

配置差异:
spring: ai: azure: openai: api-key: 你的Azure密钥 endpoint: 你的资源端点(如https://xxx.openai.azure.com/) deployment-name: 部署的模型名称(在Azure控制台创建) 

2.3 阿里云通义千问:国产模型优选

准备工作:
  1. 注册阿里云账号:阿里云控制台
  2. 创建 AccessKey:头像 → AccessKey管理 → 生成密钥(注意保存 AccessKey ID 和 Secret)
  3. 开通通义千问服务:在阿里云 AI 平台开通对应模型(有免费额度)
配置步骤:
spring: ai: tongyi: api-key: 你的AccessKey ID secret-key: 你的AccessKey Secret chat: model: qwen-turbo # 基础版,也可用qwen-plus 
调用代码:

和 OpenAI 完全一样!只需注入ChatClient,因为 Spring AI 已经统一了接口:

@GetMapping("/tongyi/chat") public String tongyiChat(@RequestParam String message) { return chatClient.call(message); // 和OpenAI调用代码完全相同 } 

2.4 模型接入流程图

3. 本地私有化部署:Ollama+Llama3 搭建无网络依赖服务

如果对数据隐私敏感,或者需要离线运行,本地部署 Llama3 是最佳选择。

3.1 Ollama:最简单的本地模型运行工具

Ollama 是一个轻量级工具,能一键运行 Llama3、Mistral 等主流模型。

安装步骤:
  1. 下载 Ollama:官网(支持 Windows/Mac/Linux,Windows 需要 WSL2)
  2. 安装后启动:会自动在本地启动一个服务(默认端口 11434)

拉取 Llama3 模型:打开 cmd,输入:

ollama run llama3 

首次运行会下载模型(约 4.7GB,耐心等),下载完成后会进入交互模式,输入你好测试是否可用。

3.2 Spring AI 接入本地 Llama3

配置application.yml
spring: ai: ollama: base-url: http://localhost:11434 # Ollama默认地址 chat: model: llama3 # 模型名称 options: temperature: 0.7 # 随机性(0-1,越低越稳定) 
调用代码:

还是熟悉的ChatClient!Spring AI 的标准化接口在这里体现得淋漓尽致:

@GetMapping("/local/chat") public String localChat(@RequestParam String message) { return chatClient.call(message); // 和调用OpenAI、通义千问的代码完全一样 } 
注意事项:
本地模型性能依赖硬件:Llama3-8B 至少需要 16GB 内存,GPU 加速需要 NVIDIA 显卡(支持 CUDA)响应速度比商业模型慢:首次调用可能需要预热 3-5 秒

4. 代理配置与排坑指南:解决 90% 的网络问题

调用国外模型时,网络问题是最常见的拦路虎,这部分教你怎么排查和解决。

4.1 代理配置:让请求顺利出国

如果你的网络需要代理才能访问 OpenAI,在application.yml中添加:

spring: ai: openai: # 其他配置... client: proxy: host: 127.0.0.1 # 代理服务器地址 port: 7890 # 代理端口(根据你的代理工具填写) 

也可以通过 JVM 参数配置(适合开发环境):在 IDEA 的启动配置中,添加 VM 选项:

-Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=7890 -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=7890 

4.2 常见网络异常与解决

异常 1:java.net.ConnectException: Connection timed out
原因:没开代理,或代理端口错误解决:检查代理是否启动,端口是否和配置一致
异常 2:SSLHandshakeException: PKIX path building failed
原因:代理证书问题(比如使用了自签名证书)

解决:添加 JVM 参数忽略证书验证(仅开发环境用):

-Djavax.net.ssl.trustStoreType=JKS -Djavax.net.ssl.trustStore=路径/to/cacerts # JDK安装目录下的jre/lib/security/cacerts -Djavax.net.ssl.trustStorePassword=changeit # 默认密码 
异常 3:429 Too Many Requests
  • 原因:API 调用频率超过限制

解决:在配置中添加限流参数:

spring: ai: openai: chat: options: rate-limit: enabled: true requests-per-second: 5 # 每秒最多5次请求 

5. 实战:同步响应 vs 流式响应 对话接口开发

实际开发中,同步响应适合简单场景,流式响应(像 ChatGPT 那样逐字输出)更适合用户体验。

5.1 同步响应接口

就是前面写的简单调用,适合一次性获取结果:

@GetMapping("/sync/chat") public String syncChat(@RequestParam String message) { return chatClient.call(message); } 

测试:访问http://localhost:8080/sync/chat?message=介绍下Spring AI,会等模型生成完整结果后一次性返回。

5.2 流式响应接口

需要用 WebFlux 的Flux(响应式编程),实现逐字输出:

import org.springframework.ai.chat.ChatResponse; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux; @RestController @RequiredArgsConstructor public class StreamController { private final ChatClient chatClient; // 注意:MediaType设为TEXT_EVENT_STREAM_VALUE @GetMapping(value = "/stream/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> streamChat(@RequestParam String message) { // 构建用户消息 Prompt prompt = new Prompt(new UserMessage(message)); // 调用流式接口,返回Flux<ChatResponse> return chatClient.stream(prompt) // 提取每个响应中的内容 .map(chatResponse -> chatResponse.getResult().getOutput().getContent()); } } 

测试:用 Postman 访问http://localhost:8080/stream/chat?message=介绍下Spring AI,会看到内容逐段返回,和 ChatGPT 的体验一致。

5.3 两种响应方式对比

6. 总结与进阶方向

通过这篇教程,你已经掌握了 Spring AI 的核心环境搭建和模型接入方法:

基础环境:JDK17+Maven3.8+Spring Boot3.x 是必须的铁三角模型接入:OpenAI / 通义千问 / Ollama 本地模型都能用ChatClient统一调用网络问题:代理配置 + 异常日志解读能解决大部分坑实战接口:同步和流式响应各有适用场景

进阶方向推荐:

  1. 多模型切换:用 Spring AI 的ModelSelector实现根据场景自动选模型
  2. Prompt 工程:结合PromptTemplate优化提示词,提升模型响应质量
  3. 本地模型优化:给 Ollama 配置 GPU 加速,提升 Llama3 响应速度

如果觉得有用,欢迎点赞收藏,有问题可以在评论区交流 —— 后续会更新 Spring AI 的高级用法,关注不迷路!

Read more

【问题反馈】JNI 开发:为什么 C++ 在 Debug 正常,Release 却返回 NaN?

【问题反馈】JNI 开发:为什么 C++ 在 Debug 正常,Release 却返回 NaN?

摘要: 在 Android NDK / JNI 开发中,经常会遇到这样一种“诡异”问题:Debug 模式下运行完全正常,而 Release 模式却出现 NaN、Infinity 甚至随机结果。 本文通过一次真实的 JNI 坐标转换案例,深入分析了该问题的根本原因——C++ 返回局部栈内存指针所导致的未定义行为(Undefined Behavior)。 【问题反馈】JNI 开发:为什么 C++ 在 Debug 正常,Release 却返回 NaN? 本文为以下问题的解决记录。由于问题较为典型,故梳理备忘。 https://github.com/eqgis/Sceneform-EQR/discussions/16 一、问题现象描述 1. 现象

By Ne0inhk
【C++开源库使用】调用开源库STB中的stbi_load_from_memory加载图片文件,进行灰化处理,然后调用stbi_write_png或stbi_write_jpg将灰化图片保存到文件中

【C++开源库使用】调用开源库STB中的stbi_load_from_memory加载图片文件,进行灰化处理,然后调用stbi_write_png或stbi_write_jpg将灰化图片保存到文件中

目录 1、图片灰化的实现思路 2、开源STB库下载 3、将图片文件的内容读到buffer中 4、将buffer中存放的图片文件数据传入到stbi_load_from_memory接口中,然后对返回的图片颜色值进行灰化处理 5、调用stbi_write_png或stbi_write_jpg接口将灰化后的图片数据保存成图片文件 6、图片灰化的完整代码        前一篇文章我们讲到了使用libcurl库发http/https请求去下载用户头像文件(文章链接:https://blog.ZEEKLOG.net/chenlycly/article/details/149175549),本篇文章则是同个SDK项目的后续需求中涉及到的功能。第三方厂商要求,对于不在线的人员,要显示灰化的头像。经研究决定使用开源STB库辅助实现图片灰化,调用STB开源库中的stbi_load_from_memory、stbi_write_png或stbi_write_jpg等接口。本文详细讲述一下实现过程,以供大家借鉴或参考。

By Ne0inhk
【C++:哈希表封装】用哈希表封装unordered_map和unordered_set

【C++:哈希表封装】用哈希表封装unordered_map和unordered_set

🔥艾莉丝努力练剑:个人主页 ❄专栏传送门:《C语言》、《数据结构与算法》、C/C++干货分享&学习过程记录、Linux操作系统编程详解、笔试/面试常见算法:从基础到进阶、测试开发要点全知道 ⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平 🎬艾莉丝的简介: 🎬艾莉丝的C++专栏简介: C++的两个参考文档  老朋友(非官方文档):cplusplus 官方文档(同步更新):C++ 官方参考文档 set和multiset的参考文档:set、multiset map和multimap的参考文档:map、multimap unordered_set和unordered_multiset的参考文档:unordered_set、unordered_multiset unordered_map和unordered_multimap的参考文档: unordered_map、unordered_

By Ne0inhk
【C++进阶】万字长文详解STL set:从基本用法到红黑树底层原理

【C++进阶】万字长文详解STL set:从基本用法到红黑树底层原理

摘要/前言: 在C++开发中,当我们面临“去重”和“排序”的双重需求时,std::set 无疑是首选利器。但你是否想过,为什么它的查找效率是 O(logN)?为什么迭代器遍历是有序的?底层红黑树到底是如何维持平衡的?本文将从基础用法出发,深入剖析 set 的底层红黑树机制,并对比 unordered_set,助你在面试和实战中游刃有余。 目录 1. 什么是 std::set? 2. set 的全解 3. 进阶:自定义类型的排序(仿函数) 4. 核心:底层数据结构——红黑树解析 5. 性能对比:set vs unordered_set 6. 面试高频问答

By Ne0inhk