多模态与附件
Langfuse 支持多模态 traces,包括文本、图像、音频和其他附件。
默认情况下,base64 编码的 data URI 由 Langfuse SDK 自动处理。它们从多模态 LLM 常用的负载中提取,上传到 Langfuse 的对象存储,并链接到 trace。
如果你执行以下操作,这也有效:
- 通过外部 URL 引用媒体文件。
- 通过
LangfuseMedia类在 SDK 中自定义媒体文件的处理。 - 直接通过 Langfuse API 集成。
关于如何开始以及这在底层如何工作,在下方了解更多。
示例
可用性
Langfuse Cloud
Langfuse Cloud 上的多模态附件目前在 Langfuse Cloud 上免费。我们保留在近期推出新定价指标的权利,以核算与大型多模态 traces 相关的额外存储和计算成本。
自托管
多模态附件今天即可用。你需要通过 Langfuse 环境变量(LANGFUSE_S3_MEDIA_UPLOAD_*)配置你自己的对象存储桶。关于这些环境变量的细节参见自托管文档。所有主要云提供商都支持 S3 兼容的 API,并可以通过 minio 自托管。请注意,配置的存储桶必须具有可公开解析的主机名,以支持通过我们的 SDK 直接上传以及直接从浏览器获取媒体资产。
支持的媒体格式
Langfuse 支持广泛的媒体类型,包括:
- 图像:.png、.jpg、.webp、.gif
- 音频:.mp3、.wav、.ogg
- 视频:.mp4、.webm、.mov
- 文本与代码:.txt、.md、.html、.csv
- 文档:.pdf、.docx、.xlsx、.pptx
- 数据与归档:.json、.xml、.zip
支持的 MIME 类型完整列表
| 类别 | MIME 类型 | 文件扩展名 |
|---|---|---|
| 图像 | image/png |
.png |
| 图像 | image/jpeg、image/jpg |
.jpg、.jpeg |
| 图像 | image/webp |
.webp |
| 图像 | image/gif |
.gif |
| 图像 | image/svg+xml |
.svg |
| 图像 | image/tiff |
.tiff |
| 图像 | image/bmp |
.bmp |
| 图像 | image/avif |
.avif |
| 图像 | image/heic |
.heic |
| 音频 | audio/mpeg、audio/mp3 |
.mp3 |
| 音频 | audio/wav |
.wav |
| 音频 | audio/ogg |
.ogg |
| 音频 | audio/oga |
.oga |
| 音频 | audio/aac |
.aac |
| 音频 | audio/mp4 |
.m4a |
| 音频 | audio/flac |
.flac |
| 音频 | audio/opus |
.opus |
| 音频 | audio/webm |
.weba |
| 视频 | video/mp4 |
.mp4 |
| 视频 | video/webm |
.webm |
| 视频 | video/ogg |
.ogv |
| 视频 | video/mpeg |
.mpeg |
| 视频 | video/quicktime |
.mov |
| 视频 | video/x-msvideo |
.avi |
| 视频 | video/x-matroska |
.mkv |
| 文本与代码 | text/plain |
.txt |
| 文本与代码 | text/html |
.html |
| 文本与代码 | text/css |
.css |
| 文本与代码 | text/csv |
.csv |
| 文本与代码 | text/markdown |
.md |
| 文本与代码 | text/x-python |
.py |
| 文本与代码 | application/javascript |
.js |
| 文本与代码 | text/x-typescript |
.ts |
| 文本与代码 | application/x-yaml |
.yaml |
| 文档 | application/pdf |
.pdf |
| 文档 | application/msword |
.doc |
| 文档 | application/vnd.openxmlformats-officedocument.wordprocessingml.document |
.docx |
| 文档 | application/vnd.ms-excel |
.xls |
| 文档 | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet |
.xlsx |
| 文档 | application/vnd.openxmlformats-officedocument.presentationml.presentation |
.pptx |
| 文档 | application/rtf |
.rtf |
| 数据与归档 | application/json |
.json |
| 数据与归档 | application/x-ndjson |
.jsonl |
| 数据与归档 | application/xml |
.xml |
| 数据与归档 | application/vnd.apache.parquet |
.parquet |
| 数据与归档 | application/zip |
.zip |
| 数据与归档 | application/gzip |
.gz |
| 数据与归档 | application/x-tar |
.tar |
| 数据与归档 | application/x-7z-compressed |
.7z |
| 数据与归档 | application/octet-stream |
.bin |
如果你需要支持额外的文件类型,请在我们的 GitHub Discussion 中告知我们,我们正在那里积极收集关于多模态支持的反馈。
开始使用
Base64 data URI 编码的媒体
如果你的 LLM 应用中使用 base64 编码的图像、音频或其他文件,请升级到最新版本的 Langfuse SDK。Langfuse SDK 通过提取 base64 编码的媒体、将其作为 Langfuse Media 文件单独上传,并在 trace 中包含引用,来自动检测和处理它们。
如果大型 base64 编码媒体未经客户端处理就到达 Langfuse,Langfuse 会在服务端处理它以保持其完整并可在 UI 中检查。这是一种降级方案。我们强烈建议在客户端或 Langfuse SDK 中处理媒体。
这适用于标准 Data URI(MDN)格式的媒体(如 OpenAI 和其他 LLM 使用的那些)。
本 notebook 包含几个使用 OpenAI SDK 和 LangChain 的示例。
外部媒体(URL)
如果媒体文件遵循常见格式,Langfuse 支持通过 URL 内联渲染媒体文件。在这种情况下,媒体文件不会上传到 Langfuse 的对象存储,而是直接在 UI 中从源渲染。
支持的格式:
Markdown 图像

OpenAI content parts
{
"content": [
{
"role": "system",
"content": "You are an AI trained to describe and interpret images. Describe the main objects and actions in the image."
},
{
"role": "user",
"content": [
{
"type": "text",
"text": "What's happening in this image?"
},
{
"type": "image_url",
"image_url": {
"url": "https://example.com/image.jpg"
}
}
]
}
]
}
自定义附件
如果你想拥有更多控制,或你的媒体不是 base64 编码的,你可以使用新的 LangfuseMedia 类通过 SDK 将任意媒体附件上传到 Langfuse。在将媒体包含到 trace 输入、输出、元数据或数据集条目之前,用 LangfuseMedia 包装媒体。示例参见多模态文档。
from langfuse import get_client, observe, propagate_attributes
from langfuse.media import LangfuseMedia
# Create a LangfuseMedia object from a file
with open("static/bitcoin.pdf", "rb") as pdf_file:
pdf_bytes = pdf_file.read()
# Wrap media in LangfuseMedia class
pdf_media = LangfuseMedia(content_bytes=pdf_bytes, content_type="application/pdf")
# Using with the decorator
@observe()
def process_document():
langfuse = get_client()
# Propagate metadata (including media) to all child observations
with propagate_attributes(
metadata={"document": pdf_media}
):
pass
# Or update the current span
langfuse.update_current_span(
input={"document": pdf_media}
)
# Using with context managers
langfuse = get_client()
with langfuse.start_as_current_observation(as_type="span", name="analyze-document") as span: # Include media in the span input, output, or metadata
span.update(
input={"document": pdf_media},
metadata={"file_size": len(pdf_bytes)}
)
# Process document...
# Add results with media to the output
span.update(output={
"summary": "This document explains Bitcoin...",
"original": pdf_media
})
import fs from "fs";
import { LangfuseMedia } from "@langfuse/core";
// Wrap media in LangfuseMedia class
const wrappedMedia = new LangfuseMedia({
source: "bytes",
contentBytes: fs.readFileSync(new URL("./bitcoin.pdf", import.meta.url)),
contentType: "application/pdf",
});
// Optionally, access media via wrappedMedia.obj
console.log(wrappedMedia.obj);
// Include media in any trace or observation
const span3 = startObservation("media-pdf-generation");
const generation3 = span3.startObservation('llm-call', {
model: 'gpt-4',
input: wrappedMedia,
}, {asType: "generation"});
generation3.end();
span3.end();
API
如果你直接使用 API 将 traces 记录到 Langfuse,你需要遵循以下步骤:
它如何工作?
当使用媒体文件(非通过外部 URL 引用)时,Langfuse 按以下方式处理它们:
1. 媒体上传过程
检测与提取
- Langfuse 支持
input、output和metadata字段上 traces 和 observations 中的媒体文件 - SDK 在客户端将媒体与追踪数据分离,以优化性能
- 媒体文件直接上传到对象存储(AWS S3 或兼容)
- 原始媒体内容被替换为引用字符串
安全与优化
- 上传使用带内容校验(内容长度、内容类型、内容 SHA256 哈希)的预签名 URL
- 去重:如果文件已上传,则仅由其
mediaId引用字符串替换 - 文件唯一性由项目、内容类型和内容 SHA256 哈希决定
实现细节
- Python SDK:后台线程处理,实现非阻塞执行
- JS/TS SDK:异步、非阻塞实现
- 支持直接上传的 API(参见指南)
2. 媒体引用系统
Langfuse traces 中的 base64 data URI 和包装的 LangfuseMedia 对象被替换为对 mediaId 的引用,采用以下标准化 token 格式,这有助于在需要时重建原始负载:
@@@langfuseMedia:type={MIME_TYPE}|id={LANGFUSE_MEDIA_ID}|source={SOURCE_TYPE}@@@
MIME_TYPE:媒体文件的 MIME 类型,例如image/jpegLANGFUSE_MEDIA_ID:Langfuse 对象存储中媒体文件的 IDSOURCE_TYPE:媒体文件的源类型,可以是base64_data_uri、bytes或file
基于此 token,Langfuse UI 可以自动检测 mediaId 并内联渲染媒体文件。LangfuseMedia 类提供从引用字符串提取 mediaId 的实用函数。
对于多模态数据集,使用通过 SDK 做实验获取带已解析 LangfuseMediaReference 对象的数据集条目,并将媒体传递给你的模型提供商。
3. 解析媒体引用
当处理包含媒体引用的 traces、observations 或数据集条目时,你可以使用 Langfuse 客户端提供的 resolve_media_references 实用方法将它们转换回 base64 data URI 格式。这在微调、数据集运行或重放 generation 期间重新插入原始内容时特别有用。该实用方法遍历解析后的对象,并返回一个深拷贝,其中所有媒体引用字符串被替换为相应的 base64 data URI 表示。
from langfuse import get_client
# Initialize Langfuse client
langfuse = get_client()
# Example object with media references
obj = {
"image": "@@@langfuseMedia:type=image/jpeg|id=some-uuid|source=bytes@@@",
"nested": {
"pdf": "@@@langfuseMedia:type=application/pdf|id=some-other-uuid|source=bytes@@@"
}
}
# Resolve media references to base64 data URIs
resolved_obj = langfuse.resolve_media_references(
obj=obj,
resolve_with="base64_data_uri"
)
# Result:
# {
# "image": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
# "nested": {
# "pdf": "data:application/pdf;base64,JVBERi0xLjcK..."
# }
# }
from langfuse import Langfuse
# Initialize Langfuse client
langfuse = Langfuse()
# Example object with media references
obj = {
"image": "@@@langfuseMedia:type=image/jpeg|id=some-uuid|source=bytes@@@",
"nested": {
"pdf": "@@@langfuseMedia:type=application/pdf|id=some-other-uuid|source=bytes@@@"
}
}
# Resolve media references to base64 data URIs
resolved_trace = langfuse.resolve_media_references(
obj=obj,
resolve_with="base64_data_uri"
)
# Result:
# {
# "image": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
# "nested": {
# "pdf": "data:application/pdf;base64,JVBERi0xLjcK..."
# }
# }
import { LangfuseClient } from "@langfuse/client";
const langfuse = new LangfuseClient()
// Example object with media references
const obj = {
image: "@@@langfuseMedia:type=image/jpeg|id=some-uuid|source=bytes@@@",
nested: {
pdf: "@@@langfuseMedia:type=application/pdf|id=some-other-uuid|source=bytes@@@",
},
};
// Resolve media references to base64 data URIs
const resolvedTrace = await langfuse.resolveMediaReferences({
obj: obj,
resolveWith: "base64DataUri",
});
// Result:
// {
// image: "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
// nested: {
// pdf: "data:application/pdf;base64,JVBERi0xLjcK..."
// }
// }