AI Agent入门实战第12篇,Spring AI Alibaba结构化输出实战--给AI发一张“标准表格”
让Java开发者像写Spring Boot一样开发AI应用——第二阶段第六篇
写在前面
前五天,我们给Agent装上了完整的记忆系统——短时记忆、长时记忆、用户画像,三层架构正式闭环。Agent不仅能“思考”、能“动手”,还能“记住你”。
但还有一个工程化的问题没有解决:Agent的“输出”不够规整。
你问Agent“帮我提取一下张三的联系方式”,它可能回答:
-
“姓名:张三,邮箱:zhangsan@example.com,电话:13800138000”
-
“联系人信息如下:张三,zhangsan@example.com,13800138000”
-
“张三 | zhangsan@example.com | 13800138000”
三种回答,三种格式。对人类来说都看得懂,但对程序来说,每种都要写一套解析逻辑。
这就像让员工随意填写报表——每个人写得都不一样,你根本没法用程序自动处理。
今天,我们给Agent发一张“标准表格”——结构化输出(Structured Output)。
📌 本文是第二阶段“核心能力实战篇”的第六篇。前面我们解决了Agent的“思考”“动手”“记忆”问题,今天解决“输出工程化”问题——让Agent的回复从“人类友好”升级为“机器友好”,真正融入业务系统。
一、为什么需要结构化输出?
自然语言输出的“三宗罪”
在Spring AI Alibaba中,默认情况下Agent的输出是纯文本的自然语言。这种输出对人类很友好,但对程序完全不友好。
问题一:格式不可靠
同样的信息,模型可能用完全不同的格式表达:
<span leaf="">可能的输出A:”姓名:张三,邮箱:zhangsan<span>@example</span>.<span>com</span>,电话:<span>13800138000</span>”</span>
问题二:字段缺失
模型可能遗漏必填字段,导致下游解析失败。
问题三:解析脆弱
微小格式变化(如多了一个空格、换行位置不同)都可能导致正则表达式或字符串解析失败。
💡 让大模型“自由发挥”就像让员工随意填写报表——每个人写得都不一样,你根本没法用程序自动处理。结构化输出就是给模型发了一张“标准表格”,必须按格填写。
结构化输出的核心价值
| 价值
|
说明
| 可预测性 |
强制模型遵循预定义的Schema,输出格式完全可控
| | 类型安全 |
直接映射到Java对象,编译期类型检查
| | 简化集成 |
无需后处理(正则、字符串解析),直接用于业务逻辑
| | 消除歧义 |
字段有明确的类型和含义,不会产生误解
|
💡 如果说前11天我们都在教Agent“怎么说”,那今天教的就是让Agent“说什么格式”——前者关乎内容,后者关乎工程。
适用场景
| 场景
|
说明
| 数据提取 |
从非结构化文本中提取结构化信息(联系方式、简历信息等)
| | 表单填充 |
生成符合表单Schema的JSON数据
| | API响应生成 |
作为下游微服务的标准输入
| | 实体识别 |
识别并结构化输出人物、地点、组织等实体
| | 路由决策 |
根据结构化输出做工作流路由
|
二、两种配置方式:outputType vs outputSchema
Spring AI Alibaba的ReactAgent.Builder通过outputSchema和outputType两个方法处理结构化输出:
| 方式
|
代码示例
|
优势
|
适用场景
| outputType(Class) | .outputType(ContactInfo.class) |
类型安全、自动Schema生成、代码简洁
| 推荐!90%场景 |
| outputSchema(String) | .outputSchema("{\"type\":\"object\",...}") |
完全控制Schema细节
|
需要自定义验证规则
|
方式一:outputType——类型安全,强烈推荐
核心思想:直接传入一个Java POJO类,框架通过BeanOutputConverter自动生成JSON Schema。
<span leaf=""><span>// 1. 定义POJO(标准Java Bean)</span></span>
outputType的优势:
| 优势
|
说明
✅ 类型安全
|
编译期类型校验,IDE自动补全
| |
✅ 零维护成本
|
修改POJO即自动更新Schema
| |
✅ 代码简洁
|
一行.outputType(Class)搞定
| |
✅ 自动推导
|
Spring AI用BeanOutputConverter自动生成JSON Schema
|
💡 outputType是推荐方式,适用于90%以上的业务场景。它让开发者只需要关心“定义什么数据结构”,而不需要关心“怎么写JSON Schema”。
方式二:outputSchema——完全控制
核心思想:手动编写JSON Schema字符串,告诉模型“必须按这个结构来”。
<span leaf=""><span>// 1. 手动定义JSON Schema</span></span>
outputSchema的优势与局限:
| 维度
|
说明
✅ 完全控制
|
可以精细控制每个字段的类型、约束、验证规则
| |
✅ 自定义验证
|
支持正则、枚举、范围等复杂验证
| |
❌ 维护成本高
|
Schema变更需要手动同步修改
| |
❌ 易出错
|
手写JSON Schema容易有语法错误
| |
❌ 无编译期检查
|
错误只能在运行时发现
|
💡 outputSchema就像“手写合同”——每个条款都精确控制,但写起来费劲、改起来麻烦。outputType就像“用标准模板”——省心省力,大部分场景都够用。
选型决策
<span leaf="">开始:我需要结构化输出</span>
💡 优先使用outputType。只有当需要自定义验证规则、字段约束等精细控制时,才考虑outputSchema。
三、BeanOutputConverter:幕后的“翻译官”
BeanOutputConverter是Spring AI提供的StructuredOutputConverter接口的一个实现,它使用JSON Schema将LLM输出转换为特定的对象类型。
工作原理
<span leaf="">① 生成<span>Schema</span>(调用前)</span>
核心接口
| 接口
|
方法
|
职责
FormatProvider |
getFormat() |
生成JSON Schema格式指令,供模型遵循
|
| Converter<String, T> | convert(String) |
将模型输出的文本转换为目标Java对象
|
复杂嵌套结构的支持
BeanOutputConverter完美支持嵌套对象、数组、复杂实体:
<span leaf=""><span>// 商品评价分析 - 嵌套结构</span></span>
四、结构化输出的完整调用链路
原生结构化输出 vs ToolCall回退
Spring AI Alibaba在指定了outputSchema或outputType后,会做一层“智能选择”:
| 模型类型
|
处理方式
|
特点
| 支持原生结构化输出的模型 |
(如DashScopeChatModel、OpenAiChatModel)
|
使用模型原生结构化输出能力
|
服务端做格式校验,非常稳定
| | 不支持原生结构化输出的模型 |
回退到Spring AI内置的ToolCall策略
|
通过动态ToolCall将输出“揉”成结构化数据
|
💡 就像有些手机支持无线充电(原生支持),有些不支持(需要插线)。Spring AI Alibaba会自动判断你的模型支不支持原生结构化输出,支持就用“无线充”,不支持就自动“插线”——开发者不需要关心底层差异。
完整调用链路
<span leaf="">用户:调用 agent.<span>call</span>(”从文本中提取联系方式”)</span>
五、实战:旅游攻略结构化输出
Step 1:定义旅游攻略POJO
<span leaf="">public <span><span>class</span></span><span> </span><span><span>TravelGuide</span></span><span> </span>{</span>
Step 2:构建Agent并配置outputType
<span leaf=""><span>@Configuration</span></span>
Step 3:Controller调用
<span leaf=""><span>@RestController</span></span>
六、异常处理与降级策略
结构化输出的风险
重要提醒:StructuredOutputConverter是尽最大努力将模型输出转换为结构化输出。AI模型不能保证按照要求返回结构化输出。
| 风险
|
表现
|
原因
| 格式不符合 |
返回纯文本而非JSON
|
模型不理解格式指令
| | 字段缺失 |
必填字段未出现
|
模型未正确提取信息
| | 类型错误 |
字符串字段返回数字
|
模型理解偏差
| | Markdown包裹 |
JSON被json ...包裹
|
模型习惯性添加代码块
| | JSON不合法 |
尾随逗号、控制字符
|
模型生成质量不佳
|
💡 结构化输出不是“银弹”——它大幅提高了可靠性,但并不能保证100%成功。就像你给员工发了一张标准表格,他可能会填错、漏填、甚至不填。我们需要有“容错机制”。
策略一:JSON清理与修复
<span leaf=""><span>public</span> <span>class</span> <span>JsonCleaner</span> {</span>
策略二:验证 + 重试
Spring AI提供了Schema验证和自校正机制。当验证失败时,第二次尝试不是盲目重试——模型知道哪里错了,可以进行修正。
<span leaf=""><span>@Service</span></span>
生产环境最佳实践
| 实践
|
说明
| 始终使用outputType |
类型安全,自动生成Schema
| | 在Prompt中明确字段要求 |
在systemPrompt中说明每个字段的含义和约束
| | 实现验证机制 |
验证模型输出是否符合预期
| | 提供降级方案 |
解析失败时返回默认值或友好提示
|
七、结构化输出的最佳实践
POJO设计建议
-
字段命名清晰、语义明确
-
使用基础类型(String、int、double、boolean)和标准集合(List、Map)
-
嵌套层级不超过3层,避免模型理解困难
-
为每个字段提供合理的默认值,用于降级场景
outputType vs outputSchema 决策矩阵
| 场景
|
推荐方式
|
理由
标准业务DTO
| outputType |
类型安全,零维护成本
| |
需要自定义验证规则
|
outputSchema
|
精细控制字段约束
| |
数据结构频繁变更
| outputType |
修改POJO即可
| |
对接第三方API的固定格式
|
outputSchema
|
必须精确匹配第三方格式
| |
快速原型开发
| outputType |
代码最少,开发最快
| |
生产环境
| outputType |
编译期检查,更可靠
|
💡 除非有特殊需求,否则一律使用outputType。
八、课后挑战
任务:为第六天构建的“智能天气助手Agent”增加结构化输出能力
要求:
- 定义
WeatherResponsePOJO,包含以下字段:
-
city:城市名称 -
temperature:温度范围 -
condition:天气状况 -
humidity:湿度 -
wind:风力 -
joke:天气冷笑话 -
advice:出行建议
-
使用
outputType(WeatherResponse.class)配置Agent -
实现异常处理:当结构化输出解析失败时,返回默认的天气对象
-
提供REST API返回JSON格式的天气数据
验收标准:
-
WeatherResponse POJO定义完整,包含所有必填字段
-
Agent配置了outputType(WeatherResponse.class)
-
调用Agent后能成功将JSON反序列化为WeatherResponse对象
-
解析失败时有降级策略(返回默认值)
-
REST API返回的是JSON格式(而非纯文本)
九、本日核心收获
-
自然语言输出“三宗罪” ——格式不可靠、字段缺失、解析脆弱
-
两种配置方式——
outputType(推荐,类型安全)和outputSchema(手写Schema,精细控制) -
BeanOutputConverter是幕后“翻译官” ——自动生成Schema、注入格式指令、转换JSON为Java对象
-
智能选择机制——支持原生结构化输出的模型用原生能力,不支持的自动回退到ToolCall策略
-
异常处理不可少——结构化输出不是100%可靠,需要清理、验证、重试、降级
-
除非有特殊需求,否则一律使用outputType
📌 本文是第二阶段“核心能力实战篇”的第六篇。前面我们解决了Agent的“思考”“动手”“记忆”问题,今天解决了“输出工程化”问题——让Agent的回复从“人类友好”升级为“机器友好”。至此,Agent的核心能力拼图(工具调用→RAG→记忆系统→结构化输出)已基本完整。下一篇,我们将进入多智能体协同的进阶实战,让多个Agent组成“组织”协同工作。
有任何问题,欢迎在评论区留言交流!
作者:Java老兵搞AI,专注Java生态下的AI应用开发
如果觉得有用,点个「关注」支持一下吧,下期见!
- 原文作者:知识铺
- 原文链接:https://index.zshipu.com/ai002/post/20260823/AI-Agent%E5%85%A5%E9%97%A8%E5%AE%9E%E6%88%98%E7%AC%AC12%E7%AF%87Spring-AI-Alibaba%E7%BB%93%E6%9E%84%E5%8C%96%E8%BE%93%E5%87%BA%E5%AE%9E%E6%88%98--%E7%BB%99AI%E5%8F%91%E4%B8%80%E5%BC%A0%E6%A0%87%E5%87%86%E8%A1%A8%E6%A0%BC/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com