Java AI转型实战(七):Output Parser,让AI输出结构化数据

0 阅读4分钟

从“自然语言”到“结构化数据”,让程序真正读懂AI的回复

01 引子

经过前六篇的实战,我们的AI已经能聊天、能记住上下文、能流式输出、能调用Java方法。但有一个问题始终存在:

AI返回的是自然语言文本,程序无法直接使用。

比如让AI“提取会议信息”,它可能返回:

“明天下午3点有一个项目评审会,在会议室A举行,预计持续1小时。”

这段文字对人类来说很好理解,但对程序来说——怎么提取时间?怎么拿到地点?怎么知道时长?——只能写正则表达式硬解析,脆弱又麻烦。

这一篇的目标:让AI直接返回结构化的JSON数据,程序拿来即用。

02 什么是Output Parser?

一句话概括:  Output Parser是Spring AI提供的工具,用于将AI的输出从“自然语言文本”转换为“结构化数据”(如Java对象、Map、List等)。

Parser输出格式适用场景
BeanOutputParserJava对象最常用,直接映射到业务对象
MapOutputParserMap<String, Object>简单场景,不需要预定义类
ListOutputParserList<?>返回列表数据

本篇重点:BeanOutputParser,最常用、功能最强大。

03 原理:AI怎么知道该输出什么格式?

你可能好奇:AI怎么知道要输出JSON?怎么知道该有哪些字段?

关键在于 Spring AI 会自动生成 JSON Schema,并附加到请求中

text

用户问题 + JSON Schema(说明输出格式) → 大模型 → 按格式返回JSONSpring AI 反序列化为Java对象

这个Schema描述了目标类的所有字段、类型和描述,AI根据它来生成符合格式的JSON。

你只需要:

  1. 定义一个Java类
  2. 创建 BeanOutputConverter<T>
  3. 调用 .entity(converter)

剩下的全部由Spring AI自动完成。

04 代码实现

第一步:定义数据类

在 com.example.myai.model 包下创建 MeetingInfo.java

image.png

关键要求:  必须有无参构造和Getter/Setter,否则JSON无法反序列化为Java对象。

第二步:在Service中使用OutputParser

修改 AIService.java,新增 extractMeetingInfo 方法:

image.png

关键点:

  • new BeanOutputConverter<>(MeetingInfo.class):创建转换器,指定目标类型
  • .entity(converter):告诉Spring AI将输出转换为MeetingInfo对象
  • 不要将BeanOutputConverter声明为Spring Bean(踩坑记录会详细说明)

第三步:暴露接口

在 AIController.java 中新增接口:

image.png

05 测试验证

启动项目,在浏览器中访问:

image.png

更复杂的输入测试:

image.png

换个说法再测:

image.png

三个不同场景全部成功,AI能准确提取信息并返回结构化JSON。  ✅

06 踩坑记录

坑:BeanOutputConverter不能声明为Spring Bean

一开始我这样写:

@Configuration
public class OutputParserConfig {
    @Bean
    public BeanOutputConverter<MeetingInfo> meetingInfoConverter() {
        return new BeanOutputConverter<>(MeetingInfo.class);
    }
}

然后在Service中注入:

public AIService(..., BeanOutputConverter<MeetingInfo> meetingInfoConverter) {
    // ...
}

启动报错:

Unable to determine source type <S> and target type <T> for your Converter 
[org.springframework.ai.converter.BeanOutputConverter]; 
does the class parameterize those types?

原因:  BeanOutputConverter 虽然实现了 Converter<S, T> 接口,但它的泛型参数是在运行时通过构造函数传入的。Spring在启动时扫描所有 Converter 类型的Bean并注册到 ConversionService,由于泛型信息不完整,导致类型推断失败。

解决方法:  不在配置类中声明为Bean,而是在Service方法内直接创建:

// ✅ 正确做法
public MeetingInfo extractMeetingInfo(...) {
    BeanOutputConverter<MeetingInfo> converter = new BeanOutputConverter<>(MeetingInfo.class);
    return chatClient.prompt()
            ...
            .entity(converter);
}

这样避免了Spring自动配置机制的干扰。

07 应用场景扩展

场景用户输入OutputParser输出后续用途
会议信息提取"明天下午3点开会"{topic, time, location, duration}自动创建日历事件
订餐系统"我要一份宫保鸡丁,微辣"{dish:"宫保鸡丁", spice:"微辣", quantity:1}生成订单
智能表单用户任意描述需求{title, description, priority, assignee}自动创建工单
数据查询"帮我看看上个月销售额"{total:1280000, month:7, growth:0.12}生成报表

08 下期预告

到此为止,我们已经完成了 Spring AI 的核心功能闭环:

功能状态
首次调用 API
多轮对话
流式输出
Function Calling
Output Parser

接下来,我们将进入企业级AI应用的核心领域——RAG(检索增强生成)。

RAG让AI能够基于你的私有文档(PDF、Word、TXT等)回答问题,解决大模型“知识陈旧”和“幻觉”问题。这也是目前企业AI应用落地最广泛的技术方案。

下一篇,我们开始搭建第一个RAG知识库。


📌 我是超超不吵吵,10年Java全栈,正在转型AI应用开发。
每周一篇实战笔记,不贩卖焦虑,只分享能落地的技术。
掘金/CSDN同名,欢迎关注。