当前位置: 首页 > 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.jsqmd.com/news/908415/

相关文章:

  • 从打电话、对讲机到广播:用生活例子秒懂通信的‘单工、半双工、全双工’
  • Deepoc开发板:智能轮椅动态协同的VLA实现解析
  • 脑机接口在游戏中的应用:从生物信号到沉浸式交互
  • 别再傻傻分不清!用UART、SPI、CAN这些协议实例,5分钟搞懂同步/异步与单/双工
  • CentOS 7.6安装避坑指南:VMware里选NAT还是桥接?磁盘分区怎么设才不浪费空间?
  • 湖州市2026年最新黄金回收靠谱门店推荐 黄金+K金+白银+铂金回收门店TOP5排行榜+联系方式 - 大熊猫898989
  • GPT-4编程能力解析:从原理到实战的人机协作工作流
  • 在VirtualBox里给RHEL 7.9装NBU 8.1.1,我踩过的那些坑都帮你填平了
  • MacBook上玩转国民技术N32G430:从零搭建ARM开发环境(含VSCode配置)
  • AI智能体正在如何改变物流行业
  • 别再混淆了!用Python的sklearn手把手教你算多分类的精确率、召回率(附完整代码与常见误区)
  • 从理论到代码:手把手教你用MATLAB验证Eb/N0与SNR转换公式(附完整仿真脚本)
  • 别再死记硬背递归了!从‘士兵淘汰’游戏带你真正理解递归思想
  • AI 时代全栈升级路线
  • 保姆级教程:用PFC 7.0搞定岩土双轴压缩模拟(从参数化建模到伺服加载)
  • 梦饷科技蝉联BCMM评估咨询服务机构权威资质 领跑商业数字化转型赋能赛道
  • 告别YOLO!RT-DETR2保姆级部署教程:从论文到T4 GPU实战,114FPS真香了
  • cad文件在线查看
  • 从开源PCV到自研工具:一个嵌入式工程师的点云软件实战复盘(含完整CMake配置)
  • 从DBC文件到AUTOSAR COM信号映射:手把手教你用ISOLAR实现自动化配置与集成
  • 一个人在长沙,怎么过一个有质感的周末?
  • 50行Python手搓一个原生AI Agent:彻底看懂智能体的本质
  • 高强度螺栓怎么选?从强度等级到应用场景,六月上海紧固件专业展
  • Smoothieware固件配置项探秘:手把手教你通过Code Review定位隐藏参数(如mm_per_arc_segment)
  • 搞定7nm DRC收敛:一份给Innovus和ICC2用户的联合调试备忘录
  • AI时代数据管道设计:从ETL到MLOps的现代化实践
  • MATLAB机器人控制器仿真代码包:从建模、设计到响应验证的一站式实现
  • 从关键词匹配到任务理解:Agent 意图识别的五代技术演进
  • 如何快速掌握BepInEx:Unity游戏模组开发的终极框架指南
  • 26个摄影实战故事:从新手到高手的避坑指南与创作心法