当前位置: 首页 > news >正文

Spring AI结构化输出

1. 核心概念与设计思想

1.1 什么是结构化输出

Spring AI 结构化输出是一种类型安全的 AI 交互范式。它通过向 LLM 注入格式指令,强制模型输出符合特定 Schema 的内容,再由框架自动将字符串转换为 Java 对象,实现了从 "字符串拼接与解析" 到 "面向对象编程" 的跨越。

1.2 核心接口契约

Spring AI 定义了两个职责单一的核心接口,共同构成结构化输出的基础:

// 格式提供者:生成AI能够理解并严格遵守的输出格式说明 public interface FormatProvider { String getFormat(); } // 结构化输出转换器:组合"格式生成"与"字符串转对象"能力 public interface StructuredOutputConverter<T> extends Converter<String, T>, FormatProvider { }

接口职责分离原则

  • Converter<String, T>:定义从字符串到目标类型 T 的反序列化逻辑
  • FormatProvider:定义如何生成 AI 可执行的格式指令(通常是 JSON Schema)
  • StructuredOutputConverter:组合两者,形成完整的 "指令 - 生成 - 解析" 闭环

1.3 底层工作原理

Spring AI 内部会自动执行以下 4 个步骤,全程对开发者透明:

  1. Schema 生成:根据目标 Java 类自动生成 JSON Schema 格式说明
  2. 提示词注入:将格式说明注入到提示词的{format}占位符
  3. 模型调用:发送包含格式要求的完整提示词给 LLM
  4. 自动反序列化:将 LLM 返回的字符串转换为强类型 Java 对象

2. 快速上手:恋爱报告实战

2.1 第一步:定义结构化输出类

使用 Java 16 + 的Record特性(推荐)定义不可变的数据载体,这是结构化输出的最佳实践:

/** * 恋爱报告结构化输出类 * 字段名会直接影响AI生成内容的准确性,请使用清晰易懂的命名 */ public record LoveReport( String title, // 报告标题(要求:{用户名}的恋爱报告) List<String> s // 恋爱建议列表(每条建议为一个字符串元素) ) {}

2.2 第二步:实现结构化输出调用

使用 Spring AI 的ChatClient流式 API,一行代码完成从对话到对象的转换:

import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.ChatMemoryAdvisor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @Slf4j @Service public class LoveConsultationService { private final ChatClient chatClient; // 基础系统提示词 private static final String SYSTEM_PROMPT = "你是一位专业、温和的恋爱咨询师,擅长提供客观、可执行的恋爱建议。"; // 构造注入ChatClient.Builder(Spring Boot自动配置) public LoveConsultationService(ChatClient.Builder chatClientBuilder) { this.chatClient = chatClientBuilder.build(); } /** * 与AI对话并生成结构化的恋爱报告 * @param userMessage 用户输入的恋爱问题 * @param chatId 会话唯一标识,用于实现对话记忆 * @return 强类型的LoveReport对象 */ public LoveReport doChatWithReport(String userMessage, String chatId) { LoveReport loveReport = chatClient .prompt() // 系统提示词:明确业务要求+格式要求 .system(SYSTEM_PROMPT + "每次对话后必须生成恋爱结果,标题严格为'用户名的恋爱报告',内容为建议列表。") .user(userMessage) // 配置对话记忆:指定会话ID和历史消息检索条数 .advisors(spec -> spec .param(ChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, chatId) .param(ChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10)) .call() // 核心魔法:自动将AI输出转换为LoveReport对象 .entity(LoveReport.class); log.info("成功生成恋爱报告: {}", loveReport); return loveReport; } }

3. 核心 API 详解

3.1 ChatClient.entity () 方法

entity(Class<T> entityType)是 Spring AI 结构化输出的核心入口,它内部封装了所有复杂逻辑:

  • 自动创建对应类型的StructuredOutputConverter实例
  • 生成该类型的完整 JSON Schema
  • 将 Schema 注入到提示词的适当位置
  • 调用 LLM 并捕获输出
  • 执行反序列化并返回强类型对象

支持的类型范围

  • 基本类型:StringIntegerLongBooleanDouble
  • 集合类型:List<T>Set<T>Map<K, V>
  • 自定义 POJO/Record(支持嵌套)
  • 枚举类型
  • 泛型类型(需使用ParameterizedTypeReference

3.2 内置转换器

Spring AI 提供了多种开箱即用的转换器:

转换器用途特点
JacksonStructuredOutputConverterJSON 格式转换默认使用,基于 Jackson,支持所有 Java 类型
BeanOutputConverterBean 属性映射基于 BeanUtils,兼容性好
EnumOutputConverter枚举类型转换自动处理枚举值的大小写和别名
ListOutputConverter列表类型转换专门优化列表输出的格式指令

4. 高级用法:自定义转换器

当内置转换器无法满足需求时,可以实现自定义的StructuredOutputConverter

import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.ai.converter.StructuredOutputConverter; import org.springframework.core.convert.ConversionException; public class CustomLoveReportConverter implements StructuredOutputConverter<LoveReport> { private final ObjectMapper objectMapper; public CustomLoveReportConverter(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public LoveReport convert(String source) { try { // 自定义解析逻辑:可以处理AI输出中的额外文本 String json = extractJsonFromText(source); return objectMapper.readValue(json, LoveReport.class); } catch (Exception e) { throw new ConversionException("无法转换为LoveReport对象", e); } } @Override public String getFormat() { // 自定义格式说明:比自动生成的更简洁、更符合业务需求 return """ 请严格按照以下JSON格式输出,不要添加任何其他内容: { "title": "报告标题,格式为'用户名的恋爱报告'", "s": ["建议1", "建议2", "建议3"] } """; } // 从AI输出的文本中提取JSON部分 private String extractJsonFromText(String text) { int start = text.indexOf('{'); int end = text.lastIndexOf('}'); if (start == -1 || end == -1 || start >= end) { throw new IllegalArgumentException("未找到有效的JSON内容"); } return text.substring(start, end + 1); } }

使用自定义转换器:

public LoveReport doChatWithCustomConverter(String userMessage, String chatId) { CustomLoveReportConverter converter = new CustomLoveReportConverter(objectMapper); return chatClient .prompt() .system(SYSTEM_PROMPT) .user(userMessage) .call() .entity(converter); // 使用自定义转换器 }

http://www.rkmt.cn/news/1419721.html

相关文章:

  • Deepoc开发板:智能轮椅动态协同的VLA实现解析
  • 从理论到代码:手把手教你用MATLAB验证Eb/N0与SNR转换公式(附完整仿真脚本)
  • 别再死记硬背递归了!从‘士兵淘汰’游戏带你真正理解递归思想
  • 梦饷科技蝉联BCMM评估咨询服务机构权威资质 领跑商业数字化转型赋能赛道
  • AI 时代全栈升级路线
  • 保姆级教程:用PFC 7.0搞定岩土双轴压缩模拟(从参数化建模到伺服加载)
  • 50行Python手搓一个原生AI Agent:彻底看懂智能体的本质
  • MATLAB机器人控制器仿真代码包:从建模、设计到响应验证的一站式实现
  • 如何快速掌握BepInEx:Unity游戏模组开发的终极框架指南
  • 2026年4月目前靠谱的变压器定制推荐,龙门架电力构架/四管塔避雷塔/独立避雷针/三柱塔避雷针,变压器来图加工厂家销售 - 品牌推荐师
  • 别再靠猜了!用SystemView+FreeRTOS实时‘看透’你的任务调度(保姆级配置避坑)
  • 从抓包看本质:Wireshark深度解读TCP报文头每个字段的含义与实战作用
  • 基于Whisper、Llama 2与Bark构建本地离线语音助手实战指南
  • Uber 4 个月烧光 2026 全年 AI 预算:人均月账单 $500-$2000,企业 token 计费失控的第一个公开样本
  • 术语俗话 --- 什么是类C代码
  • 体育科技革命:从数据采集到AI分析,技术如何重塑竞技体育
  • 如何用 ChatGPT 提升学习指导效率?完整实现指南
  • Gemini多语言翻译质量深度拆解(中/日/阿/印地语实测盲区大曝光)
  • 微服务间的远程接口调用:OpenFeign 的使用
  • 鸿蒙数学 108 篇 第二十八篇:计数体系完整推演
  • MATLAB配电网状态估计算法包:最小二乘+解耦双模型,改参数就能跑不同拓扑
  • 如何用tcc-g15实现戴尔G15散热控制的终极开源替代方案
  • Hermes Agent框架连接Taotoken自定义模型提供商详细步骤
  • 2026专业的杭州酒店花园设计施工公司口碑排行榜 - 品牌排行榜
  • Django+OpenCV人脸采集与比对Web系统(含数据库、媒体资源和完整迁移文件)
  • 2025-2026年维克顿数字能源电话查询:使用前请核实资质与产品适配性 - 品牌推荐
  • 炉石传说HsMod插件:55项实用功能全面优化你的游戏体验
  • 水文极值适线拟合工具:支持6h/12h/24h降雨样本,内置皮III型与极值I型分布
  • Claude架构评审实战指南:7步完成生产级AI系统健壮性评估
  • 仅限首批内测团队获取:DeepSeek官方未公开的移动端Profile模板(含GPU占用热力图+KV Cache命中率实时监控)