SpringAI多模态的基本使用

SpringAI 多模态

一、多模态的概念

模态是指表达或感知事务的方式,例如视觉、听觉、嗅觉。对应的信息传递媒介可以是文本、图像、声音、视频等

多模态是指从多个模态表达或者感知事物。

表达可以理解为输出,而感知则是输入。

deepseek、qwen-max等模型都是纯文本模型,不过在ollama和阿里云百炼等大模型

平台,能找到很多多模态模型。

以阿里云百炼平台为例:

有很多模态的模型,甚至还有一个分类是全模态模型。

阿里云的qwen3-omni-flash模型是支持文本、图像、音频、视频输入的全模态模

型,还能支持语音合成功能,非常强大。

二、常见使用

像deepseek、文心一言、千问等都支持文件上传的同时去回答问题,这就相当于是一种多模态,使用文字和文件的方式去感知,然后做出输出。

三、代码实现

下面代码基于SpringAI1.0.03。

3.1 定义bean

首先,定义一个用于AI对话的ChatClient的bean,将模型修改为OpenAIChatModel,不仅如此,由于其它业务使用的是不同模型,不能改变,只需添加自定义配置,将模型改为qwen3-omni-flash:

java 复制代码
@Bean("chatClient")
public ChatClient chatClient(OpenAiChatModel model, ChatMemory chatMemory) {
    return ChatClient.builder(model)
        .defaultOptions(ChatOptions.builder().model("qwen3-omni-flash").build())
        .defaultSystem("你是可爱且热情、人见人爱,花见花开的AI助手,你的名字是墩墩,请用墩墩的身份回答用户的问题!")
        .defaultAdvisors(
        new SimpleLoggerAdvisor(),
        MessageChatMemoryAdvisor.builder(chatMemory).build()         // 如果失去它,系统就不再有会话记忆功能了,不过这个会话记忆是在内存里的,重启项目就不存在了
    )
        .build();
}

在这里配置defaultOptions(ChatOptions.builder().model("qwen3-omni-flash").build()) 可以独立配置这个ChatClient使用的大模型,而不是使用yaml中配置的全局模型了。

3.2 编写controller

java 复制代码
    // 再弄一个流式的,但是这里一定要设置字符编码,要不然是会乱码的
    @RequestMapping(value = "/chat", produces = "text/html;charset=UTF-8")
    public Flux<String> chatStream(@RequestParam("prompt") String prompt,
                                   @RequestParam("chatId") String chatId,
                                   @RequestParam(value = "files", required = false) List<MultipartFile> files
    ) {
        // 1.保存会话id (这一步如果是走的redis就不需要自己实现了)
        chatHistoryService.save(ServiceTypeEnum.CHAT.getType(), chatId);
        // 2.请求模型
        if (files == null || files.isEmpty()) {
            // 没有附件,纯文本聊天
            return textChat(prompt, chatId);
        } else {
            // 有附件,多模态聊天
            return multiModalChat(prompt, chatId, files);
        }
    }

    private Flux<String> multiModalChat(String prompt, String chatId, List<MultipartFile> files) {
        // 1.解析多媒体, 其实就是把文件对象解析成没提对象
        List<Media> medias = files.stream()
                .map(file -> new Media(
                                MimeType.valueOf(Objects.requireNonNull(file.getContentType())),
                                file.getResource()
                        )
                )
                .toList();
        // 2.请求模型
        return chatClient.prompt()
                .user(p -> p.text(prompt).media(medias.toArray(Media[]::new)))
                .advisors(a -> a.param(CONVERSATION_ID, chatId))
                .stream()
                .content();
    }

    private Flux<String> textChat(String prompt, String chatId) {
        return chatClient.prompt()
                .user(prompt)
                .advisors(a -> a.param(CONVERSATION_ID, chatId))
                .stream()
                .content();
    }

四、测试效果

现在我传递这张图片给AI,询问图片的内容:

可以看到现在AI能够同时理解文字和图片这两种模态的信息,并且进行理解和输入。

相关推荐
pshdhx_albert2 小时前
AI agent实现打字机效果
java·http·ai编程
沉鱼.442 小时前
第十二届题目
java·前端·算法
建行一世3 小时前
【Windows笔记本大模型“傻瓜式”教程】使用LLaMA-Factory工具来完成对Windows笔记本大模型Qwen2.5-3B-Instruct微调
windows·ai·语言模型·llama
轩轩分享AI3 小时前
DeepSeek、Kimi、笔灵谁最好用?5款网文作者亲测的AI写作神器横评
人工智能·ai·ai写作·小说写作·小说·小说干货
赫瑞3 小时前
数据结构中的排列组合 —— Java实现
java·开发语言·数据结构
哥布林学者4 小时前
深度学习进阶(五)Vision Transformer
机器学习·ai
叹一曲当时只道是寻常4 小时前
Xcode 接入智谱 GLM Coding Plan 报错解决方案
ai·xcode
周末也要写八哥4 小时前
多进程和多线程的特点和区别
java·开发语言·jvm
惜茶5 小时前
vue+SpringBoot(前后端交互)
java·vue.js·spring boot
杰克尼6 小时前
springCloud_day07(MQ高级)
java·spring·spring cloud