结构化输出转换器
本站(springdoc.cn)中的内容来源于 spring.io ,原始版权归属于 spring.io。由 springdoc.cn 进行翻译,整理。可供个人学习、研究,未经许可,不得进行任何转载、商用或与之相关的行为。 商标声明:Spring 是 Pivotal Software, Inc. 在美国以及其他国家的商标。 |
截至 2024 年 5 月 2 日,旧版 OutputParser 、BeanOutputParser 、 ListOutputParser 和 MapOutputParser 类已弃用,推荐改用新版 StructuredOutputConverter 、BeanOutputConverter 、ListOutputConverter 和 MapOutputConverter 实现。后者可直接替换前者并提供相同功能,此次变更主要出于命名规范化考虑(实际并无解析操作),同时也为对齐 Spring 的 org.springframework.core.convert.converter 包并引入增强功能。
|
大语言模型生成结构化输出的能力对依赖可靠解析结果的下游应用至关重要。开发者希望快速将 AI 模型结果转换为 JSON、XML 或 Java Class 等数据类型,以便传递给其他应用函数和方法。
Spring AI 结构化输出转换器(Structured Output Converter)帮助将 LLM 输出转为结构化格式。如下图所示,该方案围绕 LLM 文本补全端点运作:

使用通用补全 API 从大语言模型(LLM)生成结构化输出需谨慎处理输入输出。结构化输出转换器在 LLM 调用前后起关键作用,确保获得预期输出结构。
在 LLM 调用前,转换器向提示词追加格式指令,为模型生成预期输出结构提供明确指导。这些指令作为蓝图,引导模型响应符合指定格式。
LLM 调用后,转换器(Converter)将模型的原始文本输出转换为结构化类型实例。该转换过程包括解析原始文本输出,并将其映射 为JSON、XML 或领域特定数据结构等对应的结构化数据表示。
StructuredOutputConverter 会尽力将模型输出转换为结构化格式,但 AI 模型并不保证按请求返回结构化输出(可能无法理解提示或生成所需结构)。建议实现验证机制以确保模型输出符合预期。
|
StructuredOutputConverter 不用于 LLM 工具调用 功能,因此特性默认已提供结构化输出。
|
结构化输出 API
StructuredOutputConverter
接口允许从基于文本的 AI 模型输出中获取结构化结果,例如映射到 Java Class 或值数组。其接口定义为:
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}
"""; // 包含 "format" 占位符的用户输入。
Prompt prompt = new Prompt(
new PromptTemplate(
this.userInputTemplate,
Map.of(..., "format", outputConverter.getFormat()) // 将 "format" 占位符替换为转换器的格式指令。
).createMessage());
Converter<String, T>
负责将模型的文本输出转换为指定类型 T
的实例。
可用的转换器
目前 Spring AI 提供以下实现:AbstractConversionServiceOutputConverter
、AbstractMessageOutputConverter、BeanOutputConverter
、MapOutputConverter和ListOutputConverter
。

-
AbstractConversionServiceOutputConverter<T>
- 提供预配置的GenericConversionService
用于将 LLM 输出转换为目标格式,未提供默认FormatProvider
实现。 -
AbstractMessageOutputConverter<T>
- 提供预配置的MessageConverter
用于将 LLM 输出转换为目标格式,未提供默认FormatProvider
实现。 -
BeanOutputConverter<T>
-BeanOutputConverter<T>
:通过配置 Java 类或ParameterizedTypeReference
,该转换器(Converter)使用FormatProvider
实现指导 AI 模型生成符合DRAFT_2020_12
、JSON Schema
的响应(基于指定 Java 类生成),随后用ObjectMapper
将 JSON 输出反序列化为目标类的 Java 对象实例。 -
MapOutputConverter
- 继承AbstractMessageOutputConverter
的功能,通过FormatProvider
实现引导 AI 模型生成符合 RFC8259 标准的 JSON 响应,并利用提供的MessageConverter
将 JSON Payload 转换为java.util.Map<String, Object>
实例。 -
ListOutputConverter
- 继承AbstractConversionServiceOutputConverter
,包含专为逗号分隔列表输出定制的FormatProvider
实现。该转换器利用提供的ConversionService
将模型文本输出转换为java.util.List
。
使用转换器
以下章节提供使用现有转换器生成结构化输出的指南。
BeanOutputConverter
以下示例展示如何使用 BeanOutputConverter
生成演员作品表:
表示演员作品表的目标 record
类型:
record ActorsFilms(String actor, List<String> movies) {
}
以下是使用高阶 Fluent 式 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(
new PromptTemplate(this.template, Map.of("actor", this.actor, "format", this.format)).create()).getResult();
ActorsFilms actorsFilms = this.beanOutputConverter.convert(this.generation.getOutput().getText());
生成模式中的属性顺序
BeanOutputConverter
通过 @JsonPropertyOrder
注解支持自定义 JSON Schema 中的属性顺序,该注解允许指定属性在模式中的精确出现顺序(无视 class
或 record
中的声明顺序)。
例如,确保 ActorsFilms
record
中的属性特定顺序:
@JsonPropertyOrder({"actor", "movies"})
record ActorsFilms(String actor, List<String> movies) {}
该注解同时适用于 record
和常规 Java class
。
泛型 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 = 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().getText());
MapOutputConverter
以下片段展示如何使用 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>>() {});
或直接使用底层 ChatModel
API:
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().getText());
ListOutputConverter
以下片段展示如何使用 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().getText());
内置 JSON Schema
部分 AI 模型提供专用配置选项以生成结构化(通常为 JSON)输出。
-
OpenAI 结构化输出 确保模型生成严格符合所提供 JSON Schema 的响应。可选模式包括:保证生成有效 JSON 的
JSON_OBJECT
,或通过spring.ai.openai.chat.options.responseFormat
配置、确保响应匹配指定 schema 的JSON_SCHEMA
。 -
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。