Prompt约束、StructuredOutputConverter、原生JSON Schema与validateSchema怎么选?
文章摘要
企业AI应用需要把模型输出用于路由、入库、审批或工具调用时,不能长期依赖自然语言解析。Spring AI提供了多种结构化输出路径:在Prompt中手写格式要求、使用StructuredOutputConverter生成格式指令和反序列化、启用Provider原生JSON Schema约束,以及通过validateSchema()进行本地校验和自修复。四种方案的可靠性、兼容性、成本和复杂度不同。本文给出分层选型方法和生产组合建议。
一、四种方案解决的问题不同
方案一:手写Prompt约束
请只输出JSON,不要输出解释。
方案二:StructuredOutputConverter
Java类型
→ 生成格式指令
→ 模型输出文本
→ 转换为Java对象
方案三:Provider原生JSON Schema
Schema作为API参数
→ Provider约束输出
方案四:validateSchema自修复
本地验证响应
→ 把错误反馈给模型
→ 有上限地重新生成
它们不是完全互斥,可以组合使用。
二、只写Prompt什么时候够用
示例:
返回JSON:
{
"category": "string",
"summary": "string"
}
适合:
- 原型验证;
- 低风险内部工具;
- 结果只用于展示;
- 失败后可以人工重试;
- Provider不支持结构化输出。
优势:
- 最简单;
- 不依赖框架;
- 跨模型兼容性高;
- 调试直观。
不足:
- 模型可能加Markdown;
- 可能漏字段;
- 类型无法保证;
- Prompt越复杂越脆弱;
- 下游代码需要大量容错。
结论:
只写Prompt适合原型
不适合关键业务协议
三、StructuredOutputConverter适合什么场景
Spring AI的Converter可以根据Java类型生成Schema或格式说明,再把返回文本转换为对象。
示例:
record CustomerIntent(
String intent,
double confidence
) {
}
调用:
CustomerIntent intent = chatClient.prompt()
.user("判断客户意图")
.call()
.entity(CustomerIntent.class);
优点:
- 与Java领域对象直接衔接;
- 减少手写JSON模板;
- 支持List、Map和泛型;
- 跨Provider;
- 适合Spring项目。
不足:
- 默认仍可能是Prompt级约束;
- 不保证模型一定满足格式;
- 复杂Schema容易失败;
- 需要完整响应后才能解析。
适合:
- 信息提取;
- 分类;
- 报告摘要字段;
- 普通工作流输出;
- 多Provider兼容层。
四、Provider原生结构化输出的优势
原生结构化输出把JSON Schema放到模型API参数中,而不是只写进Prompt。
优点:
- 约束更强;
- Prompt更干净;
- 输出通常更稳定;
- 减少Markdown包裹;
- 更适合机器消费。
Spring AI示意:
CustomerIntent intent = chatClient.prompt()
.user(message)
.call()
.entity(
CustomerIntent.class,
spec -> spec.useProviderStructuredOutput()
);
适合:
- 工作流路由;
- API返回对象;
- 规则判断;
- 自动审批前置结果;
- 大批量信息提取。
五、原生JSON Schema为什么不是万能方案
不同Provider支持的Schema子集不同。
常见限制:
- 顶层数组;
$ref;- 深层嵌套;
oneOf、anyOf、allOf;- 递归类型;
- 正则;
- Map动态键;
- 复杂泛型。
因此,跨Provider应用要采用Schema最小公共集:
object
string
number
integer
boolean
array
required
additionalProperties
简单enum
不要把Java完整领域模型原样暴露给模型。
六、validateSchema解决什么问题
即使Provider宣称支持原生结构化输出,也可能存在:
- 模型版本边界行为;
- 推理文本混入;
- Schema子集不完整;
- Provider兼容层问题;
- 自建模型不稳定。
validateSchema()属于响应侧安全网:
收到响应
→ 本地Schema验证
→ 失败则反馈具体错误
→ 重新生成
适合:
- 关键结构;
- 模型偶发格式漂移;
- 本地模型;
- 多Provider路由;
- 升级灰度期。
七、四种方案对比
| 维度 | Prompt约束 | Converter | 原生JSON Schema | validateSchema |
|---|---|---|---|---|
| 接入复杂度 | 低 | 低 | 中 | 中 |
| 格式可靠性 | 低 | 中 | 高 | 高 |
| Provider兼容 | 高 | 高 | 中 | 高 |
| 额外调用 | 无 | 无 | 无 | 失败时增加 |
| 流式支持 | 文本可流式 | entity不流式 | 取决于调用 | 通常不流式 |
| 类型映射 | 手工 | 自动 | 配合Converter | 配合Converter |
| 适合生产关键流程 | 不推荐 | 需校验 | 推荐 | 推荐作为安全网 |
八、生产项目推荐组合
低风险展示
Converter
例如:
- 推荐标签;
- 页面摘要;
- 普通内容分类。
中风险工作流
Provider原生结构化输出
+本地业务校验
例如:
- 工单分类;
- 售前需求提取;
- 任务分派。
高风险流程
Provider原生JSON Schema
+validateSchema
+业务规则校验
+人工审批
例如:
- 退款建议;
- 合同风险;
- 权限变更;
- 对外正式承诺。
九、Schema设计的五条原则
1. 字段少
结构化输出不是报告全文。
2. 枚举明确
LOW, MEDIUM, HIGH
不要使用开放字符串表达核心状态。
3. 文本字段有限长
避免模型把整篇分析塞进reason。
4. 不使用深层嵌套
建议控制在两到三层。
5. 协议与领域模型分离
定义AI专用DTO:
record AiRiskDecision(...)
再映射到业务对象,不要让模型直接构造数据库实体。
十、业务校验不能被Schema替代
Schema可以验证:
字段存在
类型正确
枚举合法
结构符合要求
Schema无法判断:
订单是否属于用户
金额是否超限
文档是否过期
审批人是否有权限
日期是否符合业务规则
因此需要第二层:
public void validateBusiness(
RefundDecision decision,
Order order
) {
if (decision.amount().compareTo(order.paidAmount()) > 0) {
throw new BusinessValidationException(
"退款金额超过实付金额"
);
}
}
十一、什么时候不应该自动修复
以下情况不适合让模型继续尝试:
- 输入本身缺少关键事实;
- 用户无权限;
- 业务状态已变化;
- Provider预算已耗尽;
- 输出包含潜在攻击;
- 高风险结果存在冲突。
自动修复只解决格式问题,不解决事实和权限问题。
十二、模型路由中的结构化输出能力
多模型路由时,应登记:
supports_native_structured_output
supported_schema_features
max_schema_size
supports_top_level_array
reasoning_output_behavior
路由不能只按价格和智能水平,还要看输出协议能力。
例如:
分类任务
→ 选择结构化输出稳定的小模型
复杂分析
→ 强模型生成证据
→ 小模型整理结构
有时“强模型一次完成全部工作”并不是成本和稳定性最优方案。
十三、如何测试结构化输出
测试集需要覆盖:
- 正常输入;
- 空输入;
- 超长输入;
- 中英文混合;
- 枚举边界;
- 日期歧义;
- 数值单位;
- Prompt Injection;
- 缺少事实;
- Provider切换。
指标:
first_attempt_success_rate
repair_success_rate
average_attempts
schema_failure_rate
business_validation_failure_rate
cost_per_valid_object
p95_latency
最终应关注:
每1000个有效对象的总成本
而不是单次模型价格。
十四、选型决策树
只做原型或展示?
→ Prompt约束或Converter
需要稳定Java对象?
→ Converter
Provider支持JSON Schema且流程关键?
→ 原生结构化输出
偶发格式失败需要自动恢复?
→ validateSchema
涉及业务动作?
→ 再加业务校验和人工审批
总结
四种方案的合理分工是:
Prompt约束
→ 最广泛兼容
StructuredOutputConverter
→ Java类型映射
Provider原生JSON Schema
→ 请求侧强约束
validateSchema
→ 响应侧校验和自修复
企业项目通常不应只选其中一种,而应根据风险组合使用,并始终保留业务校验、观测和失败降级。
延伸阅读
如果你正在关注企业级AI应用、Spring AI、RAG、Agent与MCP工程化落地,欢迎访问 智元界:
https://www.zyentor.com/
智元界将持续分享可运行的技术实战、架构设计、问题排查与企业应用案例。