|
此版本仍在开发中,尚未被视为稳定版。为了获取最新的快照版本,请使用Spring AI 1.1.3! |
OpenAI 聊天
Spring AI 支持 OpenAI 开发的各种 AI 语言模型,由于其创建行业领先的文本生成模型和嵌入式技术,使其成为 AI 文本生成领域的引领者。
前提条件
您将需要通过与OpenAI创建一个API来访问ChatGPT模型。
在OpenAI注册页面创建一个帐户,并在API密钥页面生成Tokens。
Spring AI项目定义了一个名为spring.ai.openai.api-key的配置属性,您应将其设置为从openai.com获取的API Key值。
您可以在application.properties文件中设置此配置属性:
spring.ai.openai.api-key=<your-openai-api-key>
为了在处理API密钥等敏感信息时增强安全性,您可以使用Spring表达式语言(SpEL)引用自定义环境变量:
# In application.yml
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
# In your environment or .env file
export OPENAI_API_KEY=<your-openai-api-key>
您也可以在应用程序代码中以编程方式设置此配置:
// Retrieve API key from a secure source or environment variable
String apiKey = System.getenv("OPENAI_API_KEY");
自动配置
|
There has been a significant change in the Spring AI auto-configuration, starter modules' artifact names. Please refer to the 升级说明以获取更多信息。 |
Spring AI 为 OpenAI 聊天客户端提供了 Spring Boot 自动配置功能。
要启用该功能,请在项目的 Maven pom.xml 或 Gradle build.gradle 构建文件中添加以下依赖项:
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
dependencies {
implementation 'org.springframework.ai:spring-ai-starter-model-openai'
}
| 参考以下依赖管理部分,添加Spring AI BOM到你的构建文件中。 |
聊天属性
重试属性
前缀 spring.ai.retry 用于作为属性前缀,允许您配置OpenAI聊天模型的重试机制。
| 属性 | 描述 | 默认 |
|---|---|---|
spring.ai.retry.max-attempts |
最大重试次数。 |
10 |
spring.ai.retry.backoff.initial-interval |
指数退避策略的初始睡眠时长。 |
2 秒 |
spring.ai.retry.backoff.multiplier |
退避间隔乘数。 |
5 |
spring.ai.retry.backoff.max-interval |
最大退避时长。 |
3 分钟。 |
spring.ai.retry.on-client-errors |
如果为false,则抛出NonTransientAiException,且不重试客户端错误代码 |
false |
spring.ai.retry.exclude-on-http-codes |
不应触发重试的HTTP状态代码列表(例如,用于抛出非暂时性AI异常)。 |
empty |
spring.ai.retry.on-http-codes |
应触发重试的HTTP状态码列表(例如,用于抛出TransientAiException)。 |
empty |
连接属性
前缀 spring.ai.openai 用于作为属性前缀,以便您连接到OpenAI。
| 属性 | 描述 | 默认 |
|---|---|---|
spring.ai.openai.base-url |
要连接的URL |
|
spring.ai.openai.api-key |
API 密钥 |
- |
spring.ai.openai.organization-id |
你可以指定使用哪个组织来处理API请求。 |
- |
spring.ai.openai.project-id |
可选地,当你进行API请求时,你可以指定要使用哪一个项目。 |
- |
| 对于属于多个组织的用户(或通过其旧用户API访问项目),您可以在API请求中可选地指定使用哪个组织和项目。这些API调用将计入指定组织和项目的使用次数。 |
用户代理头目使用代理头目
Spring AI自动向OpenAI发送一个User-Agent: spring-ai的头,所有请求都会被发送。
这有助于OpenAI识别来自Spring AI的请求,以便进行分析和支持。
这个头自动发送,无需Spring AI用户进行任何配置。
If you are an OpenAI兼容的API提供者构建一个服务,您可以通过读取客户端服务器上的User-Agent HTTP头来跟踪Spring AI的使用情况。
配置属性
|
启用和禁用聊天自动配置现在通过顶级属性使用前缀 要启用,请设置 spring.ai.model.chat=openai (默认情况下已启用) 要禁用,请设置 spring.ai.model.chat=none(或任何不匹配 openai 的值) 这种修改是为了允许配置多个模型。 |
前缀 spring.ai.openai.chat 是属性前缀,用于配置OpenAI聊天模型的实现方式。
| 属性 | 描述 | 默认 |
|---|---|---|
spring.ai.openai.chat.enabled(已移除,不再有效) |
启用OpenAI聊天模型。 |
true |
spring.ai.model.chat |
启用OpenAI聊天模型。 |
开源人工智能 |
spring.ai.openai.chat.base-url |
必选项的实现,用于在 |
- |
spring.ai.openai.chat.completions-path |
要追加到基URL后面的路径是什么。 |
|
spring.ai.openai.chat.api-key |
可选地,通过代码0提供一个聊天特定的API密钥。 |
- |
spring.ai.openai.chat.organization-id |
你可以指定使用哪个组织来处理API请求。 |
- |
spring.ai.openai.chat.project-id |
可选地,当你进行API请求时,你可以指定要使用哪一个项目。 |
- |
spring.ai.openai.chat.options.model |
模型名称。您可以选择以下模型之一: |
|
spring.ai.openai.chat.options.temperature |
用于控制生成内容的表面创新性的采样温度。较高的值会使输出更加随机,而较低的值会使结果更加集中和确定性。不建议在同一完成请求中修改 |
0.8 |
spring.ai.openai.chat.options.frequencyPenalty |
介于-2.0和2.0之间的数值。正值会根据新词在文本中已有的出现频率对其进行惩罚,从而降低模型重复相同行文的确切概率。 |
0.0f |
spring.ai.openai.chat.options.logitBias |
调整指定标记词在生成内容中的出现几率。 |
- |
spring.ai.openai.chat.options.maxTokens |
The maximum number of tokens to generate in the chat completion. The total length of input tokens and generated tokens is limited by the model’s context length. 使用于非推理模型(例如GPT-4o、GPT-3.5-turbo)。 不能用于推理模型(例如O1、O3、O4系列)。 与maxCompletionTokens互斥 - 设置两者将导致API错误。 |
- |
spring.ai.openai.chat.options.maxCompletionTokens |
一个生成完成指令所需的上限,包括可见输出Tokens和推理Tokens。用于推理模型(例如 o1, o3, o4-mini 系列)。不能用于非推理模型(例如 gpt-4o, gpt-3.5-turbo)。与 maxTokens 互斥 - 同时设置将导致 API 错误。 |
- |
spring.ai.openai.chat.options.n |
有多少个生成的聊天补全选项来为每个输入消息生成。注意,您将根据所有选项生成的Tokens数量按数量计费。将 |
1 |
spring.ai.openai.chat.options.store |
是否需要将此聊天补全请求的输出用于我们的模型中 |
false |
spring.ai.openai.chat.options.metadata |
开发者自定义的标签和值用于过滤聊天补全度摘要中的完成项 |
空映射 |
spring.ai.openai.chat.options.output-modalities |
输出模型应为该请求生成的类型。大多数模型都可以生成文本,这是默认选项。 代码标记0的模型还可以生成音频。要请求该模型同时生成文本和音频响应,可以使用代码标记1和2。不支持流式传输。 |
- |
spring.ai.openai.chat.options.output-audio |
音频参数,用于音频生成。当需要音频输出时( |
- |
spring.ai.openai.chat.options.presencePenalty |
介于-2.0和2.0之间的数值。正值会根据新词是否已出现在文本中对其进行惩罚,从而增加模型谈论新主题的可能性。 |
- |
spring.ai.openai.chat.options.responseFormat.type |
兼容 |
- |
spring.ai.openai.chat.options.responseFormat.name |
响应格式说明名称。仅适用于 |
custom_schema |
spring.ai.openai.chat.options.responseFormat.schema |
响应格式JSON schemas。仅适用于 |
- |
spring.ai.openai.chat.options.responseFormat.strict |
响应格式 JSON 格式规范遵守严格程度。仅适用于 |
- |
spring.ai.openai.chat.options.seed |
此功能处于测试阶段。如果指定了,我们的系统将尽力进行确定性采样,以便使用相同的种子和参数的重复请求应返回相同的结果。 |
- |
spring.ai.openai.chat.options.stop |
最多4个序列,到达这些序列后API将停止生成更多Tokens。 |
- |
spring.ai.openai.chat.options.topP |
一种替代温度采样的方法是核采样(nucleus sampling),这种方法中,模型考虑了概率质量为零的Tokens。0.1表示只有那些占据前10%概率质量的Tokens被考虑。我们通常建议仅更改其中之一,但不要同时更改。 |
- |
spring.ai.openai.chat.options.tools |
模型可能调用的工具列表。当前,仅支持函数作为工具。使用此功能来提供模型可能为其生成JSON输入的函数列表。 |
- |
spring.ai.openai.chat.options.toolChoice |
控制模型调用(如有)的函数。 |
- |
spring.ai.openai.chat.options.user |
代表您终端用户的唯一标识符,有助于OpenAI监控和检测滥用行为。 |
- |
spring.ai.openai.chat.options.stream-usage |
(仅限流式处理)设置此选项可添加一个额外的块,用于统计整个请求的Tokens使用情况。此块的 |
false |
spring.ai.openai.chat.options.parallel-tool-calls |
是否在使用工具时启用多线程函数调用。 |
true |
spring.ai.openai.chat.options.prompt-cache-key |
OpenAI公司提供一个缓存密钥,用于优化相似请求的缓存命中率。通过减少延迟并降低成本。取代了用于缓存目的的废弃 |
- |
spring.ai.openai.chat.options.safety-identifier |
一个用于OpenAI检测用户违反使用政策的稳定标识符。应为哈希值(例如哈希后的用户名或电子邮箱)。取代了过时的 |
- |
spring.ai.openai.chat.options.http-headers |
可选的聊天补全请求的HTTP头信息。要覆盖 |
- |
spring.ai.openai.chat.options.tool-names |
用于在单个提示请求中启用函数调用的工具列表,这些工具通过它们的名称来识别。具有这些名称的工具必须存在于ToolCallback注册表中。 |
- |
spring.ai.openai.chat.options.tool-callbacks |
向ChatModel注册的工具回调。 |
- |
spring.ai.openai.chat.options.internal-tool-execution-enabled |
如果为 false,Spring AI 将不内部处理工具调用,而是将它们代理给客户端。此后,处理工具调用、将其分派给适当函数并返回结果的责任在于客户端。如果为 true(默认值),Spring AI 将内部处理函数调用。此设置仅适用于支持函数调用的聊天模型。 |
true |
spring.ai.openai.chat.options.service-tier |
Specifies the 处理类型用于为请求服务。 |
- |
spring.ai.openai.chat.options.extra-body |
额外的参数可以包含在请求中。接受任何以扁平结构发送到JSON请求顶层的键值对。用于与支持超出OpenAI标准API的服务器(如vLLM、Ollama等)配合使用。官方OpenAI API忽略未知参数。有关如何使用OpenAI兼容服务器的额外参数,请参阅使用OpenAI兼容服务器的额外参数以获取详细信息。 |
- |
|
GPT-5 模型,例如 |
你可以覆盖通用的spring.ai.openai.base-url和spring.ai.openai.api-key,用于ChatModel和EmbeddingModel的实现。
如果设置spring.ai.openai.chat.base-url和spring.ai.openai.chat.api-key属性,它们将优先于通用属性。
这很有用,如果你希望使用不同的OpenAI账户于不同的模型以及不同的模型端点。 |
所有以spring.ai.openai.chat.options为前缀的属性都可以通过向Prompt调用中添加请求特定的运行时选项在运行时覆盖。 |
Tokens限制参数:模型特定使用
OpenAI为控制生成Tokens的限制提供了两个互斥参数:
| 参数 | 使用案例 | 兼容性模型 |
|---|---|---|
|
非推理型模型 |
gpt-4o, gpt-4o-mini, gpt-4-turbo, gpt-3.5-turbo |
|
推理模型 |
o1, o1-mini, o1-preview, o3, o4-mini系列 |
| 这些参数是互斥的。同时设置两者将导致OpenAI的API返回错误。 |
使用示例
非推理模型(GPT-4o,GPT-3.5 Turbo):
ChatResponse response = chatModel.call(
new Prompt(
"Explain quantum computing in simple terms.",
OpenAiChatOptions.builder()
.model("gpt-4o")
.maxTokens(150) // Use maxTokens for non-reasoning models
.build()
));
对于推理模型(o1, o3系列):
ChatResponse response = chatModel.call(
new Prompt(
"Solve this complex math problem step by step: ...",
OpenAiChatOptions.builder()
.model("o1-preview")
.maxCompletionTokens(1000) // Use maxCompletionTokens for reasoning models
.build()
));
Builder模式验证: OpenAI ChatOptions builder自动实现互斥性,采用“最后一个设置占胜法”:
// This will automatically clear maxTokens and use maxCompletionTokens
OpenAiChatOptions options = OpenAiChatOptions.builder()
.maxTokens(100) // Set first
.maxCompletionTokens(200) // This clears maxTokens and logs a warning
.build();
// Result: maxTokens = null, maxCompletionTokens = 200
运行时选项
The OpenAIChatOptions.java class provides model configurations such as the model to use, the temperature, the frequency penalty, etc.
On start-up, the default options can be configured with the OpenAiChatModel(api, options) constructor or the spring.ai.openai.chat.options.* properties.
在运行时,您可以通过向 Prompt 调用添加新的、特定于请求的选项来覆盖默认选项。
例如,要为特定请求覆盖默认模型和温度:
ChatResponse response = chatModel.call(
new Prompt(
"Generate the names of 5 famous pirates.",
OpenAiChatOptions.builder()
.model("gpt-4o")
.temperature(0.4)
.build()
));
| 除了针对特定模型的OpenAI的聊天选项外,还可以使用一个通用的聊天选项实例,该实例可以通过ChatOptions#builder()方法创建。 |
函数调用
您可以使用 OpenAiChatModel 注册自定义的 Java 函数,并让 OpenAI 模型智能地选择输出一个 JSON 对象,该对象包含调用一个或多个已注册函数所需的参数。
这是一种强大的技术,可将大语言模型(LLM)的能力与外部工具和 API 连接起来。
阅读有关 工具调用 的更多内容。
多模态
多模态是指模型同时理解并处理来自多种来源信息的能力,这些来源包括文本、图像、音频及其他数据格式。 OpenAI 支持文本、视觉和音频输入模式。
愿景
支持视觉多模态功能的OpenAI模型包括gpt-4、gpt-4o和gpt-4o-mini。
请参考视觉文档获取更多信息。
OpenAI 用户消息 API 可以在消息中包含一个 base64 编码的图像或图像 URL 列表。
Spring AI 的 Message 接口通过引入 Media 类型来支持多模态 AI 模型。
该类型包含消息中媒体附件的数据和详细信息,使用 Spring 的 org.springframework.util.MimeType 和 org.springframework.core.io.Resource 来表示原始媒体数据。
以下是摘自 OpenAiChatModelIT.java 的代码示例,展示了如何使用 gpt-4o 模型将用户文本与图像进行融合。
var imageResource = new ClassPathResource("/multimodal.test.png");
var userMessage = new UserMessage("Explain what do you see on this picture?",
new Media(MimeTypeUtils.IMAGE_PNG, this.imageResource));
ChatResponse response = chatModel.call(new Prompt(this.userMessage,
OpenAiChatOptions.builder().model(OpenAiApi.ChatModel.GPT_4_O.getValue()).build()));
| GPT_4_VISION_PREVIEW 自2024年6月17日起将仅对现有用户开放。如果您不是现有用户,请使用 GPT_4_O 或 GPT_4_TURBO 模型。更多详情 此处 |
或使用 gpt-4o 模型的图像URL等效项:
var userMessage = new UserMessage("Explain what do you see on this picture?",
new Media(MimeTypeUtils.IMAGE_PNG,
URI.create("https://docs.spring.io/spring-ai/reference/_images/multimodal.test.png")));
ChatResponse response = chatModel.call(new Prompt(this.userMessage,
OpenAiChatOptions.builder().model(OpenAiApi.ChatModel.GPT_4_O.getValue()).build()));
| 您可以同时传递多张图片。 |
示例展示了一个模型,其输入为multimodal.test.png号图像:

伴随着文本信息 "解释一下你在图片中看到了什么?",并生成如下的回复:
This is an image of a fruit bowl with a simple design. The bowl is made of metal with curved wire edges that create an open structure, allowing the fruit to be visible from all angles. Inside the bowl, there are two yellow bananas resting on top of what appears to be a red apple. The bananas are slightly overripe, as indicated by the brown spots on their peels. The bowl has a metal ring at the top, likely to serve as a handle for carrying. The bowl is placed on a flat surface with a neutral-colored background that provides a clear view of the fruit inside.
音频
支持输入音频多模态的OpenAI模型包括 gpt-4o-audio-preview。
有关更多信息,请参阅音频指南。
OpenAI 用户消息API 可以在消息中包含一个经过base64编码的音频文件列表。
Spring AI 的 Message 接口通过引入 Media 类型来支持多模态AI模型。
该类型包含消息中媒体附件的数据和详细信息,使用 Spring 的 org.springframework.util.MimeType 和一个 org.springframework.core.io.Resource 来表示原始媒体数据。
目前,OpenAI 仅支持以下媒体类型:audio/mp3 和 audio/wav。
以下是摘自 OpenAiChatModelIT.java 的代码示例,展示了如何使用 gpt-4o-audio-preview 模型将用户文本与音频文件进行融合。
var audioResource = new ClassPathResource("speech1.mp3");
var userMessage = new UserMessage("What is this recording about?",
List.of(new Media(MimeTypeUtils.parseMimeType("audio/mp3"), audioResource)));
ChatResponse response = chatModel.call(new Prompt(List.of(userMessage),
OpenAiChatOptions.builder().model(OpenAiApi.ChatModel.GPT_4_O_AUDIO_PREVIEW).build()));
| 您也可以传递多个音频文件。 |
输出音频
支持输入音频多模态的OpenAI模型包括 gpt-4o-audio-preview。
有关更多信息,请参阅音频指南。
OpenAI 助手消息API 可以在消息中包含一个以base64编码的音频文件列表。
Spring AI 的 Message 接口通过引入 Media 类型来支持多模态AI模型。
该类型包含消息中媒体附件的数据和详细信息,使用 Spring 的 org.springframework.util.MimeType 和一个 org.springframework.core.io.Resource 来表示原始媒体数据。
目前,OpenAI 仅支持以下音频类型:audio/mp3 和 audio/wav。
以下是代码示例,演示了使用 gpt-4o-audio-preview 模型响应用户文本及音频字节数组:
var userMessage = new UserMessage("Tell me joke about Spring Framework");
ChatResponse response = chatModel.call(new Prompt(List.of(userMessage),
OpenAiChatOptions.builder()
.model(OpenAiApi.ChatModel.GPT_4_O_AUDIO_PREVIEW)
.outputModalities(List.of("text", "audio"))
.outputAudio(new AudioParameters(Voice.ALLOY, AudioResponseFormat.WAV))
.build()));
String text = response.getResult().getOutput().getText(); // audio transcript
byte[] waveAudio = response.getResult().getOutput().getMedia().get(0).getDataAsByteArray(); // audio data
您必须在 OpenAiChatOptions 中指定一个 audio 模式以生成音频输出。
AudioParameters 类为音频输出提供语音和音频格式。
结构化输出
OpenAI 提供自定义的 结构化输出 API,可确保您的模型生成的响应严格符合您提供的 JSON Schema。
除了现有的 Spring AI 模型无关的 结构化输出转换器 之外,这些 API 提供了更强的控制力和精确性。
| 目前,OpenAI 支持 JSON Schema 语言的子集 格式。 |
配置
Spring AI 允许您通过 OpenAiChatOptions 构建器以编程方式或通过应用程序属性来配置响应格式。
使用聊天选项构建器
您可以使用下面所示的 OpenAiChatOptions 构建器以编程方式设置响应格式:
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
}
""";
Prompt prompt = new Prompt("how can I solve 8x + 7 = -23",
OpenAiChatOptions.builder()
.model(ChatModel.GPT_4_O_MINI)
.responseFormat(new ResponseFormat(ResponseFormat.Type.JSON_SCHEMA, this.jsonSchema))
.build());
ChatResponse response = this.openAiChatModel.call(this.prompt);
| 遵循 OpenAI JSON Schema 语言的子集 格式。 |
与BeanOutputConverter工具集成
您可以利用现有的BeanOutputConverter工具自动从领域对象生成JSON Schema,之后将结构化响应转换为领域特定的实例:
-
Java
-
Kotlin
record MathReasoning(
@JsonProperty(required = true, value = "steps") Steps steps,
@JsonProperty(required = true, value = "final_answer") String finalAnswer) {
record Steps(
@JsonProperty(required = true, value = "items") Items[] items) {
record Items(
@JsonProperty(required = true, value = "explanation") String explanation,
@JsonProperty(required = true, value = "output") String output) {
}
}
}
var outputConverter = new BeanOutputConverter<>(MathReasoning.class);
var jsonSchema = this.outputConverter.getJsonSchema();
Prompt prompt = new Prompt("how can I solve 8x + 7 = -23",
OpenAiChatOptions.builder()
.model(ChatModel.GPT_4_O_MINI)
.responseFormat(new ResponseFormat(ResponseFormat.Type.JSON_SCHEMA, this.jsonSchema))
.build());
ChatResponse response = this.openAiChatModel.call(this.prompt);
String content = this.response.getResult().getOutput().getText();
MathReasoning mathReasoning = this.outputConverter.convert(this.content);
data class MathReasoning(
val steps: Steps,
@get:JsonProperty(value = "final_answer") val finalAnswer: String) {
data class Steps(val items: Array<Items>) {
data class Items(
val explanation: String,
val output: String)
}
}
val outputConverter = BeanOutputConverter(MathReasoning::class.java)
val jsonSchema = outputConverter.jsonSchema;
val prompt = Prompt("how can I solve 8x + 7 = -23",
OpenAiChatOptions.builder()
.model(ChatModel.GPT_4_O_MINI)
.responseFormat(ResponseFormat(ResponseFormat.Type.JSON_SCHEMA, jsonSchema))
.build())
val response = openAiChatModel.call(prompt)
val content = response.getResult().getOutput().getText()
val mathReasoning = outputConverter.convert(content)
通过应用程序属性进行配置
或者,当使用 OpenAI 自动配置时,你可以通过以下应用程序属性来配置所需响应格式:
spring.ai.openai.api-key=YOUR_API_KEY
spring.ai.openai.chat.options.model=gpt-4o-mini
spring.ai.openai.chat.options.response-format.type=JSON_SCHEMA
spring.ai.openai.chat.options.response-format.name=MySchemaName
spring.ai.openai.chat.options.response-format.schema={"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}
spring.ai.openai.chat.options.response-format.strict=true
示例控制器
创建一个新的Spring Boot项目,并将spring-boot-starter-web添加到您的pom(或gradle)依赖中。
在 src/main/resources 目录下添加一个 application.properties 文件,以启用并配置 OpenAi 聊天模型:
spring.ai.openai.api-key=YOUR_API_KEY
spring.ai.openai.chat.options.model=gpt-4o
spring.ai.openai.chat.options.temperature=0.7
将api-key替换为您的OpenAI凭据。 |
这将创建一个您可以注入到类中的OpenAiChatModel实现。
下面是一个使用聊天模型进行文本生成的简单@RestController类的例子。
@RestController
public class ChatController {
private final OpenAiChatModel chatModel;
@Autowired
public ChatController(OpenAiChatModel chatModel) {
this.chatModel = chatModel;
}
@GetMapping("/ai/generate")
public Map<String,String> generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
return Map.of("generation", this.chatModel.call(message));
}
@GetMapping("/ai/generateStream")
public Flux<ChatResponse> generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
Prompt prompt = new Prompt(new UserMessage(message));
return this.chatModel.stream(prompt);
}
}
手动配置
OpenAiChatModel 实现了 ChatModel 和 StreamingChatModel,并使用 低级别的 OpenAiApi 客户端 连接到 OpenAI 服务。
将 spring-ai-openai 依赖添加到您项目的 Maven pom.xml 文件中:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai</artifactId>
</dependency>
或者添加到您的Gradle 构建脚本文件中。
dependencies {
implementation 'org.springframework.ai:spring-ai-openai'
}
| 参考以下依赖管理部分,添加Spring AI BOM到你的构建文件中。 |
接下来,创建一个标识为OpenAiChatModel的代码块,并用于文本生成:
var openAiApi = OpenAiApi.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.build();
var openAiChatOptions = OpenAiChatOptions.builder()
.model("gpt-3.5-turbo")
.temperature(0.4)
.maxTokens(200)
.build();
var chatModel = new OpenAiChatModel(this.openAiApi, this.openAiChatOptions);
ChatResponse response = this.chatModel.call(
new Prompt("Generate the names of 5 famous pirates."));
// Or with streaming responses
Flux<ChatResponse> response = this.chatModel.stream(
new Prompt("Generate the names of 5 famous pirates."));
OpenAiChatOptions 提供了聊天请求的配置信息。
OpenAiApi.Builder 和 OpenAiChatOptions.Builder 分别是 API 客户端和聊天配置的流式选项构建器。
低级别的 OpenAiApi 客户端
OpenAiApi 提供了一个轻量级的 Java 客户端,用于 OpenAI 聊天 API OpenAI Chat API。
以下类图说明了 OpenAiApi 聊天接口和构建块:

以下是一个简单示例,展示了如何以编程方式使用API:
OpenAiApi openAiApi = OpenAiApi.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.build();
ChatCompletionMessage chatCompletionMessage =
new ChatCompletionMessage("Hello world", Role.USER);
// Sync request
ResponseEntity<ChatCompletion> response = this.openAiApi.chatCompletionEntity(
new ChatCompletionRequest(List.of(this.chatCompletionMessage), "gpt-3.5-turbo", 0.8, false));
// Streaming request
Flux<ChatCompletionChunk> streamResponse = this.openAiApi.chatCompletionStream(
new ChatCompletionRequest(List.of(this.chatCompletionMessage), "gpt-3.5-turbo", 0.8, true));
请参阅 OpenAiApi.java 的 JavaDoc 以获取更多信息。
底层API示例
-
OpenAiApiIT.java 测试提供了一些关于如何使用轻量级库的通用示例。
-
OpenAiApiToolFunctionCallIT.java 测试展示了如何使用低级 API 调用工具函数。 基于 OpenAI 函数调用 教程。
底层 OpenAiFileApi 客户端
OpenAiFileApi 为 OpenAI 文件 API 提供了一个轻量级的 Java 客户端,支持文件管理操作,例如上传、列出、检索、删除文件以及访问文件内容。OpenAI 文件 API
以下是一个简单示例,展示了如何以编程方式使用API:
OpenAiFileApi openAiFileApi = OpenAiFileApi.builder()
.apiKey(new SimpleApiKey(System.getenv("OPENAI_API_KEY")))
.build();
// Upload a file
byte[] fileBytes = Files.readAllBytes(Paths.get("evals.jsonl"));
OpenAiFileApi.UploadFileRequest uploadRequest = OpenAiFileApi.UploadFileRequest.builder()
.file(fileBytes)
.fileName("evals-data.jsonl")
.purpose(OpenAiFileApi.Purpose.EVALS)
.build();
ResponseEntity<OpenAiFileApi.FileObject> uploadResponse = openAiFileApi.uploadFile(uploadRequest);
// List files
OpenAiFileApi.ListFileRequest listRequest = OpenAiFileApi.ListFileRequest.builder()
.purpose(OpenAiFileApi.Purpose.EVALS)
.build();
ResponseEntity<OpenAiFileApi.FileObjectResponse> listResponse = openAiFileApi.listFiles(listRequest);
// Retrieve file information
ResponseEntity<OpenAiFileApi.FileObject> fileInfo = openAiFileApi.retrieveFile("file-id");
// Delete a file
ResponseEntity<OpenAiFileApi.DeleteFileResponse> deleteResponse = openAiFileApi.deleteFile("file-id");
// Retrieve file content
ResponseEntity<String> fileContent = openAiFileApi.retrieveFileContent("file-id");
底层文件API示例
-
OpenAiFileApiIT.java 测试提供了一些关于如何使用轻量级文件 API 库的通用示例。
API密钥管理
Spring AI 通过 ApiKey 接口及其实现提供了灵活的 API 密钥管理功能。默认实现 SimpleApiKey 适用于大多数使用场景,但您也可以为更复杂的场景创建自定义实现。
默认配置
默认情况下,Spring Boot 自动配置将使用 spring.ai.openai.api-key 属性创建一个 API 密钥 Bean:
spring.ai.openai.api-key=your-api-key-here
自定义API密钥配置
您可以使用构建器模式,通过您自己的 ApiKey 实现来创建一个自定义的 OpenAiApi 实例:
ApiKey customApiKey = new ApiKey() {
@Override
public String getValue() {
// Custom logic to retrieve API key
return "your-api-key-here";
}
};
OpenAiApi openAiApi = OpenAiApi.builder()
.apiKey(customApiKey)
.build();
// Create a chat model with the custom OpenAiApi instance
OpenAiChatModel chatModel = OpenAiChatModel.builder()
.openAiApi(openAiApi)
.build();
// Build the ChatClient using the custom chat model
ChatClient openAiChatClient = ChatClient.builder(chatModel).build();
这在你需要时非常有用:
-
从安全的密钥存储中获取API密钥
-
动态轮换API密钥
-
实现自定义API密钥选择逻辑
在与 OpenAI 兼容的服务器上使用额外参数
像 vLLM、Ollama 和其他一些与 OpenAI 兼容的推理服务器,通常支持超出 OpenAI 标准 API 所定义的额外参数。
例如,这些服务器可能接受 top_k、repetition_penalty 或其他采样控制参数,而这些参数是官方 OpenAI API 不支持的。
extraBody 选项允许你向这些服务器传递任意参数。
在 extraBody 中提供的任何键值对都将包含在 JSON 请求的顶层,使你能够在使用 Spring AI 的 OpenAI 客户端时利用服务器特定的功能。
|
|
使用属性进行配置
您可以使用 Spring Boot 属性来配置额外的参数。
spring.ai.openai.chat.options.extra-body 下的每个属性都将成为请求中的顶级参数:
spring.ai.openai.base-url=http://localhost:8000
spring.ai.openai.chat.options.model=meta-llama/Llama-3-8B-Instruct
spring.ai.openai.chat.options.temperature=0.7
spring.ai.openai.chat.options.extra-body.top_k=50
spring.ai.openai.chat.options.extra-body.repetition_penalty=1.1
此配置将生成一个类似如下的 JSON 请求:
{
"model": "meta-llama/Llama-3-8B-Instruct",
"temperature": 0.7,
"top_k": 50,
"repetition_penalty": 1.1,
"messages": [...]
}
使用构建器进行运行时配置
您还可以使用选项构建器在运行时指定额外的参数:
ChatResponse response = chatModel.call(
new Prompt(
"Tell me a creative story",
OpenAiChatOptions.builder()
.model("meta-llama/Llama-3-8B-Instruct")
.temperature(0.7)
.extraBody(Map.of(
"top_k", 50,
"repetition_penalty", 1.1,
"frequency_penalty", 0.5
))
.build()
));
示例:vLLM 服务器
在使用 vLLM 运行 Llama 模型时,你可能需要使用特定于 vLLM 的采样参数:
spring.ai.openai.base-url=http://localhost:8000
spring.ai.openai.chat.options.model=meta-llama/Llama-3-70B-Instruct
spring.ai.openai.chat.options.extra-body.top_k=40
spring.ai.openai.chat.options.extra-body.top_p=0.95
spring.ai.openai.chat.options.extra-body.repetition_penalty=1.05
spring.ai.openai.chat.options.extra-body.min_p=0.05
有关受支持的采样参数的完整列表,请参阅 vLLM 文档。
示例:Ollama 服务器
当通过与 OpenAI 兼容的端点使用 Ollama 时,可以传递 Ollama 特定的参数:
OpenAiChatOptions options = OpenAiChatOptions.builder()
.model("llama3.2")
.extraBody(Map.of(
"num_predict", 100,
"top_k", 40,
"repeat_penalty", 1.1
))
.build();
ChatResponse response = chatModel.call(new Prompt("Generate text", options));
有关可用参数,请查阅 Ollama API 文档。
|
参数 |
推理模型的推理内容
一些支持推理模型的 OpenAI 兼容服务器(例如 DeepSeek R1、带有推理解析器的 vLLM)会在其 API 响应中通过一个 reasoning_content 字段公开模型的内部思维链。
该字段包含模型为得出最终答案所采用的逐步推理过程。
Spring AI 将此字段从 JSON 响应映射到 AssistantMessage 元数据中的 reasoningContent 键。
|
关于
官方 OpenAI 推理模型在使用 Chat Completions API 时会隐藏思维链内容。
它们在使用统计中仅显示 回退行为:当服务器未提供 |
访问推理内容
当使用兼容的服务器时,您可以从响应元数据中访问推理内容。
直接使用 ChatModel:
// Configure to use DeepSeek R1 or vLLM with a reasoning model
ChatResponse response = chatModel.call(
new Prompt("Which number is larger: 9.11 or 9.8?")
);
// Get the assistant message
AssistantMessage message = response.getResult().getOutput();
// Access the reasoning content from metadata
String reasoning = message.getMetadata().get("reasoningContent");
if (reasoning != null && !reasoning.isEmpty()) {
System.out.println("Model's reasoning process:");
System.out.println(reasoning);
}
// The final answer is in the regular content
System.out.println("\nFinal answer:");
System.out.println(message.getContent());
使用 ChatClient:
ChatClient chatClient = ChatClient.create(chatModel);
String result = chatClient.prompt()
.user("Which number is larger: 9.11 or 9.8?")
.call()
.chatResponse()
.getResult()
.getOutput()
.getContent();
// To access reasoning content with ChatClient, retrieve the full response
ChatResponse response = chatClient.prompt()
.user("Which number is larger: 9.11 or 9.8?")
.call()
.chatResponse();
AssistantMessage message = response.getResult().getOutput();
String reasoning = message.getMetadata().get("reasoningContent");
流式推理内容
在使用流式响应时,推理内容会像常规消息内容一样跨多个分块累积:
Flux<ChatResponse> responseFlux = chatModel.stream(
new Prompt("Solve this logic puzzle...")
);
StringBuilder reasoning = new StringBuilder();
StringBuilder answer = new StringBuilder();
responseFlux.subscribe(chunk -> {
AssistantMessage message = chunk.getResult().getOutput();
// Accumulate reasoning if present
String reasoningChunk = message.getMetadata().get("reasoningContent");
if (reasoningChunk != null) {
reasoning.append(reasoningChunk);
}
// Accumulate the final answer
if (message.getContent() != null) {
answer.append(message.getContent());
}
});
示例:DeepSeek R1
DeepSeek R1 是一款能够公开其内部推理过程的推理模型:
spring.ai.openai.api-key=${DEEPSEEK_API_KEY}
spring.ai.openai.base-url=https://api.deepseek.com
spring.ai.openai.chat.options.model=deepseek-reasoner
当你向 DeepSeek R1 发起请求时,响应将同时包含推理内容(模型的思考过程)和最终答案。
请参阅 DeepSeek API 文档 以获取有关推理模型的更多详细信息。
示例:带有推理解析器的vLLM
vLLM 在配置了推理解析器时支持推理模型:
vllm serve deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B \
--enable-reasoning \
--reasoning-parser deepseek_r1
spring.ai.openai.base-url=http://localhost:8000
spring.ai.openai.chat.options.model=deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
请参阅 vLLM 推理输出文档 以了解支持的推理模型和解析器。
|
|