Spring AI
官方文档:Spring AI
Spring AI 是一个面向 AI 工程的应用框架,其目标是将 Spring 生态系统的可移植性和模块化设计等设计原则应用到AI 领域,并推动将 POJO 作为应用的构建块应用于 AI 领域。 其特点是跨 AI 供应商支持的便携式 API,用于聊天、文本转图像和嵌入模型。支持同步和流 API 选项。还支持降级访问模型特定功能。
主要功能:
- 支持所有主要的模型提供商,如 OpenAI、Microsoft、Amazon、Google 和 Huggingface。
- 支持的模型类型包括聊天、文本转图像、音频转录、文本转语音,以及更多即将推出的功能。
- 跨所有模型提供商的便携式 API。支持同步和流 API 选项。还支持降级访问模型特定功能。
- AI 模型输出到 POJO 的映射。
- 支持所有主要的向量数据库提供者,如 Apache Cassandra、Azure Vector Search、Chroma、Milvus、Neo4j、PostgreSQL/PGVector、PineCone、Qdrant、Redis 和 Weaviate。
- 跨向量存储提供者的可移植 API,包括一种新颖的类 SQL 元数据过滤 API,也是可移植的。
- Spring Boot 自动配置和启动器用于 AI 模型和向量存储。
概念
Model模型
人工智能模型是用来处理和生成信息的算法,通常模仿人类的认知功能。有许多不同类型的人工智能模型,每种模型都适合特定的场景。Spring AI目前支持将输入和输出处理为语言、图像和音频的模型。
Prompts提示
它作为基于语言的输入基础,指导 AI 模型生成特定输出。对于熟悉ChatGPT的人来说,提示可能看起来只是在发送到API的对话框中输入的文本。然而,它包含的远不止这些。另外,ChatGPT的API在一个提示中有多个文本输入,制作有效的提示既是一门艺术,也是一门科学。ChatGPT 被设计用于与人类对话。这与使用 SQL 之类的东西来“‘提问’”有很大不同。必须像与另一个人对话一样与 AI 模型进行沟通。这种交互方式的重要性如此之大,以至于“提示工程”这一术语已经成为一个独立的学科。有越来越多的技术方法可以提高提示的有效性。投入时间精心设计提示可以显著改善最终的输出效果。
Prompt Templates: 提示模板
创建有效的提示涉及建立请求的上下文,并用特定于用户输入的值替换请求的部分。这个过程使用传统的基于文本的模板引擎来进行提示的创建和管理。Spring AI 使用开源库 StringTemplate 来实现这一目的。在 Spring AI 中,提示模板可以类比为 Spring MVC 架构中的"‘View’“。通常会提供一个模型对象,通常是一个 java.util.Map ,用于填充模板中的占位符。”‘rendered’"字符串成为提供给 AI 模型的提示内容。
下面就是 一个简单的提示模板
Tell me a {adjective} joke about {content}.
Embeddings嵌入
嵌入将文本转换为数字数组或矢/向量,使人工智能模型能够处理和解释语言数据。这种从文本到数字的转换是人工智能如何与人类语言互动和理解人类语言的关键因素。作为一名探索人工智能的Java开发人员,没有必要理解这些矢量表示背后复杂的数学理论或具体实现。基本了解它们在人工智能系统中的作用和功能就足够了。嵌入在实际应用中特别重要,如检索增强生成(RAG)模式。它们使数据能够在语义空间中表示为点,类似于欧几里得几何的二维空间,但是在更高的维度上。这意味着,就像欧几里得几何中平面上的点根据它们的坐标可以相互靠近或远离一样,在语义空间中,点的接近程度反映了它们在含义上的相似性。关于类似主题的句子在这个多维空间中位置更接近,就像图表上互相靠近的点一样。这种接近有助于文本分类、语义搜索甚至产品推荐等任务,因为它允许 AI 根据它们在这个扩展的语义景观中的“位置”辨别和分组相关概念。
Tokens 令牌
是 AI 模型工作的基本组成部分。在输入时,模型将单词转换为令牌。在输出时,它们将令牌转换回单词。在英语中,一个标记大约相当于一个单词的 75%。作为参考,莎士比亚的全部作品总计约为 90 万字,大约翻译成 120 万个标记。
Structured Output : 结构化输出
AI 模型的输出传统上会以字符串形式呈现,即使你要求回复为 JSON 格式。它可能是正确的 JSON 格式,但不是一个JSON 数据结构。它只是一个字符串。此外,将“for JSON”作为提示的一部分要求并不是 100%准确。
RAG(Retrieval Augmented Generation)检索增强生成
Spring AI 库帮助您实现基于“填充提示”技术的解决方案,也被称为检索增强生成(RAG)。检索增强生成RAG技术是用来解决将相关数据整合到提示中,以获取准确的人工智能模型响应的挑战。它涉及一个批处理风格的编程模型,在该模型中,运行中的任务从文档中读取非结构化数据,对其进行转换,然后将其写入矢量数据库。从高层来看,这是一个ETL(提取、转换和加载)管道。矢量数据库用于RAG技术的检索部分。
将非结构化数据加载到向量数据库的一部分,最重要的转换之一是将原始文档分割成较小的片段。将原始文档分割成较小片段的过程包括两个重要步骤:
步骤1:将文档分成若干部分,同时保持内容的语义边界。例如,对于包含段落和表格的文档,应避免在段落或表 格中间进行分割。对于代码,避免在方法实现的中间分割代码。
步骤2:将文档进一步分割为大小是 AI 模型 token 限制的一小部分的部分。
如下图所示:
RAG 的下一阶段是处理用户输入。当用户的问题需要由 AI 模型回答时,问题及所有“相似”的文档片段被放入提示中,然后发送给 AI 模型。这就是使用向量数据库的原因。它非常擅长找到相似内容。
Function Calling 函数调用
大型语言模型(LLMs)在训练后被冻结,导致知识陈旧,无法访问或修改外部数据。Function Calling 机制解决了这些缺点。它允许注册自己的函数,将大型语言模型连接到外部系统的 API。这些系统可以向 LLMs 提供实时数据,并代表它们执行数据处理操作。
Evaluating AI responses 评估人工智能的响应
有效评估人工智能系统对用户请求的输出对确保最终应用的准确性和实用性非常重要。几种新兴技术使得可以利用预训练模型本身来实现这一目的。这个评估过程涉及分析生成的回复是否与用户意图和查询的语境相符。用于衡量 AI生成回复质量的指标包括相关性、连贯性和事实正确性。
快速入门
API架构图如下:
支持来自 OpenAI、Microsoft、Amazon、Google、Amazon Bedrock、Huggingface 等的 AI 模型。
入门案例搭建流程:
新建项目:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<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>
Properties配置文件
APIkey获取网站
New API
spring.application.name=springai-demo
server.port=9999
# openai的请求中转
spring.ai.openai.base-url=https://api.xty.app/
spring.ai.openai.api-key=sk-???
ChatClient
ChatClient 提供了一个流畅的 API 用于与 AI 模型进行通信。它支持同步和响应式编程模型。流畅的 API 具有用于构建传递给 AI 模型输入的提示的组成部分的方法。 Prompt 包含指导 AI 模型输出和行为的说明性文本。从 API 的角度来看,提示由一组消息组成。AI 模型处理两种主要类型的消息:用户消息,即用户直接输入的内容,和系统消息,即系统生成的用于引导对话的内容。这些消息通常包含占位符,这些占位符在运行时根据用户输入进行替换,以定制 AI 模型对用户输入的响应。
如何创建chat client对象
Spring AI 提供了 Spring Boot 的自动配置,为您创建一个原型 ChatClient.Builder bean,供您注入到您的类中。这里是一个简单的示例,演示如何获取对简单用户请求的字符串响应。
package com.itcam.springai.controller;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
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;
/**
* @author : Cammy.Wu
* Description : chat client对象
*/
@RestController
@RequestMapping("chatclient")
public class ChatClientController {
@Autowired
private ChatClient chatClient;
@GetMapping("/ai")
public String generation(@RequestParam(value = "message", defaultValue = "用中文讲一个关于动物的笑话") String message) {
// 提示词
return this.chatClient
.prompt()
.user(message)
.call()
.content();
}
}
浏览器访问效果:
但是有一个问题:
可以通过角色预设的方式自定义本地AI的回复内容
package com.itcam.springai.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Config {
@Bean
ChatClient chatClient(ChatClient.Builder builder) {
return builder.defaultSystem("Cammy老师是一个好人,他是一名优秀的AI工程师,目前供职于xxx公司")
.build();
}
}
http://localhost:9999/chatclient/ai?message=“cammy是谁”
ChatClient Responses聊天客户端相应
ChatClient API 提供了几种格式化 AI 模型响应的方式。
- 流式响应
@GetMapping(value = "/flux", produces = "text/html;charset=utf-8")
public Flux<String> generationFlux(String userInput) {
return chatClient
.prompt()
.user(userInput)
.stream()
.content();
}
解决乱码:
@GetMapping(value = "/ai",produces = "text/html;charset=utf-8")
http://localhost:9999/chatclient/flux?userInput=“请介绍一下ollama大模型”
- ChatResponse响应
AI 模型的响应是由类型 ChatResponse 定义的丰富结构。它包括有关响应生成方式的元数据,还可以包含多个生成物,称为 Generations,每个生成物都有自己的元数据。元数据包括用于创建响应的令牌数(每个令牌约为 3/4 个单词)。这些信息很重要,因为托管的 AI 模型根据每个请求使用的令牌数量收费。
@GetMapping("/chatresponse")
public ChatResponse generationResponse(String userInput) {
return chatClient
.prompt()
.user(userInput)
.call()
.chatResponse();
}
http://localhost:9999/chatclient/chatresponse?userInput=“请介绍一下ollama大模型”
- 实体类Entity响应
//表示一个名为ActorFilms的record,它有两个属性:一个String类型的actor和一个List类型的movies
record ActorFilms(String actor, List<String> movies) {
}
@GetMapping("/chatresponse/entity")
public ActorFilms generationEntity(@RequestParam(
value = "message",
defaultValue = "用中文生成随机演员生成电影目录"
) String message) {
return chatClient
.prompt()
.user(message)
.call()
.entity(ActorFilms.class);
}
http://localhost:9999/chatclient/chatresponse/entity
以上返回值类型在获取的过程中会涉及到call方法的使用 在 ChatClient 上指定 call 方法后,响应类型有几种不同的选项。
- String content() :返回响应的字符串内容 —入门案例
- ChatResponse chatResponse() :返回包含多个生成的 ChatResponse 对象,并包含关于响应的元数据,例如用于创建响应的令牌数量。 --测试返回值
以上返回值类型在获取的过程中会涉及到stream方法的使用 在 ChatClient 上指定 stream 方法后,响应类型有几个选项:
Flux content() :返回由 AI 模型生成的字符串的 Flux。
Flux chatResponse() :返回一个包含关于响应的附加元数据的 ChatResponse 对象的Flux。
ChatModel
聊天模型 API 为开发者提供了将基于人工智能的聊天补全能力集成到他们的应用程序中的能力。它利用预训练的语言模型,如 GPT(生成式预训练变换器),以生成类似人类的自然语言响应,以响应用户输入。
API 通常通过向 AI 模型发送提示或部分对话来工作,然后根据其训练数据和对自然语言模式的理解生成对话的完成或延续。完成的响应随后返回给应用程序,应用程序可以将其呈现给用户或用于进一步处理。
Spring AI Chat Model 设计为与各种人工智能模型交互的简单便携界面,使开发人员能够在最小代码更改的情况下切换不同模型。这种设计符合 Spring 的模块化和互换性理念 后续会介绍两种具体的聊天模型 一种的openAI的chat模型 另外一种的ollama的chat模型。
Spring AI 支持 OpenAI 的 AI 语言模型 ChatGPT。ChatGPT 在激发对 AI 驱动文本生成的兴趣方面发挥了重要作用,这要归功于它创建了行业领先的文本生成模型和嵌入技术。
chatClient与chatModel关系和区别
- chatClient 是负责管理客户端与服务器通信的组件,聚焦于数据传输和请求管理。
- chatModel 是实际处理和生成自然语言内容的模型,聚焦于智能和算法。
OpenAI chat模型
入门案例中就是以openAI为例 核心步骤
第一步::导入依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
第二步:编写配置信息
spring.application.name=springai-demo
server.port=9999
# openai的请求中转
spring.ai.openai.base-url=https://api.xty.app/
spring.ai.openai.api-key=sk-???
# 指定模型名称
spring.ai.openai.chat.options.model=gpt-3.5-turbo
第三步:编写代码并测试
package com.itcam.springai.controller;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.beans.factory.annotation.Autowired;
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;
import java.util.Map;
/**
* @author : Cammy.Wu
* Description : OpenAI chat模型
*/
@RestController
@RequestMapping("/openai")
public class OpenAiChatController {
@Autowired
private OpenAiChatModel openAiChatModel;
@GetMapping("/generate")
public Map chat(@RequestParam(value = "message", defaultValue = "介绍一下汕尾")
String message) {
return Map.of("generation", openAiChatModel.call(message));
}
@GetMapping(value = "/generateStream", produces = "text/html;charset=utf-8")
public Flux<String> stream(@RequestParam(value = "message", defaultValue = "介绍一下汕尾")
String message) {
return openAiChatModel
.stream(message);
}
}
第四步:执行效果如下图所示
http://localhost:9999/openai/generate
http://localhost:9999/openai/generateStream
ollama模型
步骤1:启动本地ollama
步骤2:导入ollama模型依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
</dependency>
步骤3:编写配置文件
server.port=9999
spring.ai.ollama.base-url=http://localhost:11434
spring.ai.ollama.chat.enabled=true
#提前在ollama中安装qwen2:7b模型 系统默认是mistral
spring.ai.ollama.chat.options.model = qwen2:7b
步骤4:编写代码
package com.itcam.springai.controller;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author : Cammy.Wu
* Description : ollama模型
*/
@RestController
@RequestMapping("/ollama")
public class OllamaChatController {
@Autowired
private OllamaChatModel ollamaChatModel;
@RequestMapping("/chatOllama")
public String chat(String prompt) {
return ollamaChatModel.call(prompt);
}
}
步骤5:测试效果
由于运行的是本地的ollama模型 响应速度慢
localhost:9999/ollama/chatOllama?prompt=介绍一下东三省
高级语法
ImageModel图片模型
即文生图
Spring Image Model API 设计为一个简单便携的界面,用于与各种专门的图像生成的 AI 模型进行交互,允许开发者在最小代码更改的情况下切换不同的与图像相关的模型。这种设计符合 Spring 的模块化和互换性理念,确保开发者能够快速适应与图像处理相关的不同 AI 能力。
此外,借助像 ImagePrompt 这样的伴随类来进行输入封装,以及像ImageResponse 这样的输出处理类的支持,图像模型 API 统一了与专用于图像生成的 AI 模型的通信。它管理了请求准备和响应解析的复杂性,为图像生成功能提供了直接简化的 API 交互。
配置文件信息
注意:需要提前联系客服在未充值状态下进行免费开通 充值之后再开通 客服会让你重新注册一个新账户
第一步:编写配置信息
# openAI 图片生成配置 默认为true
spring.ai.openai.image.enabled=true
#使用默认
spring.ai.openai.image.options.model=dall-e-3
第二步:编写代码并测试
package com.itcam.springai.controller;
import org.springframework.ai.image.Image;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.ai.openai.OpenAiImageModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author : Cammy.Wu
* Description : ImageModel图片模型
*/
@RestController
@RequestMapping("openai")
public class OpenImageChatController {
@Autowired
private OpenAiImageModel openAiImageModel;
@RequestMapping(value = "image", produces = "text/html")
public String image(String prompt){
ImagePrompt imagePrompt = new ImagePrompt(prompt);
ImageResponse imageResponse = openAiImageModel.call(imagePrompt);
Image output = imageResponse.getResult().getOutput();
// 获取图片的url
String outputUrl = output.getUrl();
return "<img src='" + outputUrl + "'>";
}
}
第三步:访问浏览器即可
http://localhost:9999/openai/ai/image?prompt=鸡哥打篮球的图片
文字与声音
文本转声音
spring AI 支持 OpenAI 的转录模型 即将 文本转变为语音进行输出 演示如下
第一步: 导入依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
第二步: 编写配置
# openAI
spring.ai.openai.audio.speech.options.model=tts-1
第三步:编写代码
在resources类路径下新建文件speech.txt
package com.itcam.springai.controller;
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.beans.factory.annotation.Autowired;
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 java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author : Cammy.Wu
* Description : 文字与声音
*/
@RestController
@RequestMapping("/tts")
public class OpenAiTestToSpeechController {
@Autowired
private OpenAiAudioSpeechModel openAiAudioSpeechModel;
@GetMapping("/textToSpeech")
public String textToSpeech(String text) throws IOException {
byte[] contentAsByteArray = new ClassPathResource("speech.txt")
.getContentAsByteArray();
String content = new String(contentAsByteArray);
SpeechPrompt speechPrompt = new SpeechPrompt(content, OpenAiAudioSpeechOptions
.builder()
.withSpeed(1f)
.withResponseFormat(OpenAiAudioApi.SpeechRequest.AudioResponseFormat.MP3)
.build());
SpeechResponse response = openAiAudioSpeechModel.call(speechPrompt);
byte[] output = response.getResult().getOutput();
writeByteAyyayToMp3(output,"F:\\");
return "success";
}
private static void writeByteAyyayToMp3(byte[] audioBytes, String outputFilePath) throws IOException {
//场景fileOutPutStream实例
FileOutputStream fileOutPutStream = new FileOutputStream(outputFilePath+"蔡徐坤.mp3");
//将字节数组数组写入文件
fileOutPutStream.write(audioBytes);
//关闭流
fileOutPutStream.close();
}
}
第四步: 测试
http://localhost:9999/tts/textToSpeech
声音转文本
将上一步生成的mp3 保存到类路径下
第一步:编写配置
spring.ai.openai.audio.transcription.options.model=whisper-1
#spring.ai.openai.audio.transcription.options.response-format=text
第二步:编写代码
注意: 官方文档中openAiTranscriptionModel在其自动配置类没有找到 没有提供相应的类
@Autowired
private OpenAiAudioTranscriptionModel openAiAudioTranscriptionModel;
@GetMapping("/speechToText")
public String speechToText(){
OpenAiAudioApi.TranscriptResponseFormat responseFormat = OpenAiAudioApi.TranscriptResponseFormat.TEXT;
OpenAiAudioTranscriptionOptions transcriptionOptions = OpenAiAudioTranscriptionOptions
.builder()
.withTemperature(0f)
.withResponseFormat(responseFormat)
.build();
ClassPathResource resource = new ClassPathResource("蔡徐坤.mp3");
AudioTranscriptionPrompt transcriptionRequest = new AudioTranscriptionPrompt(resource, transcriptionOptions);
AudioTranscriptionResponse response = openAiAudioTranscriptionModel.call(transcriptionRequest);
return response.getResult().getOutput();
}
第三步: 测试
http://localhost:9999/tts/speechToText
多模态(Multimodality)
概念总述
在 Spring AI 中,多模态(Multimodal)通常指的是集成和处理多种类型的输入数据(如文本、图像、音频、视频等)来进行建模和推理的能力。这种技术能够使模型从不同的模态(即不同形式的数据)中获取信息,从而增强模型的表现力和决策能力。
这些学习的基础原则是由现代教育之父约翰·阿莫斯·孔美尼斯在他的著作《感官世界图解》中阐述的,该书的创作可以追溯到 1658 年。
模态:
- 模态指的是数据的不同形式或类别。例如,图像、文本、语音、视频、传感器数据等都是不同的模态。
- 每种模态都提供了独特的信息,比如图像包含视觉信息,文本传达语义信息,音频捕捉声音和语调等。
多模态数据:
- 多模态数据是指在一个任务中同时使用多种类型的数据输入。例如,分析一个视频时,可以使用图像帧(视觉模态)、音频(听觉模态)、以及字幕或对话文本(文本模态)来对视频内容进行更全面的理解。
多模态的重要性
信息的互补性:
- 不同模态的数据可以相互补充。例如,图像可以提供空间信息,而文本可以提供语义解释,结合两者可以使模型对场景的理解更深刻。
提高模型的鲁棒性:
- 当一个模态的数据质量不高或缺失时,其他模态的数据可以提供支持,从而保持系统的性能。例如,在噪声较大的环境下,文本字幕可以帮助理解语音内容。
增强用户体验:
- 多模态技术可以创造更自然和直观的人机交互。例如,虚拟助手可以通过语音理解用户的指令,同时通过视觉传感器检测用户的手势或面部表情,提供更丰富的交互体验。
多模态应用场景
- 图像描述生成:
这种任务要求模型根据输入的图像生成相应的文本描述。模型需要结合图像的视觉信息和语言的语义知识
来生成准确且流畅的描述。 - 视频理解与分析:
视频理解涉及处理视频帧、音频和文本字幕等多种模态的数据,常用于动作识别、事件检测等任务。 - 情感分析:
情感分析可以结合文本的内容、语音的语调和面部表情数据来判断用户的情感状态。多模态情感分析在客
户服务、心理治疗等领域有广泛应用。 - 人机交互:
通过结合语音识别、手势识别和自然语言处理等技术,多模态 AI 系统能够理解和响应用户的多种输入方
式,提供更加自然和智能化的交互体验。
演示如下
第一步: 配置文件(需要gpt-4版本)
spring.ai.openai.chat.options.model=gpt-4o-2024-08-06
第二步:编写代码
@RestController
@RequestMapping("/mutil")
public class MutilModelController {
@Autowired
private ChatModel chatModel;
@RequestMapping("/ai/mutiltest")
public String chat(@RequestParam(value ="message",defaultValue = "你从这种图片中看到了什么")
String message) throws IOException {
//将类路径下的路片转换为二进制字节流
byte[] imageData = new ClassPathResource("/test.png").getContentAsByteArray();
//将二进制字节流封装成媒体对象 此处不是报错仅仅是一个提示
UserMessage userMessage = new UserMessage(message, List.of(new
Media(MimeTypeUtils.IMAGE_PNG, imageData)));
//调用chat模型
Prompt prompt = new Prompt(userMessage);
//调用chat模型
ChatResponse chatResponse = chatModel.call(prompt);
return chatResponse.getResult().getOutput().getContent();
}
}
第三步: 将测试图片置于项目类路径中
测试图片:
第四步: 浏览器执行并查看执行效果
http://localhost:9999/multi/multiTest
如果提示如下错误: 更换中转站的模型即可
Function Calling API
概念总述
Function Calling 是现代 AI 模型,尤其是在大语言模型(如 GPT-4)中引入的一种强大功能。它允许 AI 模型不仅生成自然语言,还能够根据输入的语境自动调用预定义的函数,以执行特定的任务或操作。这种能力大大扩展了 AI 系统的应用范围,使其能够与外部系统进行交互、执行动态任务,并在不同的上下文中提供更具针对性和智能化的响应。
在 Spring AI 框架中,Function Calling 作为一种增强 AI 模型功能的方法,使模型能够直接调用外部服务、函数或API,执行任务或获取特定数据。这一功能不仅提高了模型的实用性,也为开发者提供了更高的灵活性,能够将模型应用到更广泛的实际场景中。
函数定义与注册函数定义是指开发者在系统中定义特定的操作或服务,这些操作可以是简单的数据检索、复杂的业务逻辑处理,或者与其他系统的交互。例如,可以定义一个函数来查询数据库中的用户信息,或者调用一个第三方API来获取实时天气数据。 函数注册则是将这些定义好的函数注册到 Spring AI 系统中,使得 AI 模型能够识别并调用这些函数。
动态调用当 AI 模型生成的文本触发了某个特定的关键词或语境时,模型能够动态决定是否调用相关的函数。这种调用是基于上下文的,这意味着模型可以在对话中自主判断何时需要调用外部函数来补充其生成的内容。 例如,当用户在对话中询问“当前的天气如何?”时,模型可以自动调用一个天气查询函数,并返回实时的天气信息。
上下文感知Function Calling 是上下文感知的,这意味着模型能够根据对话的内容和用户的需求智能地选择要调用的函数。上下文感知能力使得模型在更复杂的交互中表现更为出色,因为它不仅能生成文本,还能做出实际的操作。
比如,在客户支持场景中,用户询问订单状态时,模型可以调用订单查询函数,直接提供订单的最新状态,而不仅仅是给出一个模板化的回答。
参数传递与结果处理在调用函数时,AI 模型能够提取用户输入中的相关信息并将其作为参数传递给函数。这些参数可以是具体的数据项,如日期、地名,或者是更复杂的对象。调用函数后,模型还能够处理函数返回的结果,将其以自然语言的形式反馈给用户。例如,如果查询天气的函数返回了温度和天气状况,模型可以将这些信息组织成一句完整的话:“今天的天气是晴天,温度为25摄氏度。”
实现流程
- 定义与注册函数:
- 训练与配置模型:
- 运行时调用与结果处理:
Function接口
在 Spring AI 中, Function 接口(java.util.function包中)的实现是用于支持 Function Calling 特性的一个重要部分。通过实现 Function 接口,你可以创建一个可供 AI 模型调用的函数对象,从而将 AI 模型的推理结果或用户输入与外部服务的调用结合起来。
它定义了一个接受一个输入参数并返回一个输出结果的抽象方法 apply 。通过实现这个接口,你可以创建一个符合标准的函数对象,使得函数调用逻辑可以被清晰、统一地表示和使用。
在 Spring AI 的上下文中, Function 接口通常与 Spring Cloud Function 框架结合使用。Spring Cloud Function 允许你将业务逻辑封装为函数,并以不同的方式部署和调用(如 REST API、消息驱动、或本地调用)。通过实现Function 接口,开发者可以方便地将业务逻辑整合到 Spring Cloud Function 生态系统中,从而在 Spring AI 系统中轻松调用这些逻辑。
当实现了 Function 接口之后,Spring AI 可以在运行时将此函数对象作为一个可调用的函数注册到系统中。这使得AI 模型能够通过 Function Calling 的机制,动态地调用这个模拟的天气服务,并根据输入参数生成相应的输出结果通过实现 Function 接口,你的函数对象可以在不同的上下文中被灵活地使用和重用。这不仅限于 AI 模型的调用,还可以在其他需要调用天气服务的场景下使用。这种封装使得代码更具模块化和可维护性。
案例演示
步骤一:编写一个假的第三方天气服务API
package com.itcam.springai.service;
import java.util.function.Function;
// 假装为第三方天气信息服务商 通过实现 Function 接口来处理天气查询请求并返回响应
public class MockWeatherService implements
Function<MockWeatherService.Request, MockWeatherService.Response> {
//接收gpt提取的location信息,并返回weather信息
//apply 方法是 Function 接口中定义的抽象方法。它接收一个 Request 对象作为输入,
// 并返回一个 Response 对象作为输出。通过这个方法,模拟天气服务处理输入的请求,生成相应的天气数据并返回。
@Override
public Response apply(Request request) {
if(request.location == null){
return new MockWeatherService.Response("城市名称为空");
}
if(request.location.equals("上海")){
return new MockWeatherService.Response("晴");
}
if(request.location.equals("北京")){
return new MockWeatherService.Response("阴");
}
if(request.location.equals("广州")){
return new MockWeatherService.Response("多云");
}
if(request.location.equals("成都")){
return new MockWeatherService.Response("大雨");
}
return new Response("未知城市");
}
//定义查询天气时所需的参数 密封类
public record Request(String name, String location ) {}
//封装了返回的天气信息 密封类
public record Response(String message) {}
}
步骤二:将函数注册为 Bean
package com.itcam.springai.config;
import com.itcam.springai.service.MockWeatherService;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Description;
import java.util.function.Function;
@Configuration
public class Config {
@Bean
@Description("某个城市的天气情况")// 注释是可选的,提供一个功能描述(2),帮助模型理解何时调用该函数。
// 这是一个重要的属性,有助于 AI 模型确定调用哪个客户端函数。
public Function<MockWeatherService.Request, MockWeatherService.Response>
mockWeather() {
return new MockWeatherService();
}
}
步骤三:在聊天选项中指定功能
注意:此处Model3.5的无法测试 只能为4.0版本
package com.itcam.springai.controller;
import org.springframework.ai.chat.messages.UserMessage;
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.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author : Cammy.Wu
* Description : Function Calling API
*/
@RestController
@RequestMapping("/function")
public class FunctionCallController {
@Autowired
private OpenAiChatModel openAiChatModel;
@GetMapping("/city")
public String weather() {
UserMessage userMessage = new UserMessage("What's the weather like in 北京,成都 and 上海?,用中文回答");
OpenAiChatOptions openAiChatOptions = OpenAiChatOptions.builder()
.withFunction("mockWeather")
.withModel("gpt-4")
.build();
ChatResponse response = openAiChatModel.call(new Prompt(List.of(userMessage), openAiChatOptions));
return response.getResult().getOutput().getContent();
}
}
步骤四: 浏览器执行并查看执行效果
http://localhost:9999/function/city
Spring AI 中的 Function Calling 是一个功能强大的概念,它赋予了 AI 模型超越文本生成的能力,使得模型能够在实际操作中提供更智能、更实用的服务。这种能力在各种应用场景中都可以带来显著的优势,尤其是在需要与外部系统交互或处理复杂任务的情况下。通过有效利用 Function Calling,开发者可以构建更加智能、更加高效的 AI 驱动应用。