Spring AI - 结构化输出
科学处理事物的片段和碎片,并假设存在连续性,而艺术则只关注事物的连续性,假设存在片段和碎片。- 罗伯特·M·皮尔西格
LLM(大型语言模型)生成结构化输出的能力对于依赖于可靠解析输出值的下游应用非常重要。开发人员希望将 AI 模型的结果快速转化为数据类型,如 JSON、XML 或 Java 类,以便传递给应用中的其他函数和方法。
Spring AI Structured Output Converter(结构化输出转换器)有助于将 LLM 输出转换为结构化格式。如下图所示,这种方法围绕 LLM 文本补全端点进行操作:
使用通用的补全 API 从大型语言模型(LLM)生成结构化输出需要对输入和输出进行仔细处理。结构化输出转换器在 LLM 调用之前和之后发挥着关键作用,确保实现所需的输出结构。
在进行 LLM 调用之前,转换器会将格式指令附加到提示中,为模型提供明确的指导,以生成所需的输出结构。这些指令充当蓝图,使模型的响应符合指定的格式。
在 LLM 调用之后,转换器会获取模型的输出文本,并将其转换为结构化类型的实例。转换过程包括解析原始文本输出,并将其映射到相应的结构化数据表示,如 JSON、XML 或特定领域(Domain)的数据结构。
注意,AI 模型不能保证按要求返回结构化输出。它可能不理解提示,也可能无法按要求生成结构化输出。
TIP: 如果你不想深入了解 API 的细节,可以过下一段,直接看 “使用转换器 ”部分。
1、结构化输出 API
StructuredOutputConverter
接口定义如下:
public interface StructuredOutputConverter<T> extends Converter<String, T>, FormatProvider {
}
它以目标结构化类型 T
为参数,结合了 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.
格式说明(Format Instruction)通常使用 PromptTemplate
附加到用户输入的末尾,如下所示:
StructuredOutputConverter outputConverter = ...
String userInputTemplate = """
... user text input ....
{format}
"""; // 用 “format” 占位符输入用户输入内容
Prompt prompt = new Prompt(
new PromptTemplate(
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
- 提供一个预配置的MessageConverter
,用于将 LLM 输出转换为所需格式。没有提供默认的FormatProvider
实现。BeanOutputConverter
- 使用指定的 Java 类(如 Bean)进行配置,此转换器采用FormatProvider
实现,指示 AI 模型生成符合DRAFT_2020_12
、从指定 Java 类派生的JSON Schema
的 JSON 响应。随后,它利用对象映射器(ObjectMapper
)将 JSON 输出反序列化为目标类的 Java 对象实例。MapOutputConverter
通过一个FormatProvider
实现扩展了AbstractMessageOutputConverter
的功能,该实现可引导 AI 模型生成符合 RFC8259 标准的 JSON 响应。此外,它还集成了一个转换器实现,利用所提供的MessageConverter
将 JSON Payload 转换为java.util.Map<String, Object>
实例。ListOutputConverter
继承了AbstractConversionServiceOutputConverter
,并包含一个专为逗号分隔列表输出定制的FormatProvider
实现。转换器实现利用所提供的ConversionService
将模型文本输出转换为java.util.List
输出。
2、使用转换器
接下来详细介绍如何利用可用的转换器生成结构化输出。源代码可从 spring-ai-structured-output-demo 仓库中获取。
BeanOutputConverter
下面的示例展示了如何使用 BeanOutputConverter
生成演员的影片记录。
代表演员的影片记录的 Record
如下:
record ActorsFilms(String actor, List<String> movies) {
}
以下是应用 BeanOutputConverter
的方法:
String userInputTemplate = """
Generate the filmography of 5 movies for {actor}.
{format}
""";
BeanOutputConverter<ActorsFilms> beanOutputConverter = new BeanOutputConverter<>(ActorsFilms.class);
String format = beanOutputConverter.getFormat();
String actor = "Tom Hanks";
Prompt prompt = new Prompt(
new PromptTemplate(userInputTemplate, Map.of("actor", actor, "format", format)).createMessage());
Generation generation = chatClient.call(prompt).getResult();
ActorsFilms actorsFilms = beanOutputConverter.convert(generation.getOutput().getContent());
MapOutputConverter
以下代码片段展示了如何使用 MapOutputConverter
生成数字列表。
MapOutputConverter mapOutputConverter = new MapOutputConverter();
String format = mapOutputConverter.getFormat();
String userInputTemplate = """
Provide me a List of {subject}
{format}
""";
PromptTemplate promptTemplate = new PromptTemplate(userInputTemplate,
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 = chatClient.call(prompt).getResult();
Map<String, Object> result = mapOutputConverter.convert(generation.getOutput().getContent());
ListOutputConverter
以下代码段展示了如何使用 ListOutputConverter
生成冰淇淋口味列表。
ListOutputConverter listOutputConverter = new ListOutputConverter(new DefaultConversionService());
String format = listOutputConverter.getFormat();
String userInputTemplate = """
List five {subject}
{format}
""";
PromptTemplate promptTemplate = new PromptTemplate(userInputTemplate,
Map.of("subject", "ice cream flavors", "format", format));
Prompt prompt = new Prompt(promptTemplate.createMessage());
Generation generation = this.chatClient.call(prompt).getResult();
List<String> list = listOutputConverter.convert(generation.getOutput().getContent());
3、参考资料
- 如需了解更多信息,请查阅 Spring AI 结构化输出转换器 文档。
- 有关代码示例,请查看 Spring-ai-structured-output-demo GitHub 仓库。
- 结构化输出 API 支持的 AI 模型。
- 支持内置 JSON 模式的 模型。
4、总结
LLM(大型语言模型)生成结构化输出的能力使开发人员能够与下游应用实现无缝集成。结构化输出转换器(Structured Output Converter)有助于简化这一过程,确保将模型输出可靠地解析为 JSON 或 Java 类等结构化格式。
本文提供了 BeanOutputConverter
、MapOutputConverter
和 ListOutputConverter
等转换器的实际使用示例,展示了为不同数据类型生成结构化输出的过程。
总之,Spring AI 的结构化输出转换器为开发人员提供了一个强大的解决方案,旨在在应用中利用 LLM 的能力,并通过结构化输出格式确保兼容性和可靠性。
Ref:https://spring.io/blog/2024/05/09/spring-ai-structured-output