一、概述
1.1发展历史
1.2大模型
大模型,是指具有大规模参数和复杂计算结构的机器学习模型。这些模型通常由深度神经网络构建而成,拥有数十亿甚至数千亿个参数。其设计目的在于提高模型的表达能力和预测性能,以应对更加复杂的任务和数据;
大模型,简单来说,就是一个特别聪明、特别能干的“大脑”,这个“大脑”由很多个小小的“神经元”组成,每个“神经元”都能处理一部分信息,当这些“神经元”一起工作时,大模型就能理解并回答各种问题,或者完成各种复杂的任务。就像你有一个超级聪明的助手,它能帮你写邮件、写PPT、回答你的各种问题等等,它就像是一个上知天文,下知地理,无所不知的人;
1.3Spring AI
Spring AI提供的API支持跨人工智能提供商的 聊天,文本到图像,和嵌入模型等,同时支持同步和流API选项;
1、Chat Models 聊天模型:
2、Text-to-image Models 文本到图像模型:
- OpenAI with DALL-E
- StabilityAI
3、Transcription (audio to text) Models 转录(音频到文本)模型
- OpenAI
4、Embedding Models 嵌入模型
5、Vector Store API提供了跨不同提供商的可移植性,其特点是提供了一种新颖的类似SQL的元数据过滤API,以保持可移植性;
6、用于AI模型和矢量存储的Spring Boot自动配置和启动器;(xxxx-spring-ai-starter)
7、函数调用
8、用于数据工程的ETL框架
9、广泛的参考文档、示例应用程序和研讨会/课程材料;
未来的版本将在此基础上提供对其他人工智能模型的访问,例如,谷歌刚刚发布的Gemini多模式模态,一个评估人工智能应用程序有效性的框架,更方便的API,以及帮助解决“查询/汇总我的文档”用例的功能。有关即将发布的版本的详细信息,请查看GitHub;
二、Spring AI聊天
2.1方式一String
1、建项目:创建一个Spring Boot项目;
2、加依赖:加入spring-ai-openai-spring-boot-starter依赖;
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
3、配文件
spring:
ai:
openai:
api-key: sk-3sfER03LDLG3SDFsdlwe283JSdw023lkrmrHDND32fmREKFD (换成你的api-key)
base-url: https://api.openai.com
4.编写代码
@RestController
public class ChatController {
/**
* spring-ai 自动装配的,可以直接注入使用
*/
@Resource
private OpenAiChatClient openAiChatClient;
/**
* 调用OpenAI的接口
*
* @param msg 我们提的问题
* @return
*/
@RequestMapping(value = "/ai/chat")
public String chat(@RequestParam(value = "msg") String msg) {
String called = openAiChatClient.call(msg);
return called;
}
}
2.2方式二 Prompt
概述
在JavaScript中,prompt()函数用于显示一个包含文本消息和一个输入框的对话框,并等待用户输入信息。该函数的语法如下:
prompt(message, defaultValue)
- message:要显示给用户的消息文本,通常是一个提示用户输入信息的文本。
- defaultValue:可选参数,表示输入框中的默认值。
用户可以在输入框中输入信息,然后点击确定按钮以提交信息。prompt()函数将返回用户输入的内容作为字符串。如果用户点击取消按钮,则返回null。通常,开发人员会将返回值存储在变量中,以便后续使用。
名词解释: 结构化的 Prompt 是一种高效和有组织的方式来指导和指示聊天机器人的回应和功能。这种方法类似于在面向对象编程(OOP)中的思维方式,其中强调了对象、类、继承、接口和多态性等概念。
prompt顾名思义就是“提示”的意思,应该有人玩过你画我猜这个游戏吧,对方根据一个词语画一幅画,我们来猜他画的是什么,因为有太多灵魂画手了,画风清奇,或者你们没有心有灵犀,根本就不好猜啊!这时候屏幕上会出现一些提示词比如3个字,水果,那岂不是好猜一点了嘛,毕竟3个字的水果也不多呀。看到了吧,这就是prompt的魅力,让我们心有灵犀一点通!
任务提示型prompt
答案指示型prompt
模型对prompt很敏感,不同的模板得到的效果差别很大。
实现
@RequestMapping(value = "/ai/chat2") // 定义一个请求映射,当访问"/ai/chat2"路径时,会调用下面的chat2方法
public Object chat2(@RequestParam(value = "msg") String msg) { // 定义一个名为chat2的方法,接收一个名为msg的请求参数
ChatResponse chatResponse = openAiChatClient.call(new Prompt(msg)); // 使用openAiChatClient对象调用call方法,并传入一个新的Prompt对象,该对象包含msg参数的值
return chatResponse.getResult().getOutput().getContent(); // 从chatResponse对象中获取结果,然后获取输出内容,并将其作为返回值返回
}
结构化 Prompt 与面向对象编程的类比
1. 万物皆对象 / 万事皆主题
- 面向对象编程:在OOP中,一切都被视为对象,每个对象都有其属性和方法。
- 结构化 Prompt:在撰写文章或指导ChatGPT时,每个主题或问题都被视为一个“对象”,每个对象都有其详细的描述和子话题。
2. 类和继承 / 结构化模板和延伸
- 面向对象编程:类定义了对象的蓝图,而继承允许新类采用并扩展现有类的属性。
- 结构化 Prompt:模板定义了Prompt的基本结构,包括角色、规则、技能等,可以根据需要进行扩展和修改,以适应不同的场景。
3. 封装和接口 / 主题分隔和提示
- 面向对象编程:封装隐藏了对象的内部实现,而接口定义了与对象交互的方式。
- 结构化 Prompt:每个主题部分被清晰地隔开,例如使用标题和子标题,同时通过明确的指示(如指令、问题)定义与ChatGPT的交互方式。
4. 多态性 / 灵活的响应
- 面向对象编程:多态性允许对象以多种形式表现。
- 结构化 Prompt:根据不同的输入,ChatGPT可以灵活地调整其响应,即使是基于相同的基础模板。
5. 对象的生命周期 / Prompt 的发展
- 面向对象编程:对象从创建到销毁经历一个完整的生命周期。
- 结构化 Prompt:一个Prompt从创建开始,随着交互的深入和用户需求的变化,可能会发展和变化,直到其目的被满足。
结构化 Prompt 的开发工作流
日常使用时,直接问 ChatGPT 效果可以的话,直接问就行。
构建复杂高性能结构化 Prompt 有以下几种工作流:
- 自动化生成初版结构化 Prompt -> 手工迭代调优 -> 符合需求的 prompt (推荐)
- 自动化生成初版结构化 Prompt -> 自动化分析评估 Prompt -> 基于评估结果迭代调优 -> 符合需求的 prompt (推荐)
- 手工套用现有模板 —> 手工迭代调优 -> 符合需求的 prompt
1, 2 较为推荐,能够大大降低工作量,大佬请随意。
自动化生成初版结构化 Prompt 推荐使用 LangGPT,使用其他 Prompt 生成方法也可。
自动化分析评估 Prompt 可以使用 prompt 评分分析类 Prompt,可参考 AI Prompt 群精选——Prompt 优化。中的高质量 Prompt。
结构化 Prompt 的局限性
结构化 Prompt 依赖于基座模型能力,并不能解决模型本身的问题,结构化 Prompt 并不能突破大模型 Prompt 方法本身的局限性。
已知的无法解决的问题: 大模型本身的幻觉问题 大模型本身知识老旧问题 大模型的数学推理能力弱问题 (解数学问题) 大模型的视觉能力弱问题(构建 SVG 矢量图等场景) 大模型字数统计问题(不论是字符数和 token 数,大模型都无法统计准确。需要输出指定字数时,将数值设定的高一些,后期自己调整一下,比如希望他输出100字文案,告诉他输出150字。) 同一 Prompt 在不同模型间的性能差异问题 * 其他已知问题等
可参考:构建生产级鲁棒高性能 Prompt
2.3方式三 Prompt加参数
/**
* 调用OpenAI的接口
*
* @param msg 我们提的问题
* @return
*/
@RequestMapping(value = "/ai/chat3")
public Object chat3(@RequestParam(value = "msg") String msg) {
//可选参数在配置文件中配置了,在代码中也配置了,那么以代码的配置为准,也就是代码的配置会覆盖掉配置文件中的配置
ChatResponse chatResponse = openAiChatClient.call(new Prompt(msg, OpenAiChatOptions.builder()
.withModel("gpt-4-32k") //gpt的版本,32k是参数量
.withTemperature(0.4F) //温度越高,回答得比较有创新性,但是准确率会下降,温度越低,回答的准确率会更好
.build()));
return chatResponse.getResult().getOutput().getContent();
}
2.4方式四flux+配置文件
spring.ai.openai.api-key=sk-
spring.ai.openai.chat.options.model=gpt-3.5-turbo
spring.ai.openai.chat.options.temperature=0.7
/**
* 调用OpenAI的接口
*
* @param msg 我们提的问题
* @return
*/
@RequestMapping(value = "/ai/chat4")
public Object chat4(@RequestParam(value = "msg") String msg) {
//可选参数在配置文件中配置了,在代码中也配置了,那么以代码的配置为准,也就是代码的配置会覆盖掉配置文件中的配置
Flux<ChatResponse> flux = openAiChatClient.stream(new Prompt(msg, OpenAiChatOptions.builder()
//.withModel("gpt-4-32k") //gpt的版本,32k是参数量
.withTemperature(0.4F) //温度越高,回答得比较有创新性,但是准确率会下降,温度越低,回答的准确率会更好
.build()));
flux.toStream().forEach(chatResponse -> {
System.out.println(chatResponse.getResult().getOutput().getContent());
});
return flux.collectList(); //数据的序列,一序列的数据,一个一个的数据返回
}
三、Spring Ai图像
3.1方式一
package com.yanyu.springai02image.Controller;
import jakarta.annotation.Resource;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.ai.openai.OpenAiImageClient;
import org.springframework.ai.openai.OpenAiImageOptions;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ImageController {
@Resource
private OpenAiImageClient openAiImageClient;
@RequestMapping("/ai/image")
private Object image(@RequestParam(value = "msg") String msg) {
ImageResponse imageResponse = openAiImageClient.call(new ImagePrompt(msg));
System.out.println(imageResponse);
String imageUrl = imageResponse.getResult().getOutput().getUrl();
//把图片进行业务处理
return imageResponse.getResult().getOutput();
}
}
3.2方式二参数配置
@RequestMapping("/ai/image2")
private Object image2(@RequestParam(value = "msg") String msg) {
ImageResponse imageResponse = openAiImageClient.call(new ImagePrompt(msg, OpenAiImageOptions.builder()
.withQuality("hd") //高清图像
.withN(1) //生成1张图片
.withHeight(1024) //生成的图片高度
.withWidth(1024) //生成的图片宽度
.build()));
System.out.println(imageResponse);
String imageUrl = imageResponse.getResult().getOutput().getUrl();
//把图片进行业务处理
return imageResponse.getResult().getOutput();
}
四、Spring AI文本到语音
4.1转文本
@RestController
public class TranscriptionController {
@Resource
private OpenAiAudioTranscriptionClient openAiAudioTranscriptionClient;
@RequestMapping(value = "/ai/transcription")
public Object transcription() {
//org.springframework.core.io.Resource audioFile = new ClassPathResource("jfk.flac");
org.springframework.core.io.Resource audioFile = new ClassPathResource("D:\\桌面\\好玩的\\跨年烟花3.0\\跨年烟花\\跨年烟花\\fire\\打上花火.mp3");
String called = openAiAudioTranscriptionClient.call(audioFile);
System.out.println(called);
return called;
}
}
4.2配置
spring:
application:
name: spring-ai-03-transcription
ai:
openai:
api-key: s
base-url: h
chat:
options:
model: gpt-4-32k
audio:
transcription:
options:
model: whisper-1
4.3文本转语言
@RestController
public class TTSController {
@Resource
private OpenAiAudioSpeechClient openAiAudioSpeechClient;
@RequestMapping(value = "/ai/tts")
public Object tts() {
String text = "2023年全球汽车销量重回9000万辆大关,同比2022年增长11%。分区域看,西欧(14%)、中国(12%)两大市场均实现两位数增长。面对这样亮眼的数据,全球汽车行业却都对2024年的市场前景表示悲观,宏观数据和企业体感之前的差异并非中国独有,在汽车市场中,这是共性问题。";
byte[] bytes = openAiAudioSpeechClient.call(text);
FileUtils.save2File("D:\\SpringAI\\test.mp3", bytes);
return "OK";
}
@RequestMapping(value = "/ai/tts2")
public Object tts2() {
String text = "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.";
byte[] bytes = openAiAudioSpeechClient.call(text);
FileUtils.save2File("D:\\SpringAI\\test2.mp3", bytes);
return "OK";
}
}
工具类
public class FileUtils {
public static boolean save2File(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) {}
}
}
}
}
五、Spring Ai 多模态
- 多模态是指模型同时理解和处理来自各种来源的信息的能力,包括文本、图像、音频和其他数据格式;
- 多模式大语言模型(LLM)特征使模型能够结合其他模态(如图像、音频或视频)来处理和生成文本;
- Spring AI 多模态API提供了所有必要的统一抽象和代码封装来支持多模式LLM;
@RestController
public class MultiModelController {
@Resource
private ChatClient chatClient;
@RequestMapping(value = "/ai/multi")
public Object multi(String msg, String imageUrl) {
UserMessage userMessage = new UserMessage(msg, List.of(new Media(MimeTypeUtils.IMAGE_PNG, imageUrl)));
ChatResponse response = chatClient.call(new Prompt(userMessage, OpenAiChatOptions.builder()
.withModel(OpenAiApi.ChatModel.GPT_4_VISION_PREVIEW.getValue())
.build()));
System.out.println(response.getResult().getOutput());
return response.getResult().getOutput().getContent();
}
}