主题
模式校验与自我纠正
默认的 .entity(...) 调用要求模型产出匹配模式的 JSON,但无法强制它。 当模型多返回一个字段、漏掉一个必填字段,或把 JSON 包裹在文字里时,解析器会抛出异常。
处理格式错误输出的最简单方式是检测它并重试。 Spring AI 通过 EntityParamSpec 消费者上的一个开关自动完成这一点:
java
ActorsFilms films = chatClient.prompt()
.user("Generate the filmography for a random actor.")
.call()
.entity(ActorsFilms.class, spec -> spec.validateSchema());自我纠正循环如何工作
spec -> spec.validateSchema() 消费者会开启一个自我纠正的重试循环:
- 模型给出响应。
- Spring AI 依据目标类型的 JSON 模式校验该响应。
- 如果校验通过,你就能拿回有类型的记录。
- 如果校验失败,验证错误(例如“missing required field
actor”、“expectedarray, gotstring”)会被追加到用户提示词,并重新发起调用——默认最多 3 次尝试。
在每次重试时模型都会看到具体的错误,因此第二次尝试并非盲目重试:模型知道哪里出了问题并能纠正它。
这由 StructuredOutputValidationAdvisor 驱动,它是一个在你调用 validateSchema() 时自动注册的递归顾问。 你无需装配任何东西;这个开关就是全部配置。
NOTE
当 validateSchema() 处于启用状态时,不支持流式传输。
该顾问需要完整的响应才能对其进行校验。
定制顾问
StructuredOutputValidationAdvisor 默认为 3 次重试尝试,并使用 Spring AI 默认的 JsonMapper。 要定制——例如更多次尝试、预先给定的模式,或不同的映射器——请构建你自己的实例并注册到 ChatClient 上。 显式注册的顾问会替换自动注册的那个:
java
var validationAdvisor = StructuredOutputValidationAdvisor.builder()
.outputType(ActorsFilms.class)
.maxRepeatAttempts(5)
.build();
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(validationAdvisor)
.build();该顾问可通过 outputType(自动派生模式)或 outputJsonSchema(预先给定的模式字符串)来配置;这两种选项互斥。
java
var validationAdvisor = StructuredOutputValidationAdvisor.builder()
.outputJsonSchema(myConverter.getJsonSchema())
.build();关键行为:
- 从期望的输出类型派生一个 JSON 模式,或接受一个预先给定的模式字符串。
- 使用 JSON 模式
DRAFT_2020_12依据模式校验 LLM 响应。 - 校验失败时重试调用(默认:最多 3 次尝试)。
- 在重试尝试时用验证错误消息增强提示词,以帮助模型自我纠正。
- 在每次验证尝试间累计令牌用量,因此返回的
ChatResponse报告所有重试的累计用量,而不仅仅是最后一次(参见 多步流程中的累计用量)。 - 可选地支持自定义
JsonMapper。
关于此顾问背后递归顾问机制的细节,参见 StructuredOutputValidationAdvisor。
与服务商原生输出结合
validateSchema() 是一层响应侧的安全网——它在事后捕获错误输出并重试。 useProviderStructuredOutput() 是一层互补的请求侧约束。 两者能自然地组合:
java
ActorsFilms films = chatClient.prompt()
.user("Generate the filmography for a random actor.")
.call()
.entity(ActorsFilms.class, spec -> spec
.useProviderStructuredOutput()
.validateSchema());这对于原生强制仅为部分生效的服务商边缘情况尤其有用——例如,Ollama 推理模型可能输出纯文本的推理轨迹而非 JSON。 参见 已知限制。