Spring AI 拥抱 OpenAI 的结构化输出:增强 JSON 响应的可靠性
OpenAI 最近 推出了 一项名为 “结构化输出”(Structured Outputs)的强大功能,可确保 AI 生成的响应严格遵守预定义的 JSON Schema。这一功能大大提高了 AI 生成的内容在实际应用中的可靠性和可用性。
Spring AI(1.0.0-SNAPSHOT) 已 完全集成 了对 OpenAI 的结构化输出的支持,以一种无缝的 Spring 原生方式为 Java 开发人员带来了这一功能。
下图显示了新的结构化输出功能如何扩展 OpenAI Chat API:
注:Spring AI 已经提供了 功能强大、与模型无关的结构化输出 工具,可用于包括 OpenAI 在内的各种 AI 模型。OpenAI 结构化输出功能提供了一个额外的、一致的、但针对特定模型的解决方案,目前仅适用于 gpt-4o、gpt-4o-mini 和更高版本的模型。
OpenAI 结构化输出功能可确保 AI 模型生成的响应符合所提供的 JSON Schema。这解决了 AI 驱动的应用程序中的几个常见难题:
- 类型安全:不再担心缺少必填 KEY 或枚举值无效;
- 明确拒绝:基于安全性的模型拒绝变得可以通过编程检测到;
- 简化的提示:实现一致的格式化,而无需使用过于具体的 Prompt(提示)。
Spring AI 允许开发人员以最少的配置利用这一功能。接下来看看如何在 Spring 应用中使用它。
编程式配置
你可以使用 OpenAiChatOptions
Builder 以编程式设置响应格式,如下所示:
String jsonSchema = """
{
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": { "type": "string" },
"output": { "type": "string" }
},
"required": ["explanation", "output"],
"additionalProperties": false
}
},
"final_answer": { "type": "string" }
},
"required": ["steps", "final_answer"],
"additionalProperties": false
}
""";
Prompt prompt = new Prompt("how can I solve 8x + 7 = -23",
OpenAiChatOptions.builder()
.withModel(ChatModel.GPT_4_O_MINI)
.withResponseFormat(new ResponseFormat(ResponseFormat.Type.JSON_SCHEMA, jsonSchema))
.build());
ChatResponse response = this.openAiChatModel.call(prompt);
注意:你必须遵守 JSON Schema 语言格式的 OpenAI 子集。
使用 BeanOutputConverter
Spring AI 提供了一个方便的 BeanOutputConverter
工具类,它可以从 Domain 对象自动生成 JSON Schema,并将结构化响应转换为 Java 实例:
record MathReasoning(
@JsonProperty(required = true, value = "steps") Steps steps,
@JsonProperty(required = true, value = "final_answer") String finalAnswer) {
record Steps(
@JsonProperty(required = true, value = "items") Items[] items) {
record Items(
@JsonProperty(required = true, value = "explanation") String explanation,
@JsonProperty(required = true, value = "output") String output) {}
}
}
var outputConverter = new BeanOutputConverter<>(MathReasoning.class);
var jsonSchema = outputConverter.getJsonSchema();
Prompt prompt = new Prompt("how can I solve 8x + 7 = -23",
OpenAiChatOptions.builder()
.withModel(ChatModel.GPT_4_O_MINI)
.withResponseFormat(new ResponseFormat(ResponseFormat.Type.JSON_SCHEMA, jsonSchema))
.build());
ChatResponse response = this.openAiChatModel.call(prompt);
String content = response.getResult().getOutput().getContent();
MathReasoning mathReasoning = outputConverter.convert(content);
注意:确保使用 @JsonProperty(required = true,...)
注解。这对于生成能准确标记为必填字段的 Schema 至关重要。OpenAI 必须 使用它才能使结构化响应正常运行。
通过 Application Properties 进行配置
或者,在使用 OpenAI 自动配置 时,可以通过以下 chat application properties 配置所需的响应格式:
spring.ai.openai.api-key=YOUR_API_KEY
spring.ai.openai.chat.options.model=gpt-4o-mini
spring.ai.openai.chat.options.response-format.type=JSON_SCHEMA
spring.ai.openai.chat.options.response-format.name=MySchemaName
spring.ai.openai.chat.options.response-format.schema={"type":"object","properties":{"steps":{"type":"array","items":{"type":"object","properties":{"explanation":{"type":"string"},"output":{"type":"string"}},"required":["explanation","output"],"additionalProperties":false}},"final_answer":{"type":"string"}},"required":["steps","final_answer"],"additionalProperties":false}
spring.ai.openai.chat.options.response-format.strict=true
拒绝响应
在使用结构化输出(Structured Outputs)时,OpenAI 模型有时可能会出于安全原因拒绝执行请求。由于拒绝不一定遵循你在 response_format
中提供的 Schema,因此 API 响应会包含一个名为 refusal
的新字段,以表示模型拒绝执行请求。
Spring AI 会将此 refusal
字段映射到 AssistantMessage
的元数据中。按 refusal
KEY 检索。
接下来的工作
我们正在探索将新的 OpenAI 特定结构化输出功能集成到 Spring AI 的 与模型无关结构化输出工具集 中的可能性。
参考资料
欲了解更多信息,请查阅 Spring AI 和 OpenAI 参考文档。
- Spring AI OpenAI 结构化输出
- Spring AI、与模型无关的结构化 Output Converter
- Spring AI - 结构化输出
- OpenAI 结构化输出
- Spring AI 博客:
总结
Spring AI 对 OpenAI 结构化输出功能的支持使 AI 驱动的应用程序更可靠、更易于开发。通过确保类型安全和一致的结构化格式,开发人员可以专注于构建创新功能,而不是与不可预测的 AI 输出斗智斗勇。
我们可以看到 Spring 开发人员的以下优势:
- 无缝集成:利用结构化输出,无需离开 Spring 生态系统。
- 类型安全:使用强类型 Java 对象,减少运行时错误。
- 灵活性:可选择编程式配置或基于配置属性的配置。
- 领域驱动设计:使用你的 Domain 对象来定义预期的 AI 输出结构。
Ref:https://spring.io/blog/2024/08/09/spring-ai-embraces-openais-structured-outputs-enhancing-json-response