结构化输出转换器

截至 02.05.2024,旧的 OutputParserBeanOutputParserListOutputParserMapOutputParser 类已弃用,取而代之的是新的 StructuredOutputConverterBeanOutputConverterListOutputConverterMapOutputConverter 实现。后者是前者的直接替代品,并提供相同的功能。更改的原因主要是命名,因为没有进行任何解析,但也与 Spring org.springframework.core.convert.converter 包保持一致,带来了一些改进的功能。

LLM 生成结构化输出的能力对于依赖于可靠解析输出值的下游应用程序非常重要。开发人员希望快速将 AI 模型的结果转换为数据类型,例如 JSON、XML 或 Java 类,这些数据类型可以传递给其他应用程序函数和方法。

Spring AI Structured Output Converters 帮助将 LLM 输出转换为结构化格式。如下图所示,此方法围绕 LLM 文本完成端点进行操作

Structured Output Converter Architecture

使用通用完成 API 从大型语言模型 (LLM) 生成结构化输出需要仔细处理输入和输出。结构化输出转换器在 LLM 调用之前和之后扮演着至关重要的角色,确保实现所需的输出结构。

在 LLM 调用之前,转换器会将格式指令附加到提示中,为模型提供生成所需输出结构的明确指导。这些指令充当蓝图,塑造模型的响应以符合指定的格式。

在 LLM 调用之后,转换器获取模型的输出文本,并将其转换为结构化类型的实例。此转换过程涉及解析原始文本输出,并将其映射到相应的结构化数据表示,例如 JSON、XML 或特定于领域的的数据结构。

StructuredOutputConverter 尽力将模型输出转换为结构化输出。人工智能模型无法保证按请求返回结构化输出。模型可能无法理解提示或无法按请求生成结构化输出。考虑实现验证机制,以确保模型输出符合预期。
StructuredOutputConverter 不用于 LLM 函数调用,因为此功能本质上默认提供结构化输出。

结构化输出 API

StructuredOutputConverter 接口允许你获取结构化输出,例如将输出映射到 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 向人工智能模型提供特定的格式化准则,使其能够生成可使用 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(
       new PromptTemplate(
          userInputTemplate,
          Map.of(..., "format", outputConverter.getFormat()) // replace the "format" placeholder with the converter's format.
       ).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 模型生成符合 DRAFT_2020_12 的 JSON 响应,JSON Schema 从指定的 Java 类派生。随后,它使用 ObjectMapper 将 JSON 输出反序列化为目标类的 Java 对象实例。

  • MapOutputConverter - 使用 FormatProvider 实现扩展 AbstractMessageOutputConverter 的功能,指导 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) {
}

以下是应用 BeanOutputConverter 的方法

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

String format = beanOutputConverter.getFormat();

String actor = "Tom Hanks";

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

Generation generation = chatModel.call(
    new Prompt(new PromptTemplate(template, Map.of("actor", actor, "format", format)).createMessage())).getResult();

ActorsFilms actorsFilms = beanOutputConverter.convert(generation.getOutput().getContent());

泛型 Bean 类型

使用 ParameterizedTypeReference 构造函数指定更复杂的类结构。例如,表示演员列表及其电影作品列表

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

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

Prompt prompt = new Prompt(new PromptTemplate(template, Map.of("format", format)).createMessage());

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

List<ActorsFilmsRecord> actorsFilms = outputConverter.convert(generation.getOutput().getContent());

Map 输出转换器

以下代码段展示了如何使用 MapOutputConverter 生成数字列表。

MapOutputConverter mapOutputConverter = new MapOutputConverter();

String format = mapOutputConverter.getFormat();
String template = """
        Provide me a List of {subject}
        {format}
        """;
PromptTemplate promptTemplate = new PromptTemplate(template,
        Map.of("subject", "an array of numbers from 1 to 9 under they key name 'numbers'", "format", format));
Prompt prompt = new Prompt(promptTemplate.createMessage());
Generation generation = chatModel.call(prompt).getResult();

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

列表输出转换器

以下代码段展示了如何使用 ListOutputConverter 生成冰淇淋口味列表。

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

String format = listOutputConverter.getFormat();
String template = """
        List five {subject}
        {format}
        """;
PromptTemplate promptTemplate = new PromptTemplate(template,
        Map.of("subject", "ice cream flavors", "format", format));
Prompt prompt = new Prompt(promptTemplate.createMessage());
Generation generation = this.chatModel.call(prompt).getResult();

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

内置 JSON 模式

一些 AI 模型提供专门的配置选项来生成结构化(通常为 JSON)输出。

  • OpenAI - 提供 spring.ai.openai.chat.options.responseFormat 选项,指定模型必须输出的格式。设置为 { "type": "json_object" } 可启用 JSON 模式,该模式保证模型生成的消息为有效的 JSON。

  • 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。