行业资讯 2025年08月6日
0 收藏 0 点赞 404 浏览 8451 个字
摘要 :

文章目录 一、准备工作 二、Spring AI中MapOutputConverter的使用示例 三、Spring AI中ListOutputConverter的使用示例 四、Spring AI中BeanOutputConverter的使用示例 ……




  • 一、准备工作
  • 二、Spring AI中MapOutputConverter的使用示例
  • 三、Spring AI中ListOutputConverter的使用示例
  • 四、Spring AI中BeanOutputConverter的使用示例
  • 五、总结

在Spring AI的开发场景中,和大语言模型(LLM)交互时,经常会遇到需要将模型输出转换为特定结构化格式的需求。本文就聚焦于此,详细介绍Spring AI提供的MapOutputConverterListOutputConverterBeanOutputConverter这三个内置类,它们能帮助我们将LLM的输出转化为列表、映射或Java Bean定义的复杂结构,还会结合实际示例,教大家如何使用这些转换器来实现结构化输出。Spring AI结构化输出转换器:List、Map和Bean的应用详解

一、准备工作

在运行代码之前,有两个关键步骤需要完成。首先是设置OpenAPI项目密钥,要把它设为环境变量,让应用程序能从环境变量中读取。比如在终端里,可以通过下面这条命令来设置(其中[api_key_copied_from_openai_site]需要替换成从OpenAI网站复制的真实密钥):

export OPENAI_API_KEY=[api_key_copied_from_openai_site]

然后在项目的application.properties文件里,就可以这样引用这个API密钥:

spring.ai.openai.api-key=${OPENAI_API_KEY}

接下来,要添加与我们交互的LLM相关的Maven依赖。在这个示例里,我们使用OpenAI的ChatGPT,所以需要在项目里添加下面这个依赖:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>

如果想了解完整的设置步骤,可以参考Spring AI教程。

二、Spring AI中MapOutputConverter的使用示例

MapOutputConverter类的作用是,让提示要求LLM以符合RFC8259标准的JSON格式输出,并且输出的结构要是java.util.HashMap类型。等LLM返回响应后,这个转换器会把JSON格式的响应解析出来,填充到Map实例里。

MapOutputConverter的工作方式是,在用户消息后面追加一段固定文本,以此来要求特定的格式。我们可以查看MapOutputConverter类的源代码,或者调用它的toFormat()方法,就能看到这段固定文本。下面是MapOutputConverter类里getFormat()方法的代码:

public class MapOutputConverter extends AbstractMessageOutputConverter<Map<String, Object>> {
    //...
    @Override
    public String getFormat() {
        String raw = \"\"\"
                Your response should be in JSON format.
                The data structure for the JSON should match this Java class: %s
                Do not include any explanations, only provide a RFC8259 compliant JSON response following this format without deviation.
                \"\"\";
        return String.format(raw, HashMap.class.getName());
    }
}

在下面这个例子里,我们给程序提供一个国家列表,然后让LLM以Map格式返回每个国家及其首都的信息。

import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.prompt.Prompt;
import org.springframework.ai.prompt.PromptTemplate;
import org.springframework.ai.response.MapOutputConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;

// 定义一个RestController,用于处理HTTP请求
@RestController 
public class CountryCapitalController {
    // 注入ChatClient实例,用于和LLM交互
    @Autowired 
    private ChatClient chatClient; 

    // 处理GET请求,路径为/country-capital-service/map
    @GetMapping(\"/country-capital-service/map\") 
    public Map<String, Object> getCapitalNamesInMap(@RequestParam String countryNamesCsv) {
        // 检查传入的国家名称CSV字符串是否为空
        if (countryNamesCsv == null || countryNamesCsv.isEmpty()) {
            // 如果为空,抛出异常
            throw new IllegalArgumentException(\"Country names CSV cannot be null or empty\"); 
        }
        // 创建MapOutputConverter实例
        MapOutputConverter converter = new MapOutputConverter(); 
        // 获取要求的格式文本
        String format = converter.getFormat(); 

        // 创建提示模板对象
        PromptTemplate pt = new PromptTemplate(\"For these list of countries {countryNamesCsv}, return the list of capitals. {format}\"); 
        // 根据传入的参数和格式,渲染提示
        Prompt renderedPrompt = pt.create(Map.of(\"countryNamesCsv\", countryNamesCsv, \"format\", format)); 

        // 调用ChatClient发送提示,获取响应
        ChatResponse response = chatClient.call(renderedPrompt); 
        // 获取响应结果
        Generation generation = response.getResult(); 
        // 解析响应内容,返回Map对象
        return converter.parse(generation.getOutput().getContent()); 
    }
}

当API收到请求后,会把countryNamesCsv替换为传入的国家列表,把format替换为MapOutputConvertergetFormat()方法返回的固定文本,从而准备好最终的提示。LLM返回的响应,以及API最终返回的内容,都是Map格式的JSON输出。比如,我们访问http://localhost:8080/country-capital-service/map?countryNamesCsv=India, USA, Canada, Israel,得到的响应可能是这样:

{
    \"Canada\": \"Ottawa\",
    \"USA\": \"Washington D.C.\",
    \"Israel\": \"Jerusalem\",
    \"India\": \"New Delhi\"
}

Spring AI结构化输出转换器:List、Map和Bean的应用详解

三、Spring AI中ListOutputConverter的使用示例

ListOutputConverter类的工作原理和MapOutputConverter类似,不过它是让提示要求LLM以逗号分隔值的列表形式输出。之后,Spring AI会借助Jackson把这些CSV值解析成List。下面是ListOutputConverter类里getFormat()方法的代码:

public class ListOutputConverter extends AbstractConversionServiceOutputConverter<List<String>> {
    //...
    @Override
    public String getFormat() {
        return \"\"\"
                Your response should be a list of comma separated values
                eg: `foo, bar, baz`
                \"\"\";
    }
}

在下面这个例子里,我们同样提供一个国家列表,这次要求LLM以列表形式返回这些国家的首都。

import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.prompt.Prompt;
import org.springframework.ai.prompt.PromptTemplate;
import org.springframework.ai.response.ListOutputConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

// 定义一个RestController,用于处理HTTP请求
@RestController 
public class CountryCapitalListController {
    // 注入ChatClient实例,用于和LLM交互
    @Autowired 
    private ChatClient chatClient; 

    // 处理GET请求,路径为/country-capital-service/list
    @GetMapping(\"/country-capital-service/list\") 
    public List<String> getCapitalNamesInList(@RequestParam String countryNamesCsv) {
        // 检查传入的国家名称CSV字符串是否为空
        if (countryNamesCsv == null || countryNamesCsv.isEmpty()) {
            // 如果为空,抛出异常
            throw new IllegalArgumentException(\"Country names CSV cannot be null or empty\"); 
        }
        // 创建ListOutputConverter实例,传入DefaultConversionService
        ListOutputConverter converter = new ListOutputConverter(new DefaultConversionService()); 
        // 获取要求的格式文本
        String format = converter.getFormat(); 

        // 创建提示模板对象
        PromptTemplate pt = new PromptTemplate(\"For these list of countries {countryNamesCsv}, return the list of capitals. {format}\"); 
        // 根据传入的参数和格式,渲染提示
        Prompt renderedPrompt = pt.create(Map.of(\"countryNamesCsv\", countryNamesCsv, \"format\", format)); 

        // 调用ChatClient发送提示,获取响应
        ChatResponse response = chatClient.call(renderedPrompt); 
        // 获取响应结果
        Generation generation = response.getResult(); 
        // 解析响应内容,返回List对象
        return converter.parse(generation.getOutput().getContent()); 
    }
}

LLM返回的响应是CSV格式的普通字符串,比如:

New Delhi, Washington D.C., Ottawa, Jerusalem

然后,程序会用converter.parse()方法把这个CSV字符串解析成java.util.List。我们可以通过访问http://localhost:8080/country-capital-service/list?countryNamesCsv=India, USA, Canada, Israel来测试这个API,得到的响应可能是这样:

[
    \"New Delhi\",
    \"Washington D.C.\",
    \"Ottawa\",
    \"Jerusalem\"
]

Spring AI结构化输出转换器:List、Map和Bean的应用详解

四、Spring AI中BeanOutputConverter的使用示例

BeanOutputConverter类主要用于让LLM以和Java POJO匹配的JSON格式和结构返回响应,保证LLM响应里的字段和指定Java Bean里的字段是兼容的。在下面这个BeanOutputConverter类的getFormat()方法里,会根据提供的Java Bean类生成JSON模式。

public class BeanOutputConverter<T> implements StructuredOutputConverter<T> {
    //...
    @Override
    public String getFormat() {
        String template = \"\"\"
                Your response should be in JSON format.
                Do not include any explanations, only provide a RFC8259 compliant JSON response following this format without deviation.
                Do not include markdown code blocks in your response.
                Remove the ```json markdown from the output.
                Here is the JSON Schema instance your output must adhere to:
                ```%s```
                \"\"\";
        return String.format(template, this.jsonSchema);
    }
}

来看另一个例子,在这个例子里,我们传入一个国家名称,让LLM返回这个国家最受欢迎的10个城市,并且响应要遵循下面这个Java Bean的结构:

// 定义一个记录类Pair,包含国家名称和城市列表两个字段
public record Pair(String countryName, List<String> cities) {} 

下面看看如何使用BeanOutputConverter来设置提示并解析收到的响应:

import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.prompt.Prompt;
import org.springframework.ai.prompt.PromptTemplate;
import org.springframework.ai.response.BeanOutputConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

// 定义一个RestController,用于处理HTTP请求
@RestController 
public class CountryCitiesController {
    // 注入ChatClient实例,用于和LLM交互
    @Autowired 
    private ChatClient chatClient; 

    // 处理GET请求,路径为/country-capital-service/bean
    @GetMapping(\"/country-capital-service/bean\") 
    public Pair getCapitalNamesInPojo(@RequestParam String countryName) {
        // 创建BeanOutputConverter实例,指定要转换的目标类型为Pair
        BeanOutputConverter<Pair> converter = new BeanOutputConverter(Pair.class); 
        // 获取要求的格式文本
        String format = converter.getFormat(); 

        // 创建提示模板对象
        PromptTemplate pt = new PromptTemplate(\"For these list of countries {countryName}, return the list of its 10 popular cities. {format}\"); 
        // 根据传入的参数和格式,渲染提示
        Prompt renderedPrompt = pt.create(Map.of(\"countryName\", countryName, \"format\", format)); 

        // 调用ChatClient发送提示,获取响应
        ChatResponse response = chatClient.call(renderedPrompt); 
        // 获取响应结果
        Generation generation = response.getResult(); 
        // 解析响应内容,返回Pair对象
        return converter.parse(generation.getOutput().getContent()); 
    }
}

我们可以通过访问http://localhost:8080/country-capital-service/bean?countryName=USA来验证生成的响应,得到的响应可能是这样:

{
    \"countryName\": \"USA\",
    \"cities\": [
        \"New York City\",
        \"Los Angeles\",
        \"Chicago\",
        \"Houston\",
        \"Phoenix\",
        \"Philadelphia\",
        \"San Antonio\",
        \"San Diego\",
        \"Dallas\",
        \"San Jose\"
    ]
}

Spring AI结构化输出转换器:List、Map和Bean的应用详解

五、总结

在这篇Spring AI教程里,我们详细了解了LLM的输出并不总是非结构化文本,很多时候需要它以固定格式返回内容,这时候MapOutputConverterListOutputConverterBeanOutputConverter这些结构化输出转换器就派上用场了。建议大家多去尝试使用这些API,用不同的格式请求输出,这样能更好地理解和掌握它们的用法。希望大家在学习和实践中不断积累经验,在Spring AI开发中更上一层楼!如果有任何问题,欢迎一起交流探讨。

归属教程 Spring AI 快速入门教程汇总

文章目录 Spring AI是什么?有啥优势? 如何在项目中使用Spring AI? Spring AI详细功 […]

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/10265.html

管理员

相关推荐
2025-08-06

文章目录 一、Reader 接口概述 1.1 什么是 Reader 接口? 1.2 Reader 与 InputStream 的区别 1.3 …

988
2025-08-06

文章目录 一、事件溯源 (一)核心概念 (二)Kafka与Golang的优势 (三)完整代码实现 二、命令…

465
2025-08-06

文章目录 一、证明GC期间执行native函数的线程仍在运行 二、native线程操作Java对象的影响及处理方…

348
2025-08-06

文章目录 一、事务基础概念 二、MyBatis事务管理机制 (一)JDBC原生事务管理(JdbcTransaction)…

456
2025-08-06

文章目录 一、SnowFlake算法核心原理 二、SnowFlake算法工作流程详解 三、SnowFlake算法的Java代码…

517
2025-08-06

文章目录 一、本地Jar包的加载操作 二、本地Class的加载方法 三、远程Jar包的加载方式 你知道Groo…

832
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号