结构化输出转换器
大型语言模型生成结构化输出的能力,对于依赖可靠解析输出值的下游应用至关重要。开发者希望能够快速将AI模型的结果转换为JSON、XML或Java类等数据类型,以便传递给其他应用程序函数和方法。
Spring AI 的 Structured Output Converters 帮助将 LLM 的输出转换为结构化格式。如下图所示,该方法围绕 LLM 的文本补全端点运作:

利用通用完成API从大型语言模型(LLM)生成结构化输出需要仔细处理输入与输出。结构化输出转换器在LLM调用前后扮演着关键角色,确保实现期望的输出结构。
在进行LLM调用之前,转换器会将格式指令附加到提示中,为模型生成所需输出结构提供明确指导。这些指令如同蓝图,引导模型的响应符合指定的格式。
随着越来越多的 AI 模型原生支持结构化输出,你可以通过 AdvisorParams.ENABLE_NATIVE_STRUCTURED_OUTPUT 参数,利用 原生结构化输出 功能。这种方法直接使用生成的 JSON 模式与模型的原生结构化输出 API 交互,无需预提示格式化指令,并能提供更可靠的结果。
在完成大语言模型调用后,转换器会接收模型的输出文本并将其转化为结构化类型的实例。这一转换过程涉及解析原始文本输出,并将其映射到对应的结构化数据表示形式,例如JSON、XML或特定领域的数据结构。
StructuredOutputConverter 会尽最大努力将模型输出转换为结构化输出。AI 模型不保证能按请求返回结构化输出。模型可能无法理解提示,或无法按要求生成结构化输出。建议实现验证机制,以确保模型输出符合预期。
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 时的数据流向。

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 提供了 AbstractConversionServiceOutputConverter、AbstractMessageOutputConverter、BeanOutputConverter、MapOutputConverter 和 ListOutputConverter 这些实现:

-
AbstractConversionServiceOutputConverter<T>- 提供一个预配置的 GenericConversionService,用于将 LLM 输出转换为所需格式。未提供默认的FormatProvider实现。 -
AbstractMessageOutputConverter<T>- 提供一个预配置的 MessageConverter,用于将 LLM 输出转换为所需格式。未提供默认的FormatProvider实现。 -
BeanOutputConverter<T>- 此转换器配置了指定的 Java 类(例如,Bean)或 ParameterizedTypeReference。它采用一个FormatProvider实现,该实现指示 AI 模型生成符合DRAFT_2020_12JSON Schema的 JSON 响应,该模式派生自指定的 Java 类。随后,它利用ObjectMapper将 JSON 输出反序列化为目标类的 Java 对象实例。 -
MapOutputConverter- 扩展了AbstractMessageOutputConverter的功能,包含一个FormatProvider实现,该实现引导 AI 模型生成符合 RFC 8259 的 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) {}
此注解适用于记录(records)和常规 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());
列表输出转换器
以下片段展示了如何使用 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());
原生结构化输出
许多现代AI模型现在原生支持结构化输出,相比基于提示的格式化,它能提供更可靠的结果。Spring AI通过原生结构化输出功能对此提供支持。
在使用原生结构化输出时,由BeanOutputConverter生成的JSON模式会直接发送至模型的结构化输出API,无需在提示中添加格式指令。这种方法具备以下优势:
-
更高的可靠性:模型确保输出符合模式
-
更简洁的提示词:无需附加格式说明
-
更好的性能:模型可在内部针对结构化输出进行优化
使用原生结构化输出
要启用原生结构化输出,请使用 AdvisorParams.ENABLE_NATIVE_STRUCTURED_OUTPUT 参数:
ActorsFilms actorsFilms = ChatClient.create(chatModel).prompt()
.advisors(AdvisorParams.ENABLE_NATIVE_STRUCTURED_OUTPUT)
.user("Generate the filmography for a random actor.")
.call()
.entity(ActorsFilms.class);
你也可以通过 ChatClient.Builder 上的 defaultAdvisors() 方法全局设置此功能:
@Bean
ChatClient chatClient(ChatClient.Builder builder) {
return builder
.defaultAdvisors(AdvisorParams.ENABLE_NATIVE_STRUCTURED_OUTPUT)
.build();
}
原生结构化输出支持的模型
目前支持原生结构化输出的模型如下:
-
OpenAI:支持 JSON Schema 的 GPT-4o 及后续模型
-
Anthropic:Claude 3.5 Sonnet 及后续模型
-
Vertex AI Gemini:Gemini 1.5 Pro 及后续模型
某些 AI 模型(例如 OpenAI)并不原生支持在顶层使用对象数组。在这种情况下,你可以使用 Spring AI 默认的结构化输出转换(无需原生结构化输出顾问)。
内置 JSON 模式
一些AI模型提供了专门的配置选项来生成结构化(通常是JSON)输出。
-
OpenAI 结构化输出 可以确保您的模型生成严格符合您提供的 JSON Schema 的响应。您可以在保证模型生成的消息是有效 JSON 的
JSON_OBJECT和附带一个保证模型生成响应匹配您所提供模式的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。