第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 如何在不污染业务代码的情况下增强模型调用链。

相关推荐
175******631731 小时前
灰片调色适合什么素材
人工智能
大模型真好玩1 小时前
从 SDK 到成熟智能体:拆解 LangChain、Pi、DeepSeek Harness、Claude Code的本质区别
人工智能·agent·deepseek
程序哥聊面试1 小时前
什么是 Sandbox?给 AI Agent 划一道安全边界
人工智能·安全
梦在远山后1 小时前
通过 WSS 让 Server 安全调用 Desktop 本地工具(下01):Ticket、人工确认、幂等与断线对账
python·langchain·agent
大虾别跑1 小时前
ai-daily-2026-10-08
人工智能·chatgpt
adinnet20261 小时前
保单、赔付与渠道问数:保险经营数据如何实现按需查询
大数据·数据库·人工智能
泡海椒2 小时前
JQuick-Excel 实战:FORMAT 管理日期与数字的 Excel 显示
开发语言·python·excel
老金带你玩AI2 小时前
反向背调,豆包工作算是把它玩明白了!
人工智能
qq_401700412 小时前
Qt 串口/网口通信:Hex 与 ASCII 编码转换深度指南
开发语言·数据库·qt