Spring AI集成多模态模型
未完待续
模态和多模态的概念等前置知识,已经在以下文章中提到
Spring AI对于多模态也做了支持,本文介绍Spring AI对接多模态模型的用法。
1.视觉理解
很多多模态大模型产品也都支持OpenAI的协议,因此还是使用spring-ai-starter-model-openai
pom.xml
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.5.7</version></parent><dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>1.1.2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies></dependencyManagement><dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> </dependency> <!-- Lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency></dependencies><build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>21</source> <target>21</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins></build>application.yml
spring: ai: openai: base-url: https://dashscope.aliyuncs.com/compatible-mode api-key: ${QWKEY} chat: options: model: qwen3-vl-pluslogging: level: org.springframework.ai: debug配置类不变,使用OpenAI协议的模型
package org.example;import org.springframework.ai.chat.client.ChatClient;import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;import org.springframework.ai.chat.memory.ChatMemory;import org.springframework.ai.openai.OpenAiChatModel;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class SpringAiConfig { @Bean public ChatClient chatClient(OpenAiChatModel model, ChatMemory chatMemory) { return ChatClient.builder(model) .defaultAdvisors( SimpleLoggerAdvisor.builder().build(), MessageChatMemoryAdvisor.builder(chatMemory).build() ) .build(); }}新建测试类,测试多模态模型。user提示词中使用.user(e -> e.text("图片中的统计数据是谁发布的,大学学历网民占比是多少。").media(media))传递图片内容
package org.example.test;import jakarta.annotation.Resource;import lombok.extern.slf4j.Slf4j;import org.example.Main;import org.junit.jupiter.api.Test;import org.springframework.ai.chat.client.ChatClient;import org.springframework.ai.chat.memory.ChatMemory;import org.springframework.ai.content.Media;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.http.MediaType;@SpringBootTest(classes = Main.class)@Slf4jpublic class UnitTest { @Resource private ChatClient chatClient; @Value("classpath:image.png") private org.springframework.core.io.Resource resource; @Test public void test() { Media media = new Media(MediaType.valueOf("image/png"), resource); String content = chatClient.prompt() .user(e -> e.text("图片中的统计数据是谁发布的,大学学历网民占比是多少。") .media(media)) .advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, 1)) .call() .content(); log.info("************** {}", content); }}然后得到大模型分析结果
2026-01-13T09:11:37.737+08:00 DEBUG 8620 --- [ main] o.s.a.c.c.advisor.SimpleLoggerAdvisor : request: ChatClientRequest[prompt=Prompt{messages=[UserMessage{content='图片中的统计数据是谁发布的,大学学历网民占比是多少。', metadata={messageType=USER}, messageType=USER}], modelOptions=OpenAiChatOptions: {"streamUsage":false,"model":"qwen3-vl-plus","temperature":0.7}}, context={chat_memory_conversation_id=1}]2026-01-13T09:11:44.273+08:00 DEBUG 8620 --- [ main] o.s.a.c.c.advisor.SimpleLoggerAdvisor : response: { "result" : { "metadata" : { "finishReason" : "STOP", "contentFilters" : [ ], "empty" : true }, "output" : { "messageType" : "ASSISTANT", "metadata" : { "role" : "ASSISTANT", "messageType" : "ASSISTANT", "refusal" : "", "finishReason" : "STOP", "annotations" : [ { } ], "index" : 0, "id" : "chatcmpl-47c0652b-2526-9dd5-8d56-b3067f837901" }, "toolCalls" : [ ], "media" : [ ], "text" : "根据图片信息:\n\n1. **统计数据发布方**: \n 该数据由 **CNNIC(中国互联网络信息中心)** 发布,来源于其《中国互联网络发展状况统计调查》。\n\n2. **大学本科及以上学历网民占比**: \n - 在 **2016年12月** 的数据中,占比为 **11.5%**。 \n - 在 **2017年6月** 的数据中,占比为 **11.6%**。\n\n因此,截至2017年6月,**大学本科及以上学历的网民占比为 11.6%**。\n\n✅ 总结:\n- 发布机构:**CNNIC**\n- 大学本科及以上学历网民占比(2017.6):**11.6%**" } }, "metadata" : { "id" : "chatcmpl-47c0652b-2526-9dd5-8d56-b3067f837901", "model" : "qwen3-vl-plus", "rateLimit" : { "requestsLimit" : null, "requestsRemaining" : null, "requestsReset" : null, "tokensLimit" : null, "tokensRemaining" : null, "tokensReset" : null }, "usage" : { "promptTokens" : 457, "completionTokens" : 178, "totalTokens" : 635, "nativeUsage" : { "completion_tokens" : 178, "prompt_tokens" : 457, "total_tokens" : 635, "prompt_tokens_details" : { }, "completion_tokens_details" : { } } }, "promptMetadata" : [ ], "empty" : false }, "results" : [ { "metadata" : { "finishReason" : "STOP", "contentFilters" : [ ], "empty" : true }, "output" : { "messageType" : "ASSISTANT", "metadata" : { "role" : "ASSISTANT", "messageType" : "ASSISTANT", "refusal" : "", "finishReason" : "STOP", "annotations" : [ { } ], "index" : 0, "id" : "chatcmpl-47c0652b-2526-9dd5-8d56-b3067f837901" }, "toolCalls" : [ ], "media" : [ ], "text" : "根据图片信息:\n\n1. **统计数据发布方**: \n 该数据由 **CNNIC(中国互联网络信息中心)** 发布,来源于其《中国互联网络发展状况统计调查》。\n\n2. **大学本科及以上学历网民占比**: \n - 在 **2016年12月** 的数据中,占比为 **11.5%**。 \n - 在 **2017年6月** 的数据中,占比为 **11.6%**。\n\n因此,截至2017年6月,**大学本科及以上学历的网民占比为 11.6%**。\n\n✅ 总结:\n- 发布机构:**CNNIC**\n- 大学本科及以上学历网民占比(2017.6):**11.6%**" } } ]}2026-01-13T09:11:44.273+08:00 INFO 8620 --- [ main] org.example.test.UnitTest : ************** 根据图片信息:1. **统计数据发布方**: 该数据由 **CNNIC(中国互联网络信息中心)** 发布,来源于其《中国互联网络发展状况统计调查》。2. **大学本科及以上学历网民占比**: - 在 **2016年12月** 的数据中,占比为 **11.5%**。 - 在 **2017年6月** 的数据中,占比为 **11.6%**。因此,截至2017年6月,**大学本科及以上学历的网民占比为 11.6%**。✅ 总结:- 发布机构:**CNNIC**- 大学本科及以上学历网民占比(2017.6):**11.6%**