352-Spring AI Alibaba OpenAI DashScope 多模态示例

本示例演示如何通过 Spring AI 的 OpenAI 客户端接口调用阿里云 DashScope 的多模态模型(如 qwen-vl-max-latest),实现图片分析功能。虽然依赖了 Spring AI 的 OpenAI 模块,但底层实际调用的是 DashScope 的兼容模式接口。

1. 案例目标

我们将创建一个 Spring Boot 应用,实现以下功能:

  1. 图片 URL 分析:通过 GET 请求传入图片 URL 和描述文本,由 DashScope 多模态模型分析图片内容。
  2. 图片文件上传分析:通过 POST 请求上传本地图片文件,结合提示词进行多模态分析。

2. 技术栈与核心依赖

  • Spring Boot 3.x
  • Spring AI OpenAI Starter(用于调用 DashScope 兼容模式接口)
  • Maven(项目构建工具)

pom.xml 中,你需要引入以下核心依赖:

复制代码
<dependencies>
    <!-- Spring Web 用于构建 RESTful API -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Spring AI OpenAI Starter -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-openai</artifactId>
    </dependency>
</dependencies>

3. 项目配置

src/main/resources/application.yml 文件中,配置 DashScope API Key 和服务地址。

复制代码
server:
  port: 10014

spring:
  application:
    name: spring-ai-alibaba-dashscope-chat-example
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB
  ai:
    openai:
      api-key: ${AI_DASHSCOPE_API_KEY}
      base-url: https://dashscope.aliyuncs.com/compatible-mode
      chat:
        options:
          model: qwen-plus-latest

重要提示 :请将 AI_DASHSCOPE_API_KEY 环境变量设置为你从阿里云获取的有效 API Key。你也可以直接将其写在配置文件中,但这不推荐用于生产环境。

4. 编写 Java 代码

4.1 主应用类

OpenAiDashScopeMultiModelApplication.java - Spring Boot 应用的入口点。

复制代码
package com.alibaba.cloud.ai.example.multi;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class OpenAiDashScopeMultiModelApplication {
    public static void main(String[] args) {
        SpringApplication.run(OpenAiDashScopeMultiModelApplication.class, args);
    }
}

4.2 控制器类

OpenAiChatClientController.java - 实现多模态图片分析功能的核心控制器。

复制代码
package com.alibaba.cloud.ai.example.multi.controller;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.content.Media;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.net.URI;


@RestController
@RequestMapping("openai/client")
public class OpenAiChatClientController {

    private final ChatClient chatClient;

    public OpenAiChatClientController(@Qualifier("openAiChatModel") ChatModel chatModel) {
        chatClient = ChatClient.builder(chatModel)
                .defaultAdvisors(new SimpleLoggerAdvisor())
                .defaultOptions(OpenAiChatOptions.builder().temperature(0.7).build())
                .build();
    }

    /**
     * 图片分析接口 - 通过 URL
     * 使用 OpenAI 多模态模型分析图片内容
     */
    @GetMapping("/image/analyze/url")
    public String analyzeImageByUrl(@RequestParam(defaultValue = "请分析这张图片的内容") String prompt,
                                    @RequestParam String imageUrl) {
        try {
            // 创建包含图片的用户消息
            String mineType = determineMimeTypeFromUrl(imageUrl);
            Media media = Media.builder()
                    .data(new URI(imageUrl))
                    .mimeType(MimeTypeUtils.parseMimeType(mineType))
                    .build();
            UserMessage message = UserMessage.builder()
                    .text(prompt)
                    .media(media)
                    .build();

            // 创建提示词,使用 OpenAI 多模态模型
            Prompt chatPrompt = new Prompt(message,
                    OpenAiChatOptions.builder()
                            .model("qwen-vl-max-latest")  // 使用 OpenAI 视觉模型
                            .temperature(0.7)
                            .maxTokens(1000)
                            .build());
            // 调用模型进行图片分析
            return chatClient.prompt(chatPrompt).call().content();
        } catch (Exception e) {
            return "图片分析失败: " + e.getMessage();
        }
    }

    /**
     * 图片分析接口 - 通过文件上传
     */
    @PostMapping("/image/analyze/upload")
    public String analyzeImageByUpload(@RequestParam(defaultValue = "请分析这张图片的内容") String prompt,
                                       @RequestParam("file") MultipartFile file) {
        try {
            // 验证文件类型
            if (!file.getContentType().startsWith("image/")) {
                return "请上传图片文件";
            }

            // 创建包含图片的用户消息
            Media media = new Media(MimeTypeUtils.parseMimeType(file.getContentType()), file.getResource());
            UserMessage message = UserMessage.builder()
                    .text(prompt)
                    .media(media)
                    .build();

            // 创建提示词,启用多模态模型
            // 创建提示词,使用 OpenAI 多模态模型
            Prompt chatPrompt = new Prompt(message,
                    OpenAiChatOptions.builder()
                            .model("qwen-vl-max-latest")  // 使用 OpenAI 视觉模型
                            .temperature(0.7)
                            .maxTokens(1000)
                            .build());

            // 调用模型进行图片分析
            return chatClient.prompt(chatPrompt).call().content();

        } catch (Exception e) {
            return "图片分析失败: " + e.getMessage();
        }
    }

    /**
     * 根据URL确定MIME类型
     * @param imageUrl 图片URL
     * @return MIME类型字符串
     */
    private String determineMimeTypeFromUrl(String imageUrl) {
        String lowerUrl = imageUrl.toLowerCase();
        if (lowerUrl.endsWith(".jpg") || lowerUrl.endsWith(".jpeg")) {
            return "image/jpeg";
        } else if (lowerUrl.endsWith(".png")) {
            return "image/png";
        } else if (lowerUrl.endsWith(".gif")) {
            return "image/gif";
        } else if (lowerUrl.endsWith(".webp")) {
            return "image/webp";
        } else {
            // 默认使用JPEG
            return "image/jpeg";
        }
    }
}

5. 环境准备

  1. API 密钥配置 :配置阿里云 DashScope 的 API Key:

    复制代码
    export AI_DASHSCOPE_API_KEY=your_api_key_here
  2. 依赖服务:无需额外依赖,DashScope 服务通过公网访问。

6. 运行与测试

  1. 构建项目

    复制代码
    mvn clean install
  2. 运行服务

    复制代码
    cd openai-dashscope-multi-model
    mvn spring-boot:run
  3. 访问接口 :服务启动后,默认监听端口 10014

测试 1:图片 URL 分析

使用 curl 或浏览器访问以下 URL,分析网络图片:

复制代码
http://localhost:10014/openai/client/image/analyze/url?imageUrl=https://example.com/image.jpg&prompt=请描述这张图片中的内容

预期响应

这是一张[图片内容描述]的图片。图片中包含[详细描述]...

测试 2:图片文件上传分析

使用 curl 或 Postman 上传本地图片文件:

复制代码
curl -X POST -F "file=@/path/to/your/image.jpg" -F "prompt=请分析这张图片" http://localhost:10014/openai/client/image/analyze/upload

预期响应

根据您上传的图片,我可以看到[图片内容分析]...

7. 实现思路与扩展建议

实现思路

本示例的核心思想是利用 Spring AI 的 OpenAI 兼容接口调用 DashScope 多模态模型。关键点包括:

  • 兼容模式配置 :通过设置 base-url 为 DashScope 的兼容模式地址,使 Spring AI OpenAI 客户端能够调用 DashScope 服务。
  • 多模态消息构建 :使用 UserMessageMedia 对象构建包含图片和文本的多模态消息。
  • 模型选择 :通过 OpenAiChatOptions 指定使用 DashScope 的多模态模型 qwen-vl-max-latest

扩展建议

  • 多模型支持 :扩展控制器以支持多种多模态模型,如 qwen-vl-plus 等,通过参数动态选择模型。
  • 批量处理:添加批量图片分析接口,支持一次请求分析多张图片。
  • 结果缓存:对相同图片的分析结果进行缓存,提高响应速度并降低 API 调用成本。
  • 异步处理:对于大文件或复杂分析场景,实现异步处理机制,避免请求超时。
  • 安全增强:添加文件类型验证、大小限制和内容安全检查,防止恶意文件上传。
  • 自定义提示词模板:实现提示词模板管理,支持不同场景下的定制化分析需求。

8. 特性说明

多模态兼容性

通过以下配置切换 DashScope 多模态模型:

复制代码
spring:
  ai:
    openai:
      base-url: https://dashscope.aliyuncs.com/compatible-mode  # DashScope 兼容模式
      chat:
        options:
          model: qwen-vl-max-latest  # DashScope 多模态模型

文件上传限制

默认支持最大 10MB 文件上传,可通过 application.yml 修改:

复制代码
spring:
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB
相关推荐
音视频牛哥6 小时前
RTMP/RTSP/WebRTC/SRT/HLS/DASH/GB28181/WebTransport/QUIC协议规范深度分析
人工智能·计算机视觉·音视频·webrtc·大牛直播sdk·dash·webtransport
张较瘦_6 小时前
[论文阅读] AI+ | AI如何重塑审计行业?从“手工筛查”到“智能决策”:AI审计的核心逻辑与未来路径
论文阅读·人工智能
不爱学英文的码字机器7 小时前
深度解析《AI+Java编程入门》:一本为零基础重构的Java学习路径
java·人工智能·后端·重构
B站计算机毕业设计之家7 小时前
python图像识别系统 AI多功能图像识别检测系统(11种识别功能)银行卡、植物、动物、通用票据、营业执照、身份证、车牌号、驾驶证、行驶证、车型、Logo✅
大数据·开发语言·人工智能·python·图像识别·1024程序员节·识别
晨非辰7 小时前
《数据结构风云》递归算法:二叉树遍历的精髓实现
c语言·数据结构·c++·人工智能·算法·leetcode·面试
mailangduoduo7 小时前
命令行传参及调试——vscode平台
c++·人工智能·vscode·代码调试·命令行传参
ProgrammerPulse7 小时前
超融合架构下,如何智能调度让每台虚拟机都“跑得更快”?
人工智能·云计算
wwlsm_zql7 小时前
微软Copilot+企业版亮相:GPT-5赋能,效率激增47%,多模态操控金融级安全
人工智能·gpt·microsoft·copilot
bylander7 小时前
【AI工具】dify智能体-Kimi-K2+Mermaid ,一键生成系统架构图
人工智能·系统架构·大模型