ag2-multimodal-input
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMultimodal inputs
多模态输入
When to use
使用场景
The user wants the agent to process non-text input: an image to describe, audio to transcribe, video to summarise, or a PDF / document to extract from. The same factory pattern works across providers; per-provider support varies.
当用户需要Agent处理非文本输入时:比如描述图片、转录音频、总结视频,或从PDF/文档中提取信息。同一工厂模式适用于各服务商,但不同服务商的支持范围有所差异。
60-second recipe
60秒快速上手
python
from ag2 import Agent
from ag2.config import GeminiConfig
from ag2.events import ImageInput
agent = Agent(
"vision",
"You describe images.",
config=GeminiConfig(model="gemini-3-flash-preview"),
)
image = ImageInput("https://example.com/photo.jpg")
reply = await agent.ask("Describe this image in detail.", image)
print(reply.body)Multiple inputs in one ask are fine:
python
reply = await agent.ask(
"Compare these two images.",
ImageInput("https://example.com/before.jpg"),
ImageInput("https://example.com/after.jpg"),
)python
from ag2 import Agent
from ag2.config import GeminiConfig
from ag2.events import ImageInput
agent = Agent(
"vision",
"You describe images.",
config=GeminiConfig(model="gemini-3-flash-preview"),
)
image = ImageInput("https://example.com/photo.jpg")
reply = await agent.ask("Describe this image in detail.", image)
print(reply.body)一次请求中支持传入多个输入:
python
reply = await agent.ask(
"Compare these two images.",
ImageInput("https://example.com/before.jpg"),
ImageInput("https://example.com/after.jpg"),
)Input factories
输入工厂类
| Factory | Formats |
|---|---|
| JPEG, PNG, GIF, WebP |
| WAV, MP3, OGG, FLAC, AAC |
| MP4, WebM, MOV, MKV, MPEG |
| PDF, TXT, HTML, Markdown, CSV, JSON, Office formats |
Each accepts the same four data sources:
python
from ag2.events import ImageInput
ImageInput("https://example.com/photo.jpg") # URL
ImageInput(path="photo.jpg") # local file
ImageInput(data=raw_bytes, media_type="image/png") # bytes
ImageInput(file_id="file-abc123") # provider-uploaded| 工厂类 | 支持格式 |
|---|---|
| JPEG、PNG、GIF、WebP |
| WAV、MP3、OGG、FLAC、AAC |
| MP4、WebM、MOV、MKV、MPEG |
| PDF、TXT、HTML、Markdown、CSV、JSON、Office格式 |
每个工厂类均支持以下四种数据来源:
python
from ag2.events import ImageInput
ImageInput("https://example.com/photo.jpg") # URL
ImageInput(path="photo.jpg") # 本地文件
ImageInput(data=raw_bytes, media_type="image/png") # 字节数据
ImageInput(file_id="file-abc123") # 服务商已上传文件IDProvider matrix
服务商支持矩阵
| Input type | OpenAI | OpenAI Responses | Gemini | Anthropic |
|---|---|---|---|---|
| Text | ✓ | ✓ | ✓ | ✓ |
| Image (URL) | ✓ | ✓ | ✓ | ✓ |
| Image (binary) | ✓ | ✓ | ✓ | ✓ |
| Audio (URL) | – | – | ✓ | – |
| Audio (binary) | ✓ | – | ✓ | – |
| Video (URL) | – | – | ✓ | – |
| Video (binary) | – | – | ✓ | – |
| Document (URL) | – | ✓ | ✓ | ✓ |
| Document (binary) | ✓ | ✓ | ✓ | ✓ |
| File ID | ✓ | ✓ | ✓ | ✓ |
Unsupported combinations raise with a clear message.
UnsupportedInputErrorGemini has the broadest multimodal support. If you don't know which provider to pick for a multimodal task, start there.
| 输入类型 | OpenAI | OpenAI Responses | Gemini | Anthropic |
|---|---|---|---|---|
| 文本 | ✓ | ✓ | ✓ | ✓ |
| 图片(URL) | ✓ | ✓ | ✓ | ✓ |
| 图片(二进制) | ✓ | ✓ | ✓ | ✓ |
| 音频(URL) | – | – | ✓ | – |
| 音频(二进制) | ✓ | – | ✓ | – |
| 视频(URL) | – | – | ✓ | – |
| 视频(二进制) | – | – | ✓ | – |
| 文档(URL) | – | ✓ | ✓ | ✓ |
| 文档(二进制) | ✓ | ✓ | ✓ | ✓ |
| 文件ID | ✓ | ✓ | ✓ | ✓ |
不支持的组合会抛出并给出明确提示。
UnsupportedInputErrorGemini的多模态支持范围最广。如果不确定为多模态任务选择哪个服务商,建议从Gemini开始。
Provider-specific niceties
各服务商专属特性
Gemini — YouTube URLs work directly
Gemini — 直接支持YouTube URL
python
from ag2.events import VideoInput
video = VideoInput("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
reply = await agent.ask("Summarize this video.", video)python
from ag2.events import VideoInput
video = VideoInput("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
reply = await agent.ask("Summarize this video.", video)Gemini — large files (> 20MB) via Google Files API
Gemini — 大文件(>20MB)需通过Google Files API上传
python
from google import genai
from ag2.events import VideoInput
import time
client = genai.Client()
uploaded = client.files.upload(file="large_video.mp4")
while uploaded.state.name == "PROCESSING":
time.sleep(2)
uploaded = client.files.get(name=uploaded.name)
video = VideoInput(uploaded.uri)python
from google import genai
from ag2.events import VideoInput
import time
client = genai.Client()
uploaded = client.files.upload(file="large_video.mp4")
while uploaded.state.name == "PROCESSING":
time.sleep(2)
uploaded = client.files.get(name=uploaded.name)
video = VideoInput(uploaded.uri)Gemini — vendor_metadata
vendor_metadataGemini — vendor_metadata
参数
vendor_metadata| Key | Purpose |
|---|---|
| |
| Clipping ( |
| Display name for the file |
python
ImageInput(data=raw, media_type="image/jpeg", vendor_metadata={"media_resolution": "MEDIA_RESOLUTION_LOW"})
VideoInput(path="lecture.mp4", vendor_metadata={
"video_metadata": {"start_offset": "60s", "end_offset": "120s", "fps": 0.5},
})| 键名 | 用途 |
|---|---|
| |
| 视频剪辑( |
| 文件的显示名称 |
python
ImageInput(data=raw, media_type="image/jpeg", vendor_metadata={"media_resolution": "MEDIA_RESOLUTION_LOW"})
VideoInput(path="lecture.mp4", vendor_metadata={
"video_metadata": {"start_offset": "60s", "end_offset": "120s", "fps": 0.5},
})OpenAI — image detail
OpenAI — 图像细节设置
python
ImageInput(data=raw, media_type="image/png", vendor_metadata={"detail": "low"}) # "low" | "high" | "auto"python
ImageInput(data=raw, media_type="image/png", vendor_metadata={"detail": "low"}) # "low" | "high" | "auto"Anthropic — File ID + prompt caching
Anthropic — 文件ID + 提示缓存
python
import anthropic
from ag2.events import ImageInput, DocumentInput
client = anthropic.Anthropic()
uploaded = client.beta.files.upload(file=("photo.jpg", open("photo.jpg", "rb"), "image/jpeg"))python
import anthropic
from ag2.events import ImageInput, DocumentInput
client = anthropic.Anthropic()
uploaded = client.beta.files.upload(file=("photo.jpg", open("photo.jpg", "rb"), "image/jpeg"))filename determines block type (image vs document)
文件名决定块类型(图片 vs 文档)
image = ImageInput(file_id=uploaded.id, filename="photo.jpg")
image = ImageInput(file_id=uploaded.id, filename="photo.jpg")
Cache an attachment so subsequent turns skip re-uploading
缓存附件,后续对话无需重新上传
doc = DocumentInput(path="report.pdf", vendor_metadata={"cache_control": {"type": "ephemeral"}})
undefineddoc = DocumentInput(path="report.pdf", vendor_metadata={"cache_control": {"type": "ephemeral"}})
undefinedFilesAPI
— upload lifecycle, provider-agnostic
FilesAPIFilesAPI
— 跨服务商的上传生命周期管理
FilesAPIFor any provider that has a file API (, , , ):
OpenAIConfigOpenAIResponsesConfigAnthropicConfigGeminiConfigpython
from ag2 import FilesAPI
from ag2.config import OpenAIResponsesConfig
files = FilesAPI(OpenAIResponsesConfig(model="gpt-5-mini"))
uploaded = await files.upload(path="report.pdf", purpose="assistants")
print(uploaded.file_id)对于支持文件API的服务商(、、、):
OpenAIConfigOpenAIResponsesConfigAnthropicConfigGeminiConfigpython
from ag2 import FilesAPI
from ag2.config import OpenAIResponsesConfig
files = FilesAPI(OpenAIResponsesConfig(model="gpt-5-mini"))
uploaded = await files.upload(path="report.pdf", purpose="assistants")
print(uploaded.file_id)Or from bytes (filename required)
或从字节数据上传(需指定文件名)
uploaded = await files.upload(data=b"...", filename="hello.txt", purpose="assistants")
uploaded = await files.upload(data=b"...", filename="hello.txt", purpose="assistants")
List, read, delete
列出、读取、删除文件
all_files = await files.list()
data = await files.read(uploaded.file_id) # NotImplementedError on Gemini
await files.delete(uploaded.file_id)
Pass the `file_id` to `DocumentInput`, `ImageInput`, etc.:
```python
from ag2.events import DocumentInput
doc = DocumentInput(file_id=uploaded.file_id)
reply = await agent.ask("Summarize this report.", doc)all_files = await files.list()
data = await files.read(uploaded.file_id) # Gemini不支持此方法,会抛出NotImplementedError
await files.delete(uploaded.file_id)
将`file_id`传入`DocumentInput`、`ImageInput`等:
```python
from ag2.events import DocumentInput
doc = DocumentInput(file_id=uploaded.file_id)
reply = await agent.ask("Summarize this report.", doc)Going deeper
深入学习
- — full provider matrix and
website/docs/user-guide/multimodal/inputs.mdxreference.vendor_metadata - —
website/docs/user-guide/advanced/files.mdxreference (upload / list / read / delete).FilesAPI - For tools that return images / binary back to the LLM, see (
ag2-add-custom-tool,ImageInput,BinaryInput).ToolResult
- — 完整的服务商支持矩阵与
website/docs/user-guide/multimodal/inputs.mdx参考文档。vendor_metadata - —
website/docs/user-guide/advanced/files.mdx参考文档(上传/列出/读取/删除)。FilesAPI - 若需工具向LLM返回图片/二进制数据,请查看(涉及
ag2-add-custom-tool、ImageInput、BinaryInput)。ToolResult
Common pitfalls
常见陷阱
- Picking a provider that doesn't support your input type — silently you'll get . Check the matrix; Gemini is broadest.
UnsupportedInputError - on Gemini — raises
FilesAPI.read(). Gemini doesn't expose download.NotImplementedError - Calling without
files.upload(data=...)— raisesfilename=. Filename is required for in-memory uploads.ValueError - Supplying more than one source to a factory — not an error. The factory resolves in priority order >
url>file_id>path, so extra sources are silently ignored. Pass exactly one to get what you intend. Supplying zero sources raisesdata.ValueError - Anthropic without
ImageInput(file_id=...)— Anthropic decides block type (image vs document) by filename extension. Pass it.filename= - Gemini keys are nested —
vendor_metadataitself takes a dict. Check the doc table for shape.video_metadata - Forgetting to wait for Gemini file processing — large uploads have a state. Poll
PROCESSINGuntil ready before referencing the URI.client.files.get(name=...)
- 选择不支持目标输入类型的服务商 — 会静默抛出。请查看支持矩阵;Gemini的支持范围最广。
UnsupportedInputError - 在Gemini上调用— 会抛出
FilesAPI.read()。Gemini不提供下载接口。NotImplementedError - 调用时未指定
files.upload(data=...)— 会抛出filename=。内存上传必须指定文件名。ValueError - 向工厂类传入多个数据来源 — 不会报错,但工厂类会按优先级>
url>file_id>path解析,多余的来源会被静默忽略。为确保预期效果,请仅传入一个来源。若未传入任何来源,会抛出data。ValueError - Anthropic的未指定
ImageInput(file_id=...)— Anthropic通过文件扩展名判断块类型(图片 vs 文档),请务必传入文件名。filename= - Gemini的参数为嵌套结构 —
vendor_metadata本身需要传入字典。请参考文档表格中的结构。video_metadata - 忘记等待Gemini文件处理完成 — 大文件上传后会处于状态。在引用URI前,需轮询
PROCESSING直到状态就绪。client.files.get(name=...)