恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

第五篇:结构化输出——让 AI 返回类型安全的 Java 对象

  • 首页
  • 资讯中心
  • /
  • 第五篇:结构化输出——让 AI 返回类型安全的 Java 对象

相关资讯

Python3.10自然语言处理项目:HuggingFace+镜像部署教程 2026/8/25 14:50:00
Python:商品期货布林指标突破策略 2026/8/25 14:50:00
中国技术大败局TBL-20260809-043深度解剖报告V2.1 决策迭代版 2026/8/25 14:50:00

最新资讯

【好靶场】PHP反序列化绕过
谈谈Flutter中的Key(二)——常用的Key
Go实战:实时推送系统设计
Python HTTPX 超时不是一个数字:连接池、重试与可观测性排障实战
MSSQL 手册
关于LeetCode第9题的题解

今日推荐

三步把QQ空间历史说说导出到本地:GetQzonehistory 极简指南
洛谷 P7912:[CSP-J 2021 T4] 小熊的果篮 ← 双向链表
Transformers.js 网页端图像抠图实战:零后端 3 行代码返回透明 PNG

本周热门

Nextcloud 桌面客户端:把同步交给它,你只管改文件
如何将 HTML 转成 Word 文档且格式不丢失?html-to-docx 使用教程
Anki 批量操作卡片完整指南:一次搞定上千张,不再逐张修改

本月精选

如何用DamaiHelper实现演唱会门票的智能自动化抢购:完整技术解决方案指南
第4篇:59 倍性能差距的索引瓶颈定位——一次教科书级的全表扫描调优
终极歌词批量下载神器:5分钟解决离线音乐库歌词同步难题

第五篇:结构化输出——让 AI 返回类型安全的 Java 对象

发布时间:2026/8/25 14:55:00
第五篇:结构化输出——让 AI 返回类型安全的 Java 对象 一、前言前四篇我写的所有接口返回的都是字符串。AI 说什么我就原样返回什么。但在真实项目中我们很少直接把 AI 的回复扔给前端。更常见的需求是从回复中提取某个字段做业务路由把回复持久化到数据库根据结果做分支判断这就需要把 AI 返回的文本转换成类型化的 Java 对象。Spring AI 提供了entity()方法来实现这个能力。在幕后Spring AI 做了三件事模式生成器将您的WeatherInfo记录转换为 JSON 模式该模式被附加到提示的系统上下文中模型的 JSON 答案被传递给类型转换器该转换器将其解析回您的记录。这篇博客通过五个接口逐个拆解结构化输出的五种用法。二、准备工作沿用第一篇的项目结构和 POM 配置。2.1 配置文件spring: ai: openai: base-url: https://api.deepseek.com/v1 api-key: ${DEEPSEEK_API_KEY} chat: options: model: deepseek-chat三、定义返回类型在com.yoyo.demo.dto包下创建两个 POJO 类。3.1 WeatherInfo天气信息package com.yoyo.demo.dto; /** 城市天气信息 */ public class WeatherInfo { private String city; private String date; private double temperature; private String condition; private int humidity; // 无参构造器必须Jackson 反序列化需要 public WeatherInfo() {} public String getCity() { return city; } public void setCity(String city) { this.city city; } public String getDate() { return date; } public void setDate(String date) { this.date date; } public double getTemperature() { return temperature; } public void setTemperature(double temperature) { this.temperature temperature; } public String getCondition() { return condition; } public void setCondition(String condition) { this.condition condition; } public int getHumidity() { return humidity; } public void setHumidity(int humidity) { this.humidity humidity; } }3.2 AttractionInfo景点信息package com.yoyo.demo.dto; import java.util.List; /** 旅游景点推荐 */ public class AttractionInfo { private String name; private String city; private String description; private double rating; private ListString tips; // 无参构造器必须 public AttractionInfo() {} public String getName() { return name; } public void setName(String name) { this.name name; } public String getCity() { return city; } public void setCity(String city) { this.city city; } public String getDescription() { return description; } public void setDescription(String description) { this.description description; } public double getRating() { return rating; } public void setRating(double rating) { this.rating rating; } public ListString getTips() { return tips; } public void setTips(ListString tips) { this.tips tips; } }四、五种结构化输出用法详解4.1 用法一基础结构化输出——返回单个 Java 对象4.1.1 代码/** * 用法一基础结构化输出 * 返回单个 Java 对象 * * 场景查询某个城市的天气预报 * 接口GET /structured/weather?city北京 */ GetMapping(/weather) public WeatherInfo getWeather(RequestParam(defaultValue 北京) String city) { return chatClient.prompt() .user(请生成 city 今天的天气预报。返回城市名称、日期、温度、天气状况和湿度。) .call() .entity(WeatherInfo.class); }4.1.2 逐行拆解代码作用chatClient.prompt()创建一个新的 Prompt 构建器.user(请生成 city 今天的天气预报...)设置用户消息告诉 AI 要做什么.call()发起同步调用等待模型返回完整响应.entity(WeatherInfo.class)将模型返回的 JSON 反序列化为WeatherInfo对象4.1.3 调用与结果请求GET http://localhost:8080/structured/weather?city北京返回{ city: 北京, date: 2026-08-22, temperature: 30.5, condition: 晴, humidity: 47 }在 Java 代码中使用WeatherInfo weather getWeather(北京); String city weather.getCity(); // 北京 double temp weather.getTemperature(); // 30.5 String condition weather.getCondition(); // 晴4.1.4 核心要点entity(WeatherInfo.class)是call()的终结方法不是链式调用的中间步骤返回的不是字符串而是已经反序列化好的 Java 对象类必须有无参构造器和标准的getter/setter否则反序列化会失败4.2 用法二泛型类型——返回 List4.2.1 代码/** * 用法二泛型类型——返回 List * * 场景推荐某个城市的多个旅游景点 * 接口GET /structured/attractions?city成都count3 */ GetMapping(/attractions) public ListAttractionInfo getAttractions(RequestParam(defaultValue 成都) String city, RequestParam(defaultValue 3) int count) { return chatClient.prompt() .user(请推荐 city 的 count 个热门旅游景点。 返回一个列表每个景点包含名称、所在城市、简介、评分满分5分、游玩建议数组。) .call() .entity(new ParameterizedTypeReferenceListAttractionInfo() {}); }4.2.2 逐行拆解代码作用.entity(new ParameterizedTypeReferenceListAttractionInfo() {})告诉 Spring AI 要反序列化成ListAttractionInfo类型4.2.3 为什么不能用entity(ListAttractionInfo.class)Java 的泛型在运行时会被擦除。ListAttractionInfo.class这种写法在 Java 中是不合法的因为运行时只知道是List不知道List里装的是什么类型。ParameterizedTypeReference通过匿名内部类的写法在编译期捕获泛型信息运行时仍然可以获取到完整的ListAttractionInfo类型信息。正确写法// ✅ 正确带 {} 的匿名内部类保留泛型信息 .entity(new ParameterizedTypeReferenceListAttractionInfo() {}) // ❌ 错误不带 {}泛型信息在运行时被擦除 .entity(new ParameterizedTypeReferenceListAttractionInfo())4.2.4 调用与结果请求GET http://localhost:8080/structured/attractions?city成都count3返回[ { name: 宽窄巷子, city: 成都, description: 由宽巷子、窄巷子和井巷子组成的清代古街是成都保存最完好的历史文化街区之一。, rating: 4.5, tips: [建议傍晚前往, 可以品尝三大炮等小吃] }, { name: 大熊猫繁育研究基地, city: 成都, description: 世界著名的大熊猫保护研究机构游客可以近距离观察大熊猫。, rating: 4.8, tips: [建议早上8点入园, 至少预留3小时] }, { name: 都江堰, city: 成都, description: 战国时期李冰父子修建的水利工程至今仍在发挥作用。, rating: 4.6, tips: [建议请导游讲解, 春秋两季景色最佳] } ]在 Java 代码中使用ListAttractionInfo list getAttractions(成都, 3); for (AttractionInfo item : list) { String name item.getName(); double rating item.getRating(); ListString tips item.getTips(); }4.3 用法三泛型类型——返回 Map4.3.1 代码/** * 用法三泛型类型——返回 Map * * 场景批量查询多个城市的天气预报 * 接口GET /structured/city-weather?cities北京,上海,广州 */ GetMapping(/city-weather) public MapString, WeatherInfo getMultiCityWeather(RequestParam(defaultValue 北京,上海,广州) String cities) { return chatClient.prompt() .user(请生成以下城市今天的天气预报 cities 。 返回一个 Mapkey 是城市名称value 是包含 date、temperature、condition、humidity 的天气对象。) .call() .entity(new ParameterizedTypeReferenceMapString, WeatherInfo() {}); }4.3.2 逐行拆解代码作用.entity(new ParameterizedTypeReferenceMapString, WeatherInfo() {})告诉 Spring AI 要反序列化成MapString, WeatherInfo类型4.3.3 调用与结果请求GET http://localhost:8080/structured/city-weather?cities北京,上海,广州,深圳,杭州返回{ 北京: { city: null, date: 2026-08-22, temperature: 26.5, condition: 晴, humidity: 46 }, 上海: { city: null, date: 2026-08-22, temperature: 29.2, condition: 多云, humidity: 69 }, 广州: { city: null, date: 2026-08-22, temperature: 33.8, condition: 阵雨, humidity: 83 }, 深圳: { city: null, date: 2026-08-22, temperature: 15.0, condition: 雷阵雨, humidity: 88 }, 杭州: { city: null, date: 2026-08-22, temperature: 6.0, condition: 阴, humidity: 65 } }4.3.4 Map 结构的优势相比 ListMap 结构在按城市查找时更方便// List 方式需要遍历查找 ListWeatherInfo list ...; for (WeatherInfo w : list) { if (北京.equals(w.getCity())) { /* 找到了 */ } } // Map 方式直接通过 key 获取 MapString, WeatherInfo map ...; WeatherInfo w map.get(北京); // 一步到位4.3.5 ⚠️ 踩坑一city 字段为 null现象返回的 JSON 中每个WeatherInfo对象的city字段都是null。原因城市名已经被放在外层 Map 的 key 中了北京: {...}模型认为内层的city字段是冗余信息所以直接留空或忽略。这不是 Bug而是模型的一种「合理化」行为——既然你已经通过 key 知道了城市名为什么还要在内层重复一遍解决方案方案一接受 Map 结构使用时直接从 key 获取城市名推荐既然外层 Map 的 key 已经是城市名内层的city字段就没必要用了。使用时直接从 Map key 获取MapString, WeatherInfo map getMultiCityWeather(北京,上海,广州); for (Map.EntryString, WeatherInfo entry : map.entrySet()) { String cityName entry.getKey(); // 从 key 获取城市名 WeatherInfo weather entry.getValue(); // weather.getCity() 是 null不用它 System.out.println(cityName weather.getTemperature() °C); }方案二在 Prompt 中强制要求填充 city 字段.user(请生成以下城市今天的天气预报 cities 。 返回一个 Mapkey 是城市名称。 注意每个 value 对象中的 city 字段也必须填写城市名称不能为空不能省略。 即使外层 key 已经有了城市名内层的 city 字段也要重复填写一遍。)方案三去掉 POJO 中的 city 字段如果不需要如果 Map 的 key 已经足够标识城市可以考虑把WeatherInfo中的city字段去掉public class WeatherInfo { // private String city; // 去掉这个字段 private String date; private double temperature; private String condition; private int humidity; // ... }4.3.6 ⚠️ 踩坑二模型返回不稳定导致反序列化失败现象方法三调用时时而成功时而抛出以下异常Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception: tools.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type double from String 18°C: not a valid double value at [Source: REDACTED; byte offset: #UNKNOWN] (through reference chain: java.util.LinkedHashMap[北京] -com.yoyo.demo.dto.WeatherInfo[temperature])原因分析异常信息暴露了两个不匹配的问题问题一结构不匹配异常中的LinkedHashMap[北京]表明模型这次返回的 JSON 结构是{北京: {...}}外面包了一层城市名 key。但WeatherInfo本身已经有city字段了模型却在外层又套了一个 Map key。这是因为模型对 Prompt 的理解不稳定。有时它严格按照你要求的「返回一个 Mapkey 是城市名称」来执行有时它又自作主张把城市名提取出来作为外层 key导致WeatherInfo内部的city字段反而变成了冗余信息。问题二类型不匹配WeatherInfo.temperature声明为double但模型给了18°C带单位的字符串。Jackson 无法把18°C转成double所以抛出InvalidFormatException。这是因为模型有时会自作聪明地在数值后面加上单位°C、℃而不是只返回纯数字。解决方案方案一优化 Prompt明确约束格式推荐GetMapping(/city-weather) public MapString, WeatherInfo getMultiCityWeather(RequestParam(defaultValue 北京,上海,广州) String cities) { return chatClient.prompt() .user(请生成以下城市今天的天气预报 cities 。 返回一个 JSON 对象key 是城市名称value 是天气对象。 要求temperature 字段只返回纯数字不要带单位如 26.5不要写成 26.5°C 不要在外层再嵌套多余的 key直接返回 {城市名: {...}} 格式 每个 value 对象中的 city 字段也必须填写城市名称不能为空。) .call() .entity(new ParameterizedTypeReferenceMapString, WeatherInfo() {}); }方案二修改 POJO用 String 接收 temperature容错性更强public class WeatherInfo { private String city; private String date; private String temperature; // 改为 String避免类型转换失败 private String condition; private String humidity; // 也改为 String统一处理 // 无参构造器 public WeatherInfo() {} // getter/setter... // 提供一个便捷方法获取纯数字温度 public double getTemperatureValue() { if (temperature null) return 0; return Double.parseDouble(temperature.replaceAll([^0-9.], )); } }方案三开启validateSchema()自动纠错GetMapping(/city-weather) public MapString, WeatherInfo getMultiCityWeather(RequestParam(defaultValue 北京,上海,广州) String cities) { return chatClient.prompt() .user(请生成以下城市今天的天气预报 cities 。) .call() .entity(new ParameterizedTypeReferenceMapString, WeatherInfo() {}, spec - spec.validateSchema()); }validateSchema()会检测反序列化是否失败如果失败则将错误信息附加到 Prompt 中重新请求模型默认最多重试 3 次。⚠️ 注意validateSchema()适用于偶发性的格式异常比如模型偶尔一次输出不规范。但当前这个场景中模型返回带单位的温度字符串如18°C是系统性行为每次调用大概率都会出现不属于偶发情况。所以validateSchema()在这里无法根治问题重试 3 次后依然会报错。根本解决方案还是要用方案一优化 Prompt或者用方案二让 POJO 兼容字符串格式。最佳实践方案一 方案二组合使用。先用清晰的 Prompt 约束模型行为同时 POJO 做好容错双管齐下。4.4 用法四获取完整响应——单对象 元数据4.4.1 代码/** * 用法四获取完整响应类型化对象 元数据 * 使用 responseEntity() 同时拿到实体和 ChatResponse * * 场景查询天气的同时监控 token 消耗 * 接口GET /structured/weather-with-meta?city武汉 */ GetMapping(/weather-with-meta) public MapString, Object getWeatherWithMetadata(RequestParam(defaultValue 武汉) String city) { // 1. 调用 responseEntity()同时拿到实体和原始响应 ResponseEntityChatResponse, WeatherInfo result chatClient.prompt() .user(请生成 city 今天的天气预报。返回城市名称、日期、温度、天气状况和湿度。) .call() .responseEntity(WeatherInfo.class); // 2. 分别取出实体和响应 WeatherInfo weather result.entity(); ChatResponse response result.response(); // 3. 构建返回结果 Maplt;String, Objectgt; output new HashMaplt;gt;(); output.put(city, weather.getCity()); output.put(date, weather.getDate()); output.put(temperature, weather.getTemperature()); output.put(condition, weather.getCondition()); output.put(humidity, weather.getHumidity()); // 4. 提取 token 用量可能为 null需要判空 if (response.getMetadata() ! null amp;amp; response.getMetadata().getUsage() ! null) { output.put(promptTokens, response.getMetadata().getUsage().getPromptTokens()); output.put(completionTokens, response.getMetadata().getUsage().getCompletionTokens()); output.put(totalTokens, response.getMetadata().getUsage().getTotalTokens()); } return output; }4.4.2 逐行拆解代码作用.responseEntity(WeatherInfo.class)替代.entity()返回一个ResponseEntity包装对象result.entity()取出反序列化后的WeatherInfo对象result.response()取出原始的ChatResponse里面包含 token 用量、finishReason 等元数据response.getMetadata().getUsage().getTotalTokens()获取本次调用的总 token 数4.4.3 调用与结果请求GET http://localhost:8080/structured/weather-with-meta?city武汉返回{ city: 武汉, date: 2026-08-22, temperature: 36.2, condition: 晴, humidity: 57, promptTokens: 42, completionTokens: 51, totalTokens: 93 }4.4.4 什么时候用responseEntity()场景用.entity()用.responseEntity()只需要业务数据✅❌需要监控 token 消耗❌✅需要 finishReason 判断是否被截断❌✅需要做可观测性埋点❌✅4.5 用法五获取完整响应——List 类型 元数据4.5.1 代码/** * 用法五获取完整响应类型化对象 元数据 * 使用 responseEntity() 同时拿到实体和 ChatResponse * * 场景批量查询多个城市的天气预报同时监控 token 消耗 * 接口GET /structured/weather-with-meta-citys?cities武汉,长沙,深圳 */ GetMapping(/weather-with-meta-citys) public MapString, Object getWeatherWithMetadataCitys(RequestParam(defaultValue 武汉) String cities) { // 1. 调用 responseEntity()同时拿到实体和原始响应 String[] cityArray cities.split(,); ResponseEntityChatResponse, ListWeatherInfo result chatClient.prompt() .user(请生成以下城市 cityArray 今天的天气预报。返回城市名称、日期、温度、天气状况和湿度。) .call() .responseEntity(new ParameterizedTypeReferenceListWeatherInfo() {}); // 2. 分别取出实体和响应 Listlt;WeatherInfogt; weather result.entity(); ChatResponse response result.response(); // 3. 构建返回结果 Maplt;String, Objectgt; output new HashMaplt;gt;(); output.put(weather, weather.toArray()); // 4. 提取 token 用量可能为 null需要判空 if (response.getMetadata() ! null amp;amp; response.getMetadata().getUsage() ! null) { output.put(promptTokens, response.getMetadata().getUsage().getPromptTokens()); output.put(completionTokens, response.getMetadata().getUsage().getCompletionTokens()); output.put(totalTokens, response.getMetadata().getUsage().getTotalTokens()); } return output; }4.5.2 逐行拆解代码作用ResponseEntityChatResponse, ListWeatherInfo泛型声明第一个参数是ChatResponse原始响应第二个参数是ListWeatherInfo实体类型.responseEntity(new ParameterizedTypeReferenceListWeatherInfo() {})替代.entity()返回包装对象同时支持泛型类型result.entity()取出反序列化后的ListWeatherInfo对象result.response()取出原始的ChatResponse里面包含 token 用量、finishReason 等元数据4.5.3 调用与结果请求GET http://localhost:8080/structured/weather-with-meta-citys?cities武汉,长沙,深圳,成都返回{ weather: [ { city: 北京市, date: 2023-10-01, temperature: 22.5, condition: 晴, humidity: 54 }, { city: 上海市, date: 2023-10-01, temperature: 24.0, condition: 多云, humidity: 67 }, { city: 广州市, date: 2023-10-01, temperature: 23.5, condition: 小雨, humidity: 78 }, { city: 深圳市, date: 2023-10-01, temperature: 27.0, condition: 雷阵雨, humidity: 85 }, { city: 成都市, date: 2023-10-01, temperature: 19.0, condition: 阴, humidity: 72 } ], promptTokens: 347, completionTokens: 148, totalTokens: 495 }4.5.4 与用法四的区别对比维度用法四单对象用法五List接口路径/weather-with-meta/weather-with-meta-citys实体类型WeatherInfo单个对象ListWeatherInfo列表核心代码.responseEntity(WeatherInfo.class).responseEntity(new ParameterizedTypeReferenceListWeatherInfo() {})适用场景查一个城市查多个城市4.5.5 核心要点responseEntity()同样支持ParameterizedTypeReference可以处理泛型类型这是唯一一种既能拿到类型安全的对象列表又能拿到原始响应元数据的方式适合生产环境中需要批量查询并监控 token 消耗的场景五、五种用法对比用法接口路径返回类型核心代码适用场景基础对象/weatherWeatherInfo.entity(WeatherInfo.class)单个对象的查询List/attractionsListAttractionInfo.entity(new ParameterizedTypeReferenceListAttractionInfo() {})多条记录的列表Map/city-weatherMapString, WeatherInfo.entity(new ParameterizedTypeReferenceMapString, WeatherInfo() {})按 key 查找的数据单对象元数据/weather-with-metaMapString, Object.responseEntity(WeatherInfo.class)需要监控 token 消耗List元数据/weather-with-meta-citysMapString, Object.responseEntity(new ParameterizedTypeReferenceListWeatherInfo() {})批量查询监控 token六、结构化输出的工作原理Spring AI 的entity()方法在幕后做了三件事你的 Java POJO 类 ↓ ① JSON Schema 生成器 ↓ 将类的字段和类型转换为 JSON Schema ② 将 Schema 附加到系统提示 ↓ 引导模型按指定格式返回 JSON ③ JSON 反序列化 ↓ 将模型返回的 JSON 解析为你的 POJO 对象 类型安全的 Java 对象6.1 生成的 JSON Schema 长什么样对于WeatherInfo类public class WeatherInfo { private String city; private String date; private double temperature; private String condition; private int humidity; }Spring AI 自动生成类似这样的 JSON Schema{ type: object, properties: { city: { type: string }, date: { type: string }, temperature: { type: number }, condition: { type: string }, humidity: { type: integer } }, required: [city, date, temperature, condition, humidity] }这个 Schema 被附加到系统提示中告诉模型「你必须按这个格式返回 JSON」。七、POJO 类的注意事项7.1 必须有无参构造器Spring AI 使用 Jackson 进行 JSON 反序列化Jackson 默认通过无参构造器创建对象然后调用 setter 方法赋值。// ✅ 正确有无参构造器 public WeatherInfo() {} // ❌ 错误只有带参构造器没有无参构造器 public WeatherInfo(String city, String date, double temperature, String condition, int humidity) { this.city city; // ... }7.2 getter/setter 命名规范Jackson 通过 getter 方法推断 JSON 字段名getter 方法JSON 字段名getCity()citygetTemperature()temperaturegetTips()tipssetter 方法也必须对应setter 方法JSON 字段名setCity(String)citysetTemperature(double)temperature7.3 字段类型匹配Java 类型JSON 类型Stringstringint/Integerintegerdouble/Doublenumberboolean/BooleanbooleanListStringarrayListObjectarray八、踩坑记录坑 1缺少无参构造器现象启动时不报错但调用接口时抛出JsonMappingException提示无法实例化对象。原因Jackson 找不到无参构造器。解决给 POJO 类加上无参构造器。坑 2ParameterizedTypeReference忘记写{}现象编译报错提示泛型信息丢失。原因new ParameterizedTypeReferenceListAttractionInfo()后面必须跟{}否则 Java 无法在运行时保留泛型信息。解决// ✅ 正确 .entity(new ParameterizedTypeReferenceListAttractionInfo() {}) // ❌ 错误 .entity(new ParameterizedTypeReferenceListAttractionInfo())坑 3模型返回的 JSON 不符合预期现象entity()抛出异常提示 JSON 解析失败。原因模型可能返回了 Markdown 代码块包裹的 JSON或者多了/少了字段。解决可以使用validateSchema()开启自动纠错WeatherInfo weather chatClient.prompt() .user(请生成北京的天气预报。) .call() .entity(WeatherInfo.class, spec - spec.validateSchema());坑 4流式响应不支持结构化输出现象在.stream()后面调用.entity()编译报错。原因结构化输出需要完整的响应才能反序列化流式返回的是文本块不是完整对象。解决结构化输出只能用.call()不能用.stream()。坑 5Map 结构中内层 city 字段为 null现象返回的 JSON 中每个WeatherInfo的city字段都是null。原因模型认为外层 Map key 已经标识了城市名内层不再需要。解决从 Map key 获取城市名或在 Prompt 中强制要求填充。坑 6模型返回带单位的字符串导致类型转换失败现象temperature字段声明为double但模型返回18°CJackson 无法解析。原因模型自作聪明地在数值后加上了单位。解决优化 Prompt 明确要求纯数字或将 POJO 字段改为String类型做容错。九、速查表你需要使用返回单个对象.entity(Type.class)返回 List.entity(new ParameterizedTypeReferenceListT() {})返回 Map.entity(new ParameterizedTypeReferenceMapK, V() {})防止输出格式错误.entity(Type.class, spec → spec.validateSchema())获取 token 用量等元数据.responseEntity(Type.class)获取 List 类型 元数据.responseEntity(new ParameterizedTypeReferenceListT() {})流式响应不支持用.call()十、总结这篇博客通过五个接口逐个拆解了结构化输出的五种用法/weather.entity(WeatherInfo.class)—— 返回单个对象最简单/attractions.entity(new ParameterizedTypeReferenceListAttractionInfo() {})—— 返回 List/city-weather.entity(new ParameterizedTypeReferenceMapString, WeatherInfo() {})—— 返回 Map需注意 city 字段为 null 的问题/weather-with-meta.responseEntity(WeatherInfo.class)—— 单对象 元数据/weather-with-meta-citys.responseEntity(new ParameterizedTypeReferenceListWeatherInfo() {})—— List 元数据有了结构化输出你的业务代码就不再需要手写 JSON 解析代码更干净、更安全。十一、参考链接Spring AI 结构化输出文档Spring AI ChatClient entity() APISpring AI ParameterizedTypeReferenceSpring AI validateSchema 文档

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号