图像生成初探:OpenAI 与千帆平台一键出图

前面我们让 AI 学会了对话、推理,但一直局限于文字。今天我们要解锁一个新维度------图像生成。只需要一句描述,AI 就能帮你画出对应的图片。

在 Spring AI 中,图像生成和对话聊天使用的是完全不同的模型接口。对话用的是 ChatClient,而图像生成用的是 ImageModel。好消息是,Spring AI 对图像模型也做了统一抽象,接入 OpenAI DALL-E 和百度千帆的文生图服务,代码结构几乎一样。今天我们就来同时打通这两条路,让你感受"一套 API,两套模型"的便捷。

一、痛点场景:当文字不够用的时候

你是否遇到过这样的需求:

  • 做一个"AI 绘画"功能,用户输入"一只戴着墨镜的柴犬在沙滩上冲浪",后端调用模型生成图片并返回。
  • 需要动态生成营销海报背景,而不是让设计师手动出图。
  • 想在应用中集成图片生成能力,但不想维护两套代码去对接不同的厂商。

如果你之前有过对接图像生成 API 的经验,可能会头疼于各家不同的请求格式、认证方式、返回结构。Spring AI 的 ImageModel 抽象正是为此而生:它定义了统一的 ImagePrompt 输入和 ImageResponse 输出,让你用同样的代码风格调用完全不同的图像模型。

二、核心概念快览

2.1 ImageModel:图像生成的"ChatClient"

ChatModel 负责聊天类似,ImageModel 是 Spring AI 中负责图像生成的核心接口。它定义了一个 call 方法,接收 ImagePrompt,返回 ImageResponse

2.2 ImagePrompt 与 ImageOptions

  • ImagePrompt :封装了一次图像生成请求的所有信息,包括提示词(描述文字)和生成选项(ImageOptions)。
  • ImageOptions :控制生成参数,比如图片尺寸、数量、风格等。不同模型支持的选项不同,但 Spring AI 提供了一组通用的属性,比如 heightwidthn(生成数量)。

2.3 工作流程

复制代码
用户输入描述文字
    ↓
构建 ImagePrompt(描述 + 选项)
    ↓
调用 imageModel.call(imagePrompt)
    ↓
返回 ImageResponse(包含生成的图片 URL 或 Base64 数据)

你不需要关心底层是 OpenAI 的 HTTP API 还是千帆的 RESTful 接口,因为 Spring AI 的自动配置已经帮你封装好了。

三、环境准备

3.1 获取 API Key

OpenAI

访问 platform.openai.com/api-keys 创建 API Key。图像生成需要账户有额度,DALL-E 2 和 DALL-E 3 的计费不同,建议先用 DALL-E 2 测试(成本更低)。

百度千帆

访问 console.bce.baidu.com/qianfan 开通千帆服务。在"应用接入"中创建应用,获取 API KeySecret Key。千帆需要使用这两把钥匙通过 OAuth 获取 access_token,Spring AI 的 starter 会自动处理。

务必设置环境变量,避免将 Key 写入代码仓库:

  • OpenAI:export OPENAI_API_KEY=sk-xxx
  • 千帆:export QIANFAN_API_KEY=your-api-keyexport QIANFAN_SECRET_KEY=your-secret-key

3.2 Maven 依赖

pom.xml 中同时引入 OpenAI 和千帆的图像生成支持。我们继续使用 Spring AI 的 BOM 管理版本。

xml 复制代码
<dependencies>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring AI OpenAI Starter(包含 Chat 和 Image 模型) -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-openai</artifactId>
    </dependency>

    <!-- Spring AI Qianfan Starter(包含聊天、图像、嵌入等) -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-qianfan</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>1.1.6</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

这两个 starter 可以在同一项目中共存,因为它们的自动配置会根据配置的前缀(spring.ai.openaispring.ai.qianfan)区分,不会互相冲突。如果你的项目之前只有 OpenAI starter,直接添加千帆依赖即可。

3.3 application.yml 配置

yaml 复制代码
spring:
  ai:
    # OpenAI 图像生成配置
    openai:
      api-key: ${OPENAI_API_KEY}
      image:
        options:
          model: dall-e-2          # 可选 dall-e-3,但更贵
          size: 1024x1024          # 图片尺寸
          quality: standard        # dall-e-3 支持 hd
          n: 1                     # 生成数量

    # 百度千帆图像生成配置
    qianfan:
      api-key: ${QIANFAN_API_KEY}
      secret-key: ${QIANFAN_SECRET_KEY}
      image:
        options:
          model: Stable-Diffusion-XL  # 千帆支持的文生图模型
          style: default              # 风格
          n: 1

四、代码实战

4.1 创建 ImageService

我们将分别使用 OpenAiImageModelQianfanImageModel 来演示,因为它们各自需要不同的配置。Service 层直接注入具体实现类,避免歧义。

java 复制代码
package com.example.springaihelloworld.service;

import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.ai.openai.OpenAiImageModel;
import org.springframework.ai.openai.OpenAiImageOptions;
import org.springframework.ai.qianfan.QianfanImageModel;
import org.springframework.ai.qianfan.QianfanImageOptions;
import org.springframework.stereotype.Service;

@Service
public class ImageService {

    private final OpenAiImageModel openAiImageModel;
    private final QianfanImageModel qianfanImageModel;

    public ImageService(OpenAiImageModel openAiImageModel,
                        QianfanImageModel qianfanImageModel) {
        this.openAiImageModel = openAiImageModel;
        this.qianfanImageModel = qianfanImageModel;
    }

    /**
     * 使用 OpenAI DALL-E 生成图片,返回图片 URL
     */
    public String generateImageOpenAI(String prompt) {
        ImageResponse response = openAiImageModel.call(
                new ImagePrompt(prompt,
                        OpenAiImageOptions.builder()
                                .withModel("dall-e-2")       // 模型名称
                                .withHeight(1024)
                                .withWidth(1024)
                                .withN(1)                     // 生成一张
                                .build()));

        // 从响应中提取图片 URL
        String imageUrl = response.getResult().getOutput().getUrl();
        return imageUrl;
    }

    /**
     * 使用百度千帆生成图片,返回图片 URL
     */
    public String generateImageQianfan(String prompt) {
        ImageResponse response = qianfanImageModel.call(
                new ImagePrompt(prompt,
                        QianfanImageOptions.builder()
                                .withModel("Stable-Diffusion-XL")   // 千帆模型
                                .withN(1)
                                .build()));

        String imageUrl = response.getResult().getOutput().getUrl();
        return imageUrl;
    }
}

关键点解读

  • ImagePrompt 的构造函数接收提示词和 ImageOptions
  • 每个模型有自己的 XxxImageOptions 构建器,可以设置特定参数。你也可以跳过这一步,直接使用配置文件中的默认选项。
  • getResult().getOutput().getUrl() 返回生成图片的临时 URL。如果是 Base64 返回,可以使用 getB64Json()(DALL-E 3 默认返回 Base64),但 URL 模式更方便前端直接展示。

4.2 创建 ImageController

java 复制代码
package com.example.springaihelloworld.controller;

import com.example.springaihelloworld.service.ImageService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ImageController {

    private final ImageService imageService;

    public ImageController(ImageService imageService) {
        this.imageService = imageService;
    }

    /**
     * OpenAI 图像生成
     * GET /image/openai?prompt=一只戴着墨镜的柴犬
     * 返回图片 URL
     */
    @GetMapping("/image/openai")
    public String generateOpenAiImage(@RequestParam String prompt) {
        String imageUrl = imageService.generateImageOpenAI(prompt);
        return "图片已生成,URL: " + imageUrl;
    }

    /**
     * 千帆图像生成
     * GET /image/qianfan?prompt=一只戴着墨镜的柴犬
     * 返回图片 URL
     */
    @GetMapping("/image/qianfan")
    public String generateQianfanImage(@RequestParam String prompt) {
        String imageUrl = imageService.generateImageQianfan(prompt);
        return "图片已生成,URL: " + imageUrl;
    }
}

五、运行与演示

5.1 启动应用

确保 OPENAI_API_KEYQIANFAN_API_KEYQIANFAN_SECRET_KEY 三个环境变量已正确设置,然后启动 Spring Boot 应用。

5.2 测试 OpenAI 图像生成

访问:

复制代码
http://localhost:8080/image/openai?prompt=一只戴着墨镜的柴犬在沙滩上冲浪

返回类似:

复制代码
图片已生成,URL: https://oaidalleapiprodscus.blob.core.windows.net/private/org-.../img-....png

复制该 URL 到浏览器,就能看到 AI 画的柴犬冲浪图了。

5.3 测试千帆图像生成

访问:

复制代码
http://localhost:8080/image/qianfan?prompt=一只戴着墨镜的柴犬在沙滩上冲浪

稍等几秒,返回图片 URL。同样在浏览器中打开,验证效果。你可能会发现两个模型生成的风格有所不同,千帆的 Stable Diffusion 画面更偏写实或动漫风格(取决于你的模型选择),而 DALL-E 2 更倾向于艺术化渲染。

六、常见问题与避坑提示

问题一:OpenAI 返回"b64_json"而不是 URL

在 DALL-E 3 中,默认响应格式是 Base64 编码的图片数据,而不是 URL。如果你需要 URL,可以在 OpenAiImageOptions 中设置 withResponseFormat("url")(DALL-E 3 不支持 URL,只支持 Base64)。对于 DALL-E 3,你需要从 getOutput().getB64Json() 获取 Base64 字符串,然后在前端解码显示。

修改方法示例:

java 复制代码
OpenAiImageOptions.builder()
    .withModel("dall-e-3")
    .withResponseFormat("b64_json")  // dall-e-3 只能这样
    .build();
String b64 = response.getResult().getOutput().getB64Json();

问题二:千帆 API 返回"access_token invalid"

原因通常是 api-keysecret-key 配置错误。千帆的认证流程需要先通过 key 和 secret 换取 token,Spring AI 的 starter 会自动处理。如果 token 获取失败,检查环境变量是否正确,且千帆控制台中该应用已启用"图像生成"服务。

问题三:同时存在两个 ImageModel Bean 导致启动报错

我们直接注入了 OpenAiImageModelQianfanImageModel 的具体类型,没有使用 ImageModel 接口,因此不存在歧义。如果你通过 @Autowired ImageModel 注入,Spring 会发现两个候选 Bean 而报错。此时需要使用 @Qualifier@Primary 解决。建议直接注入具体类型,这是最简单稳妥的方式。

问题四:生成的图片有内容安全限制

OpenAI 和千帆都有内容审核机制。如果提示词包含违规内容,API 会拒绝生成并返回错误。应用中应捕获相关异常并给出友好提示。

问题五:生成速度较慢

图像生成通常比文本生成耗时更长,5-20 秒都属正常。如果想提升用户体验,可以像上一篇的流式对话一样,结合异步处理:接口立刻返回"正在生成",然后通过轮询或 WebSocket 推送完成通知和图片地址。

七、小结与下一步预告

本篇回顾

  • 理解了 Spring AI 中 ImageModel 的统一图像生成接口。
  • 掌握了 ImagePromptImageOptions 的构建方式。
  • 使用同一个 Service 结构,分别接入了 OpenAI DALL-E 和百度千帆两个图像生成平台。
  • 学会了如何处理 Base64 和 URL 两种返回格式。

动手建议

在你的项目中挑选一个场景(比如生成用户头像、海报背景),用本文的代码骨架,分别接入 OpenAI 和千帆,对比出图质量和成本,选出最适合你业务的模型。

下一步预告

图像能生成了,那声音呢?下一篇我们将进入 语音交互实战,用 Spring AI 的语音模型封装,实现文本转语音(TTS)和语音转文字(STT)。让你的 AI 应用不仅能"看",还能"说"和"听"。

下一篇《语音交互实战:TTS 与 STT 的 Spring AI 封装》见。


本系列博客基于 Spring AI 1.1.6 版本编写。图像生成模型的可用性和计费规则可能随时变化,请参考各平台的官方文档。实际开发中,请注意图片 URL 的有效期和访问权限限制。

相关推荐
Python大数据分析@4 小时前
现在怎么去学习AI,在哪里去学习?
人工智能·学习
阿里云大数据AI技术4 小时前
开发者博客|在阿里云 PAI 平台实现规模化的机器人感知强化学习
人工智能·阿里云·机器人·强化学习·nvidia
Luhui Dev4 小时前
业务级 Agent 的 Runtime 设计:从 LangChain 看可靠性工程
人工智能·agent·luhuidev
魔乐社区4 小时前
基于昇腾 MindSpeed LLM 玩转 DeepSeek-V4-Flash
人工智能·开源·大模型
传说故事4 小时前
【论文阅读】Code as Policies: Language Model Programs for Embodied Control
论文阅读·人工智能·具身智能
Jurio.4 小时前
AI Daily Paper Reader(ADPR):零服务器搭建个人/团队通用大模型API驱动的论文阅读与推荐平台
论文阅读·人工智能·ai
emfuture4 小时前
国产工控机选型实录:基于龙芯2K3000的中嵌科技EU-7500在边缘计算场景下的适配笔记
人工智能·笔记·边缘计算
IT_陈寒4 小时前
React状态更新后视图不刷新?我差点以为是灵异事件
前端·人工智能·后端
蓦然回首却已人去楼空4 小时前
深度学习进阶:自然语言处理|3.4 QA|共享权重与 `remove_duplicate` 详解
人工智能·深度学习·自然语言处理