Spring AI Alibaba 1.x 系列【24】结构化输出(Structured Output)

文章目录

  • [1. 核心概念](#1. 核心概念)
    • [1.1 什么是结构化输出](#1.1 什么是结构化输出)
    • [1.2 Spring AI Alibaba 实现方式](#1.2 Spring AI Alibaba 实现方式)
  • [2. 快速入门](#2. 快速入门)
    • [2.1 定义输出 POJO](#2.1 定义输出 POJO)
    • [2.2 使用 outputType](#2.2 使用 outputType)
    • [2.3 使用 outputSchema](#2.3 使用 outputSchema)
  • [3. 复杂嵌套结构](#3. 复杂嵌套结构)
    • [3.1 商品评价分析(嵌套对象)](#3.1 商品评价分析(嵌套对象))
    • [3.2 文本实体分析](#3.2 文本实体分析)
  • [4. 实现原理](#4. 实现原理)
    • [4.1 模型原生结构化输出(最优)](#4.1 模型原生结构化输出(最优))
    • [4.2 ToolCall 兜底(通用)](#4.2 ToolCall 兜底(通用))
    • [4.3 指令增强机制](#4.3 指令增强机制)
  • [5. 错误处理策略](#5. 错误处理策略)
    • [5.1 Try-Catch 基础处理](#5.1 Try-Catch 基础处理)
    • [5.2 数据验证模式](#5.2 数据验证模式)
    • [5.3 重试模式](#5.3 重试模式)

1. 核心概念

1.1 什么是结构化输出

结构化输出允许 Agent 按照预定义的格式返回数据,替代传统的自然语言响应:

  • 输入:用户指令 + 输出格式规则
  • 输出:标准 JSON 字符串 / 直接映射为 Java POJO
  • 优势:类型安全、无歧义、程序可直接消费

结构化输出是 AI Agent 工程化落地的核心能力,它让 Agent 摆脱自然语言的模糊性,以固定格式返回数据,应用程序可直接解析使用,无需复杂的文本提取逻辑。

1.2 Spring AI Alibaba 实现方式

ReactAgent.Builder 提供两个核心方法实现结构化输出:

  1. outputSchema(String schema):手动指定 JSON Schema 字符串
  2. outputType(Class<?> type):传入 Java 类,自动生成 JSON Schema(推荐)

outputType 直接传入 Java POJO 类,框架通过 BeanOutputConverter 自动生成 JSON Schema,无需手动编写 ,编译期类型校验。

方法签名

java 复制代码
Builder outputType(Class<?> outputType)

outputSchema 手动传入 JSON Schema 字符串,支持完全自定义输出格式。

方法签名

java 复制代码
Builder outputSchema(String outputSchema)
特性 outputType outputSchema
使用方式 直接传入 Java 类 传入 JSON Schema 字符串
类型安全 ✅ 编译期校验 ❌ 运行时校验
维护成本 低(自动生成) 高(手动维护)
灵活性 标准格式 完全自定义
推荐场景 绝大多数业务场景 极端自定义格式场景

2. 快速入门

2.1 定义输出 POJO

java 复制代码
/**
 * 联系方式输出实体(标准Java POJO)
 */
public static class ContactInfo {
    private String name;
    private String email;
    private String phone;

    // Getter & Setter
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public String getPhone() { return phone; }
    public void setPhone(String phone) { this.phone = phone; }
}

2.2 使用 outputType

java 复制代码
import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import com.alibaba.cloud.ai.graph.checkpoint.savers.MemorySaver;
import org.springframework.ai.chat.messages.AssistantMessage;

// 构建Agent,直接指定输出类型
ReactAgent agent = ReactAgent.builder()
        .name("contact_extractor")
        .model(chatModel) // 注入ChatModel
        .outputType(ContactInfo.class) // 核心:指定输出POJO
        .saver(new MemorySaver())
        .build();

// 执行调用
AssistantMessage result = agent.call("从以下信息提取联系方式:张三,zhangsan@example.com,(555) 123-4567");

// 输出标准JSON
System.out.println(result.getText());

输出结果

json 复制代码
{"name": "张三", "email": "zhangsan@example.com", "phone": "(555) 123-4567"}

2.3 使用 outputSchema

java 复制代码
import org.springframework.ai.converter.BeanOutputConverter;

// 自动从POJO生成JSON Schema
BeanOutputConverter<ContactInfo> converter = new BeanOutputConverter<>(ContactInfo.class);
String schema = converter.getFormat();

// 构建Agent
ReactAgent agent = ReactAgent.builder()
        .name("contact_extractor")
        .model(chatModel)
        .outputSchema(schema) // 传入Schema
        .build();

3. 复杂嵌套结构

结构化输出完美支持嵌套对象、数组、复杂实体,适用于文本分析、评价提取、实体识别等场景。

3.1 商品评价分析(嵌套对象)

java 复制代码
/**
 * 商品评价复杂输出结构
 */
public static class ProductReview {
    private int rating;
    private String sentiment;
    private String[] keyPoints;
    private ReviewDetails details;

    // 嵌套子类
    public static class ReviewDetails {
        private String[] pros;
        private String[] cons;
        // Getter & Setter
    }

    // Getter & Setter
}

// 使用
BeanOutputConverter<ProductReview> converter = new BeanOutputConverter<>(ProductReview.class);
ReactAgent agent = ReactAgent.builder()
        .name("review_analyzer")
        .model(chatModel)
        .outputSchema(converter.getFormat())
        .build();

AssistantMessage result = agent.call("分析评价:这个产品很棒,5星好评。配送快速,但价格稍贵。");

3.2 文本实体分析

java 复制代码
/**
 * 文本分析输出结构
 */
public static class TextAnalysis {
    private String summary;
    private String[] keywords;
    private String sentiment;
    private Entities entities;

    public static class Entities {
        private String[] persons;
        private String[] locations;
        private String[] organizations;
        // Getter & Setter
    }
    // Getter & Setter
}

4. 实现原理

4.1 模型原生结构化输出(最优)

支持原生结构化输出的模型(OpenAI、通义千问 DashScope),框架自动启用模型内置能力:

  • 严格保证 JSON 格式
  • 模型服务端自动校验格式

示例(DashScope):

java 复制代码
ChatOptions options = DashScopeChatOptions.builder()
        .withResponseFormat(DashScopeResponseFormat.builder()
                .type(DashScopeResponseFormat.Type.JSON_OBJECT)
                .build())
        .build();

Spring AI Alibaba 框架会增强系统 Prompt,引导模型输出格式化内容

增强用户消息方法示例:

java 复制代码
/ In AgentLlmNode.augmentUserMessage() method
public void augmentUserMessage(List<Message> messages, String outputSchema) {
  if (!StringUtils.hasText(outputSchema)) {
      return;
  }

  for (int i = messages.size() - 1; i >= 0; i--) {
      Message message = messages.get(i);
      if (message instanceof UserMessage userMessage) {
          messages.set(i, userMessage.mutate()
              .text(userMessage.getText() + System.lineSeparator() + outputSchema)
              .build());
          break;
      }
  }
}

注意 ,相比于 DashScope 模型是通过增强 Prompt 提示词实现最终的 JSON 格式,实现的是一个尽最大努力的效果,OpenAI 模型则是在模型 API 层面支持 Json 格式,提供格式的严格保证支持。

4.2 ToolCall 兜底(通用)

对于不支持原生结构化输出的模型,Spring AI Alibaba 支持通过调用工具来实现相同效果。此方法适用于所有支持工具调用的模型,即大多数现代模型。

4.3 指令增强机制

框架会自动在用户消息末尾追加格式指令,引导模型输出规范内容:

java 复制代码
// 核心增强逻辑:为用户消息追加Schema指令
public void augmentUserMessage(List<Message> messages, String outputSchema) {
    for (int i = messages.size() - 1; i >= 0; i--) {
        Message message = messages.get(i);
        if (message instanceof UserMessage userMessage) {
            messages.set(i, userMessage.mutate()
                    .text(userMessage.getText() + "\n" + outputSchema)
                    .build());
            break;
        }
    }
}

5. 错误处理策略

模型可能偶尔返回格式异常的 JSONSpring AI Alibaba 提供三种可靠的错误处理方案。

5.1 Try-Catch 基础处理

java 复制代码
import com.fasterxml.jackson.databind.ObjectMapper;

ObjectMapper mapper = new ObjectMapper();
try {
    AssistantMessage result = agent.call("提取数据");
    // JSON 转 Java 对象
    ContactInfo data = mapper.readValue(result.getText(), ContactInfo.class);
} catch (JsonProcessingException e) {
    System.err.println("JSON 解析失败:" + e.getMessage());
    System.err.println("原始响应:" + result.getText());
}

5.2 数据验证模式

java 复制代码
/**
 * 带校验逻辑的输出实体
 */
public class ValidatedOutput {
    private String title;
    private Integer rating;

    // 自定义校验规则
    public void validate() {
        if (title == null || title.isEmpty()) {
            throw new IllegalArgumentException("标题不能为空");
        }
        if (rating < 1 || rating > 5) {
            throw new IllegalArgumentException("评分必须在1-5之间");
        }
    }
}

AssistantMessage result = agent.call("生成评价");
ValidatedOutput output = mapper.readValue(result.getText(), ValidatedOutput.class);
output.validate();  // 如果无效则抛出异常

5.3 重试模式

java 复制代码
int maxRetries = 3;
ContactInfo data = null;
ObjectMapper mapper = new ObjectMapper();

for (int i = 0; i < maxRetries; i++) {
    try {
        AssistantMessage result = agent.call("提取联系方式");
        data = mapper.readValue(result.getText(), ContactInfo.class);
        break;
    } catch (Exception e) {
        if (i == maxRetries - 1) {
            throw new RuntimeException("重试" + maxRetries + "次后失败", e);
        }
        System.out.println("第" + (i+1) + "次失败,正在重试...");
    }
}
相关推荐
北京耐用通信2 小时前
告别通讯掉线!耐达讯自动化Modbus转Profinet网关:工业现场的“定海神针”
服务器·人工智能·网络协议·自动化·信息与通信
Ww.xh2 小时前
ESP8266连接AI大模型完整指南
人工智能·算法·语言模型
奇思智算2 小时前
GPU 算力显存延迟核心参数解读(2026 年)
人工智能·智星云·gpu算力租用
东离与糖宝2 小时前
循环神经网络 RNN 基础:处理序列数据的核心
人工智能
l1t2 小时前
DeepSeek总结的Open DUMP Viewer for Oracle发版说明
数据库·oracle
程序员雷欧2 小时前
Redis基础知识全解析:从数据结构到生产实战
数据结构·数据库·redis
谁似人间西林客2 小时前
汽车智能制造提质增效,柔性生产是核心破局点
人工智能·汽车·制造
Allnadyy2 小时前
Hnu人工智能导论期中复习(下)
人工智能
21439652 小时前
Redis如何解决哨兵通知延迟问题_优化客户端连接池动态刷新拓扑的订阅监听机制
jvm·数据库·python