乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • Spring AI 学习路径
  • 第1章 Spring AI 概述与核心理念

    • 章节导读
    • Spring AI 概述与可移植 API
    • 核心模块与依赖关系
  • 第2章 快速入门与第一个AI应用

    • 章节导读
    • 环境准备与配置
    • 第一个 AI 对话应用
  • 第3章 聊天模型与ChatClient

    • 章节导读
    • ChatClient 详解
    • ChatModel 底层抽象
    • 多轮对话与 ChatMemory
  • 第4章 提示词管理与模板

    • 章节导读
    • Prompt 与 Message 体系
    • 提示词模板与动态构建
  • 第5章 输出解析与结构化响应

    • 章节导读
    • 输出解析器与 BeanOutputConverter
  • 第6章 嵌入模型与向量存储

    • 章节导读
    • EmbeddingModel 与文本向量化
    • ETL 数据注入流水线
    • 向量存储抽象与配置
  • 第7章 检索增强生成(RAG)

    • 章节导读
    • RAG 核心机制与流程
    • QuestionAnswerAdvisor 详解
    • RAG 实战案例
  • 第8章 函数调用(Function Calling)

    • 章节导读
    • Tool 注解与函数声明
    • 函数调用实战
  • 第9章 多模态

    • 章节导读
    • 图像输入与视觉模型
    • 图像生成
  • 第10章 Advisor拦截器链

    • 章节导读
    • Advisor 链与内置拦截器
  • 第11章 MCP 协议与跨语言工具集成

    • 章节导读
    • MCP 协议深入
  • 第12章 可观测性测试与最佳实践

    • 章节导读
    • 可观测性与指标监控
    • 测试策略与 Mock 实践
    • 最佳实践与面试考点汇总

黄俪在设计课程管理后台时抱怨:"每门课都要配封面图,找素材太费时间了。"白歌指了指屏幕:"让 AI 画——ImageModel 一行代码出图。"

图像生成

定义与作用

Spring AI 的 ImageModel 接口封装了 AI 图像生成能力——通过文本描述(Prompt)生成图片。与视觉模型("看图说话")方向相反,图像生成是"依话画图"。

核心原理

图释:ImageModel 接收文本描述,调用图像生成 API(如 OpenAI DALL-E),返回 ImageResponse 包含生成的图片数据,应用可将其保存到本地文件系统。

完整示例一:生成课程封面图

场景说明

黄俪需要为飞翔大学课程管理系统自动生成课程封面图。

依赖引入与配置

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      image:
        options:
          model: dall-e-3
          size: 1024x1024
          quality: standard

关键代码

@Service
public class CourseCoverService {

    private final ImageModel imageModel;

    public CourseCoverService(ImageModel imageModel) {
        this.imageModel = imageModel;
    }

    public String generateAndSave(String courseName, String outputPath) 
            throws IOException {
        // 构建生成提示词
        ImagePrompt prompt = new ImagePrompt(
            String.format("""
                为课程"%s"设计一张现代简约风格的封面图。
                要求:教育科技主题,蓝白配色,包含抽象的算法/数据结构图案,
                不要出现文字。适合用于在线教育平台展示。
                """, courseName),
            ImageOptions.builder()
                .model("dall-e-3")
                .quality("standard")
                .N(1)
                .height(1024)
                .width(1024)
                .build()
        );

        // 调用图像生成
        ImageResponse response = imageModel.call(prompt);
        Image image = response.getResult().getOutput();

        // 保存到本地
        String url = image.getUrl();   // 或 image.getB64Json() 获取 Base64
        if (url != null) {
            downloadImage(url, outputPath);
        } else {
            saveBase64Image(image.getB64Json(), outputPath);
        }

        return outputPath;
    }

    private void downloadImage(String url, String path) throws IOException {
        try (InputStream in = new URL(url).openStream()) {
            Files.copy(in, Path.of(path), StandardCopyOption.REPLACE_EXISTING);
        }
    }

    private void saveBase64Image(String b64Json, String path) 
            throws IOException {
        byte[] data = Base64.getDecoder().decode(b64Json);
        Files.write(Path.of(path), data);
    }
}
@RestController
public class CoverController {

    private final CourseCoverService coverService;

    public CoverController(CourseCoverService coverService) {
        this.coverService = coverService;
    }

    @PostMapping("/course/cover")
    public Map<String, String> generateCover(@RequestParam String courseName) 
            throws IOException {
        String fileName = courseName.replaceAll("\\s+", "_") + "_cover.png";
        String outputPath = "C:\\Users\\AOXIANG\\Desktop\\SpringAI\\covers\\" 
                          + fileName;

        Files.createDirectories(Path.of(outputPath).getParent());
        String savedPath = coverService.generateAndSave(courseName, outputPath);

        return Map.of("course", courseName, "coverPath", savedPath);
    }
}

运行结果

POST /course/cover?courseName=数据结构与算法

{
  "course": "数据结构与算法",
  "coverPath": "C:\\Users\\AOXIANG\\Desktop\\SpringAI\\covers\\数据结构与算法_cover.png"
}

控制台日志:
[main] INFO  c.f.s.CourseCoverService - 调用 DALL-E 3 生成课程封面...
[main] INFO  c.f.s.CourseCoverService - 图片已保存:1024×1024,文件大小 2.3MB

完整示例二:批量生成多尺寸缩略图

场景说明

杨英要做活动推广,需要为同一门课程生成多种尺寸的推广图。

关键代码

@Service
public class ThumbnailService {

    private final ImageModel imageModel;

    public ThumbnailService(ImageModel imageModel) {
        this.imageModel = imageModel;
    }

    public Map<String, String> generateThumbnails(
            String courseName, String outputDir) throws IOException {
        
        Map<String, String> results = new HashMap<>();

        // 尺寸 1:大图 1024×1024
        results.put("large", generate(courseName, outputDir, "large", 
            1024, 1024));

        // 尺寸 2:小图 256×256
        results.put("small", generate(courseName, outputDir, "small", 
            256, 256));

        return results;
    }

    private String generate(String courseName, String dir, 
            String sizeLabel, int w, int h) throws IOException {
        
        ImagePrompt prompt = new ImagePrompt(
            String.format("课程封面:%s,简洁风格", courseName),
            ImageOptions.builder()
                .model("dall-e-2")       // dall-e-2 便宜且够用
                .N(1)
                .height(h)
                .width(w)
                .build()
        );

        ImageResponse response = imageModel.call(prompt);
        String url = response.getResult().getOutput().getUrl();
        String path = dir + "\\" + courseName + "_" + sizeLabel + ".png";

        try (InputStream in = new URL(url).openStream()) {
            Files.copy(in, Path.of(path), StandardCopyOption.REPLACE_EXISTING);
        }

        return path;
    }
}

运行结果

POST /course/thumbnails?courseName=线性代数

{
  "large": ".../covers/线性代数_large.png (1024×1024, 2.3MB)",
  "small": ".../covers/线性代数_small.png (256×256, 48KB)"
}

易错场景与面试考点

易错场景一:混淆 ImageModel 和 Vision Model

// ❌ 错误:想用 ChatClient 生成图片
chatClient.prompt()
    .user("画一张课程封面")
    .call()
    .content();  // 返回文本描述,不是图片

问题分析

ChatClient 返回的是文本,ImageModel 返回的是图片数据。两者方向相反。

// ✅ 正确:使用 ImageModel 生成图片
ImagePrompt prompt = new ImagePrompt("课程封面:数据结构");
ImageResponse response = imageModel.call(prompt);
// 从 response 获取图片 URL 或 Base64 数据

面试高频题

Q1:ImageModel 和 ChatClient 的视觉输入有什么区别?

ImageModel 是"文本 → 图片"(生成式),ChatClient + Media 是"图片 → 文本"(理解式)。前者创建新图片,后者分析已有图片。两者在 Spring AI 中使用不同的接口。

Q2:如何降低图像生成的 API 成本?

①小图优先用 dall-e-2(约 $0.02/张),大图用 dall-e-3(约 $0.04/张);②合理设置尺寸(256×256 比 1024×1024 便宜很多);③缓存已生成的封面图,避免重复调用。④本地环境可使用 Stable Diffusion 等开源模型完全免费。

本章小结

  • ImageModel 接口实现"文本 → 图片"的 AI 生成
  • ImagePrompt + ImageOptions 控制生成参数(模型、尺寸、质量)
  • 返回的 ImageResponse 可通过 URL 或 Base64 获取图片数据
  • 与视觉模型方向相反:"看图说话"用 ChatClient + Media,"依话画图"用 ImageModel
上一页
图像输入与视觉模型