Spring AI深度解析(6/50):Structured Output结构化输出


一、结构化输出的本质价值

在大模型应用中,非结构化文本输出(如自由格式回答)会导致下游系统难以编程处理。Spring AI通过结构化输出技术,将大模型的自由文本输出转化为机器可读的数据结构(JSON/XML/Java对象),从而实现两大核心价值:

  1. 系统集成友好性:API返回值可直接映射为DTO对象
  2. 流程自动化:输出结构可触发后续业务逻辑(如自动创建工单、更新数据库)

二、Spring AI的三大实现路径

  1. 提示工程法(Prompt Engineering)
    通过提示词约束模型输出格式,适合简单场景。
String promptTemplate = """
    请将以下用户反馈分类为JSON格式:
    {feedback}
    
    输出要求:
    - 包含字段:category(问题类型), priority(优先级1-5), tags(标签数组)
    - 示例:{"category": "支付问题", "priority": 3, "tags": ["支付失败", "订单异常"]}
    """;

Prompt prompt = new PromptTemplate(promptTemplate)
    .create(Map.of("feedback", "付款后订单状态未更新"));
  1. 输出解析器(OutputParser)
    将模型输出解析为Java对象,支持类型安全操作。
// 定义数据结构
public record FeedbackAnalysis(
    String category, 
    int priority, 
    List<String> tags
) {}

// 注册JSON解析器
@Bean
public OutputParser<FeedbackAnalysis> jsonParser() {
    return new JacksonOutputParser<>(FeedbackAnalysis.class);
}

// 调用模型并解析
String modelOutput = chatClient.call(prompt).getContent();
FeedbackAnalysis analysis = jsonParser().parse(modelOutput);
  1. 函数调用(Function Calling)
    模型直接返回结构化参数,实现最高可靠性。
// 定义函数规范
@FunctionDescription(name = "analyzeFeedback", description = "分析用户反馈")
public record FeedbackFunction(
    @ParameterDescription(description = "问题类型") String category,
    @ParameterDescription(description = "优先级1-5") int priority,
    @ParameterDescription(description = "标签列表") List<String> tags
) {}

// 调用模型并获取结构化参数
ChatResponse response = chatClient.call(
    new Prompt(prompt, 
        OpenAiChatOptions.builder()
            .withFunction("analyzeFeedback")
            .build())
);

FunctionCall functionCall = response.getResult().getFunctionCall();
FeedbackFunction params = functionCall.getArgumentsAs(FeedbackFunction.class);

三、生产级结构化输出实战

  1. 多模型适配方案
    不同模型需采用不同策略(以智谱AI为例):
// 智谱AI需通过Prompt约束JSON输出(暂不支持函数调用)
String zhipuPrompt = """
    请严格按以下JSON格式分析用户反馈:
    {feedback}
    
    格式示例:{"category": "账户问题", "priority": 2}
    """;

// 使用Jackson手动解析
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(modelOutput);
String category = root.get("category").asText();
  1. 混合校验机制
    结合Schema校验与LLM自检,确保输出可靠性。
public FeedbackAnalysis validateOutput(String json) {
    // 1. 基础JSON校验
    if (!jsonSchemaValidator.validate(json)) {
        throw new InvalidOutputException("JSON格式错误");
    }
    
    // 2. 调用模型进行语义校验
    String validationPrompt = """
        请检查以下分析结果是否合理:
        {json}
        
        用户反馈内容:{feedback}
        返回YES或NO
        """;
    
    String result = chatClient.call(
        new PromptTemplate(validationPrompt)
            .create(Map.of("json", json, "feedback", feedback))
    ).getContent();
    
    if (!"YES".equalsIgnoreCase(result)) {
        throw new SemanticValidationException("逻辑校验失败");
    }
    
    return mapper.readValue(json, FeedbackAnalysis.class);
}

四、性能优化与陷阱规避

  1. 性能优化技巧
优化维度 策略
Token开销 优先使用函数调用(结构化参数通常比JSON字符串更紧凑)
解析性能 缓存ObjectMapper实例,避免重复创建
模型适配 对不支持函数调用的模型,在Prompt中提供更详细的格式示例
  1. 常见陷阱与解决方案
问题现象 根本原因 解决方案
JSON格式错误 模型未严格遵循格式要求 在Prompt中添加Schema示例 + 输出后正则表达式修正
字段语义漂移 模型对字段含义理解偏差 在Prompt中明确定义字段枚举值(如priority只能是1-5)
数组元素数量不可控 模型动态生成标签数量 使用@ParameterDescription明确约束(如"最多3个标签") + 后处理截断

五、端到端案例:工单自动分类系统

  1. 业务需求
    将用户提交的文本反馈自动分类为结构化工单,触发后续处理流程。

  2. 技术实现

// 1. 定义工单结构
public record SupportTicket(
    String category, 
    int priority, 
    List<String> tags,
    String summary
) {}

// 2. 构建提示(含示例)
String promptTemplate = """
    根据用户反馈生成工单:
    {feedback}
    
    输出要求:
    - 包含字段:category, priority(1-5), tags, summary
    - 示例:
      {
        "category": "登录问题",
        "priority": 2,
        "tags": ["密码错误", "账户锁定"],
        "summary": "用户多次登录失败导致账户锁定"
      }
    """;

// 3. 调用模型
String feedback = "重置密码后仍无法登录,提示‘安全验证失败’";
Prompt prompt = new PromptTemplate(promptTemplate)
    .create(Map.of("feedback", feedback));
ChatResponse response = chatClient.call(prompt);

// 4. 解析并校验
ObjectMapper mapper = new ObjectMapper();
SupportTicket ticket = mapper.readValue(response.getContent(), SupportTicket.class);

// 5. 触发下游系统
jdbcTemplate.update(
    "INSERT INTO tickets(category, priority) VALUES (?, ?)",
    ticket.category(), ticket.priority()
);

六、总结与演进方向

  1. 核心价值总结
    • 数据就绪性:输出可直接进入业务系统,无需人工解析

• 质量可控性:通过Schema校验与混合验证保障输出可靠性

• 多模型适配:统一接口兼容不同厂商模型能力差异

  1. 演进趋势
    • 多模态结构化输出:输出包含文本、图片链接的复合结构

• 动态Schema适配:根据用户请求自动生成输出格式

• 自愈式解析:当解析失败时,自动触发模型修正流程


通过结构化输出,Spring AI帮助开发者将大模型的非结构化能力无缝集成至企业系统,实现从「对话交互」到「业务动作」的质变升级。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐