图片多模态输入
随着多模态模型的发展,越来越多的业务场景需要直接向大模型输入图片,并结合文本指令完成任务,例如:
- 图片文字识别(OCR)
- 图片内容理解与描述
- 图表、试题、合同、截图等内容解析
- 图片 + 文本混合推理(VLM / Vision-Language Model)
java-openai 在统一聊天抽象的基础上,提供了统一的图片输入模型,使业务侧可以用一致的方式对接支持视觉能力的模型,而无需关心各平台在图片参数、编码方式上的差异。
设计思路概述
在 java-openai 中,图片输入并不是一个“独立 API”,而是作为 消息的一部分 存在:
- 图片被抽象为
ChatImageFile - 图片与文本一起挂载到
UniChatMessage - 通过
UniChatRequest统一发送 - 由底层平台适配层转换为对应模型所需的协议格式
这使得以下场景成为可能:
- 纯图片任务(只发图片)
- 图片 + 指令(如“识别图片中的文字”)
- 图片 + 多轮对话上下文
示例:图片文字识别接口
下面示例实现了一个 HTTP 接口:
- 客户端通过
multipart/form-data上传图片 - 服务端将图片转换为 Base64
- 使用支持视觉能力的模型进行推理
- 返回模型识别出的文本内容
示例代码
package com.litongjava.tio.web.hello.handler;
import java.util.ArrayList;
import java.util.List;
import com.litongjava.chat.ChatImageFile;
import com.litongjava.chat.PlatformInput;
import com.litongjava.chat.UniChatClient;
import com.litongjava.chat.UniChatMessage;
import com.litongjava.chat.UniChatRequest;
import com.litongjava.chat.UniChatResponse;
import com.litongjava.consts.ModelPlatformName;
import com.litongjava.openrouter.OpenRouterModels;
import com.litongjava.tio.boot.http.TioRequestContext;
import com.litongjava.tio.http.common.HttpRequest;
import com.litongjava.tio.http.common.HttpResponse;
import com.litongjava.model.upload.UploadFile;
import com.litongjava.tio.http.server.handler.HttpRequestHandler;
import com.litongjava.tio.http.server.util.CORSUtils;
import com.litongjava.tio.utils.base64.Base64Utils;
import com.litongjava.tio.utils.http.ContentTypeUtils;
import com.litongjava.tio.utils.hutool.FilenameUtils;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class PredictFileHandler implements HttpRequestHandler {
@Override
public HttpResponse handle(HttpRequest httpRequest) throws Exception {
HttpResponse response = TioRequestContext.getResponse();
CORSUtils.enableCORS(response);
UploadFile uploadFile = httpRequest.getUploadFile("file");
byte[] data = uploadFile.getData();
String name = uploadFile.getName();
String systemPrompt = "识别图片中的文字";
String result = predict(systemPrompt, data, name);
return response.setBody(result);
}
private String predict(String systemPrompt, byte[] data, String filename) {
// 1. 推断文件类型
String suffix = FilenameUtils.getSuffix(filename);
String mimeType = ContentTypeUtils.getContentType(suffix);
// 2. 图片转 Base64
String encodeImage = Base64Utils.encodeImage(data, mimeType);
// 3. 构造图片文件对象
List<ChatImageFile> files = new ArrayList<>();
ChatImageFile file = ChatImageFile.base64(mimeType, encodeImage);
files.add(file);
// 4. 构造消息(图片作为 message 的一部分)
UniChatMessage uniChatMessage = new UniChatMessage();
uniChatMessage.setContent("image");
uniChatMessage.setFiles(files);
// 5. 选择支持视觉能力的模型
PlatformInput platformInput = new PlatformInput(
ModelPlatformName.OPENROUTER,
OpenRouterModels.QWEN_QWEN2_5_VL_7B_INSTRUCT_FREE
);
// 6. 构造统一请求
UniChatRequest uniChatRequest = new UniChatRequest(platformInput);
uniChatRequest.setSystemPrompt(systemPrompt);
List<UniChatMessage> messages = new ArrayList<>();
messages.add(uniChatMessage);
uniChatRequest.setMessages(messages);
try {
UniChatResponse response = UniChatClient.generate(uniChatRequest);
return response.getMessage().getContent();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return null;
}
}
客户端调用示例
使用 curl 以 multipart/form-data 方式上传图片:
curl -X POST http://127.0.0.1/predict/image \
-F "file=@challenging-sat-math-geometry-problem-v0-6h5fen0qwkzc1.jpg"
服务端将返回模型对图片内容的识别结果(例如图片中的文字或题目内容)。
关键点说明
1. 图片如何传递给模型
在 java-openai 中,图片的传递流程是:
- 原始图片 → 二进制
byte[] - 根据文件后缀推断
mimeType - 转换为 Base64 编码
- 封装为
ChatImageFile - 挂载到
UniChatMessage.files - 随
UniChatRequest一起发送
业务侧不需要关心底层平台是使用:
image_urlinline_datacontent.parts- 或其他私有字段
这些差异都由平台适配层自动处理。
2. 为什么 content 设置为 "image"
在图片任务中:
UniChatMessage.content用于表达“这是一个图片消息”- 实际的图片数据通过
files传递 - 文本指令通过
systemPrompt或额外的 user message 提供
这种设计便于支持:
- 多图片输入
- 图片 + 文本混合消息
- 与后续文本对话自然衔接
3. 模型选择的重要性
并非所有模型都支持图片输入。 在使用图片能力时,必须选择:
- 明确支持 Vision / VL / Multimodal 的模型
- 例如:
Qwen-VL、Gemini、Claude Vision等
在示例中,通过:
OpenRouterModels.QWEN_QWEN2_5_VL_7B_INSTRUCT_FREE
明确选择了一个支持图片理解的模型。
4. 与纯文本调用的统一性
尽管引入了图片能力,但你会发现:
- 入口仍然是
UniChatClient.generate(...) - 请求对象仍然是
UniChatRequest - 返回对象仍然是
UniChatResponse - 获取结果仍然是
response.getMessage().getContent()
这正是 java-openai 统一抽象的价值所在: 多模态能力是对消息的扩展,而不是对调用方式的破坏。
常见扩展场景
基于当前结构,可以很自然地扩展出:
- 图片 + 提示词:“请解释这张图的含义”
- 图片 + 多轮上下文:先上传图片,再追问细节
- 多图片对比分析
- 图片 + 搜索 / 工具调用(结合前文 search 能力)
小结
java-openai通过ChatImageFile抽象图片输入- 图片作为
UniChatMessage的一部分参与对话 - 统一使用
UniChatRequest / UniChatResponse调用与返回 - 平台差异完全由内部适配层处理
- 只要更换模型,即可在同一套代码下切换不同视觉模型能力
