一、前言

Spring AI 提供跨 AI 供应商(如 OpenAI、Hugging Face 等)的一致性 API, 通过分装的ChatModelChatClient即可轻松调动LLM进行流式或非流式对话。

本专栏主要围绕着通过OpenAI兼容接口调用各种大语言模型展开学习(因为大部分模型都兼容OpenAI方式调用接口),本篇文章目标:探索Spring AI的结构化输出,即将 LLM 的非结构化文本输出转换为结构化数据(如 Java 对象、Map、List 或 JSON)

二、转化器Converter概述

2.1 核心作用

在调用 LLM 之前,转换器将格式指令附加到提示中,为模型提供明确的指导,以生成所需的输出结构。这些指令充当蓝图,塑造模型的响应以符合指定的格式。

在 LLM 调用后,转换器将模型的输出文本转换为结构化类型的实例。此转换过程涉及解析原始文本输出并将其映射到相应的结构化数据表示形式,例如 JSON、XML 或特定领域的数据结构。

2.2 数据流向

PS : 转换器有点类似Java中的AOP(拦截器)的作用,在调用LLM前注入结构化指令,在调用LLM后将非结构化文本后转换成指定的结构化输出!

2.3 三大核心转换器对比

Spring AI通过三大核心转换器实现将LLM的响应响应转成特定的结构化输出!

三、代码

3.1 项目依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.better</groupId><artifactId>spring-ai-parent</artifactId><version>1.0-SNAPSHOT</version><packaging>pom</packaging><modules><module>models/chat/chat-openai-deepseek</module></modules><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.4.5</version><relativePath/></parent><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-openai</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>2.0.57</version></dependency></dependencies><!--Spring AI模块的依赖版本管理--><dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><!--正式生产版本:1.0.0 GA(2025年5月20日发布)是首个稳定且支持生产环境的版本,ChatClient 成为官方推荐的核心 API--><version>1.0.0</version> <!-- GA 版本 --><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement></project>

3.2 配置yml

server:port: 8321
spring:ai:openai:base-url: https://api.deepseek.comapi-key: ${OPENAI_API_KEY}chat:options:model: deepseek-chat  # 可选模型:deepseek-chat/deepseek-reasonertemperature: 0.6      # 响应随机性控制,默认值

3.3 Bean对象转换器

    @GetMapping("/chat/bean")BookInfo chatBeanOutput(String author) {var userPromptTemplate = """告诉我作者{author}最有名的书名.""";BookInfo bookInfo = chatClient.prompt().user(userSpec -> userSpec.text(userPromptTemplate).param("author", author)).call().entity(BookInfo.class);log.info("LLM响应结果:{}", JSONObject.toJSONString(bookInfo));return bookInfo;}

执行结果:

3.4 Map转换器

    @GetMapping("/chat/map")Map<String,Object> chatMapOutput() {Map<String, Object> result = chatClient.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>>() {});log.info("LLM响应结果:{}", JSONObject.toJSONString(result));return result;}

执行结果:

3.5 List转换器

    @GetMapping("/chat/list")List<String> chatListOutput() {List<String> flavors = chatClient.prompt().user(u -> u.text("List five {subject}").param("subject", "李笑来写的书")).call().entity(new ListOutputConverter(new DefaultConversionService()));log.info("LLM响应结果:{}", JSONObject.toJSONString(flavors));return flavors;}

执行结果:

3.6 完整代码

package com.better.springai.structured_output;import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.converter.ListOutputConverter;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;
import java.util.Map;/*** 高级封装ChatClient*/
@RestController
@Slf4j
class StructuredOutputController {private final ChatClient chatClient;StructuredOutputController(ChatClient.Builder chatClientBuilder) {this.chatClient = chatClientBuilder.build();}/*** 结构化输出-转成Bean对象* @param author* return com.better.springai.structured_output.BookInfo* @author luchuyan* @time 2025/7/23 8:33**/@GetMapping("/chat/bean")BookInfo chatBeanOutput(String author) {var userPromptTemplate = """告诉我作者{author}最有名的书名.""";BookInfo bookInfo = chatClient.prompt().user(userSpec -> userSpec.text(userPromptTemplate).param("author", author)).call().entity(BookInfo.class);log.info("LLM响应结果:{}", JSONObject.toJSONString(bookInfo));return bookInfo;}/*** 结构化输出-转成Map* return java.util.Map<java.lang.String,java.lang.Object>* @author luchuyan* @time 2025/7/23 8:34**/@GetMapping("/chat/map")Map<String,Object> chatMapOutput() {Map<String, Object> result = chatClient.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>>() {});log.info("LLM响应结果:{}", JSONObject.toJSONString(result));return result;}/*** 结构化输出-转成List* return java.util.List<java.lang.String>* @author luchuyan* @time 2025/7/23 8:34**/@GetMapping("/chat/list")List<String> chatListOutput() {List<String> flavors = chatClient.prompt().user(u -> u.text("List five {subject}").param("subject", "李笑来写的书")).call().entity(new ListOutputConverter(new DefaultConversionService()));log.info("LLM响应结果:{}", JSONObject.toJSONString(flavors));return flavors;}}

3.7 一定能结构化输出吗?

能不能转成指定的结构化输出主要还要看LLM的能力,如调用DeepSeek的推理模型一般就比调用非推理模型的效果好些,较大参数的模型比较少的好些 (如Qwen32B比Qwen7B好些~)。

在我们的业务中调用本地部署的Qwen2-7B模型,尽管在Prompt中要求模型按JSON结构化输出,但往往不能如期所愿(非完整JSON格式导致解析时异常,如缺少了花括弧、带了一些特殊字符等),我们的一个解决方案是再调一次腾讯元的混元模型进行修复,通过混元模型基本都能修复成正常的JSON!

四、参考资料

4.1 Spring AI官网文档

  • Structured Output Converter :: Spring AI Reference

最后:如果文章对你有帮助,别忘了点赞支持一下,谢谢~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/90578.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/90578.shtml
英文地址,请注明出处:http://en.pswp.cn/web/90578.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Data Redis 从入门到精通:原理与实战指南

一、Redis 基础概念 Redis&#xff08;Remote Dictionary Server&#xff09;是开源的内存键值对数据库&#xff0c;以高性能著称。它支持多种数据结构&#xff08;String、Hash、List、Set、ZSet&#xff09;&#xff0c;并提供持久化机制&#xff08;RDB、AOF&#xff09;。 …

免费版酒店押金原路退回系统——仙盟创梦IDE

项目介绍​东方仙盟开源酒店押金管理系统是一款面向中小型酒店、民宿、客栈的轻量级前台管理工具&#xff0c;专注于简化房态管理、订单处理和押金跟踪流程。作为完全开源的解决方案&#xff0c;它无需依赖任何第三方服务&#xff0c;所有数据存储在本地浏览器中&#xff0c;确…

10. isaacsim4.2教程-RTX Lidar 传感器

1. 前言RTX Lidar 传感器Isaac Sim的RTX或光线追踪Lidar支持通过JSON配置文件设置固态和旋转Lidar配置。每个RTX传感器必须附加到自己的视口或渲染产品&#xff0c;以确保正确模拟。重要提示&#xff1a; 在运行RTX Lidar仿真时&#xff0c;如果你在Isaac Sim UI中停靠窗口&…

QT6 源,七章对话框与多窗体(14)栈式窗体 QStackedWidget:本类里代码很少。举例,以及源代码带注释。

&#xff08;1&#xff09;这不是本章节要用到的窗体组件&#xff0c;只是跟着标签窗体 QTabWidget 一起学了。这也是 QT 的 UI 界面里的最后几个容器了。而且本类也很简单。就了解一下它。 本类的继承关系如下 &#xff1a; UI 设计界面 &#xff1a;运行效果 &#xff1a;&…

魔百和M401H_国科GK6323V100C_安卓9_不分地区免拆卡刷固件包

魔百和M401H_国科GK6323V100C_安卓9_不分地区免拆卡刷固件包刷机说明&#xff1a;1&#xff0c;进机顶盒设置&#xff08;密码10086&#xff09;&#xff0c;在其他里&#xff0c;一直按左键约32下&#xff0c;打开调试模式2&#xff0c;进网络设置&#xff0c;查看IP地址。3&a…

MySQL基础02

一. 函数在 MySQL 中&#xff0c;函数是用于对数据进行特定处理或计算的工具&#xff0c;根据作用范围和返回结果的不同&#xff0c;主要分为单行函数和聚合函数&#xff08;又称分组函数&#xff09;。以下是详细介绍&#xff1a;1.单行函数单行函数对每一行数据单独处理&…

LabVIEW 视觉检测SIM卡槽

针对SIM 卡槽生产中人工检测效率低、漏检误检率高的问题&#xff0c;设计了基于 LabVIEW 机器视觉的缺陷检测系统。该系统通过光学采集与图像处理算法&#xff0c;实现对卡槽引脚折弯、变形、漏铜等缺陷的自动检测&#xff0c;误报率为 0&#xff0c;平均检测时间小于 750ms&am…

RocketMQ5.3.1的安装

1、下载安装 RocketMQ 的安装包分为两种&#xff0c;二进制包和源码包。1 下载 Apache RocketMQ 5.3.1的源码包后上传到linux https://dist.apache.org/repos/dist/release/rocketmq/5.3.1/rocketmq-all-5.3.1-source-release.zip2 解压编译 $ unzip rocketmq-all-5.3.1-source…

FunASR实时多人对话语音识别、分析、端点检测

核心功能&#xff1a;FunASR是一个基础语音识别工具包&#xff0c;提供多种功能&#xff0c;包括语音识别&#xff08;ASR&#xff09;、语音端点检测&#xff08;VAD&#xff09;、标点恢复、语言模型、说话人验证、说话人分离和多人对话语音识别等。FunASR提供了便捷的脚本和…

opencv--day01--opencv基础知识及基础操作

文章目录前言一、opencv基础知识1.opencv相关概念1.1背景1.2特点1.3主要功能与应用1.4.opencv-python2.计算机中的图像概念2.1图像表示2.2图像存储彩色图像二、opencv基础操作1.图像的读取2.图像的显示3.保存图像4.创建黑白图及随机像素彩图5. 图像切片&#xff08;图片剪裁&am…

如何撤销Git提交误操作

要撤销在主分支上的 git add . 和 git commit 操作&#xff0c;可以按照以下步骤安全回退&#xff1a; 完整回退步骤&#xff1a; # 1. 查看提交历史&#xff0c;确认要回退的commit git log --oneline# 示例输出&#xff1a; # d3f4g7h (HEAD -> main) 误操作提交 # a1b2c3…

React+Three.js实现3D场景压力/温度/密度分布可视化

本文介绍了一个基于React和Three.js的3D压力可视化解决方案&#xff0c;该方案能够&#xff1a; 加载并渲染3D压力模型数据 提供动态颜色映射功能&#xff0c;支持多种颜色方案&#xff1a;彩虹-rainbow,冷暖-cooltowarm,黑体-blackbody,灰度-grayscale 实现固定位置的颜色图…

Go 官方 Elasticsearch 客户端 v9 快速上手与进阶实践*

1、为什么选择 go-elasticsearch&#xff1f; 版本同步&#xff1a;与 Elasticsearch 主版本保持一一映射&#xff0c;当前稳定分支为 v9&#xff0c;对应 ES 9.x 系列。(GitHub)完全覆盖 REST API&#xff1a;所有 HTTP 端点都有等价方法&#xff0c;避免手写 JSON/HTTP。可插…

`/etc/samba/smb.conf`笔记250720

/etc/samba/smb.conf笔记250720 /etc/samba/smb.conf 是 Samba 服务的核心配置文件&#xff0c;用于实现 Linux/Unix 与 Windows 系统间的文件和打印机共享。以下详解其结构和常用参数&#xff1a; 配置文件结构 1. 全局设置段 [global] 控制 Samba 服务器的整体行为。 …

Java从入门到精通!第十六天,重点!(多线程和线程池)

一、多线程1&#xff0e;基本概念&#xff08;1&#xff09;程序&#xff08;Program&#xff09;&#xff1a;为了完成特定的任务&#xff0c;用某种计算机语言编写的一组指令的集合&#xff0c;即指一段静态的代码&#xff08;源代码经编译之后形成的二进制格式的文件&#x…

轨道交通为什么要有信号系统?

轨道交通为什么要有信号系统&#xff1f;轨道交通信号系统与公路信号系统有什么不同&#xff1f; 在轨道交通中信号系统是必不可少的&#xff0c;其根本原因在于&#xff1a;在轨道交通中已经没有办法纯靠人力去保证行车安全。 在公路交通中&#xff0c;信号其实是起辅助作用的…

docker 挂载卷

以下是针对您遇到的问题分步解答和解决方案&#xff1a;一、核心结论 ✅ 可以采用目录方式&#xff1a;您的命令中的 -v /root/nginx05-vol/:/usr/share/nginx/html/ 是正确的目录挂载语法。 ❌ 看不到新文件的可能原因主要集中在 权限问题、缓存机制 或 操作顺序错误 上。二、…

uniapp 报错 Not found ... at view.umd.min.js:1的问题

问题描述&#xff1a; uniapp的app中&#xff0c;当页面中使用多个v-if后会出现这个报错解决方案&#xff1a; 1、在v-if的地方加上key属性&#xff08;key属性要保证唯一&#xff09; 2、用v-show替换v-if&#xff08;不建议&#xff0c;可能会影响业务&#xff09;

水电站自动化升级:Modbus TCP与DeviceNet的跨协议协同应用

水电站的自动化系统就像一个精密的“神经中枢”&#xff0c;既要应对水流变化带来的动态负载&#xff0c;又得保证闸门启闭、水轮机调节等关键动作的精准性。我们去年参与的某水电站改造项目里&#xff0c;就遇到了一个典型问题&#xff1a;中控室的施耐德PLC采用Modbus TCP协议…

基于Matlab图像处理的火灾检测系统设计与实现

随着计算机视觉技术的快速发展&#xff0c;基于图像处理的火灾检测系统在安全监控领域的应用得到了广泛关注。本文提出了一种基于图像处理的火灾检测系统&#xff0c;该系统通过对图像进行预处理、颜色空间转换、阈值化处理和形态学分析&#xff0c;自动检测火灾疑似区域。首先…