格式化输出Structured Output

1.什么是格式化输出

如果您想从 LLM 接收结构化输出,Structured Output 可以协助将 ChatModel/ChatClient 方法的返回类型从 String 更改为其他类型。

LLM 生成结构化输出的能力对于依赖可靠解析输出值的下游应用程序非常重要。开发人员希望快速将 AI 模型的结果转换为可以传递给其他应用程序函数和方法的数据类型,例如 JSON、XML 或 Java 类。Spring AI 结构化输出转换器有助于将 LLM 输出转换为结构化格式。

在 LLM 调用之前,转换器会将期望的输出格式(output format instruction)附加到 prompt 中,为模型提供生成所需输出结构的明确指导,这些指令充当蓝图,塑造模型的响应以符合指定的格式。以下是此类格式说明的示例

java 复制代码
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.

在 LLM 调用之后,转换器获取模型的输出文本并将其转换为结构化类型的实例,此转换过程涉及解析原始文本输出并将其映射到相应的结构化数据表示,例如 JSON、XML 或特定于域的数据结构添加链接描述

2. 新建子模块SAA-07StructuredOutput

其余与前几个子模块中内容大同小异,pom文件中去除lombok,07子模块中使用Record。

2.1. pom文件

xml 复制代码
<?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>
    <parent>
        <groupId>com.hf.hong</groupId>
        <artifactId>SpringAIAlibaba-v1</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>SAA-07StructuredOutput</artifactId>

    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 引入 springai alibaba DashScope 模型适配的 Starter -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        </dependency>
        <!--lombok-->
<!--        <dependency>-->
<!--            <groupId>org.projectlombok</groupId>-->
<!--            <artifactId>lombok</artifactId>-->
<!--            <optional>true</optional>-->
<!--        </dependency>-->
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                    <source>21</source>
                    <target>21</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

2.2. application.properties

yaml 复制代码
server.port=8007

#大模型对话中文乱码UTF8编码处理
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
server.servlet.encoding.charset=UTF-8

spring.application.name=SAA-07StructuredOutput

# ====SpringAIAlibaba Config=============
spring.ai.dashscope.api-key=${aliQwen-api}

2.3.配置类直接复制粘贴

2.4. StuRecord

java 复制代码
package com.hf.hong.entity;

public record StuRecord(String sId,String sName,Integer sAge,String sMajor,String sEmail) {
}

2.5. StructuredOutputController

java 复制代码
package com.hf.hong.controller;

import com.hf.hong.entity.StuRecord;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.function.Consumer;

/**
 * 
 * @author admin
 * @date 2026/3/13 20:39
 * @description: 结构化输出,本代码以Record为例
 */

@RestController
public class StructuredOutputController {
    @Resource(name = "deepseekChatClient")
    private ChatClient deepseekChatClient;
    @Resource(name = "qwenChatClient")
    private ChatClient qwenChatClient;
    @Resource(name = "deepSeekChatModel")
    private ChatModel deepSeekChatModel;


    @GetMapping("/structuredOutput/testRecord")
    public StuRecord testRecord(String sname, String email) {
        return qwenChatClient.prompt()
                .user(new Consumer<ChatClient.PromptUserSpec>() {
                    @Override
                    public void accept(ChatClient.PromptUserSpec promptUserSpec)
                    {
                        promptUserSpec.text("学号001,我叫{sname},今年18,大学专业是计算机科学与技术,邮箱{email}")
                                .param("sname",sname)
                                .param("email",email);
                    }
                }).call().entity(StuRecord.class);
    }

}

3. 测试

bash 复制代码
http://localhost:8007/structuredOutput/testRecord?sname=%E5%B0%8F%E7%94%9F%E4%B8%8D%E6%89%8D&email=hst14**@163.com

切换lambda版

java 复制代码
    @GetMapping("/structuredOutput/testRecord2")
    public StuRecord testRecord2(@RequestParam(name = "sname") String sname, @RequestParam(name = "email") String email) {
        String stringTemplate = """
                学号002,我叫{sname},大学专业是软件工程,邮箱{email}
                """;
        return qwenChatClient.prompt()
                .user(promptUserSpec -> promptUserSpec.text(stringTemplate)
                        .param("sname",sname)
                        .param("email",email))
                .call()
                .entity(StuRecord.class);
    }
}

测试

bash 复制代码
http://localhost:8007/structuredOutput/testRecord2?sname=%E5%B0%8F%E7%94%9F%E4%B8%8D%E6%89%8D&email=hst14**@163.com

4. 完整代码

java 复制代码
package com.hf.hong.controller;

import com.hf.hong.entity.StuRecord;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.function.Consumer;

/**
 *
 * @author admin
 * @date 2026/3/13 20:39
 * @description: 结构化输出,本代码以Record为例
 */

@RestController
public class StructuredOutputController {
    @Resource(name = "deepseekChatClient")
    private ChatClient deepseekChatClient;
    @Resource(name = "qwenChatClient")
    private ChatClient qwenChatClient;
    @Resource(name = "deepSeekChatModel")
    private ChatModel deepSeekChatModel;


    @GetMapping("/structuredOutput/testRecord")
    public StuRecord testRecord(String sname, String email) {
        return qwenChatClient.prompt()
                .user(new Consumer<ChatClient.PromptUserSpec>() {
                    @Override
                    public void accept(ChatClient.PromptUserSpec promptUserSpec)
                    {
                        promptUserSpec.text("学号001,我叫{sname},今年18,大学专业是计算机科学与技术,邮箱{email}")
                                .param("sname",sname)
                                .param("email",email);
                    }
                }).call().entity(StuRecord.class);
    }

    @GetMapping("/structuredOutput/testRecord2")
    public StuRecord testRecord2(@RequestParam(name = "sname") String sname, @RequestParam(name = "email") String email) {
        String stringTemplate = """
                学号002,我叫{sname},大学专业是软件工程,邮箱{email}
                """;
        return qwenChatClient.prompt()
                .user(promptUserSpec -> promptUserSpec.text(stringTemplate)
                        .param("sname",sname)
                        .param("email",email))
                .call()
                .entity(StuRecord.class);
    }
}
相关推荐
还是鼠鼠6 天前
Spring AI ChatClient详解:创建第一个AI客户端
java·springboot·spring ai·chatclient
还是鼠鼠6 天前
Spring AI连接DeepSeek与通义千问:application.yaml配置详解
java·通义千问·spring ai·deepseek
中间件XL6 天前
ai-agent框架spring ai/alibaba 原理源码分析(十)沙箱
沙箱·ai agent·智能体·spring ai·spring ai graph
还是鼠鼠9 天前
【Spring AI智能体实战 02】Spring Boot 3.4整合Spring AI:项目创建与依赖配置
java·人工智能·spring boot·maven·spring ai
还是鼠鼠10 天前
【Spring AI智能体实战 01】Java开发者接入大模型:国内平台、Token与API Key入门
java·大模型·spring ai·deepseek·阿里云百炼
默辨12 天前
Spring AI Alibaba 核心知识点
java·ai·spring ai·spring alibaba
Muscleheng15 天前
Spring Boot 3.x 集成 DeepSeek 实现 Function Calling(工具调用)
人工智能·spring boot·后端·ai·spring ai·deepseek
佛祖让我来巡山16 天前
SpringAI保姆级实战教程
spring ai·springai·springai教程·springai入门
BerryS3N16 天前
Java 后端转型大模型:Demo 能跑不等于能上线
java·人工智能·python·java后端·spring ai·langchain4j·大模型转型
lichuangcsdn18 天前
【Spring AI 学习(三)】实现简单的对话
java·人工智能·学习·spring·spring ai