OpenAI 聊天

Spring AI 支援 OpenAI 的各種 AI 語言模型,OpenAI 是 ChatGPT 背後的公司,憑藉其建立行業領先的文字生成模型和嵌入,在激發人們對 AI 驅動的文字生成的興趣方面發揮了重要作用。

先決條件

您需要使用 OpenAI 建立一個 API 才能訪問 ChatGPT 模型。

OpenAI 註冊頁面 建立一個帳戶,並在 API 金鑰頁面 生成令牌。

Spring AI 專案定義了一個名為 spring.ai.openai.api-key 的配置屬性,您應該將其設定為從 openai.com 獲取的 API 金鑰 的值。

您可以在 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");

新增儲存庫和 BOM

Spring AI 工件釋出在 Maven Central 和 Spring Snapshot 儲存庫中。請參閱 工件儲存庫 部分,將這些儲存庫新增到您的構建系統。

為了幫助管理依賴項,Spring AI 提供了一個 BOM(物料清單),以確保在整個專案中使用的 Spring AI 版本一致。請參閱 依賴項管理 部分,將 Spring AI BOM 新增到您的構建系統。

自動配置

Spring AI 自動配置、啟動模組的工件名稱發生了重大變化。請參閱 升級說明 以獲取更多資訊。

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,並且不嘗試重試 4xx 客戶端錯誤程式碼

spring.ai.retry.exclude-on-http-codes

不應觸發重試的 HTTP 狀態程式碼列表(例如,丟擲 NonTransientAiException)。

spring.ai.retry.on-http-codes

應觸發重試的 HTTP 狀態程式碼列表(例如,丟擲 TransientAiException)。

連線屬性

字首 spring.ai.openai 用作屬性字首,可讓您連線到 OpenAI。

財產 描述 預設值

spring.ai.openai.base-url

要連線的 URL

api.openai.com

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 使用者進行任何配置。

如果您是 API 提供商,正在構建 OpenAI 相容服務,您可以透過讀取伺服器上傳入請求的 User-Agent HTTP 標頭來跟蹤 Spring AI 的使用情況。

配置屬性

聊天自動配置的啟用和停用現在透過以spring.ai.model.chat為字首的頂級屬性進行配置。

要啟用,請將 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 聊天模型。

openai

spring.ai.openai.chat.base-url

用於 spring.ai.openai.base-url 屬性的可選覆蓋,以提供特定於聊天的 URL。

-

spring.ai.openai.chat.completions-path

要附加到基本 URL 的路徑。

/v1/chat/completions

spring.ai.openai.chat.api-key

用於 spring.ai.openai.api-key 的可選覆蓋,以提供特定於聊天的 API 金鑰。

-

spring.ai.openai.chat.organization-id

您可以選擇指定用於 API 請求的組織。

-

spring.ai.openai.chat.project-id

您可以選擇指定用於 API 請求的專案。

-

spring.ai.openai.chat.options.model

要使用的 OpenAI 聊天模型的名稱。您可以選擇的模型包括:gpt-4ogpt-4o-minigpt-4-turbogpt-3.5-turbo 等。有關更多資訊,請參閱 模型 頁面。

gpt-4o-mini

spring.ai.openai.chat.options.temperature

用於控制生成完成內容明顯創造性的取樣溫度。較高的值會使輸出更隨機,而較低的值會使結果更集中和確定性。不建議為同一完成請求同時修改 temperaturetop_p,因為這兩個設定的互動作用難以預測。

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

在聊天完成中生成的最大標記數。輸入標記和生成標記的總長度受模型上下文長度的限制。用於非推理模型(例如,gpt-4o,gpt-3.5-turbo)。不能用於推理模型(例如,o1,o3,o4-mini 系列)。與 maxCompletionTokens 互斥 - 同時設定兩者將導致 API 錯誤。

-

spring.ai.openai.chat.options.maxCompletionTokens

完成生成標記數的上限,包括可見輸出標記和推理標記。推理模型必需(例如,o1,o3,o4-mini 系列)。不能用於非推理模型(例如,gpt-4o,gpt-3.5-turbo)。與 maxTokens 互斥 - 同時設定兩者將導致 API 錯誤。

-

spring.ai.openai.chat.options.n

為每個輸入訊息生成多少個聊天完成選項。請注意,您將根據所有選項中生成的標記數收費。將 n 保持為 1 以最大程度地降低成本。

1

spring.ai.openai.chat.options.store

是否儲存此聊天完成請求的輸出以供模型使用

spring.ai.openai.chat.options.metadata

開發人員定義的標籤和值,用於在聊天完成儀表板中過濾完成內容

空對映

spring.ai.openai.chat.options.output-modalities

您希望模型為此請求生成的輸出型別。大多數模型都能夠生成文字,這是預設設定。gpt-4o-audio-preview 模型也可用於生成音訊。要請求此模型同時生成文字和音訊響應,您可以使用:textaudio。不支援流式傳輸。

-

spring.ai.openai.chat.options.output-audio

音訊生成的音訊引數。當 output-modalities 請求音訊輸出時必需:audio。需要 gpt-4o-audio-preview 模型,並且不支援流式完成。

-

spring.ai.openai.chat.options.presencePenalty

介於 -2.0 和 2.0 之間的數字。正值根據新標記是否出現在文字中對新標記進行懲罰,從而增加模型談論新主題的可能性。

-

spring.ai.openai.chat.options.responseFormat.type

GPT-4oGPT-4o miniGPT-4 Turbo 以及所有比 gpt-3.5-turbo-1106 更新的 GPT-3.5 Turbo 模型相容。JSON_OBJECT 型別啟用 JSON 模式,它保證模型生成的訊息是有效的 JSON。JSON_SCHEMA 型別啟用 結構化輸出,它保證模型將匹配您提供的 JSON 模式。JSON_SCHEMA 型別還需要設定 responseFormat.schema 屬性。

-

spring.ai.openai.chat.options.responseFormat.name

響應格式模式名稱。僅適用於 responseFormat.type=JSON_SCHEMA

custom_schema

spring.ai.openai.chat.options.responseFormat.schema

響應格式 JSON 模式。僅適用於 responseFormat.type=JSON_SCHEMA

-

spring.ai.openai.chat.options.responseFormat.strict

響應格式 JSON 模式遵循嚴格性。僅適用於 responseFormat.type=JSON_SCHEMA

-

spring.ai.openai.chat.options.seed

此功能處於 Beta 階段。如果指定,我們的系統將盡力確定性地取樣,以便使用相同種子和引數的重複請求應返回相同的結果。

-

spring.ai.openai.chat.options.stop

API 將停止生成更多標記的最多 4 個序列。

-

spring.ai.openai.chat.options.topP

一種替代溫度取樣的核取樣方法,其中模型考慮具有 top_p 機率質量的標記結果。因此,0.1 意味著只考慮組成前 10% 機率質量的標記。我們通常建議修改此項或 temperature,但不要同時修改兩者。

-

spring.ai.openai.chat.options.tools

模型可以呼叫的工具列表。目前,僅支援函式作為工具。使用此項提供模型可以為其生成 JSON 輸入的函式列表。

-

spring.ai.openai.chat.options.toolChoice

控制模型呼叫哪個(如果有)函式。none 表示模型不會呼叫函式,而是生成訊息。auto 表示模型可以在生成訊息或呼叫函式之間進行選擇。透過 {"type: "function", "function": {"name": "my_function"}} 指定特定函式會強制模型呼叫該函式。當沒有函式時,none 是預設值。如果存在函式,auto 是預設值。

-

spring.ai.openai.chat.options.user

代表您的終端使用者的唯一識別符號,可以幫助 OpenAI 監控和檢測濫用。

-

spring.ai.openai.chat.options.stream-usage

(僅限流式傳輸)設定為新增一個額外的塊,其中包含整個請求的令牌使用統計資訊。此塊的choices欄位是一個空陣列,所有其他塊也將包含一個 usage 欄位,但值為 null。

spring.ai.openai.chat.options.parallel-tool-calls

在使用工具時是否啟用 並行函式呼叫

true

spring.ai.openai.chat.options.prompt-cache-key

OpenAI 用於最佳化類似請求的快取命中率的快取鍵。提高延遲並降低成本。取代用於快取目的的已棄用的 user 欄位。瞭解更多

-

spring.ai.openai.chat.options.safety-identifier

一個穩定的識別符號,用於幫助 OpenAI 檢測違反使用策略的使用者。應為雜湊值(例如,雜湊後的使用者名稱或電子郵件)。取代用於安全跟蹤的已棄用的 user 欄位。瞭解更多

-

spring.ai.openai.chat.options.http-headers

要新增到聊天完成請求的可選 HTTP 標頭。要覆蓋 api-key,您需要使用 Authorization 標頭鍵,並且必須在鍵值前加上 Bearer 字首。

-

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

指定用於服務請求的 處理型別

-

spring.ai.openai.chat.options.extra-body

請求中包含的附加引數。接受任何鍵值對,這些鍵值對會被展平到 JSON 請求的頂層。旨在與支援標準 OpenAI API 之外引數的 OpenAI 相容伺服器(vLLM、Ollama 等)一起使用。官方 OpenAI API 忽略未知引數。有關詳細資訊,請參閱 將額外引數與 OpenAI 相容伺服器一起使用

-

使用 GPT-5 模型(如 gpt-5gpt-5-minigpt-5-nano)時,不支援 temperature 引數。這些模型針對推理進行了最佳化,不使用溫度。指定溫度值將導致錯誤。相比之下,像 gpt-5-chat 這樣的會話模型支援 temperature 引數。

您可以為 ChatModelEmbeddingModel 實現覆蓋通用的 spring.ai.openai.base-urlspring.ai.openai.api-key。如果設定了 spring.ai.openai.chat.base-urlspring.ai.openai.chat.api-key 屬性,它們將優先於通用屬性。這在您想為不同的模型和不同的模型端點使用不同的 OpenAI 帳戶時很有用。
所有以 spring.ai.openai.chat.options 為字首的屬性都可以在執行時透過向 Prompt 呼叫新增請求特定的 執行時選項 來覆蓋。

標記限制引數:模型特定用法

OpenAI 提供了兩個互斥的引數來控制標記生成限制

引數 用例 相容模型

maxTokens

非推理模型

gpt-4o, gpt-4o-mini, gpt-4-turbo, gpt-3.5-turbo

maxCompletionTokens

推理模型

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 例項,該例項使用 ChatOptions#builder() 建立。

函式呼叫

您可以使用 OpenAiChatModel 註冊自定義 Java 函式,並讓 OpenAI 模型智慧地選擇輸出包含呼叫一個或多個註冊函式引數的 JSON 物件。這是一種將 LLM 功能與外部工具和 API 連線的強大技術。閱讀更多關於 工具呼叫 的資訊。

多模態

多模態是指模型同時理解和處理來自各種來源(包括文字、影像、音訊和其他資料格式)資訊的能力。OpenAI 支援文字、視覺和音訊輸入模態。

視覺

提供視覺多模態支援的 OpenAI 模型包括 gpt-4gpt-4ogpt-4o-mini。有關更多資訊,請參閱 視覺 指南。

OpenAI 使用者訊息 API 可以將 base64 編碼的影像列表或影像 URL 與訊息一起合併。Spring AI 的 訊息 介面透過引入 媒體 型別來促進多模態 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()));
從 2024 年 6 月 17 日起,GPT_4_VISION_PREVIEW 將僅適用於此模型的現有使用者。如果您不是現有使用者,請使用 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.springframework.tw/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 影像作為輸入

Multimodal Test Image

以及文字訊息“解釋你在這張圖片上看到了什麼?”,並生成如下響應

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 的 訊息 介面透過引入 媒體 型別來促進多模態 AI 模型。此型別包含有關訊息中媒體附件的資料和詳細資訊,利用 Spring 的 org.springframework.util.MimeType 和用於原始媒體資料的 org.springframework.core.io.Resource。目前,OpenAI 僅支援以下媒體型別:audio/mp3audio/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 的 訊息 介面透過引入 媒體 型別來促進多模態 AI 模型。此型別包含有關訊息中媒體附件的資料和詳細資訊,利用 Spring 的 org.springframework.util.MimeType 和用於原始媒體資料的 org.springframework.core.io.Resource。目前,OpenAI 僅支援以下音訊型別:audio/mp3audio/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().getContent(); // 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().getContent();

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().getContent()

val mathReasoning = outputConverter.convert(content)
儘管對於 JSON Schema 來說這是可選的,但 OpenAI 強制要求 結構化響應的必需欄位才能正常工作。Kotlin 反射用於根據型別的可空性和引數的預設值推斷哪些屬性是必需的,哪些不是,因此對於大多數用例,不需要 @get:JsonProperty(required = true)@get:JsonProperty(value = "custom_name") 可以用於自定義屬性名稱。請確保使用此 @get: 語法在相關的 getter 上生成註釋,請參閱 相關文件

透過應用程式屬性配置

或者,在使用 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-ai-starter-model-openai 新增到您的 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
用您的 OpenAI 憑據替換 api-key

這將建立一個 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 實現了 ChatModelStreamingChatModel,並使用 低階 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.BuilderOpenAiChatOptions.Builder 分別是用於 API 客戶端和聊天配置的流暢選項構建器。

低階 OpenAiApi 客戶端

OpenAiApi 為 OpenAI 聊天 API OpenAI 聊天 API 提供了輕量級 Java 客戶端。

以下類圖說明了 OpenAiApi 聊天介面和構建塊

OpenAiApi Chat API Diagram

以下是一個簡單的程式碼片段,展示瞭如何以程式設計方式使用 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 示例

低階 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 示例

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_krepetition_penalty 或其他官方 OpenAI API 不識別的取樣控制引數。

extraBody 選項允許您將任意引數傳遞給這些伺服器。extraBody 中提供的任何鍵值對都包含在 JSON 請求的頂層,使您能夠在使用 Spring AI 的 OpenAI 客戶端時利用伺服器特定功能。

extraBody 引數旨在與 OpenAI 相容伺服器一起使用,而不是官方 OpenAI API。雖然官方 OpenAI API 將忽略未知引數,但它們在那裡沒有用處。始終查閱您的特定伺服器文件以確定支援哪些引數。

使用屬性進行配置

您可以使用 Spring Boot 屬性配置額外引數。spring.ai.openai.chat.options.extra-body 下的每個屬性都成為請求中的頂級引數

spring.ai.openai.base-url=https://:8000/v1
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=https://:8000/v1
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 文件 以獲取可用引數。

extraBody 引數接受任何 Map<String, Object>,允許您傳遞目標伺服器支援的任何引數。Spring AI 不會驗證這些引數——它們會直接傳遞給伺服器。這種設計為與各種 OpenAI 相容實現協作提供了最大的靈活性。

推理模型中的推理內容

一些支援推理模型(如 DeepSeek R1、帶推理解析器的 vLLM)的 OpenAI 相容伺服器透過其 API 響應中的 reasoning_content 欄位暴露模型的內部思維鏈。此欄位包含模型得出最終答案所使用的逐步推理過程。

Spring AI 將 JSON 響應中的此欄位對映到 AssistantMessage 元資料中的 reasoningContent 鍵。

關於 reasoning_content 可用性的重要區別

  • OpenAI 相容伺服器 (DeepSeek, vLLM):在聊天完成 API 響應中暴露 reasoning_content

  • 官方 OpenAI 模型 (GPT-5, o1, o3):在聊天完成 API 響應中暴露推理文字 ❌

官方 OpenAI 推理模型在使用聊天完成 API 時會隱藏思維鏈內容。它們僅在用量統計中暴露 reasoning_tokens 計數。要從官方 OpenAI 模型訪問實際推理文字,您必須使用 OpenAI 的響應 API(此客戶端目前不支援的單獨端點)。

回退行為: 當伺服器未提供 reasoning_content 時(例如,官方 OpenAI 聊天完成),reasoningContent 元資料欄位將為空字串。

訪問推理內容

使用相容伺服器時,您可以從響應元資料中訪問推理內容。

直接使用 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=https://:8000/v1
spring.ai.openai.chat.options.model=deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B

請參閱 vLLM 推理輸出文件 以獲取支援的推理模型和解析器。

reasoning_content 的可用性完全取決於您使用的推理伺服器。並非所有與 OpenAI 相容的伺服器都暴露推理內容,即使在使用支援推理的模型時也是如此。請始終參閱您的伺服器的 API 文件,以瞭解響應中可用的欄位。

© . This site is unofficial and not affiliated with VMware.