第11章-Structured-Output

这一章节我们在第10章节的基础上把不可预测的自然语言回答转换为可解析、可校验的 Java 对象,让模型输出真正进入业务流程。

前言

页面聊天可以直接使用字符串,但订单分类、表单提取、审核结果等业务需要稳定字段。Structured Output 的目标不是让模型"回答得像 JSON",而是建立从目标结构、输出约束、转换到业务校验的完整链路。

一、为什么需要结构化输出

自然语言适合人阅读,却不适合程序稳定判断:

text 复制代码
这个问题大概属于售后咨询,可信度比较高。

业务更需要:

json 复制代码
{"category":"AFTER_SALES","confidence":0.93,"reason":"用户询问退货进度"}

结构化输出带来字段明确、类型明确、便于校验和可直接进入后续流程等优势。

二、先定义业务 DTO

java 复制代码
public record TicketClassification(
        String category,
        double confidence,
        String reason) {
}

DTO 应尽量简单:字段含义清楚、层级不过深、类型可稳定生成。模型不擅长一次可靠生成极其复杂的对象图。

三、使用 entity() 转换

java 复制代码
public TicketClassification classify(String content) {
    return chatClient.prompt()
            .system("识别工单分类,并按目标结构返回结果。")
            .user(content)
            .call()
            .entity(TicketClassification.class);
}

entity() 负责把模型结果转换为目标类型。它减少了业务层手工解析 JSON 的代码,但不代表转换永远成功。

四、String 到 DTO 经历了什么

text 复制代码
Java DTO
    ↓ 推导结构要求
Format Instructions / JSON Schema
    ↓ 加入请求或 Provider 约束
模型生成结构化文本
    ↓ 转换器解析
Java DTO
    ↓ 业务校验
可用结果

结构化输出同时依赖模型遵循能力、提示约束、Provider 能力和转换器。

五、Format Instructions

当 Provider 不提供原生 Schema 约束时,框架可以把格式说明加入 Prompt,告诉模型字段、类型及输出格式。

概念示例:

text 复制代码
请只返回 JSON。
category: 字符串
confidence: 0 到 1 的数字
reason: 字符串
不要添加 Markdown 代码围栏。

Format Instructions 是自然语言约束,能够提高成功率,但不能提供绝对保证。

六、JSON Schema 与 Provider 原生约束

支持 Structured Output 的 Provider 可以在请求层接收 JSON Schema,由模型服务约束输出结构。相比单纯把格式写进 Prompt,这通常更稳定,也能减少格式说明占用的 Token。

但仍需确认:

  • 当前模型是否支持;
  • Provider 对 Schema 特性的支持范围;
  • Spring AI 和集成版本是否开放对应选项;
  • 不支持时是否回退到 Prompt 指令。

七、转换成功后仍要校验

Java 反序列化成功只说明结构可解析,不代表业务值可信。

java 复制代码
TicketClassification result = classify(content);

if (result.confidence() < 0 || result.confidence() > 1) {
    throw new IllegalArgumentException("confidence 超出范围");
}

还应校验:

  • 必填字段是否为空;
  • category 是否在枚举白名单中;
  • 数值是否在业务范围;
  • 文本是否包含敏感内容;
  • 当前用户是否有权触发后续操作。

八、失败处理

常见失败包括缺字段、额外说明文字、类型错误、JSON 截断和枚举值不存在。

推荐策略:

  1. 记录可追踪但已脱敏的失败信息;
  2. 对格式类临时失败进行有限次数重试;
  3. 重试时把校验错误作为修正反馈;
  4. 超过次数后降级或转人工;
  5. 不让无法校验的结果进入核心业务。

不要无限重试。每次模型调用都有延迟和成本。

九、集合与嵌套结构

需要列表时,可以使用 ParameterizedTypeReference 等方式表达泛型目标,具体 API 以项目版本为准。

结构设计建议从单对象开始验证,再增加列表和嵌套字段。嵌套越深、约束越复杂,模型偏离结构的概率通常越高。

十、适用业务场景

场景 典型字段
工单分类 category、confidence、reason
简历信息提取 name、skills、experience
内容审核 passed、riskLevel、reasons
商品属性抽取 brand、category、attributes
查询条件生成 keywords、dateRange、filters

高风险场景中,结构化输出只能作为建议或中间结果,不能替代确定性规则和人工审核。

十一、从 API 进入源码

text 复制代码
CallResponseSpec.entity(type)
    ↓
StructuredOutputConverter
    ├── 生成格式约束或 Schema
    └── convert(modelText)
    ↓
Java Object

源码阅读重点:目标类型如何转换为格式说明、格式说明何时加入请求、响应文本在哪里解析、转换异常如何抛出,以及 Provider 原生结构化能力如何启用。

十二、常见误区

  • 输出是 JSON 就等于 Structured Output:还需要类型转换和校验。
  • 使用 entity() 后不会失败:模型与转换器仍可能失败。
  • DTO 越复杂越专业:复杂结构会提高生成和维护难度。
  • Schema 能保证业务正确:Schema 只能约束结构,无法判断业务事实。
  • 模型结果可以直接写库或执行支付:高风险操作必须经过程序校验和权限控制。

十三、本章总结

text 复制代码
DTO 定义
    ↓
格式指令或 JSON Schema
    ↓
模型生成
    ↓
entity() 转换
    ↓
字段与业务校验
    ↓
进入后续流程

结构化输出的核心不是 JSON 外观,而是可约束、可解析、可校验和可失败处理。

完整源码

text 复制代码
源码地址:待补充
对应章节:chapter-11-structured-output

参考资料

下一章:Advisor

下一章进入核心能力篇,学习 Advisor 如何在不污染业务代码的情况下增强模型调用链。

相关推荐
懂点Tech6 小时前
ctfshow misc28:GIF 高度修改解题与脚本实现
开发语言·windows·python
comedate6 小时前
SMLib 的 Examples 导读:PyAPI / SM_API / SMLib 三组示例怎么读
python·cad·smlib·examples·sm_api
云和数据.ChenGuang6 小时前
Python 重写(Override)深度解析:从 MRO 到 super() 的完整机制
java·开发语言·人工智能·python·langchain·1024程序员节
西西木科技丨Shopify开发机构6 小时前
CalDigit TS4案例:AI产品图的Shopify整站接入与验收
人工智能·shopify·独立站
川石课堂软件测试7 小时前
学习软件测试需掌握的一些知识
数据库·python·sql·功能测试·网络协议·mysql·http
2601_965448877 小时前
AI视频制作:做系列节气民俗视频音色不统一,AI 音色克隆省事的方法
人工智能·机器学习·音视频
美狐美颜SDK开放平台7 小时前
视频美颜SDK试用DEMO阶段应该测试什么?直播APP接入实操指南
开发语言·人工智能·深度学习·音视频·美颜sdk·直播美颜sdk·第三方美颜sdk
dtq04247 小时前
C++小案例 - 日志实战
开发语言·c++
HRaitest7 小时前
秋招技术岗招聘提效:三类 AI 招聘方案的技术底层与选型逻辑
大数据·人工智能·求职招聘·ai-native
天远数科7 小时前
零信任架构实战:基于天远企业股权变更构建自动化商业银行对公授信存续期股权异动与资产抽逃预警网关
运维·人工智能·架构·自动化