Key Findings
  • Spring AI 支援四大多模態能力:GPT-4o 圖片分析(URL、本地檔案、多圖比較)、DALL-E 3 圖片生成Whisper 語音轉文字TTS 文字轉語音
  • 圖片分析只需在 UserMessage 上加 .media() 即可——支援 URL 與本地檔案,甚至可以同時送入多張圖片進行比較分析
  • DALL-E 3 的圖片品質取決於 Prompt 品質——用 AI 先優化中文描述為英文 DALL-E Prompt,生成效果大幅提升
  • Whisper + TTS 的組合可以打造完整的語音助手管線——語音輸入 → AI 處理 → 語音輸出,成本僅約 $0.02/次互動

什麼是多模態 AI?

前七堂課處理的都是文字。但真實世界的資訊不只有文字——有圖片(發票、產品照片、設計稿)、有聲音(客戶來電、會議錄音)、有影片。多模態 AI 就是讓 AI 同時理解和產生多種資料格式[1]

【單一模態】 文字 → AI → 文字

【多模態】   文字 ─┐              ┌→ 文字
             圖片 ─┤→ AI 模型 ──┤→ 圖片
             音訊 ─┘              └→ 音訊

Spring AI 支援的多模態功能:

功能模型Spring AI 類別用途
圖片分析GPT-4oChatModel + MediaOCR、圖片描述、比較
圖片生成DALL-E 3OpenAiImageModel行銷素材、產品圖
語音轉文字WhisperOpenAiAudioTranscriptionModel會議記錄、字幕
文字轉語音OpenAI TTSOpenAiAudioSpeechModel語音助手、播報

Step 1:環境準備

開啟課程專案的 Lesson8/Lesson8_Multimodal.ipynb

@file:DependsOn("org.springframework.ai:spring-ai-openai:1.0.0")
@file:DependsOn("org.springframework.ai:spring-ai-client-chat:1.0.0")
@file:DependsOn("org.slf4j:slf4j-simple:2.0.16")

import org.springframework.ai.openai.OpenAiChatModel
import org.springframework.ai.openai.api.OpenAiApi
import org.springframework.ai.chat.client.ChatClient

val apiKey = System.getenv("OPENAI_API_KEY")
    ?: error("請先設定 OPENAI_API_KEY(參考 Lesson 0)")

val openAiApi = OpenAiApi.builder().apiKey(apiKey).build()
val chatModel = OpenAiChatModel.builder().openAiApi(openAiApi).build()
val chatClient = ChatClient.builder(chatModel).build()

println("✓ 環境準備完成")

Step 2:圖片分析——讓 AI 看得懂圖片

GPT-4o 是一個原生的多模態模型[2],可以同時理解文字和圖片。在 Spring AI 中,只需要在 UserMessage 上加 .media()

方式一:分析網路圖片(URL)

import org.springframework.ai.chat.messages.UserMessage
import org.springframework.ai.model.Media
import org.springframework.util.MimeTypeUtils
import org.springframework.ai.chat.prompt.Prompt
import org.springframework.ai.openai.OpenAiChatOptions
import java.net.URI

val imageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/PNG_transparency_demonstration_1.png/300px-PNG_transparency_demonstration_1.png"

val userMessage = UserMessage.builder()
    .text("請用繁體中文描述這張圖片的內容,包含主要元素和顏色。")
    .media(Media(MimeTypeUtils.IMAGE_PNG, URI.create(imageUrl)))
    .build()

val response = chatModel.call(
    Prompt(userMessage, OpenAiChatOptions.builder().model("gpt-4o").build())
)

println(response.result.output.text)

方式二:分析本地檔案

import org.springframework.core.io.FileSystemResource
import java.io.File

val localFile = File("sample-docs/test-image.jpg")

val localMessage = UserMessage.builder()
    .text("請用繁體中文描述這張圖片的內容。")
    .media(Media(MimeTypeUtils.IMAGE_JPEG, FileSystemResource(localFile)))
    .build()

val localResponse = chatModel.call(
    Prompt(localMessage, OpenAiChatOptions.builder().model("gpt-4o").build())
)

println(localResponse.result.output.text)

方式三:多圖比較

GPT-4o 可以同時分析多張圖片:

val img1 = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/300px-Cat03.jpg"
val img2 = "https://upload.wikimedia.org/wikipedia/commons/thumb/2/26/YellowLabradorLooking_new.jpg/300px-YellowLabradorLooking_new.jpg"

val compareMessage = UserMessage.builder()
    .text("請比較這兩張圖片的異同,用繁體中文回答。")
    .media(Media(MimeTypeUtils.IMAGE_JPEG, URI.create(img1)))
    .media(Media(MimeTypeUtils.IMAGE_JPEG, URI.create(img2)))
    .build()

val compareResponse = chatModel.call(
    Prompt(compareMessage, OpenAiChatOptions.builder().model("gpt-4o").build())
)

println(compareResponse.result.output.text)

預期輸出:

這兩張圖片都是動物的特寫照片。第一張是一隻灰色虎斑貓,
眼睛碧綠,表情警覺;第二張是一隻金色拉布拉多犬,
表情溫和友善。兩者都是受歡迎的寵物,但貓較為獨立,
狗則更親人。拍攝風格都是自然光下的近距離特寫。
企業應用: 多圖比較可用於品質檢測(比較良品/瑕疵品)、進度追蹤(比較施工前後)、版本比對(比較設計稿修改前後)。

Step 3:圖片生成——DALL-E 3

使用 DALL-E 3[3] 從文字描述生成圖片:

import org.springframework.ai.openai.OpenAiImageModel
import org.springframework.ai.openai.api.OpenAiImageApi
import org.springframework.ai.image.ImagePrompt
import org.springframework.ai.openai.OpenAiImageOptions

val imageApi = OpenAiImageApi.builder().apiKey(apiKey).build()
val imageModel = OpenAiImageModel(imageApi)

val imagePrompt = ImagePrompt(
    "A futuristic cityscape at sunset with flying cars and neon lights, cyberpunk style, ultra detailed",
    OpenAiImageOptions.builder()
        .model("dall-e-3")
        .quality("standard")
        .height(1024)
        .width(1024)
        .build()
)

val imageResponse = imageModel.call(imagePrompt)
val generatedUrl = imageResponse.result.output.url

println("生成的圖片: $generatedUrl")

DALL-E 3 的參數選項:

參數選項說明
modeldall-e-3 / dall-e-23 品質更好,2 速度更快
qualitystandard / hdhd 更精細,價格翻倍
size1024x1024 / 1792x1024 / 1024x1792正方形 / 橫幅 / 直幅
n1DALL-E 3 每次只能生成 1 張

AI 優化 Prompt——中文描述自動轉英文 DALL-E Prompt

DALL-E 對英文 Prompt 的效果遠好於中文。用 AI 先優化 Prompt:

fun generateImageWithAI(description: String): String {
    // Step 1: AI 將中文描述優化為英文 DALL-E Prompt
    val optimizedPrompt = chatClient.prompt()
        .system("""你是 DALL-E 圖像生成的 Prompt 專家。
            將使用者的中文描述轉換為高品質的英文 DALL-E Prompt。
            包含:主體、動作、風格、光線、背景、色調。
            只回傳英文 Prompt,不要其他說明。""")
        .user(description)
        .call().content() ?: description

    println("優化後 Prompt: $optimizedPrompt")

    // Step 2: 用優化後的 Prompt 生成圖片
    val response = imageModel.call(ImagePrompt(
        optimizedPrompt,
        OpenAiImageOptions.builder()
            .model("dall-e-3").quality("standard")
            .height(1024).width(1024).build()
    ))

    return response.result.output.url
}

// 測試:用中文描述生成圖片
val url = generateImageWithAI("一隻穿著太空服的柴犬在月球上散步")
println("生成結果: $url")

Step 4:語音轉文字——Whisper

OpenAI 的 Whisper 模型[4]可以將音訊檔案轉錄為文字,支援多種語言:

import org.springframework.ai.openai.OpenAiAudioTranscriptionModel
import org.springframework.ai.openai.api.OpenAiAudioApi
import org.springframework.ai.openai.OpenAiAudioTranscriptionOptions
import org.springframework.ai.audio.transcription.AudioTranscriptionPrompt

val audioApi = OpenAiAudioApi.builder().apiKey(apiKey).build()
val transcriptionModel = OpenAiAudioTranscriptionModel(audioApi)

val transcriptionOptions = OpenAiAudioTranscriptionOptions.builder()
    .language("zh")           // 指定語言(中文)
    .temperature(0.0f)        // 0.0 = 最精確
    .build()

val audioFile = File("sample-docs/test-audio.mp3")
val audioPrompt = AudioTranscriptionPrompt(
    FileSystemResource(audioFile),
    transcriptionOptions
)

val transcription = transcriptionModel.call(audioPrompt)
println("轉錄結果: ${transcription.result.output}")

Whisper 的參數選項:

參數說明建議值
language音訊語言zh(中文)、en(英文)、ja(日文)
temperature轉錄的隨機性0.0(最精確)
responseFormat輸出格式json / text / srt / vtt
實用技巧: 設定 responseFormatsrt 可以直接生成帶時間軸的字幕檔案,適合影片字幕製作。

Step 5:文字轉語音——TTS

OpenAI TTS[4] 提供六種語音風格:

語音風格適合場景
alloy中性、專業企業通知、系統語音
echo溫暖男聲播客、故事敘述
fable英式口音品牌形象、有特色的內容
onyx深沉男聲新聞播報、權威感
nova活潑女聲(推薦)客服助手、互動式內容
shimmer柔和女聲冥想、舒緩內容
import org.springframework.ai.openai.OpenAiAudioSpeechModel
import org.springframework.ai.openai.audio.speech.SpeechPrompt
import org.springframework.ai.openai.audio.speech.SpeechRequest
import org.springframework.ai.openai.OpenAiAudioSpeechOptions

val speechModel = OpenAiAudioSpeechModel(audioApi)

val text = "歡迎使用 Spring AI 智慧語音助手!今天我們來學習多模態處理。"

val speechOptions = OpenAiAudioSpeechOptions.builder()
    .voice(SpeechRequest.Voice.NOVA)
    .speed(1.0f)
    .model("tts-1")
    .build()

val speechResponse = speechModel.call(SpeechPrompt(text, speechOptions))

// 儲存為 MP3 檔案
val outputFile = File("sample-docs/output-speech.mp3")
outputFile.writeBytes(speechResponse.result.output)
println("✓ 語音已儲存: ${outputFile.name}(${outputFile.length() / 1024} KB)")

語音風格比較

val sampleText = "Spring AI 讓 Java 開發者也能輕鬆建構 AI 應用。"
val voices = listOf(
    SpeechRequest.Voice.ALLOY to "voice-alloy.mp3",
    SpeechRequest.Voice.NOVA to "voice-nova.mp3",
    SpeechRequest.Voice.ONYX to "voice-onyx.mp3"
)

voices.forEach { (voice, filename) ->
    val options = OpenAiAudioSpeechOptions.builder()
        .voice(voice).speed(1.0f).model("tts-1").build()
    val response = speechModel.call(SpeechPrompt(sampleText, options))
    File("sample-docs/$filename").writeBytes(response.result.output)
    println("✓ ${voice.name} → $filename")
}

Step 6:實戰——圖片描述 + 語音導覽

結合圖片分析與 TTS,打造一個自動語音導覽系統——上傳一張藝術品照片,AI 生成描述並轉為語音導覽:

fun imageToSpeech(imageUrl: String, outputFileName: String): String {
    // Step 1: GPT-4o 分析圖片
    val descMessage = UserMessage.builder()
        .text("你是一位美術館導覽員。請用繁體中文,以生動的語氣描述這幅藝術作品," +
              "包含作品風格、色彩運用和情感傳達。控制在 50 字以內。")
        .media(Media(MimeTypeUtils.IMAGE_JPEG, URI.create(imageUrl)))
        .build()

    val description = chatModel.call(
        Prompt(descMessage, OpenAiChatOptions.builder().model("gpt-4o").build())
    ).result.output.text

    println("📝 圖片描述: $description")

    // Step 2: TTS 將描述轉為語音
    val options = OpenAiAudioSpeechOptions.builder()
        .voice(SpeechRequest.Voice.NOVA)
        .speed(0.9f)   // 導覽語速稍慢
        .model("tts-1")
        .build()

    val speech = speechModel.call(SpeechPrompt(description, options))
    File("sample-docs/$outputFileName").writeBytes(speech.result.output)

    println("🔊 語音導覽已儲存: $outputFileName")
    return description
}

// 測試:分析一幅畫作並生成語音導覽
imageToSpeech(
    "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Van_Gogh_-_Starry_Night_-_Google_Art_Project.jpg/300px-Van_Gogh_-_Starry_Night_-_Google_Art_Project.jpg",
    "art-guide.mp3"
)

這個管線:圖片 → GPT-4o 分析 → 文字描述 → TTS 語音,可以應用在美術館導覽、房地產看屋語音介紹、電商商品語音描述等場景。

成本參考

功能模型單價說明
圖片分析GPT-4o~$0.01~0.05 / 張依圖片大小與 detail 設定
圖片生成DALL-E 3 standard$0.04 / 張HD 品質 $0.08 / 張
語音轉文字Whisper$0.006 / 分鐘1 小時約 $0.36
文字轉語音TTS-1$0.015 / 1000 字元TTS-1-HD 品質 $0.030
成本估算: 一次完整的語音助手互動(Whisper 轉錄 10 秒 + GPT-4o 處理 + TTS 回覆 200 字)約 $0.02。1 萬次互動僅 $200。

本課重點回顧

功能模型關鍵程式碼
圖片分析GPT-4oUserMessage.builder().text().media()
多圖比較GPT-4o多次 .media() 呼叫
圖片生成DALL-E 3ImagePrompt + OpenAiImageOptions
語音轉文字WhisperAudioTranscriptionPrompt
文字轉語音TTSSpeechPrompt + SpeechRequest.Voice
組合管線GPT-4o + TTS圖片分析 → 文字 → 語音

課程回顧:Lesson 0~8 完整技術棧

到此為止,你已經掌握了 Spring AI 在 Kotlin Notebook 環境中的所有核心功能

  1. Lesson 0~1 — 環境設定 + ChatClient / ChatModel 基礎
  2. Lesson 2~3 — 串流輸出 + Prompt 工程 + 結構化輸出
  3. Lesson 4~5 — Function Calling + ChatMemory
  4. Lesson 6~7 — RAG 基礎 + 進階 RAG
  5. Lesson 8 — 多模態(圖片 + 語音)

下一步:Lesson 9 — 文件處理

接下來進入企業文件處理——RAG 系統的「食材準備」階段:

  • PDF 解析 — 自動提取 PDF 文件的文字與表格
  • 文件切割 — TokenTextSplitter 的進階配置
  • 多格式支援 — Word、Excel、HTML 等格式的處理

掌握多模態,繼續前進!

AI 看得懂圖片也聽得懂語音了,下一步學習文件處理——從原始檔案建置企業知識庫。

前往 Lesson 9:文件處理與知識庫建置 →