追踪中的多模态内容与附件
MLflow Tracing(追踪)可以捕获并渲染来自多模态 AI 模型中的图像、音频和二进制附件。当你向 GPT-4o 或 Claude 等模型发送图像或音频时,MLflow 会自动将二进制内容提取为轻量级的附件,并将其内联显示在 MLflow UI 中。
支持的内容类型
MLflow 的追踪模式使用 OpenAI 聊天消息格式来表示多模态内容。每个内容部分都有一个 type 字段,用于决定其存储和渲染方式。
| 内容类型 | type 值 | 编码 | UI 渲染 |
|---|---|---|---|
| 文本 | text | UTF-8 字符串 | Markdown |
| 图像 | image_url | HTTP(S) URL 或 base64 数据 URI | 内联图像 |
| 音频 | input_audio | Base64 编码的 WAV 或 MP3 | 内联音频播放器 |
图像
图像被表示为 mlflow.types.chat.ImageContentPart() 对象,类型为 image_url。image_url.url 字段支持:
- HTTP(S) URL —— 指向托管图像的直接链接(例如
https://example.com/photo.png) - Base64 数据 URI —— 内联图像数据(例如
data:image/png;base64,iVBOR...)
一个可选的 detail 字段用于控制模型处理图像的分辨率(auto、low 或 high)。
这两种格式都会在追踪查看器的聊天 (Chat) 选项卡中内联渲染。
音频
音频被表示为 mlflow.types.chat.AudioContentPart() 对象,类型为 input_audio。input_audio.data 字段包含 base64 编码的音频数据,input_audio.format 指定编解码器(wav 或 mp3)。
音频内容会在追踪查看器的聊天 (Chat) 选项卡中使用内联音频播放器进行渲染。
自动 Base64 提取
默认情况下,MLflow 会自动检测 span 输入和输出中的 base64 编码二进制内容,并将其提取为追踪附件。这使得追踪 JSON 保持轻量,同时将完整的二进制内容作为可下载的人工制品 (artifacts) 保存下来。
以下模式会被自动检测并提取:
| 模式 | 来源示例 | 提取为 |
|---|---|---|
| Base64 数据 URI | data:image/png;base64,... | image/png 附件 |
OpenAI input_audio | {"type": "input_audio", "input_audio": {"data": "...", "format": "wav"}} | audio/wav 附件 |
DALL-E b64_json 输出 | {"b64_json": "...", "revised_prompt": "..."} | image/png 附件 |
| OpenAI 音频响应 | {"audio": {"data": "...", "transcript": "..."}} | audio/wav 附件 |
| Responses API 图像生成 | {"type": "image_generation_call", "result": "...", "output_format": "png"} | image/<format> 附件 |
| Anthropic 图像源 | {"type": "image", "source": {"type": "base64", "data": "..."}} | 带有原始 media_type 的附件 |
| Bedrock 图像 | {"image": {"format": "png", "source": {"bytes": "..."}}} | image/<format> 附件 |
| Gemini 内联数据 | {"inline_data": {"mime_type": "image/png", "data": "..."}} | 带有原始 mime_type 的附件 |
| Gemini 内联数据(字节表示) | {"inline_data": {"mime_type": "image/png", "data": "b'\\x89PNG...'"}} | 带有原始 mime_type 的附件 |
提取后,span 中的 base64 数据将被替换为轻量级的 mlflow-attachment:// 引用 URI。MLflow UI 会解析这些 URI 并内联渲染支持的内容类型(图像、音频、PDF)。
自动提取默认启用。如需禁用该功能并将原始 base64 数据保留在追踪 JSON 中,请设置环境变量。
export MLFLOW_TRACE_EXTRACT_ATTACHMENTS=false
自动追踪
使用自动检测 (auto-instrumentation) 时,多模态内容会被自动捕获。MLflow 会将特定于提供商的格式标准化为上述标准模式,并将 base64 内容提取为附件。
| 框架 | 图像 | 音频 | 文件 | 备注 |
|---|---|---|---|---|
| OpenAI | ✓ | ✓ | ✓ | 聊天补全、Responses API(包含 input_file)和 Images.generate |
| Anthropic | ✓ | ✗ | ✗ | 原生图像块已标准化为 image_url |
| Bedrock | ✓ | ✗ | ✗ | 图像内容已提取至附件 |
| Gemini | ✓ | ✗ | ✗ | inline_data 已提取(base64 和 Python 字节表示) |
| LangChain | ✓ | ✓ | ✗ | 音频格式从 LangChain 标准化为 OpenAI 模式 |
OpenAI — 图像 (URL)
在聊天补全中发送图像 URL,MLflow 会自动捕获它。
import mlflow
from openai import OpenAI
mlflow.openai.autolog()
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "What's in this image?"},
{
"type": "image_url",
"image_url": {
"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg"
},
},
],
}
],
)
OpenAI — 图像 (Base64)
将本地图像文件编码为 base64 数据 URI。MLflow 会自动将 base64 数据提取为附件。
import base64
import mlflow
from openai import OpenAI
mlflow.openai.autolog()
def encode_image(image_path):
with open(image_path, "rb") as f:
return base64.b64encode(f.read()).decode("utf-8")
base64_image = encode_image("photo.png")
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "Describe this image in detail."},
{
"type": "image_url",
"image_url": {
"url": f"data:image/png;base64,{base64_image}",
"detail": "high",
},
},
],
}
],
)
OpenAI — 音频
使用 gpt-4o-audio-preview 模型发送音频输入。
import base64
import mlflow
from openai import OpenAI
mlflow.openai.autolog()
def encode_audio(audio_path):
with open(audio_path, "rb") as f:
return base64.b64encode(f.read()).decode("utf-8")
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o-audio-preview",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "What does this audio say?"},
{
"type": "input_audio",
"input_audio": {
"data": encode_audio("recording.wav"),
"format": "wav",
},
},
],
}
],
)
OpenAI — 图像生成
DALL-E 图像生成也会被自动追踪。b64_json 输出会被提取为图像附件。
import mlflow
from openai import OpenAI
mlflow.openai.autolog()
client = OpenAI()
response = client.images.generate(
model="dall-e-3",
prompt="a white siamese cat",
n=1,
response_format="b64_json",
)
Anthropic — 图像
Anthropic 使用不同的消息格式,但 MLflow 会自动将其标准化为标准的 image_url 模式。
import base64
import mlflow
from anthropic import Anthropic
mlflow.anthropic.autolog()
def encode_image(image_path):
with open(image_path, "rb") as f:
return base64.b64encode(f.read()).decode("utf-8")
client = Anthropic()
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": encode_image("photo.png"),
},
},
{"type": "text", "text": "Describe this image."},
],
}
],
)
手动追踪
你可以使用 mlflow.start_span() 和 set_inputs() / set_outputs() 手动将多模态内容附加到追踪中。请按照 OpenAI API 使用的相同格式,用内容部分列表构建消息。
import mlflow
with mlflow.start_span(name="multimodal-call") as span:
messages = [
{
"role": "user",
"content": [
{"type": "text", "text": "What's in this image?"},
{
"type": "image_url",
"image_url": {"url": "https://example.com/photo.png"},
},
],
}
]
span.set_inputs({"messages": messages})
# Call your model here
result = "A photo of a cat."
span.set_outputs({"content": result})
当调用 set_inputs() 或 set_outputs() 时,image_url.url 字段和 input_audio.data 字段中的 base64 数据 URI 会被自动提取为附件。
在 UI 中查看
MLflow 追踪查看器会在 UI 中渲染多模态内容。
- 图像 —— 内联显示,点击可放大预览全尺寸图像。
- 音频 —— 使用内置音频播放器渲染,可直接在 UI 中播放。
- PDF —— 在嵌入式查看器中显示。
图像 URL 在聊天 (Chat) 视图中渲染。追踪附件(图像、音频、PDF)在所有视图中内联渲染——聊天、详细信息 (Details) 和 时间轴 (Timeline)。


当 base64 内容被提取为附件时,内容 (Content) 选项卡会显示轻量级的 mlflow-attachment:// 引用 URI,而不是庞大的 base64 负载。UI 会自动获取并渲染附件内容。
超大附件将显示为下载链接,而不是内联渲染,以防止浏览器性能问题。阈值如下:
| 内容类型 | 最大内联大小 |
|---|---|
image/* | 10 MB |
audio/* | 50 MB |
application/pdf | 20 MB |
追踪附件
MLflow 将二进制内容作为独立的人工制品文件与追踪数据存储在一起,在保持追踪 JSON 轻量化的同时支持富媒体。有两种创建附件的方法:
- 自动提取(默认)—— 检测 span 输入/输出中的 base64 编码内容,进行提取并替换为
mlflow-attachment://引用 URI。详见自动 Base64 提取。 - 手动创建
Attachment—— 针对不符合识别出的自动记录格式的二进制内容(例如自定义追踪用例)。操作说明请参阅创建附件。
工作原理
当二进制内容存储为附件时,MLflow 会:
- 将 span 数据中的内容替换为轻量级的引用 URI (
mlflow-attachment://...) - 在导出追踪时,将二进制内容作为独立的人工制品文件上传。
这意味着追踪 JSON 可以保持很小,而与附件大小无关,且 MLflow UI 可以内联渲染支持的内容类型。
支持的内容类型
附件支持任何二进制内容类型。MLflow UI 会内联渲染以下类型(超过大小阈值的文件将显示下载链接):
| 内容类型 | UI 渲染 | 最大内联大小 |
|---|---|---|
image/* | 内联图像 | 10 MB |
audio/* | 内联音频播放器 | 50 MB |
application/pdf | 嵌入式 PDF 查看器 | 20 MB |
| 其他 | 下载链接 | -- |
创建附件
使用 Attachment 类来封装带有显式内容类型的二进制内容,或使用 Attachment.from_file() 从文件路径加载(内容类型会自动推断)。
from mlflow.tracing.attachments import Attachment
# From raw bytes with explicit content type
image_attachment = Attachment(content_type="image/png", content_bytes=png_bytes)
# From a file path (content type is inferred from the file extension)
pdf_attachment = Attachment.from_file("report.pdf")
# From a file path with explicit content type override
audio_attachment = Attachment.from_file("recording.bin", content_type="audio/wav")
在 Span 中使用附件
将 Attachment 对象直接传递给 set_inputs() 或 set_outputs()。MLflow 会自动处理提取和替换,包括在嵌套字典、列表和元组中。
import mlflow
from mlflow.tracing.attachments import Attachment
@mlflow.trace
def generate_image(prompt: str) -> dict:
# Call your image generation model
image_bytes = my_model.generate(prompt)
return {"image": Attachment(content_type="image/png", content_bytes=image_bytes)}
# The trace will show:
# - Input: {"prompt": "a sunset over mountains"}
# - Output: {"image": "mlflow-attachment://<uuid>?content_type=image/png&trace_id=..."}
# The actual image bytes are uploaded as a separate artifact.
result = generate_image("a sunset over mountains")
你也可以在上下文管理器 API 中使用附件。
import mlflow
from mlflow.tracing.attachments import Attachment
with mlflow.start_span(name="text-to-speech") as span:
span.set_inputs({"text": "Hello, world!"})
# Generate audio
audio_bytes = tts_model.synthesize("Hello, world!")
span.set_outputs({
"audio": Attachment(content_type="audio/wav", content_bytes=audio_bytes),
})
多个附件
你可以在单个 span 中包含多个附件。每个附件都会被独立提取和上传。
import mlflow
from mlflow.tracing.attachments import Attachment
with mlflow.start_span(name="multi-output") as span:
span.set_outputs({
"image": Attachment(content_type="image/png", content_bytes=image_bytes),
"audio": Attachment(content_type="audio/mp3", content_bytes=audio_bytes),
"report": Attachment.from_file("output.pdf"),
})
何时使用显式附件
在大多数情况下,无需手动创建 Attachment 对象。自动提取功能会自动处理聊天消息中的 base64 内容。请在以下情况下使用显式的 Attachment 包装:
- 二进制内容未进行 base64 编码(例如来自 API 响应的原始字节)
- 内容格式未被自动提取识别(请参阅支持的模式)
- 你希望附加文件,如 PDF、CSV 或其他文档。
如果你正在使用 OpenAI、Anthropic 或 LangChain 的自动追踪功能,聊天消息中的图像和音频会被自动捕获并提取为附件,无需进行 Attachment 包装。
限制
- 视频不受支持——视频内容不会被捕获或渲染。
- 大附件在超过在 UI 中查看列出的阈值时,会显示为下载链接,而不是内联渲染。