Spring AI 结构化输出 + 大模型参数全解(含千问调优)

目录

一、什么是结构化输出?

[1. 定义](#1. 定义)

[2. 为什么要用?](#2. 为什么要用?)

[3. Spring AI 两种实现方式](#3. Spring AI 两种实现方式)

[方式 1:ChatClient 的 .entity ()(最简洁,推荐)](#方式 1:ChatClient 的 .entity ()(最简洁,推荐))

[方式 2:BeanOutputConverter(灵活可控,适合复杂场景)](#方式 2:BeanOutputConverter(灵活可控,适合复杂场景))

[1. 输入阶段(Prompt)](#1. 输入阶段(Prompt))

[2. 推理阶段(核心:概率计算)](#2. 推理阶段(核心:概率计算))

[3. 采样阶段(参数控制:temperature/top_p/top_k)](#3. 采样阶段(参数控制:temperature/top_p/top_k))

[4. 输出阶段(循环直到结束)](#4. 输出阶段(循环直到结束))

[5. 结构化输出的额外步骤](#5. 结构化输出的额外步骤)

四、三大核心参数详解(temperature/top_p/top_k)

[1. Temperature(温度:控制创造力)](#1. Temperature(温度:控制创造力))

[2. Top-K(限制候选词数量)](#2. Top-K(限制候选词数量))

[3. Top-P(核采样:动态累积概率)](#3. Top-P(核采样:动态累积概率))

[4. 场景化参数推荐](#4. 场景化参数推荐)

五、总结


一、什么是结构化输出?

1. 定义

结构化输出(Structured Output) :让大模型不返回自由文本,而是严格按指定格式(如 JSON)输出 ,程序可直接解析成对象,免手动字符串处理、免正则、免 JSON.parse 异常Spring。

2. 为什么要用?

  • 类型安全:直接映射到 Java Bean,编译期校验字段
  • 稳定性高:模型输出固定字段,无多余解释
  • 开发高效 :告别String→手动解析→try-catch
  • 易集成:直接对接数据库、API、前端 JSON

3. Spring AI 两种实现方式

方式 1:ChatClient 的 .entity ()(最简洁,推荐)

底层封装了BeanOutputConverter,一行代码直接返回 Bean。

复制代码
// 直接返回 Weather 对象,无需手动转换
Weather weather = chatClient.prompt("查询北京今日天气")
    .call()
    .entity(Weather.class); // 自动JSON→Bean
方式 2:BeanOutputConverter(灵活可控,适合复杂场景)

手动创建转换器,可自定义 Schema、清洗规则。

复制代码
// 1. 初始化转换器
BeanOutputConverter<Weather> converter = new BeanOutputConverter<>(Weather.class);

// 2. 提示词强制JSON格式(注入Schema要求)
String prompt = """
    查询 %s 今日天气,仅返回JSON,不要解释。
    %s
    """.formatted("北京", converter.getFormat());

// 3. 调用模型 + 转换
String json = chatClient.prompt(prompt).call().content();
Weather weather = converter.convert(json);

代码案例:

复制代码
package org.example.ai_demo.entity;

import lombok.Data;

@Data // Lombok:自动生成getter/setter/toString/无参构造
public class Weather {
    private String city;        // 城市
    private String temperature; // 温度
    private String weatherDesc; // 天气状况(晴/雨)
    private String wind;        // 风向风力
}

package org.example.ai_demo.controller;

import org.example.ai_demo.entity.Weather;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.converter.BeanOutputConverter;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class WeatherController {

    private final ChatClient chatClient;

    // 注入ChatClient(Spring AI自动配置)
    public WeatherController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    // 方式1:.entity() 简洁版(推荐)
    @GetMapping("/weather/simple")
    public Weather getWeatherSimple(@RequestParam String city) {
        return chatClient.prompt("查询" + city + "今日天气,仅返回JSON")
                .call()
                .entity(Weather.class);
    }

    // 方式2:BeanOutputConverter 完整版
    @GetMapping("/weather/full")
    public Weather getWeatherFull(@RequestParam String city) {
        // 初始化转换器
        BeanOutputConverter<Weather> converter = new BeanOutputConverter<>(Weather.class);

        // 构造提示词(强制JSON + 注入Schema)
        String prompt = String.format("""
                查询 %s 的今日天气,严格返回JSON,不要任何额外文字。
                输出格式要求:%s
                """, city, converter.getFormat());

        // 调用模型并转换
        String jsonResult = chatClient.prompt(prompt).call().content();
        return converter.convert(jsonResult);
    }
}

要记得引入依赖:

复制代码
<!-- Spring AI 核心 -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-core</artifactId>
    <version>1.0.0-M1</version>
</dependency>

<!-- 通义千问适配器(阿里云) -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-alibaba-starter</artifactId>
    <version>1.0.0-M1</version>
</dependency>

<!-- Lombok(@Data 必须) -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

<!-- Web(控制器) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

三、大模型是如何工作的?

大模型(如通义千问)的问答过程,本质是逐词预测、概率采样、拼接输出的循环:

1. 输入阶段(Prompt)

你输入问题:"查询北京今日天气" → 模型把文字转成Token(词 / 字) → 输入神经网络。

2. 推理阶段(核心:概率计算)

模型计算下一个 Token 的概率分布 (比如:"北京""今日"概率 90%,"明天"概率 8%,"昨天"概率 2%)。

3. 采样阶段(参数控制:temperature/top_p/top_k)

根据温度、top_p、top_k筛选候选 Token,随机选一个(控制输出严谨度 / 创意度)。

4. 输出阶段(循环直到结束)

选中的 Token 加入输出 → 作为新输入,重复步骤 2-3 → 直到遇到结束符(</s>) → 输出完整回答。

5. 结构化输出的额外步骤

在 Prompt 中加入JSON Schema 约束 → 模型按 Schema 生成 JSON → Spring AI 的BeanOutputConverter自动反序列化为 Java BeanSpring 框架。

四、三大核心参数详解(temperature/top_p/top_k)

1. Temperature(温度:控制创造力)

  • 范围0 ≤ temperature ≤ 2(推荐 0.1--1.0)
  • 作用 :调整概率分布的尖锐度
    • 低(0.1--0.3) :概率集中,输出严谨、稳定、少幻觉(适合代码、事实问答、RAG)
    • 中(0.4--0.7):平衡准确与多样(日常对话、文案、翻译,默认 0.7)
    • 高(0.8--1.2) :概率分散,输出创意、发散、易跑题(写诗、故事、 brainstorm)
  • 公式logits_after = logits / temperature → softmax 转概率

2. Top-K(限制候选词数量)

  • 范围1 ≤ top_k ≤ 100(常用 10--50)
  • 作用 :只保留概率最高的 K 个 Token ,其余概率置 0 → 从 K 个中采样
    • top_k=1:贪心搜索,永远选概率最高的,输出固定
    • top_k=50:保留前 50 个候选,平衡稳定与多样
  • 优缺点:避免极低概率词选中,但 K 固定,无法适配不同分布

3. Top-P(核采样:动态累积概率)

  • 范围0 ≤ top_p ≤ 1(常用 0.7--0.9)
  • 作用 :累积概率**≥P** 时截断候选 → 只从高概率集合中采样
    • top_p=0.9:保留累积概率 90% 的候选(动态数量,适配分布)
    • top_p=1.0:不截断,全候选采样
  • 优势:比 top_k 更灵活,优先选高概率词,兼顾多样性

4. 场景化参数推荐

场景 Temperature Top-P Top-K 说明
代码生成 / SQL 0.2--0.4 0.7 10 严谨、语法正确
知识库 / RAG 问答 0.1--0.3 0.8 20 少幻觉、忠于参考
日常对话 / 文案 0.5--0.7 0.9 50 平衡准确与流畅
创意写作 / 写诗 0.8--1.0 0.95 80 发散、有想象力

五、总结

  1. 结构化输出 :大模型返回 JSON,Spring AI 一键转 Java Bean,类型安全、稳定高效Spring。
  2. 两种写法.entity()简洁、BeanOutputConverter灵活。
  3. 三大参数temperature 控创意、top_k 控数量、top_p 控概率,场景化设置即可。
  4. 千问调优 :先 API 参数调优,复杂场景用 SFT 微调,temperature≤0.5是结构化输出关键。
相关推荐
云烟成雨TD1 小时前
Spring AI Alibaba 1.x 系列【79】图执行生命周期的可观测性基础设施
java·人工智能·spring
copyer_xyf1 小时前
FastAPI 项目骨架搭建
前端·后端·python
霸道流氓气质1 小时前
Java 单元测试生成大量 Excel 测试数据实战指南
java·单元测试·excel
io无心1 小时前
基于Image 2的多配件商品图生成技术实现(已开源)
java·image2
逢君学术论文AI写作1 小时前
Java第22课:Servlet获取请求参数+POST请求+表单交互
java·servlet·ai写作
神明不懂浪漫1 小时前
【第二章】Java中的数据类型,运算符与程序逻辑控制
java·开发语言·经验分享·笔记
laowangpython1 小时前
tokio-rstracing:Rust 可观测性的标准答案
开发语言·后端·其他·rust
小马爱打代码1 小时前
Java 开发:过滤器(Filter)与拦截器(Interceptor)深度解析 + CORS 跨域完整解决方案
java
IT_陈寒1 小时前
Python虚拟环境的这个坑,我居然绕了三天才爬出来
前端·人工智能·后端