| 此版本仍在开发中,尚未被视为稳定版本。最新的快照版本请使用 Spring AI 1.0.0-SNAPSHOT! | 
结构化输出转换器
| 截至 2024 年 5 月 2 日,旧的 OutputParser,BeanOutputParser,ListOutputParser和MapOutputParser类被弃用,取而代之的是新的StructuredOutputConverter,BeanOutputConverter,ListOutputConverter和MapOutputConverter实现。
后者是前者的直接替代品,并提供相同的功能。更改的原因主要是命名,因为没有进行任何解析,但也与 Spring 保持一致org.springframework.core.convert.converterpackage 中引入一些改进的功能。 | 
LLM 生成结构化输出的能力对于依赖可靠解析输出值的下游应用程序非常重要。 开发人员希望将 AI 模型的结果快速转换为数据类型,例如 JSON、XML 或 Java 类,这些数据类型可以传递给其他应用程序函数和方法。
The Spring AIStructured Output Converters帮助将 LLM 输出转换为结构化格式。
如下图所示,此方法围绕 LLM 文本完成端点运行:
 
使用通用完成 API 从大型语言模型 (LLM) 生成结构化输出需要仔细处理输入和输出。结构化输出转换器在 LLM 调用之前和之后起着至关重要的作用,确保实现所需的输出结构。
在 LLM 调用之前,转换器会将格式说明附加到提示符中,为模型生成所需的输出结构提供明确的指导。这些指令充当蓝图,调整模型的响应以符合指定的格式。
在 LLM 调用之后,转换器获取模型的输出文本并将其转换为结构化类型的实例。此转换过程包括解析原始文本输出并将其映射到相应的结构化数据表示形式,例如 JSON、XML 或特定于域的数据结构。
| 这 StructuredOutputConverter是将模型输出转换为结构化输出的最大努力。
不保证 AI 模型会按请求返回结构化输出。
模型可能无法理解提示或无法按请求生成结构化输出。
考虑实施验证机制以确保模型输出符合预期。 | 
| 这 StructuredOutputConverter不用于 LLM 工具调用,因为默认情况下,此功能本身就提供结构化输出。 | 
结构化输出 API
这StructuredOutputConverterinterface 允许您获取结构化输出,例如将输出映射到 Java 类或基于文本的 AI 模型输出中的值数组。
接口定义为:
public interface StructuredOutputConverter<T> extends Converter<String, T>, FormatProvider {
}它结合了 Spring Converter<String、T> 接口和FormatProvider接口
public interface FormatProvider {
	String getFormat();
}下图显示了使用结构化输出 API 时的数据流。
 
这FormatProvider为 AI 模型提供特定的格式准则,使其能够生成可转换为指定目标类型的文本输出T使用Converter.以下是此类格式设置说明的示例:
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(
			   this.userInputTemplate,
          Map.of(..., "format", outputConverter.getFormat()) // replace the "format" placeholder with the converter's format.
       ).createMessage());Converter<String T> 负责将模型的输出文本转换为指定类型的实例T.
可用转换器
目前,Spring AI 提供AbstractConversionServiceOutputConverter,AbstractMessageOutputConverter,BeanOutputConverter,MapOutputConverter和ListOutputConverter实现:
 
- 
AbstractConversionServiceOutputConverter<T>- 提供预配置的 GenericConversionService,用于将 LLM 输出转换为所需的格式。无默认值FormatProviderimplementation 的 implementation 的 S
- 
AbstractMessageOutputConverter<T>- 提供预配置的 MessageConverter,用于将 LLM 输出转换为所需的格式。无默认值FormatProviderimplementation 的 implementation 的 S
- 
BeanOutputConverter<T>- 使用指定的 Java 类(例如 Bean)或 ParameterizedTypeReference 进行配置,此转换器使用FormatProvider实现,该实现指示 AI 模型生成符合DRAFT_2020_12,JSON Schema派生自指定的 Java 类。随后,它使用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) {
}以下是如何使用高级的 FluentChatClient应用程序接口:
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);或使用低级ChatModelAPI 直接调用:
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(
    new PromptTemplate(this.template, Map.of("actor", this.actor, "format", this.format)).create()).getResult();
ActorsFilms actorsFilms = this.beanOutputConverter.convert(this.generation.getOutput().getContent());生成的架构中的属性排序
这BeanOutputConverter支持在生成的 JSON 架构中通过@JsonPropertyOrder注解。
此注释允许您指定属性在架构中出现的确切顺序,而不管它们在类或记录中的声明顺序如何。
例如,要确保ActorsFilms记录:
@JsonPropertyOrder({"actor", "movies"})
record ActorsFilms(String actor, List<String> movies) {}此 Annotation 适用于记录和常规 Java 类。
泛型 Bean 类型
使用ParameterizedTypeReferenceconstructor 来指定更复杂的目标类结构。
例如,要表示演员及其电影作品的列表:
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>>() {});或使用低级ChatModelAPI 直接调用:
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 = new PromptTemplate(this.template, Map.of("format", this.format)).create();
Generation generation = chatModel.call(this.prompt).getResult();
List<ActorsFilms> actorsFilms = this.outputConverter.convert(this.generation.getOutput().getContent());贴图输出转换器
以下代码段显示了如何使用MapOutputConverter将模型输出转换为 Map 中的数字列表。
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>>() {});或使用低级ChatModelAPI 直接调用:
MapOutputConverter mapOutputConverter = new MapOutputConverter();
String format = this.mapOutputConverter.getFormat();
String template = """
        Provide me a List of {subject}
        {format}
        """;
Prompt prompt = new PromptTemplate(this.template,
        Map.of("subject", "an array of numbers from 1 to 9 under they key name 'numbers'", "format", this.format)).create();
Generation generation = chatModel.call(this.prompt).getResult();
Map<String, Object> result = this.mapOutputConverter.convert(this.generation.getOutput().getContent());列出输出转换器
以下代码段显示了如何使用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 = new PromptTemplate(this.template,
        Map.of("subject", "ice cream flavors", "format", this.format)).create();
Generation generation = this.chatModel.call(this.prompt).getResult();
List<String> list = this.listOutputConverter.convert(this.generation.getOutput().getContent());内置 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。