結構化輸出轉換器

截至 2024 年 5 月 2 日,舊的 OutputParserBeanOutputParserListOutputParserMapOutputParser 類已被棄用,取而代之的是新的 StructuredOutputConverterBeanOutputConverterListOutputConverterMapOutputConverter 實現。後者是前者的直接替代品,提供相同的功能。此更改的主要原因是命名,因為沒有進行任何解析,但也與 Spring 的 org.springframework.core.convert.converter 包保持一致,帶來了一些改進的功能。

LLM 生成結構化輸出的能力對於依賴可靠解析輸出值的下游應用程式至關重要。開發人員希望快速將 AI 模型的結果轉換為資料型別,例如 JSON、XML 或 Java 類,以便傳遞給其他應用程式功能和方法。

Spring AI 結構化輸出轉換器 有助於將 LLM 輸出轉換為結構化格式。如下圖所示,此方法圍繞 LLM 文字完成端點執行

Structured Output Converter Architecture

使用通用完成 API 從大型語言模型 (LLM) 生成結構化輸出需要仔細處理輸入和輸出。結構化輸出轉換器在 LLM 呼叫之前和之後都起著關鍵作用,確保實現所需的輸出結構。

在 LLM 呼叫之前,轉換器將格式指令附加到提示中,為模型提供生成所需輸出結構的明確指導。這些指令充當藍圖,塑造模型的響應以符合指定的格式。

在 LLM 呼叫之後,轉換器獲取模型的輸出文字並將其轉換為結構化型別的例項。此轉換過程涉及解析原始文字輸出並將其對映到相應的結構化資料表示,例如 JSON、XML 或領域特定資料結構。

StructuredOutputConverter 是一種盡力而為的方法,旨在將模型輸出轉換為結構化輸出。AI 模型不保證返回所請求的結構化輸出。模型可能無法理解提示或無法生成所請求的結構化輸出。請考慮實現驗證機制以確保模型輸出符合預期。
StructuredOutputConverter 不用於 LLM 工具呼叫,因為此功能預設提供結構化輸出。

結構化輸出 API

StructuredOutputConverter 介面允許您從基於文字的 AI 模型輸出中獲取結構化輸出,例如將輸出對映到 Java 類或值陣列。介面定義為

public interface StructuredOutputConverter<T> extends Converter<String, T>, FormatProvider {

}

它結合了 Spring Converter<String, T> 介面和 FormatProvider 介面

public interface FormatProvider {
	String getFormat();
}

下圖顯示了使用結構化輸出 API 時的資料流。

Structured Output API

FormatProvider 向 AI 模型提供特定的格式化指南,使其能夠生成可使用 Converter 轉換為指定目標型別 T 的文字輸出。以下是此類格式化指令的示例

  Your response should be in JSON format.
  The data structure for the JSON should match this Java class: java.util.HashMap
  Do not include any explanations, only provide a RFC8259 compliant JSON response following this format without deviation.

格式指令通常使用 PromptTemplate 附加到使用者輸入的末尾,如下所示

    StructuredOutputConverter outputConverter = ...
    String userInputTemplate = """
        ... user text input ....
        {format}
        """; // user input with a "format" placeholder.
    Prompt prompt = new Prompt(
            PromptTemplate.builder()
						.template(this.userInputTemplate)
						.variables(Map.of(..., "format", this.outputConverter.getFormat())) // replace the "format" placeholder with the converter's format.
						.build().createMessage()
    );

Converter<String, T> 負責將模型的輸出文字轉換為指定型別 T 的例項。

可用轉換器

目前,Spring AI 提供了 AbstractConversionServiceOutputConverterAbstractMessageOutputConverterBeanOutputConverterMapOutputConverterListOutputConverter 實現

Structured Output Class Hierarchy
  • AbstractConversionServiceOutputConverter<T> - 提供預配置的 GenericConversionService 用於將 LLM 輸出轉換為所需格式。未提供預設的 FormatProvider 實現。

  • AbstractMessageOutputConverter<T> - 提供預配置的 MessageConverter 用於將 LLM 輸出轉換為所需格式。未提供預設的 FormatProvider 實現。

  • BeanOutputConverter<T> - 配置了指定的 Java 類(例如 Bean)或 ParameterizedTypeReference,此轉換器使用 FormatProvider 實現,該實現指示 AI 模型生成符合從指定 Java 類派生的 DRAFT_2020_12 JSON Schema 的 JSON 響應。隨後,它使用 ObjectMapper 將 JSON 輸出反序列化為目標類的 Java 物件例項。

  • MapOutputConverter - 擴充套件了 AbstractMessageOutputConverter 的功能,其 FormatProvider 實現指導 AI 模型生成符合 RFC8259 的 JSON 響應。此外,它還包含一個轉換器實現,該實現使用提供的 MessageConverter 將 JSON 有效負載轉換為 java.util.Map<String, Object> 例項。

  • ListOutputConverter - 擴充套件了 AbstractConversionServiceOutputConverter,幷包含一個專為逗號分隔列表輸出定製的 FormatProvider 實現。轉換器實現使用提供的 ConversionService 將模型文字輸出轉換為 java.util.List

使用轉換器

以下部分提供如何使用可用轉換器生成結構化輸出的指南。

Bean 輸出轉換器

以下示例展示瞭如何使用 BeanOutputConverter 為演員生成電影作品。

表示演員電影作品的目標記錄

record ActorsFilms(String actor, List<String> movies) {
}

以下是使用高階、流暢的 ChatClient API 應用 BeanOutputConverter 的方法

ActorsFilms actorsFilms = ChatClient.create(chatModel).prompt()
        .user(u -> u.text("Generate the filmography of 5 movies for {actor}.")
                    .param("actor", "Tom Hanks"))
        .call()
        .entity(ActorsFilms.class);

或直接使用低階 ChatModel API

BeanOutputConverter<ActorsFilms> beanOutputConverter =
    new BeanOutputConverter<>(ActorsFilms.class);

String format = this.beanOutputConverter.getFormat();

String actor = "Tom Hanks";

String template = """
        Generate the filmography of 5 movies for {actor}.
        {format}
        """;

Generation generation = chatModel.call(
    PromptTemplate.builder().template(this.template).variables(Map.of("actor", this.actor, "format", this.format)).build().create()).getResult();

ActorsFilms actorsFilms = this.beanOutputConverter.convert(this.generation.getOutput().getText());

生成模式中的屬性排序

BeanOutputConverter 支援透過 @JsonPropertyOrder 註解在生成的 JSON 模式中自定義屬性排序。此註解允許您指定屬性在模式中出現的精確順序,而無論它們在類或記錄中的宣告順序如何。

例如,為了確保 ActorsFilms 記錄中屬性的特定順序

@JsonPropertyOrder({"actor", "movies"})
record ActorsFilms(String actor, List<String> movies) {}

此註解適用於記錄和常規 Java 類。

泛型 Bean 型別

使用 ParameterizedTypeReference 建構函式指定更復雜的目標類結構。例如,表示演員及其電影作品列表

List<ActorsFilms> actorsFilms = ChatClient.create(chatModel).prompt()
        .user("Generate the filmography of 5 movies for Tom Hanks and Bill Murray.")
        .call()
        .entity(new ParameterizedTypeReference<List<ActorsFilms>>() {});

或直接使用低階 ChatModel API

BeanOutputConverter<List<ActorsFilms>> outputConverter = new BeanOutputConverter<>(
        new ParameterizedTypeReference<List<ActorsFilms>>() { });

String format = this.outputConverter.getFormat();
String template = """
        Generate the filmography of 5 movies for Tom Hanks and Bill Murray.
        {format}
        """;

Prompt prompt = PromptTemplate.builder().template(this.template).variables(Map.of("format", this.format)).build().create();

Generation generation = chatModel.call(this.prompt).getResult();

List<ActorsFilms> actorsFilms = this.outputConverter.convert(this.generation.getOutput().getText());

Map 輸出轉換器

以下程式碼片段展示瞭如何使用 MapOutputConverter 將模型輸出轉換為對映中的數字列表。

Map<String, Object> result = ChatClient.create(chatModel).prompt()
        .user(u -> u.text("Provide me a List of {subject}")
                    .param("subject", "an array of numbers from 1 to 9 under they key name 'numbers'"))
        .call()
        .entity(new ParameterizedTypeReference<Map<String, Object>>() {});

或直接使用低階 ChatModel API

MapOutputConverter mapOutputConverter = new MapOutputConverter();

String format = this.mapOutputConverter.getFormat();
String template = """
        Provide me a List of {subject}
        {format}
        """;

Prompt prompt = PromptTemplate.builder().template(this.template)
.variables(Map.of("subject", "an array of numbers from 1 to 9 under they key name 'numbers'", "format", this.format)).build().create();

Generation generation = chatModel.call(this.prompt).getResult();

Map<String, Object> result = this.mapOutputConverter.convert(this.generation.getOutput().getText());

List 輸出轉換器

以下程式碼片段展示瞭如何使用 ListOutputConverter 將模型輸出轉換為冰淇淋口味列表。

List<String> flavors = ChatClient.create(chatModel).prompt()
                .user(u -> u.text("List five {subject}")
                            .param("subject", "ice cream flavors"))
                .call()
                .entity(new ListOutputConverter(new DefaultConversionService()));

或直接使用低階 ChatModel API

ListOutputConverter listOutputConverter = new ListOutputConverter(new DefaultConversionService());

String format = this.listOutputConverter.getFormat();
String template = """
        List five {subject}
        {format}
        """;

Prompt prompt = PromptTemplate.builder().template(this.template).variables(Map.of("subject", "ice cream flavors", "format", this.format)).build().create();

Generation generation = this.chatModel.call(this.prompt).getResult();

List<String> list = this.listOutputConverter.convert(this.generation.getOutput().getText());

內建 JSON 模式

一些 AI 模型提供專門的配置選項來生成結構化(通常是 JSON)輸出。

  • OpenAI 結構化輸出 可以確保您的模型生成嚴格符合您提供的 JSON 模式的響應。您可以在 JSON_OBJECT(保證模型生成的訊息是有效的 JSON)和 JSON_SCHEMA(附帶提供的模式,保證模型將生成與您提供的模式匹配的響應)(spring.ai.openai.chat.options.responseFormat 選項)之間進行選擇。

  • Azure OpenAI - 提供 spring.ai.azure.openai.chat.options.responseFormat 選項,指定模型必須輸出的格式。設定為 { "type": "json_object" } 可啟用 JSON 模式,這保證了模型生成的訊息是有效的 JSON。

  • Ollama - 提供 spring.ai.ollama.chat.options.format 選項來指定返回響應的格式。目前,唯一接受的值是 json

  • Mistral AI - 提供 spring.ai.mistralai.chat.options.responseFormat 選項來指定返回響應的格式。將其設定為 { "type": "json_object" } 可啟用 JSON 模式,這保證了模型生成的訊息是有效的 JSON。

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