第十九章 多模态:图像、音频、视频——ImageBlock 统一替换为 DataBlock
1.x 的
ImageBlock/AudioBlock/VideoBlock在 2.0.0中被统一替换为DataBlock,通过mediaType字段区分类型。旧代码里
new ImageBlock(...)/new AudioBlock(...)在 2.0 中仍然兼容(标@Deprecated),但新代码请统一用DataBlock。本章先给旧 API 对照,再讲
DataBlock的统一用法。依赖:多模态模型需通过 OpenAI 兼容端点调用,依赖
agentscope-extensions-model-openai。
DashScope 专有协议暂不支持多模态——示例使用OpenAIChatModel+ DashScope 兼容地址https://dashscope.aliyuncs.com/compatible-mode/v1。
19.1 1.x 与 2.0 对照
| 1.x | 2.0 |
|---|---|
ImageBlock |
DataBlock.builder().mediaType("image/png") |
AudioBlock |
DataBlock.builder().mediaType("audio/mp3") |
VideoBlock |
DataBlock.builder().mediaType("video/mp4") |
Base64Source |
Base64Source(保留,但走 DataBlock.source(...)) |
URLSource |
URLSource(保留,走 DataBlock.source(...)) |
19.2 第一个多模态消息
这个例子在演示什么?
用
DataBlock把一张本地图片(PNG 文件)编码为 Base64,和文本拼成一条多模态消息发给 Agent。Agent 收到的不再是纯文本,而是"文字 + 图片"——它能看到图片内容并给出描述。
import io.agentscope.core.agent.RuntimeContext;
import io.agentscope.core.message.Base64Source;
import io.agentscope.core.message.DataBlock;
import io.agentscope.core.message.TextBlock;
import io.agentscope.core.message.UserMessage;
import io.agentscope.extensions.model.openai.OpenAIChatModel;
import io.agentscope.harness.HarnessAgent;
import java.nio.file.Files;
import java.util.Base64;
import java.util.List;
public class Chapter19_Multimodal {
public static void main(String[] args) throws Exception {
// 1. 读图片并编码 base64
byte[] bytes = Files.readAllBytes(Path.of("./cat.png"));
String b64 = Base64.getEncoder().encodeToString(bytes);
// 2. 构造 DataBlock
DataBlock imageBlock = DataBlock.builder()
.source(Base64Source.builder()
.data(b64)
.mediaType("image/png")
.build())
.build();
// 3. 多模态 user 消息
UserMessage msg = new UserMessage(
"user",
TextBlock.builder().text("这张图片里有什么?").build(),
imageBlock);
// 4. agent 调用
HarnessAgent agent = HarnessAgent.builder()
.name("vision_bot")
.sysPrompt("你是一个视觉助理,详细描述图片。")
.model(OpenAIChatModel.builder()
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.modelName("qwen3-omni-flash")
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.stream(true)
.formatter(new OpenAIChatFormatter())
.build())
.workspace(Path.of("./workspace"))
.build();
System.out.println(agent.call(List.of(msg), RuntimeContext.empty()).block().getTextContent());
}
}
19.3 DataBlock 字段
DataBlock(io.agentscope.core.message)核心字段:
| 字段 | 类型 | 说明 |
|---|---|---|
source |
Source |
数据来源,必填 |
mediaType |
String |
MIME 类型(image/png / audio/mp3 / video/mp4 / application/pdf) |
name |
String |
可选文件名 |
metadata |
Map |
业务方附加元信息 |
Source 有两种:
Base64Source—— 内联 base64 编码数据URLSource—— 远程 URL,agent 自动下载
19.4 音频 / 视频
视频和音频的 DataBlock 构造和图片一模一样,换个 mediaType 就行。但同样的代码,图片能跑、音频和视频跑不了。
限制不在 DashScope 本身,在 AgentScope 的内置 ChatModel。OpenAIChatModel 也好、DashScopeChatModel 也好,底层全部走 REST HTTP 协议。HTTP 请求体的多模态字段只支持 image_url 这一种格式,input_audio 和视频帧都塞不进去。
DashScope 自己是能处理音频的,只是需要走不同的协议通道:
- WebSocket 实时流。Qwen-Omni 实时对话、语音识别都是 WebSocket 长连接,双向推流。AgentScope 没有内置 WebSocket 客户端。
- DashScope 原生 HTTP 多模态格式。ONE-PEACE、Qwen-VL 这些模型支持 HTTP 传入音频 URL,但走的是 DashScope 自有协议,不是 OpenAI 兼容格式。
两条路都能通,但都不在 AgentScope 的 ChatModel 覆盖范围内。想用的话,学第 20 章 TTS 的做法:自己用 @Tool 包装 DashScope SDK,AgentScope 只负责调工具、不在框架层处理音频字节。
本章示例聚焦图片。图片是 REST 端点唯一稳定支持的多模态输入,也是绝大多数业务最常用的多模态场景。
19.5 与 Tool 的协作
业务方工具可以返回 DataBlock —— 适合 OCR / 截图 / 渲染结果:
@Tool(name = "screenshot_page", description = "截图某个 URL")
public DataBlock screenshot(
@ToolParam(name = "url") String url) throws Exception {
// 调 puppeteer / playwright 拿 png
byte[] png = playwright.screenshot(url);
String b64 = Base64.getEncoder().encodeToString(png);
return DataBlock.builder()
.source(Base64Source.builder()
.data(b64)
.mediaType("image/png")
.build())
.name("screenshot.png") // name 挂在 DataBlock 上,不是 Base64Source
.build();
}
LLM 看到工具返回 DataBlock 会自动把它纳入上下文——框架内部会把 DataBlock 包装成 ToolResultBlock 再发给 LLM,无需手动构造。
19.6 1.x 旧代码的兼容路径
ImageBlock / AudioBlock / VideoBlock 在 2.0 仍存在(标 @Deprecated):
// 1.x 老代码仍能跑
import io.agentscope.core.message.ImageBlock;
ImageBlock oldStyle = new ImageBlock(b64, "image/png"); // 2.0 编译会出 warning
ImageBlock 内部就是 DataBlock.builder().mediaType("image/...")。建议新代码统一用 DataBlock;老代码改起来很便宜(1 行换 1 行)。
19.7 完整可运行示例
这个例子在演示什么?
一条消息里同时拼了两种来源的图片:本地文件走
Base64Source(内联编码)、远程 URL 走URLSource(引用地址)。Agent 一次性拿到两张图,可以对比分析。这就是多模态的本质——不限制 Block 数量,需要几个拼几个。
public class Chapter19_FullMultimodal {
public static void main(String[] args) throws Exception {
// 方式一:本地文件 Base64 内联
DataBlock fromFile = DataBlock.builder()
.source(Base64Source.builder()
.data(Base64.getEncoder().encodeToString(
Files.readAllBytes(Path.of("./cat.png"))))
.mediaType("image/png")
.build())
.build();
// 方式二:远程 URL 引用
DataBlock fromUrl = DataBlock.builder()
.source(URLSource.builder()
.url("https://example.com/dog.jpg")
.mimeType("image/jpeg")
.build())
.build();
UserMessage msg = new UserMessage(
"user",
TextBlock.builder().text("对比这两张图片有什么不同。").build(),
fromFile,
fromUrl);
HarnessAgent agent = HarnessAgent.builder()
.name("multimodal_bot")
.sysPrompt("你是多模态助理,可以理解图片内容。")
.model(OpenAIChatModel.builder()
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.modelName("qwen3-omni-flash")
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.stream(true)
.formatter(new OpenAIChatFormatter())
.build())
.workspace(Path.of("./workspace"))
.build();
System.out.println(agent.call(List.of(msg), RuntimeContext.empty()).block().getTextContent());
}
}
音频/视频的
DataBlock构造方式和图片完全一样,只需改mediaType。是否能被模型理解取决于模型端点的协议支持——大部分 REST HTTP 端点仅支持图片多模态,音频/视频输入需要 WebSocket 实时协议。
19.8 最小迁移清单(1.x ImageBlock → 2.0 DataBlock)
| 1.x 用法 | 2.0 等价 |
|---|---|
new ImageBlock(b64, "image/png") |
DataBlock.builder().source(Base64Source.builder().data(b64).mediaType("image/png").build()).build() |
new AudioBlock(b64, "audio/mp3") |
DataBlock.builder().mediaType("audio/mp3") |
new VideoBlock(url, "video/mp4") |
DataBlock.builder().source(URLSource.builder().url(url).mimeType("video/mp4").build()) |
msg.getContentBlocks(ImageBlock.class) |
msg.getContentBlocks(DataBlock.class) 后按 mediaType 区分 |
19.9 本章小结
- 2.0 用
DataBlock统一图片 / 音频 / 视频 / 文件。 - 旧
ImageBlock/AudioBlock/VideoBlock仍兼容但被弃用。 - 工具可返回
DataBlock—— LLM 自动纳入上下文。 mediaType字段决定 LLM 端路由(视觉 / 音频 / 视频模型)。