聊聊Spring AI的Multimodality

Spring AI的Multimodality研究

本文主要研究一下Spring AI的Multimodality

示例

chatModel示例

var imageResource = new ClassPathResource("/multimodal.test.png");

var userMessage = new UserMessage(
	"Explain what do you see in this picture?", // content
	new Media(MimeTypeUtils.IMAGE_PNG, this.imageResource)); // media

ChatResponse response = chatModel.call(new Prompt(this.userMessage));

chatClient示例

String response = ChatClient.create(chatModel).prompt()
		.user(u -> u.text("Explain what do you see on this picture?")
				    .media(MimeTypeUtils.IMAGE_PNG, new ClassPathResource("/multimodal.test.png")))
		.call()
		.content();

目前是如下几种模型支持多模态

  • Anthropic Claude 3
  • AWS Bedrock Converse
  • Azure Open AI (e.g. GPT-4o models)
  • Mistral AI (e.g. Mistral Pixtral models)
  • Ollama (e.g. LLaVA, BakLLaVA, Llama3.2 models)
  • OpenAI (e.g. GPT-4 and GPT-4o models)
  • Vertex AI Gemini (e.g. gemini-1.5-pro-001, gemini-1.5-flash-001 models)

源码

UserMessage

org/springframework/ai/chat/messages/UserMessage.java

public class UserMessage extends AbstractMessage implements MediaContent {

	protected final List<Media> media;

	public UserMessage(String textContent) {
		this(MessageType.USER, textContent, new ArrayList<>(), Map.of());
	}

	public UserMessage(Resource resource) {
		super(MessageType.USER, resource, Map.of());
		this.media = new ArrayList<>();
	}

	public UserMessage(String textContent, List<Media> media) {
		this(MessageType.USER, textContent, media, Map.of());
	}

	public UserMessage(String textContent, Media... media) {
		this(textContent, Arrays.asList(media));
	}

	public UserMessage(String textContent, Collection<Media> mediaList, Map<String, Object> metadata) {
		this(MessageType.USER, textContent, mediaList, metadata);
	}

	public UserMessage(MessageType messageType, String textContent, Collection<Media> media,
			Map<String, Object> metadata) {
		super(messageType, textContent, metadata);
		Assert.notNull(media, "media data must not be null");
		this.media = new ArrayList<>(media);
	}

	@Override
	public String toString() {
		return "UserMessage{" + "content='" + getText() + '\'' + ", properties=" + this.metadata + ", messageType="
				+ this.messageType + '}';
	}

	@Override
	public List<Media> getMedia() {
		return this.media;
	}

	@Override
	public String getText() {
		return this.textContent;
	}

}

UserMessage实现了MediaContent的getMedia方法

Media

org/springframework/ai/model/Media.java

public class Media {

	private static final String NAME_PREFIX = "media-";

	/**
	 * An Id of the media object, usually defined when the model returns a reference to
	 * media it has been passed.
	 */
	@Nullable
	private String id;

	private final MimeType mimeType;

	private final Object data;

	/**
	 * The name of the media object that can be referenced by the AI model.
	 * <p>
	 * Important security note: This field is vulnerable to prompt injections, as the
	 * model might inadvertently interpret it as instructions. It is recommended to
	 * specify neutral names.
	 *
	 * <p>
	 * The name must only contain:
	 * <ul>
	 * <li>Alphanumeric characters
	 * <li>Whitespace characters (no more than one in a row)
	 * <li>Hyphens
	 * <li>Parentheses
	 * <li>Square brackets
	 * </ul>
	 */
	private String name;

	//......
}	

Media定义了id、mimeType、data、name属性

Format

	public static class Format {

		// -----------------
		// Document formats
		// -----------------
		/**
		 * Public constant mime type for {@code application/pdf}.
		 */
		public static final MimeType DOC_PDF = MimeType.valueOf("application/pdf");

		/**
		 * Public constant mime type for {@code text/csv}.
		 */
		public static final MimeType DOC_CSV = MimeType.valueOf("text/csv");

		/**
		 * Public constant mime type for {@code application/msword}.
		 */
		public static final MimeType DOC_DOC = MimeType.valueOf("application/msword");

		/**
		 * Public constant mime type for
		 * {@code application/vnd.openxmlformats-officedocument.wordprocessingml.document}.
		 */
		public static final MimeType DOC_DOCX = MimeType
			.valueOf("application/vnd.openxmlformats-officedocument.wordprocessingml.document");

		/**
		 * Public constant mime type for {@code application/vnd.ms-excel}.
		 */
		public static final MimeType DOC_XLS = MimeType.valueOf("application/vnd.ms-excel");

		/**
		 * Public constant mime type for
		 * {@code application/vnd.openxmlformats-officedocument.spreadsheetml.sheet}.
		 */
		public static final MimeType DOC_XLSX = MimeType
			.valueOf("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

		/**
		 * Public constant mime type for {@code text/html}.
		 */
		public static final MimeType DOC_HTML = MimeType.valueOf("text/html");

		/**
		 * Public constant mime type for {@code text/plain}.
		 */
		public static final MimeType DOC_TXT = MimeType.valueOf("text/plain");

		/**
		 * Public constant mime type for {@code text/markdown}.
		 */
		public static final MimeType DOC_MD = MimeType.valueOf("text/markdown");

		// -----------------
		// Video Formats
		// -----------------
		/**
		 * Public constant mime type for {@code video/x-matros}.
		 */
		public static final MimeType VIDEO_MKV = MimeType.valueOf("video/x-matros");

		/**
		 * Public constant mime type for {@code video/quicktime}.
		 */
		public static final MimeType VIDEO_MOV = MimeType.valueOf("video/quicktime");

		/**
		 * Public constant mime type for {@code video/mp4}.
		 */
		public static final MimeType VIDEO_MP4 = MimeType.valueOf("video/mp4");

		/**
		 * Public constant mime type for {@code video/webm}.
		 */
		public static final MimeType VIDEO_WEBM = MimeType.valueOf("video/webm");

		/**
		 * Public constant mime type for {@code video/x-flv}.
		 */
		public static final MimeType VIDEO_FLV = MimeType.valueOf("video/x-flv");

		/**
		 * Public constant mime type for {@code video/mpeg}.
		 */
		public static final MimeType VIDEO_MPEG = MimeType.valueOf("video/mpeg");

		/**
		 * Public constant mime type for {@code video/mpeg}.
		 */
		public static final MimeType VIDEO_MPG = MimeType.valueOf("video/mpeg");

		/**
		 * Public constant mime type for {@code video/x-ms-wmv}.
		 */
		public static final MimeType VIDEO_WMV = MimeType.valueOf("video/x-ms-wmv");

		/**
		 * Public constant mime type for {@code video/3gpp}.
		 */
		public static final MimeType VIDEO_THREE_GP = MimeType.valueOf("video/3gpp");

		// -----------------
		// Image Formats
		// -----------------
		/**
		 * Public constant mime type for {@code image/png}.
		 */
		public static final MimeType IMAGE_PNG = MimeType.valueOf("image/png");

		/**
		 * Public constant mime type for {@code image/jpeg}.
		 */
		public static final MimeType IMAGE_JPEG = MimeType.valueOf("image/jpeg");

		/**
		 * Public constant mime type for {@code image/gif}.
		 */
		public static final MimeType IMAGE_GIF = MimeType.valueOf("image/gif");

		/**
		 * Public constant mime type for {@code image/webp}.
		 */
		public static final MimeType IMAGE_WEBP = MimeType.valueOf("image/webp");

	}

Format定义了常用的几种MimeType

小结

Spring AI设计了各种message类型用于支持多模态,其中UserMessage有个media属性,类型List<Media>,支持传入图像、音频、视频,MimeType用于指定是哪种类型。

doc

<think>首先,用户的问题是:“我想了解使用Spring AI实现多模态图片理解的方法”。用户提供了几个引用,我需要参考这些引用来回答。 回顾用户提供的引用: - 引用[1]:介绍了多模态模型(Multimodal Models),处理文本、图像、音频等数据。提到Spring AI Multimodality结构图。 - 引用[2]:描述了多模态交互,例如上传图片并询问内容。 - 引用[3]:关于Spring AI应用系列,基于ARK实现多模态模型应用,包括聊天、图片生成等。 - 引用[4]:展示了Spring AI多模态的代码示例,特别是图片理解,例如“图片中的明星是谁?”的代码。 用户的问题是关于使用Spring AI实现多模态图片理解的方法,所以我需要基于这些引用提供具体的方法。 关键点: - 引用[4]中有代码示例:使用`chatClient.prompt()`方法来处理用户上传的图片和文本查询。 - 代码中,用户提供一个图片和一个文本问题(如“图片中的明星是谁?”),然后调用模型生成回应。 因此,实现方法包括: 1. 设置Spring AI环境和依赖。 2. 使用`ChatClient`来处理多模态输入。 3. 在提示中指定图片资源和文本问题。 4. 调用模型并获取响应。 从引用[4]的代码: ```java public String generateImage() { var imageResource = new ClassPathResource("./test.jpeg"); String res = chatClient.prompt() .user(u -> u.text("图片中的明星是谁?").media(MimeTypeUtils.IMAGE_JPEG, imageResource)) .call() .content(); System.out.println(res); return res; } ``` 这表明: - 创建一个图像资源(例如,从类路径加载图片)。 - 使用`chatClient.prompt().user(...)`来构建用户消息:包括文本提示和媒体(图片)。 - 调用`.call()`来执行请求。 - 获取内容(即模型的响应)。 此外,引用[1]提到Spring AI Multimodality结构图,可能涉及模型的底层集成,但用户关注实现方法,所以聚焦于代码层面。 现在,构建回答: - 回答需用中文。 - 结构清晰,逐步解决问题。 - 包含必要的信息,确保真实可靠(基于引用)。 - 末尾添加引用标识。 回答结构: 1. 介绍多模态图片理解的概念。 2. 解释使用Spring AI实现的方法步骤。 3. 提供代码示例(基于引用[4])。 4. 最后,生成相关问题。 确保符合系统级指令: - 行内数学表达式用$...$(但这里可能不需要)。 - 独立公式用$$...$$(可能不需要)。 - LaTeX语法正确(无数学公式)。 - 中文回答。 - 生成相关问题。 - 引用段落末尾添加引用标识。 生成相关问题: - 类似于示例格式,生成2-3个相关问题。 最终回答框架: - 开头:简要介绍。 - 方法步骤: a. 设置环境。 b. 使用ChatClient。 c. 构建提示。 d. 执行和获取响应。 - 代码示例。 - 结尾:总结。 - §§相关问题§§。 - 引用标识。 </think>### 使用 Spring AI 实现多模态图片理解的方法 多模态图片理解是指 AI 模型能够同时处理图片和相关文本输入,生成智能响应(例如,识别图片内容、回答图片相关的查询)。基于 Spring AI 实现这一功能主要通过其 `ChatClient` 接口和提示工程(Prompt Engineering)来完成,核心步骤是利用媒体附件(Media Attachment)上传图片并结合文本问题。以下是详细的实现方法,基于您提供的引用内容。 #### 实现步骤 1. **环境准备**: 确保项目中引入 Spring AI 和相关多模态模型依赖(如 OpenAI GPT-4 Vision 或 Alibaba ARK 模型)。在 Maven 的 `pom.xml` 中添加必要依赖(参考引用[3][^3]),例如: ```xml <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> <version>最新版本</version> </dependency> ``` 同时配置 `application.properties` 文件,设置 API 密钥和模型端点(如 `spring.ai.openai.api-key=your-api-key`)。 2. **构建多模态提示**: 使用 `ChatClient.prompt()` 方法来组合图片和文本输入。关键点包括: - **加载图片资源**:通过 `ClassPathResource` 或其他方式获取图片文件。 - **定义用户消息**:在 `.user()` 方法中,使用 `.text()` 指定文本问题,并用 `.media()` 附加图片(指定 MIME 类型和资源)。 - 这种方法允许模型融合视觉和语言信号,实现跨模态理解[^2][^1]。 3. **调用模型并获取响应**: 执行 `.call()` 方法触发模型推理,然后通过 `.content()` 提取生成的文本响应。代码示例基于引用[4][^4]: ```java import org.springframework.core.io.ClassPathResource; import org.springframework.util.MimeTypeUtils; import org.springframework.ai.chat.ChatClient; @Service public class ImageAnalysisService { private final ChatClient chatClient; public ImageAnalysisService(ChatClient chatClient) { this.chatClient = chatClient; } public String analyzeImage(String imagePath, String question) { // 加载图片资源(例如从类路径或文件系统) var imageResource = new ClassPathResource(imagePath); // 构建提示:文本问题 + 图片附件 String response = chatClient.prompt() .user(u -> u.text(question) .media(MimeTypeUtils.IMAGE_JPEG, imageResource)) // 支持JPEG/PNG等格式 .call() .content(); return response; // 返回模型生成的描述或答案 } } ``` 4. **集成到应用**: - 在 Controller 层暴露 REST 接口(如引用[4]中的 `@GetMapping`),允许用户上传图片和问题。 - 示例:用户调用 `/ai/analyze-image?image=test.jpg&question="图片中的物体是什么?"` ,后端服务返回分析结果。 - 项目架构通常遵循分层设计(模型层、服务层、控制器层),确保可扩展性[^3]。 #### 关键注意事项 - **模型选择**:Spring AI 支持多种多模态模型(如 OpenAI 的 GPT-4 Vision 或阿里云 ARK),需在配置中指定模型端点。 - **媒体处理**: - 图片需转换为资源对象(如 `ClassPathResource` 或 `FileSystemResource`)。 - MIME 类型必须正确(如 `MimeTypeUtils.IMAGE_JPEG`),否则模型无法识别。 - **性能优化**:对于大图片,建议压缩或使用 Base64 编码以减少网络延迟[^3][^4]。 - **错误处理**:添加异常捕获(如无效图片格式或 API 超时)。 通过以上方法,Spring AI 能高效实现图片理解任务,例如识别物体、描述场景或回答复杂查询。这种多模态集成正在推动 AI 在视觉问答、内容审核等领域的应用[^1][^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值