掘金 人工智能 07月24日 17:28
7-多模态-让AI助手充满诗意
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文介绍了如何利用Spring AI为AI助手添加多模态能力,使其能够理解图片并根据图片内容进行创作。文章详细讲解了如何配置多模态大模型,并提供了根据图片作诗的API实现。此外,还演示了两种流式输出方式:直接流式输出和通过SSE(服务器发送事件)实现更流畅的用户交互体验,为AI助手的“人味”增添了重要维度。

💡 AI助手能力升级:通过引入多模态模型,AI助手不再局限于文本交互,能够理解和处理图片等多种模态信息,显著提升了其“人味”和交互的丰富性。

🖼️ 图片内容创作实现:通过Spring AI的ChatClient,可以轻松实现让AI根据上传的图片创作诗歌等内容,具体代码展示了如何将图片资源传递给模型并获取文本输出。

🚀 流式输出增强体验:文章介绍了两种实现AI助手输出“流畅”的方式。一种是直接使用`.stream().content()`实现逐字输出,另一种是通过`SseEmitter`结合`.stream().content()`,将AI的输出以SSE格式发送,更符合前端应用的流式交互习惯。

🔧 模型配置与调用:实践部分详细指导了如何选择和配置支持图片的多模态大模型(如`qwen/qwen2.5-vl-32b-instruct:free`),并通过`application.yaml`文件进行设置,以及在代码中注入`ChatClient`来调用模型。

1-背景故事

前几篇我们从零开始,一步步创建并让AI助手有了各种能力。

但是只会文字的AI助手,终究还是差了那么点人味不是么?

好在现在已经有了多模态模型,可以理解并输出图片、文字、音频、视频等各种内容。

接下来让我们借助多模态模型,让AI助手能根据情景(图片)随兴作诗,并进一步通过流式输出让AI助手的输出更“流畅”。

2-动手实践

2.1-前置条件

作为本篇的准备工作,你需要先完成《1-Spring AI手把手教程-亲手创造我的AI助手

其它篇的内容,则不是必须。

2.2-准备多模态模型

之前用到的模型,都属于大语言模型嵌入模型,今天我们需要用到多模态大模型,通过搜索引擎、问AI助手或你能想到的任何方式,很容易找到支持图片的大模型。

作为示例,我们依然选择白嫖openrouter.ai,通过搜索支持图片的免费模型,我们可以找到一堆免费模型,找一个替换application.yaml配置文件中的模型:

spring:  ai:    openai:      base-url: "https://openrouter.ai/api"      api-key: "" #都白嫖了,你自己去注册并申请一个api-key吧      chat:        options:          # 千问图片理解模型          model: "qwen/qwen2.5-vl-32b-instruct:free"

2.3-编写代码

在我们原来的控制器类中添加根据图片作诗的API入口和代码:

@RestControllerpublic class MyChatController {    // Spring AI聊天客户端    private final ChatClient chatClient;    // 注入ChatClient生成器,Spring Boot已经根据上文的配置自动为我们创建了一个生成器实例    public MyChatController(ChatClient.Builder chatClientBuilder) {        this.chatClient = chatClientBuilder.build();    }        //...    // 根据图片作诗的API入口    @PostMapping(path = "multimodal/pic-to-poe")    public String picToPoe(MultipartFile file) {        return chatClient.prompt()                .user(u -> u                        .text("根据图片作一首诗")                        .media(MimeTypeUtils.IMAGE_PNG, file.getResource()))                .call()                .content();    }}

2.4-测试效果

使用你喜欢的http客户端测试效果,本文还是以curl为例:

# 使用新添加的图片接口上传一张图片curl -F "file=@ai-assistant/src/main/resources/multimodal.test.png" http://localhost:8080/multimodal/pic-to-poe# AI助手的回复:金篮静置果香浓,黄蕉红果映晨风。日常小景藏诗意,清韵悠然入梦中。

可以看出AI助手根据我上传的图片内容,作出了一首七言律诗。诗意优雅,就是突然迸出四句诗,有点突兀。

接下来我们用流式输出的方式,让AI助手作诗的过程更“流畅”:

2.5-编写流式输出代码

在原代码的基础上、再增加一种返回方式:

@RestControllerpublic class MyChatController {    //...    // (Spring)流式输出    @PostMapping(path = "multimodal/pic-to-poe/stream")    public Flux<String> picToPoeStream(MultipartFile file) {        return chatClient.prompt()                .user(u -> u                        .text("根据图片作一首诗")                        .media(MimeTypeUtils.IMAGE_PNG, file.getResource()))                //与非流式输出的关键区别,是使用stream()代替call()                .stream()                .content();    }}

2.6-测试流式输出

再次用工具测试以上接口,会发现AI助手的输出是一个字接一个字,看起来流畅很多:

# 使用新添加的图片接口上传一张图片curl -F "file=@ai-assistant/src/main/resources/multimodal.test.png" http://localhost:8080/multimodal/pic-to-poe/stream# AI助手的回复:金篮轻悬映晨光,黄蕉红果溢芬芳。静谧时光添雅趣,一隅清欢入梦长。

纯文字展示不出实际效果,还希望各位亲自动手实践。

2.7-编写SSE输出代码

细心的小伙伴会发现,上面的流式输出格式,并不是我们编写前端聊天代码、或客户端工具时常用到的流式输出格式。

这是因为聊天工具中所谓的流式输出,实际上是指“服务器发送事件SSE”。

使用SSE的代码也不难:

@RestControllerpublic class MyChatController {    //...    // 使用SSE流式输出    @PostMapping(path = "multimodal/pic-to-poe/sse")    public SseEmitter picToPoeSse(MultipartFile file) {        // 创建 SSE 发射器,设置超时时间(例如 1 分钟)        SseEmitter emitter = new SseEmitter(60_000L);        // 调用大模型        chatClient.prompt()                .user(u -> u                        .text("根据图片作一首诗")                        .media(MimeTypeUtils.IMAGE_PNG, file.getResource()))                //与非流式输出的关键区别,是使用stream()代替call()                .stream()                .content()                //与普通流式输出的区别,是每收到一次大模型的输出,都转换为服务器事件“发射”给客户端                .doOnEach(s-> {                    try {                        emitter.send(SseEmitter.event()                                .data(s)                                .id(String.valueOf(System.currentTimeMillis()))                                .build());                    } catch (IOException e) {                        throw new RuntimeException(e);                    }                })                // 注意大模型流结束时,也要告诉发射器结束了,否则客户端会继续等着你的输出                .doOnTerminate(emitter::complete)                .subscribe();        return emitter;    }}

2.8-测试SSE输出

SSE主要用于代码集成,输出就没那么直观了:

# 使用新添加的图片接口上传一张图片curl -F "file=@ai-assistant/src/main/resources/multimodal.test.png" http://localhost:8080/multimodal/pic-to-poe/sse# AI助手的回复(篇幅有限,下面省略了很多输出):data:金id:1753341478512...data:时光id:1753341479023...data:。id:1753341479515

3-课外拓展

    验证更多的模型,看看哪个效果好;使用不同的temperature参数,让输出更随机/确定;探索除图片外的更多多模型模型的输入输出,如:音视频输入、输出。

4-参考

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Spring AI 多模态模型 AI助手 流式输出 SSE
相关文章