对话模型(Chat Model)接收一系列消息(Message)作为输入,与模型 LLM 服务进行交互,并接收返回的聊天消息(Chat Message)作为输出。相比于普通的程序输入,模型的输入与输出消息(Message)不止支持纯字符文本,还支持包括语音、图片、视频等作为输入输出。同时,在 Spring AI Alibaba 中,消息中还支持包含不同的角色,帮助底层模型区分来自模型、用户和系统指令等的不同消息。
Spring AI Alibaba 复用了 Spring AI 抽象的 Model API,并与通义系列大模型服务进行适配(如通义千问、通义万相等),目前支持纯文本聊天、文生图、文生语音、语音转文本等。以下是框架定义的几个核心 API:
- ChatModel,文本聊天交互模型,支持纯文本格式作为输入,并将模型的输出以格式化文本形式返回。
- ImageModel,接收用户文本输入,并将模型生成的图片作为输出返回。
- AudioModel,接收用户文本输入,并将模型合成的语音作为输出返回。
Spring AI Alibaba 支持以上 Model 抽象与通义系列模型的适配,并通过 spring-ai-alibaba-starter
AutoConfiguration 自动初始化了默认实例,因此我们可以在应用程序中直接注入 ChatModel、ImageModel 等 bean,当然在需要的时候也可以自定义 Model 实例。
一、Chat Model
ChatModel API 让应用开发者可以非常方便的与 AI 模型进行文本交互,它抽象了应用与模型交互的过程,包括使用 Prompt
作为输入,使用 ChatResponse
作为输出等。ChatModel 的工作原理是接收 Prompt 或部分对话作为输入,将输入发送给后端大模型,模型根据其训练数据和对自然语言的理解生成对话响应,应用程序可以将响应呈现给用户或用于进一步处理。
1、使用示例
开发完整的 ChatModel 示例应用,您需要添加 spring-ai-alibaba-starter
依赖,请参考快速开始中的项目配置说明了解详情,您还可以访问 chatmodel-example 查看本示例完整源码。
以下是 ChatModel 基本使用示例,它可以接收 String 字符串作为输入:
@RestController
public class ChatModelController {
private final ChatModel chatModel;
public ChatModelController(ChatModel chatModel) {
this.chatModel = chatModel;
}
@RequestMapping("/chat")
public String chat(String input) {
ChatResponse response = chatModel.call(new Prompt(input));
return response.getResult().getOutput().getContent();
}
}
二、Image Model
ImageModel API 抽象了应用程序通过模型调用实现“文生图”的交互过程,即应用程序接收文本,调用模型生成图片。ImageModel 的入参为包装类型 ImagePrompt
,输出类型为 ImageResponse
。
1、使用示例
spring-ai-alibaba-starter
AutoConfiguration 默认初始化了 ImageModel 实例,我们可以选择直接注入并使用默认实例。
@RestController
public class ImageModelController {
private final ImageModel imageModel;
ImageModelController(ImageModel imageModel) {
this.imageModel = imageModel;
}
@RequestMapping("/image")
public String image(String input) {
ImageOptions options = ImageOptionsBuilder.builder()
.withModel("dall-e-3")
.build();
ImagePrompt imagePrompt = new ImagePrompt(input, options);
ImageResponse response = imageModel.call(imagePrompt);
String imageUrl = response.getResult().getOutput().getUrl();
return "redirect:" + imageUrl;
}
}
三、Audio Model
当前,Spring AI Alibaba 支持以下两种通义语音模型的适配,分别是:
- 文本生成语音 SpeechModel,对应于 OpenAI 的 Text-To-Speech (TTS) API
- 录音文件生成文字 DashScopeAudioTranscriptionModel,对应于 OpenAI 的 Transcription API
四、完整示例
server:
port: 10003
spring:
application:
name: spring-ai-alibaba-openai-chat-model-example
ai:
openai:
api-key: ${OPENAI_API_KEY}
base-url: https://api.openai-hk.com
# 兼容其他OpenAI格式的大模型配置示例
# 以下为字节火山引擎·方舟大模型(Ark LLM)配置示例
# ai:
# openai:
# # API密钥配置
# api-key: ${OPENAI_API_KEY}
# # 方舟大模型API地址
# base-url: https://ark.cn-beijing.volces.com/api/
# chat:
# options:
# # 模型ID,需要替换为实际的接入点ID
# model: ${OPENAI_MODEL_ID}
# # Chat接口路径,与OpenAI接口保持一致
# completions-path: /v3/chat/completions
package com.alibaba.cloud.ai.example.chat.openai;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @Author: wst
* @Date: 2024-12-16
*/
@SpringBootApplication
public class OpenAiChatModelApplication {
public static void main(String[] args) {
SpringApplication.run(OpenAiChatModelApplication.class, args);
}
}
package com.alibaba.cloud.ai.example.chat.openai.controller;
import jakarta.servlet.http.HttpServletResponse;
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.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
/**
* @Author: wst
* @Date: 2024-12-16
*/
@RestController
@RequestMapping("/openai/chat-model")
public class OpenAiChatModelController {
private static final String DEFAULT_PROMPT = "你好,介绍下你自己吧。";
private static final String JSON_OUTPUT_PROMPT = "how can I solve 8x + 7 = -23";
private final ChatModel openAiChatModel;
public OpenAiChatModelController(ChatModel chatModel) {
this.openAiChatModel = chatModel;
}
/**
* 最简单的使用方式,没有任何 LLMs 参数注入。
*
* @return String types.
*/
@GetMapping("/simple/chat")
public String simpleChat() {
return openAiChatModel.call(new Prompt(DEFAULT_PROMPT)).getResult().getOutput().getContent();
}
/**
* Stream 流式调用。可以使大模型的输出信息实现打字机效果。
*
* @return Flux<String> types.
*/
@GetMapping("/stream/chat")
public String streamChat(HttpServletResponse response) {
// 避免返回乱码
response.setCharacterEncoding("UTF-8");
StringBuilder res = new StringBuilder();
Flux<ChatResponse> stream = openAiChatModel.stream(new Prompt(DEFAULT_PROMPT));
stream.toStream().toList().forEach(resp -> {
res.append(resp.getResult().getOutput().getContent());
});
return res.toString();
}
/**
* 使用编程方式自定义 LLMs ChatOptions 参数, {@link org.springframework.ai.openai.OpenAiChatOptions}
* 优先级高于在 application.yml 中配置的 LLMs 参数!
*/
@GetMapping("/custom/chat")
public String customChat() {
OpenAiChatOptions customOptions = OpenAiChatOptions.builder()
.withTopP(0.7)
.withModel("gpt-4o")
.withMaxTokens(1000)
.withTemperature(0.8)
.build();
return openAiChatModel.call(new Prompt(DEFAULT_PROMPT, customOptions)).getResult().getOutput().getContent();
}
/**
* JSON mode:通过设置 response_format 参数为 JSON 类型,使大模型返回标准的 JSON 格式数据。
*
* @return JSON String.
*/
@GetMapping("/custom/chat/json-mode")
public String jsonChat() {
String jsonSchema = """
{
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": { "type": "string" },
"output": { "type": "string" }
},
"required": ["explanation", "output"],
"additionalProperties": false
}
},
"final_answer": { "type": "string" }
},
"required": ["steps", "final_answer"],
"additionalProperties": false
}
""";
OpenAiChatOptions customOptions = OpenAiChatOptions.builder()
.withTopP(0.7)
.withModel("gpt-4o")
.withTemperature(0.4)
.withMaxTokens(4096)
.withResponseFormat(new OpenAiApi.ChatCompletionRequest.ResponseFormat(OpenAiApi.ChatCompletionRequest.ResponseFormat.Type.JSON_SCHEMA, jsonSchema))
.build();
return openAiChatModel.call(new Prompt(JSON_OUTPUT_PROMPT, customOptions)).getResult().getOutput().getContent();
}
}