AI - 人工智能;Java之SpringAI(一)
一、开发SpringAI准备
1、访问OpenAI权限和API Key
(1)本机电脑要可以访问OpenAI网站 https://openai.com/;
(2)要有OpenAI的API Key;(注册账号或者购买)
例:API-Key:sk-xxxx1213xxxx23242xxxXXXX
在某宝上搜索 open ai api key,找到API key,购买之前请咨询清楚是直连还是转发地址?以及是否开发要用到的API key
2、开发SpringBoot和IDEA版本要求
*Spring AI的发布时间是2024年3月1日*
Spring AI是一个人工智能工程的应用框架,旨在为Java开发者提供一种更简洁的方式与AI交互,减轻在Java业务中接入LLM模型应用的学习成本。目前,Spring AI已经上架到Spring Initializr,开发者可以在https://start.spring.io/上使用并构建相关应用
使用SpringAI至少需要SpringBoot 3.2版本
SpringAI是Spring框架的一个新项目,旨在简化Java开发人员将AI功能集成到应用程序中的过程
使用SpringAI,需要确保开发环境满足以下2个要求:
1、JDK版本:JDK 17(含)以上
2、SpringBoot版本:3.2以上
3、IDEA2024版
此外,SpringAI支持接入多种AI服务,如OpenAI、Ollama、Azure OpenAI、Huggingface等,可以实现聊天、embedding、图片生成、语音转文字、向量数据库、function calling、prompt模板、outputparser、RAG等功能
1、创建SpringAI项目
选择Spring Boot 至少3.2版本;且勾选AI中的OpenAI选项(2024之前的老版本IDEA应该没有这个选项)
2、添加依赖;加入spring-ai-openai-spring-boot-starter依赖
<?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 https://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.2.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.demo</groupId>
<artifactId>spring-ai</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-ai</name>
<description>spring-ai</description>
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- SpringAI当前版本1.0.0-M3;快照版1.0.0-SNAPSHOT -->
<spring-ai.version>1.0.0-SNAPSHOT</spring-ai.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--spring ai的starter依赖,启动依赖-->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!--相当于是继承一个父项目:spring-ai-bom父项目-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<!--配置本项目的仓库:因为maven中心仓库还没有更新spring ai的jar包-->
<repositories>
<repository>
<!-- SpringAI快照版 -->
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<!-- 当前最新M3版 -->
<!-- <id>spring-milestones</id>-->
<!-- <name>Spring Milestones</name>-->
<!-- <url>https://repo.spring.io/milestone</url>-->
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
ai依赖:
<!-- ai依赖 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
继承父项目
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
配置项目依赖下载的AI仓库:
<!--配置本项目的仓库:因为maven中心仓库还没有更新spring ai的jar包-->
<repositories>
<repository>
<!-- SpringAI快照版 -->
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<!-- 当前最新M3版 -->
<!-- <id>spring-milestones</id>-->
<!-- <name>Spring Milestones</name>-->
<!-- <url>https://repo.spring.io/milestone</url>-->
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
Maven中心仓库搜不到这个依赖
3、配置yml文件
spring:
application:
name: spring-ai
ai:
openai:
api-key: sk-8sfKHJ03KJG3SDFfsdf283JSwsf23lkjkHDND32fmGJHF # 换成你自己的api-key
base-url: https://api.openai.com #如果是购买的转发地址,这边换成转发的OpenAI地址
4、编写测试类测试
(1)注入OpenAiChatModel
@Resource private OpenAiChatModel openAiChatModel;
注:刚开始发布的版本,这里是 OpenAiChatClient
(2)调用call方法 openAiChatModel.call(message);
package com.demo.springai1chat.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @description:
* @author: zm
*/
@RestController
@RequestMapping("/ai")
public class ChatController {
/**
* spring-ai自动装配的,可以直接注入使用
*/
@Resource
private OpenAiChatModel chatModel;
/**
* OpenAI接口调用
* @param message 提问信息
* @return OpenAI相应信息
*/
@GetMapping("/chat")
public String aiChat(@RequestParam("msg")String message) {
return chatModel.call(message);
}
}
自动装配(Auto-configuration )
添加了 spring-ai-openai-spring-boot-starter 依赖;Spring AI 为 OpenAI Chat Client 提供了 Spring Boot 自动装配。
OpenAiAutoConfiguration配置类中自动注入了,我们只需要直接注入调用即可
刚开始发布的SpringAI版本中,叫OpenAiChatClient
而该依赖中针对各个大模型提供了一个对应的自动配置类,如OpenAiAutoConfiguration,在该自动配置类中定义了以下几个Bean:
OpenAiChatModel/OpenAiChatClient(老版本):文字聊天客户端
OpenAiEmbeddingModel/OpenAiEmbeddingClient(老版本):文本向量化客户端
OpenAiImageModel/OpenAiImageClient(老版本):文生图客户端
OpenAiAudioTranscriptionModel/OpenAiAudioTranscriptionClient(老版本):语音转文字客户端
这些Bean在创建时就会构造底层连接OpenAi的客户端OpenAiApi对象,其中会用到以下几种配置:
OpenAiConnectionProperties:连接配置
OpenAiChatProperties:聊天配置
OpenAiEmbeddingProperties:向量化配置
OpenAiImageProperties:文生图配置
OpenAiAudioTranscriptionProperties:语音转文字配置
连接OpenAi的地址就apiKey就在OpenAiConnectionProperties中,比如application.properties的配置为:
spring.ai.openai.base-url=http://localhost:3000
spring.ai.openai.api-key=sk-xxxxx
5、启动调用访问 localhost:8080/ci/chat?msg=为我写一首歌http://localhost:8080/ai/chat?msg=为我写一首歌
二、AI聊天(OpenAiChatModel)
官网API文档:OpenAI Chat :: Spring AI Reference
1、application.yml配置文件
spring:
application:
name: spring-ai-01-chat
ai:
openai:
api-key: ${OPENAI_API_KEY} # 换成你自己的api-key
#如果是购买的转发地址,这边换成转发的OpenAI地址
base-url: ${OPENAI_BASE_URL}
# 可选参数在配置文件中配置了,在代码中也配置了,则以代码的配置为准(代码的配置会覆盖掉配置文件中的配置)
chat:
options:
# 当前默认版本 gpt-4o
model: gpt-4-32k
temperature: 0.4
在OpenAIChatOptions类中打上断点可以看到当前默认的版本
**2、测试类 **
package com.demo.springai1chat.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
/**
* @description:
* @author: zm
*/
@RestController
@RequestMapping("/ai")
public class ChatController {
/**
* spring-ai自动装配的,可以直接注入使用
*/
@Resource
private OpenAiChatModel chatModel;
/**
* OpenAI接口调用
* @param message 提问信息
* @return OpenAI相应信息
*/
@GetMapping("/chat")
public String aiChat(@RequestParam("msg")String message) {
String msgResp = chatModel.call(message);
return msgResp;
}
/**
* OpenAI接口调用
* @param message 提问信息
* @return OpenAI相应信息
*/
@GetMapping("/chat/prompt")
public ChatResponse aiChatPrompt(@RequestParam("msg")String message) {
ChatResponse chatResp = chatModel.call(new Prompt(message));
//chatResp.getResult().getOutput().getContent();
return chatResp;
}
/**
* OpenAI接口调用
* @param message 提问信息
* @return OpenAI相应信息
*/
@GetMapping("/chat/option")
public ChatResponse aiChatOptions(@RequestParam("msg")String message) {
//可选参数在配置文件中配置了,在代码中也配置了,则以代码的配置为准(代码的配置会覆盖掉配置文件中的配置)
ChatResponse chatResp = chatModel.call(new Prompt(message, OpenAiChatOptions.builder()
.withModel("gpt-4-32k") //gpt的版本,32k是参数量(参数量越大,回答的问题质量越好,准确率越高)
.withTemperature(0.4) //温度越高,回答得比较有创新性,但是准确率会下降,温度越低,回答的准确率会更好
.build()));
// chatResponse.getResult().getOutput().getContent();
return chatResp;
}
/**
* OpenAI接口调用
* @param message 提问信息
* @return OpenAI相应信息
*/
@GetMapping("/chat/stream")
public Object aiChatStream(@RequestParam("msg")String message) {
//可选参数在配置文件中配置了,在代码中也配置了,则以代码的配置为准(代码的配置会覆盖掉配置文件中的配置)
Flux<ChatResponse> chatRespFlux = chatModel.stream(new Prompt(message, OpenAiChatOptions.builder()
.withModel("gpt-4-32k") //gpt的版本,32k是参数量(参数量越大,回答的问题质量越好,准确率越高)
.withTemperature(0.4) //温度越高,回答得比较有创新性,但是准确率会下降,温度越低,回答的准确率会更好
.build()));
chatRespFlux.toStream().forEach(chatResp ->
System.out.println(chatResp.getResult().getOutput().getContent())
);
return chatRespFlux.collectList();
}
}
【1】使用call参数:
call
方法用于同步获取模型响应
(1)创建Prompt 对象传入message参数
(2)使用 ChatOptionsBuilder#builder() 创建的可移植 ChatOptions 实例
2、使用stream参数:
stream
方法用于流式获取模型响应,适用于需要长时间处理或大量数据的场景
三、AI图片(OpenAiImageModel)
官网API文档:OpenAI Image Generation :: Spring AI Reference
**1、application.yml配置文件 **
spring:
application:
name: spring-ai-02-image
ai:
openai:
api-key: ${OPENAI_API_KEY} # 换成你自己的api-key
#如果是购买的转发地址,这边换成转发的OpenAI地址
base-url: ${OPENAI_BASE_URL}
# 可选参数在配置文件中配置了,在代码中也配置了,则以代码的配置为准(代码的配置会覆盖掉配置文件中的配置)
image:
options:
model: dall-e-3
quality: hd
n: 1
height: 1792
width: 1024
2、测试类
package com.demo.springai02image.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.ai.openai.OpenAiImageModel;
import org.springframework.ai.openai.OpenAiImageOptions;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @description:
* @author: zm
*/
@RestController
@RequestMapping("/ai")
public class ImageController {
@Resource
private OpenAiImageModel openAiImageModel;
@GetMapping("/image")
public Object image(@RequestParam("msg") String message) {
ImageResponse imageResp = openAiImageModel.call(new ImagePrompt(message));
System.out.println(imageResp);
// 图片URL
String imageUrl = imageResp.getResult().getOutput().getUrl();
return imageResp;
}
@GetMapping("/image/option")
public Object imageOption(@RequestParam("msg") String message) {
ImageResponse imageResponse = openAiImageModel.call(new ImagePrompt(message, OpenAiImageOptions.builder()
.withQuality("hd") //高清图像
.withN(1) //生成1张图片
.withHeight(1024) //生成的图片高度
.withWidth(1024) //生成的图片宽度
.build()));
System.out.println(imageResponse);
// 图片URL
String imageUrl = imageResponse.getResult().getOutput().getUrl();
return imageResponse.getResult().getOutput();
}
}
四、音频转文字 (OpenAiAudioTranscriptionModel)
官网API文档:Untitled :: Spring AI Reference
1、application.yml配置文件
spring:
application:
name: spring-ai-02-image
ai:
openai:
api-key: ${OPENAI_API_KEY} # 换成你自己的api-key
#如果是购买的转发地址,这边换成转发的OpenAI地址
base-url: ${OPENAI_BASE_URL}
2、测试类
package com.demo.springai03audiotranscriptions.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.audio.transcription.AudioTranscriptionPrompt;
import org.springframework.ai.audio.transcription.AudioTranscriptionResponse;
import org.springframework.ai.openai.OpenAiAudioTranscriptionModel;
import org.springframework.ai.openai.OpenAiAudioTranscriptionOptions;
import org.springframework.ai.openai.api.OpenAiAudioApi;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.sound.sampled.spi.AudioFileReader;
/**
* @description:
* @author: zm
*/
@RestController
@RequestMapping("/ai")
public class AudioTranscriptionsController {
@Resource
private OpenAiAudioTranscriptionModel openAiAudioTranscriptionModel;
@GetMapping("/audio/transcriptions/en")
public Object audioTranscriptionsEn() {
org.springframework.core.io.Resource audioFile = new ClassPathResource("audioEn.flac");
OpenAiAudioApi.TranscriptResponseFormat responseFormat = OpenAiAudioApi.TranscriptResponseFormat.TEXT;
OpenAiAudioTranscriptionOptions transcriptionOptions = OpenAiAudioTranscriptionOptions.builder()
.withLanguage("en")
//.withPrompt("Ask not this, but ask that")
.withTemperature(0f)
.withResponseFormat(responseFormat)
.build();
AudioTranscriptionPrompt transcriptionRequest = new AudioTranscriptionPrompt(audioFile, transcriptionOptions);
AudioTranscriptionResponse response = openAiAudioTranscriptionModel.call(transcriptionRequest);
System.out.println("英文音频翻译:" + response);
return response.getResult().getOutput();
}
@GetMapping("/audio/transcriptions/cn")
public Object audioTranscriptionsCn() {
org.springframework.core.io.Resource audioFile = new ClassPathResource("audioCn.mp3");
OpenAiAudioApi.TranscriptResponseFormat responseFormat = OpenAiAudioApi.TranscriptResponseFormat.TEXT;
OpenAiAudioTranscriptionOptions transcriptionOptions = OpenAiAudioTranscriptionOptions.builder()
.withLanguage("cn")
//.withPrompt("Ask not this, but ask that")
.withTemperature(0f)
.withResponseFormat(responseFormat)
.build();
AudioTranscriptionPrompt transcriptionRequest = new AudioTranscriptionPrompt(audioFile, transcriptionOptions);
AudioTranscriptionResponse response = openAiAudioTranscriptionModel.call(transcriptionRequest);
System.out.println("中文音频翻译:" + response);
return response.getResult().getOutput();
}
}
五、文字转音频(OpenAiAudioSpeechModel)
官网API文档:OpenAI Text-to-Speech (TTS) :: Spring AI Reference
1、application.yml配置文件
spring:
application:
name: spring-ai-02-image
ai:
openai:
api-key: ${OPENAI_API_KEY} # 换成你自己的api-key
#如果是购买的转发地址,这边换成转发的OpenAI地址
base-url: ${OPENAI_BASE_URL}
2、测试类
package com.demo.springai04texttospeechtts.controller;
import com.demo.springai04texttospeechtts.util.FileUtils;
import jakarta.annotation.Resource;
import org.springframework.ai.openai.OpenAiAudioSpeechModel;
import org.springframework.ai.openai.OpenAiAudioSpeechOptions;
import org.springframework.ai.openai.api.OpenAiAudioApi;
import org.springframework.ai.openai.audio.speech.SpeechPrompt;
import org.springframework.ai.openai.audio.speech.SpeechResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @description:
* @author: zm
*/
@RestController
@RequestMapping("/ai")
public class TTSController {
@Resource
private OpenAiAudioSpeechModel openAiAudioSpeechModel;
@GetMapping("/tts/en")
private Object ttsEn() {
OpenAiAudioSpeechOptions speechOptions = OpenAiAudioSpeechOptions.builder()
.withModel("tts-1")
.withVoice(OpenAiAudioApi.SpeechRequest.Voice.ALLOY)
.withResponseFormat(OpenAiAudioApi.SpeechRequest.AudioResponseFormat.MP3)
.withSpeed(1.0f)
.build();
String enStr = "Spring AI is an application framework for AI engineering. Its goal is to apply to the AI domain Spring ecosystem design principles such as portability and modular design and promote using POJOs as the building blocks of an application to the AI domain.";
SpeechPrompt speechPrompt = new SpeechPrompt(enStr, speechOptions);
SpeechResponse response = openAiAudioSpeechModel.call(speechPrompt);
// 存入本地
FileUtils.saveFile("D:\\SpringAI\\英文.mp3" , response.getResult().getOutput());
return "Success";
}
@GetMapping("/tts/cn")
private Object ttsCn() {
OpenAiAudioSpeechOptions speechOptions = OpenAiAudioSpeechOptions.builder()
.withModel("tts-1")
.withVoice(OpenAiAudioApi.SpeechRequest.Voice.ALLOY)
.withResponseFormat(OpenAiAudioApi.SpeechRequest.AudioResponseFormat.MP3)
.withSpeed(1.0f)
.build();
String enStr = "据中国载人航天工程办公室消息,北京时间2024年10月30日4时27分,搭载神舟十九号载人飞船的长征二号F遥十九运载火箭在酒泉卫星发射中心点火发射,约10分钟后,神舟十九号载人飞船与火箭成功分离,进入预定轨道,航天员乘组状态良好,发射取得圆满成功。";
SpeechPrompt speechPrompt = new SpeechPrompt(enStr, speechOptions);
SpeechResponse response = openAiAudioSpeechModel.call(speechPrompt);
// 存入本地
FileUtils.saveFile("D:\\SpringAI\\中文.mp3" , response.getResult().getOutput());
return "Success";
}
}
文件存储工具
package com.demo.springai04texttospeechtts.util;
import java.io.*;
public class FileUtils {
public static boolean saveFile(String fname, byte[] msg) {
OutputStream fos = null;
try{
File file = new File(fname);
File parent = file.getParentFile();
boolean bool;
if ((!parent.exists()) &&
(!parent.mkdirs())) {
return false;
}
fos = new FileOutputStream(file);
fos.write(msg);
fos.flush();
return true;
}catch (FileNotFoundException e){
return false;
}catch (IOException e){
e.printStackTrace();
return false;
}
finally{
if (fos != null) {
try{
fos.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
六、多模态API(ChatModel)
官网API文档:Multimodality API :: Spring AI Reference
多模态是指模型同时理解和处理来自各种来源的信息的能力,包括文本、图像、音频和其他数据格式; 多模式大语言模型(LLM)特征使模型能够结合其他模态(如图像、音频或视频)来处理和生成文本; Spring AI 多模态API提供了所有必要的统一抽象和代码封装来支持多模式LLM
1、application.yml配置文件
spring:
application:
name: spring-ai-02-image
ai:
openai:
api-key: ${OPENAI_API_KEY} # 换成你自己的api-key
#如果是购买的转发地址,这边换成转发的OpenAI地址
base-url: ${OPENAI_BASE_URL}
2、测试类
package com.demo.springai05multimodel.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.model.Media;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @description:
* @author: zm
*/
@RestController
@RequestMapping("/ai")
public class MultiModelController {
@Resource
private ChatModel chatModel;
@GetMapping("/multimodel")
public String multimodel(String message, String imgUrl) {
// 也可换成网络图片
ClassPathResource classPathResource = new ClassPathResource("/花.jpeg");
UserMessage userMessage = new UserMessage(message, new Media(MimeTypeUtils.IMAGE_JPEG, classPathResource));
ChatResponse response = chatModel.call(new Prompt(userMessage));
System.out.println(response
);
return response.getResult().getOutput().getContent();
}
}
版权归原作者 MinggeQingchun 所有, 如有侵权,请联系我们删除。