|
此版本仍在开发中,尚未被视为稳定版。如需最新的快照版本,请使用 Spring AI 1.1.3! |
OpenAI 聊天
Spring AI 支持来自 OpenAI 的各种 AI 语言模型,OpenAI 是 ChatGPT 背后的公司,凭借其创建的行业领先的文本生成模型和嵌入技术,在激发人们对 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");
Auto-configuration
|
Spring AI自动配置和starter模块的artifact名称有了重大变化。 请参阅升级说明获取更多信息。 |
Spring AI 提供了对 OpenAI Chat Client 的 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 聊天模型的重试机制。
| <property> </property> | <description> </description> | 默认 |
|---|---|---|
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 min. |
spring.ai.retry.on-client-errors |
如果为假,则抛出一个NonTransientAiException,并且不尝试重试 |
false |
spring.ai.retry.exclude-on-http-codes |
不应当触发重试的HTTP状态码列表(例如,抛出NonTransientAiException)。 |
<p>空内容</p> |
spring.ai.retry.on-http-codes |
应触发重试的HTTP状态码列表(例如,抛出TransientAiException)。 |
<p>空内容</p> |
连接属性
使用前缀spring.ai.openai作为属性前缀,以便连接到OpenAI。
| <property> </property> | <description> </description> | 默认 |
|---|---|---|
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 请求的使用量将计入指定的组织和项目。 |
User-Agent 标头
Spring AI 会自动向所有发往 OpenAI 的请求发送一个 User-Agent: spring-ai 请求头。
这有助于 OpenAI 识别源自 Spring AI 的请求,以便进行分析和提供支持。
该请求头会自动发送,Spring AI 用户无需进行任何配置。
如果您是构建 OpenAI 兼容服务的 API 提供商,您可以通过读取服务器上传入请求中的 User-Agent HTTP 头来跟踪 Spring AI 的使用情况。
配置属性
|
现在通过带有前缀 要启用,请设置:spring.ai.model.chat=openai(默认已启用) 要禁用,请设置 spring.ai.model.chat=none (或任何与 openai 匹配的值) 此更改是为了允许配置多个模型。 |
spring.ai.openai.chat 前缀是属性前缀,允许你配置与 OpenAI 的聊天模型实现相关的设置。
| <property> </property> | <description> </description> | 默认 |
|---|---|---|
spring.ai.openai.chat.enabled (已删除且不再有效) |
启用OpenAI聊天模型。 |
true |
spring.ai.model.chat |
启用OpenAI聊天模型。 |
OpenAI |
spring.ai.openai.chat.base-url |
可选覆盖 |
- |
spring.ai.openai.chat.completions-path |
在基础URL后面附加的路径。 |
|
spring.ai.openai.chat.api-key |
可选覆盖 |
- |
spring.ai.openai.chat.organization-id |
您可以选择指定用于 API 请求的组织。 |
- |
spring.ai.openai.chat.project-id |
可选地,您可以指定用于 API 请求的项目。 |
- |
spring.ai.openai.chat.options.model |
要使用的 OpenAI 聊天模型的名称。您可以选择以下模型: |
|
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 |
修改指定Tokens在完成时出现的可能性。 |
- |
spring.ai.openai.chat.options.maxTokens |
聊天补全中生成的最大Tokens数。输入Tokens和生成Tokens的总长度受模型的上下文长度限制。用于非推理模型(例如,gpt-4o、gpt-3.5-turbo)。不能与推理模型一起使用(例如,o1、o3、o4-mini 系列)。与 maxCompletionTokens 互斥 - 同时设置两者将导致 API 错误。 |
- |
spring.ai.openai.chat.options.maxCompletionTokens |
完成生成时可生成的Tokens数量上限,包括可见输出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 |
您希望模型为此请求生成的输出类型。大多数模型默认能够生成文本。
|
- |
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方案。仅适用于 |
- |
spring.ai.openai.chat.options.responseFormat.strict |
响应格式 JSON 架构的严格遵循性。仅适用于 |
- |
spring.ai.openai.chat.options.seed |
此功能处于测试版。如指定,我们的系统将尽力进行确定性采样,这意味着使用相同的种子和参数重复请求应返回相同的结果。 |
- |
spring.ai.openai.chat.options.stop |
API将在生成更多Tokens之前停止生成至多4个序列。 |
- |
spring.ai.openai.chat.options.topP |
一种替代温度采样的方法,称为核采样(nucleus sampling),模型仅考虑累积概率质量为 |
- |
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 |
(仅适用于流式传输) 设置以添加一个额外的分块,其中包含整个请求的 token 使用统计信息。此分块的 |
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 |
如果为假,Spring AI 将不会内部处理工具调用,而是将它们代理给客户端。然后需要由客户端负责处理这些工具调用、将其分派到适当的函数,并返回结果。如果为真(默认值),Spring AI 将会内部处理这些函数调用。仅适用于支持功能调用的聊天模型。 |
true |
spring.ai.openai.chat.options.service-tier |
指定用于处理请求的处理类型。 |
- |
spring.ai.openai.chat.options.extra-body |
请求中包含的额外参数。接受任何键值对,这些键值对将被扁平化到 JSON 请求的顶层。旨在与支持超出标准 OpenAI API 参数的 OpenAI 兼容服务器(如 vLLM、Ollama 等)配合使用。官方 OpenAI API 会忽略未知参数。详见 在 OpenAI 兼容服务器上使用额外参数。 |
- |
|
使用GPT-5模型(如 |
您可以为 ChatModel 和 EmbeddingModel 实现覆盖通用的 spring.ai.openai.base-url 和 spring.ai.openai.api-key。
如果设置了 spring.ai.openai.chat.base-url 和 spring.ai.openai.chat.api-key 属性,它们的优先级将高于通用属性。
如果您希望针对不同的模型和不同的模型端点使用不同的 OpenAI 账户,这将非常有用。 |
所有以spring.ai.openai.chat.options开头的属性可以在运行时通过向Prompt调用添加请求特定的运行时选项来覆盖。 |
Token 限制 参数:模型特定用法
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()
));
构建器模式验证: OpenAI ChatOptions 构建器自动通过“最后设置优先”的方式强制执行互斥性:
// 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
运行时选项
OpenAiChatOptions.java 类提供了模型配置,例如要使用的模型、温度、频率惩罚等。
启动时,可以使用OpenAiChatModel(api, options)构造函数或spring.ai.openai.chat.options.*属性来配置默认选项。
在运行时,您可以通过向Prompt调用添加新的、针对请求的选项来覆盖默认选项。
例如,要为特定请求覆盖默认模型和温度设置:
ChatResponse response = chatModel.call(
new Prompt(
"Generate the names of 5 famous pirates.",
OpenAiChatOptions.builder()
.model("gpt-4o")
.temperature(0.4)
.build()
));
| 除了模型特定的 OpenAiChatOptions 之外,您还可以使用通过 ChatOptions#builder() 创建的可移植 ChatOptions 实例。 |
函数调用
您可以使用 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图像:
<p> along with the text message "请解释你在图片上看到了什么?", 并生成类似这样的响应:</p>
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,确保您的模型生成的响应严格符合您提供的 1》。
除了现有的 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 方案,并稍后将结构化的响应转换为特定于领域的实例:
-
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项目,并在pom(或gradle)依赖中添加spring-ai-starter-model-openai。
在 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 build.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 提供了用于 OpenAI 聊天 API OpenAI Chat API 的轻量级 Java 客户端。
以下类图说明了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 提供了一个轻量级的 Java 客户端,用于访问 OpenAI 文件 API,支持上传、列出、检索、删除文件以及访问文件内容等文件管理操作。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 服务器
在运行带有 Llama 模型的 vLLM 时,您可能希望使用专用于 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 文档 以了解可用参数。
|
|
来自推理模型的推理内容
一些支持推理模型(如 DeepSeek R1、带有推理解析器的 vLLM)的 OpenAI 兼容服务器,会通过其 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 推理输出文档,了解支持的推理模型和解析器。
|
|